question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Serializing monads

See original GitHub issue

Hi guys,

I have an unorthodox but really easy request. I hope you will find it reasonable enough.

It would be great if you could provide constants to access the data internals of Maybe and Result types (.value and .error properties).

Alternatively, you could add to the specs those data internals, so that if they change in the future, you consider it a breaking change and a SEMVER major release.

The reason is we need to deserialize monads and to do so we need to be coupled to these internals.

If you want more detail:

Context

We have a client with Redux that stores the app state in local storage, thus serializing all state. We want to store monads in the state. We know it is a bad practice to store classes in Redux, but Maybes and Results are data types that hold state, and they make much sense to be stored.

The Maybe and Result types serialize correctly to the following examples:

{variant: 'Just', value: 4}
{variant: 'Nothing'}
{variant: 'Ok', value: 4}
{variant: 'Err', error: 'hi!'}

We make our reducers detect the de-serialization action, and re-create the monads from the objects using Maybe.just(...), Maybe.nothing(), and so on.

The Problem

In order to de-serialize the monads, we need to be coupled to the object’s internals: .variant, .value, and .error.

The Variant property is well specified in your docs, and in fact we are using the lib’s constants Variant.Just, Variant.Nothing, etc. But the other internals are not specified (because they are internals), and as such are subject to possible change without notice.

If this change causes a major release, it allows this coupling because it is then our responsibility to keep our code consistent with the update. If these internals are exposed through a constant, then you can change them without provoking a breaking change.

Why not a deserialize method

Deserializing involves type refinement from input source, it is a whole other field in itself, and it can devolve into libraries as complex as io-ts, so in my humble opinion, it doesn’t make sense as a true-myth responsibility, but belonging to userland.

Thank you for your attention!

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:12 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
chriskrychocommented, Aug 20, 2019

Thanks for the great writeup! This is totally a use case we should support.

The obvious alternative that occurs to me, instead of making those invariants hold (in case we find a better/faster/lighter-weight way to do this in the future) is for us to supply a toJSON() method so that JSON.stringify() does the right thing, supplying sufficient information for serialization and deserialization.

class Just<T> {
  toJSON() {
    const { variant, value } = this;
    return { variant, value };
  }
}

class Nothing<T> {
  toJSON() {
    return { variant: this.variant };
  }
}

(And the same for Result.)

I think that would solve this in a way that would give nice public API that Just Works™ for the normal serialization/deserialization approach, while leaving private internals private. Thoughts?

1reaction
chriskrychocommented, Oct 9, 2019

Released in 3.1.0! Thanks again!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Serialize a program written in a free monad? - Stack Overflow
I would like to serialize small drawings in Rasterific to JSON. I want to serialize programs/drawing actions such as:
Read more >
Serialize a program written in a free monad? : r/haskell - Reddit
A free monad allows you to construct a tree -- an abstract syntax tree, where the branching factor is determined by the functor...
Read more >
The Remote Monad Design Pattern
This paper investigates the ways that monadic computations can be serialized for the purposes of being sent to remote locations for external execution....
Read more >
Refactoring with Monads - Typelevel
I'll start by giving an example function, operating on some nested data types. Then I'll explore some ways to break it into smaller...
Read more >
Towards monadic bidirectional serialization - Lysxia's blog
Serialization where import Control. ... eitherUP :: (Monad r, Applicative w) => UP r w Bool -> UP r w a -> UP...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found