Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Monoidal messages with QualifiedDo #28

Open
chshersh opened this issue Sep 14, 2018 · 2 comments
Open

[RFC] Monoidal messages with QualifiedDo #28

chshersh opened this issue Sep 14, 2018 · 2 comments

Comments

@chshersh
Copy link
Member

@chshersh chshersh commented Sep 14, 2018

This is required for extend function. Would be interesting (but difficult) think on the way how to make Message data type extensible as well.

@chshersh chshersh changed the title Think on the way to make Message data type monoid Think on the way to make Message data type Semigroup Sep 14, 2018
@chshersh
Copy link
Member Author

@chshersh chshersh commented Sep 21, 2018

I think we can reuse typerep-map for this problem as well.
But this will be possible only after this issue is done:

Currently we have:

data Message = Message
    { messageSeverity :: !Severity
    , messageStack    :: !CallStack
    , messageText     :: !Text
    }

data RichMessage (m :: Type -> Type) = RichMessage
    { richMessageMsg :: !Message
    , richMessageMap :: !(FieldMap m)
    }

What I propose is to perform the following refactoring:

data Message m = Message
    { messagePure :: FieldMap Identity  -- but here should be Map from containers
    , messageRich :: FieldMap m  -- and here is still array
    }

We can construct and perform <> operation faster on FieldMap based on containers but lookup is faster for array solution. So for IO actions configured only once at the start it's better to use array solution while for pure messages it's better to use containers.

The generalisation is easy, we only need to add couple extra instances for FieldType type family. But the coolest thing that with OverloadedLabels we have generalised interface for extensible messages!

Currently we do:

log Debug "Some text..."

If we want to add extra argument to log, it will be painful breaking change. And current Message is hardcoded, it's not configurable. co-log library is not that extensible, for now it's just a basic implementation. But if we have typerep-map we can write this:

log [ #severity Debug, #msg "Some Text" ]

So it's completely extensible and users can do whatever they want with the library! But the cost is more verbose logging call. But I hope that with OverloadedLabels it's not that verbose...

Loading

@chshersh chshersh assigned chshersh and unassigned chshersh May 2, 2019
@chshersh chshersh pinned this issue Jun 4, 2020
@chshersh chshersh changed the title Think on the way to make Message data type Semigroup [RFC] Monoidal messages with QualifiedDo Aug 21, 2020
@chshersh
Copy link
Member Author

@chshersh chshersh commented Aug 21, 2020

I finally found an acceptable solution to this problem! Since GHC 9.0 we can use QualifiedDo to have a fast and type-safe interface. The obvious monoid I was looking for is Builder. So having #93 implemented first will be a huge step forward. With QualifiedDo we can implement our custom >>= which behaves like <> but also changes type-level tags, so we can be sure that all fields are specified. Usage can look like this:

log $ Message.do
    severityB Debug
    userIdB userId

Once Structured logging is implemented, we will get messages-as-monoids for free, since in structured logging messages are key-value maps. But this QualifiedDo approach is something to keep in mind for future interface improvements.

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants