-
Notifications
You must be signed in to change notification settings - Fork 18
Description
This is purely for discussion/passing consideration, but I was poking around with the code, and I noticed it might be interesting to define a type for the decoder function Js.Json.t => M.t('a)
One way to do it would be like this (the type annotations were for me - you can leave them out):
// inside DecodeBase
type t('a) =
| Decoder(Js.Json.t => M.t('a));
// run function to apply the json input and produce the M result
let run: (Js.Json.t, t('a)) => M.t('a) =
(json, Decoder(decode)) => decode(json);
module Functor: FUNCTOR with type t('a) = t('a) = {
type nonrec t('a) = t('a);
let map = (f, Decoder(decode)) => Decoder(decode >> M.map(f));
};
module Apply: APPLY with type t('a) = t('a) = {
include Functor;
let apply: (t('a => 'b), t('a)) => t('b) =
(Decoder(f), Decoder(decode)) =>
Decoder(json => M.apply(f(json), decode(json)));
};
module Applicative: APPLICATIVE with type t('a) = t('a) = {
include Apply;
let pure = a => Decoder(_ => M.pure(a));
};
module Monad: MONAD with type t('a) = t('a) = {
include Applicative;
let flat_map: (t('a), 'a => t('b)) => t('b) =
(Decoder(decode), f) =>
Decoder(json => M.flat_map(decode(json), a => f(a) |> run(json)));
};
// ... etcAnother way would be to leave out the data constructor Decoder and just make it an alias. I don't think you'd have to change much at all if you just did this.
type t('a) = Js.Json.t => M.t('a);Doing that kind of cleans up the signatures for map/apply/bind/etc, and makes the implementations maybe a little more clear in that the Js.Json.t => M.t('a) bit would be hidden inside a type, rather than repeated. It might also make it more obvious what your core decoder type is for those new to the library - at its core it's just a Js.Json.t => M.t('a) function.
I'd also point out that the decoder function 'a => M.t('b) is basically the same as the definition of ReaderT. https://github.com/reazen/relude/blob/master/src/Relude_ReaderT.re#L10 - there might be some things to reuse from Relude or some general ideas that might come out of that. ReaderT is an abstraction where you can compose functions that will eventually be supplied some "environment" value in order to run and produce the result. In this case the "environment" is the json value.