The recently released
Seqes library offers functors to mix the
Stdlib.Seq abstraction with monads. The original impetus for development was the use of Lwt, result and Lwt+result monads in the octez code-base. The use of these monads in combination with
Seq introduced a lot of boilerplate code, which
Seqes aims to alleviate.
The Lwt “monad” (something something exceptions can break one of the monadic law) has one parameter. Thus the functor allowing to define a Seq+Lwt module is:
module Make1 (Mon: sig type 'a t val return : 'a -> 'a t val bind : 'a t -> ('a -> 'b t) -> 'b t end) : S1 with type 'a mon := 'a Mon.t = struct (* code here *) end
The Result monad has two parameters. Thus the functor for defining a Seq+Result module is:
module Make2 (Mon: sig type ('a, 'e) t val return : 'a -> ('a, 'e) t val bind : ('a. 'e) t -> ('a -> ('b, 'e) t) -> ('b, 'e) t end) : S2 with type ('a, 'e) mon := ('a, 'e) Mon.t = struct (* code here *) end
Interestingly, there is no difference in the code of the two functor apart from type definition.
Technically, it’s worse than just that:
- There is a (duplicated) functor for making traversors over the
- There is a (duplicated) functor as presented above.
- There is a (duplicated) functor inside the functor presented above formaking additional traversors.
But the observation is still valid: only the types differ, the control structures are 1-to-1 identical. The library is essentially fully duplicated: there’s a one-parameter version and two-parameter version.
Can I encode the arity of a type constructor in the type system and use that to deduplicate the code?
Of course once can pass a two-parameter monad as a one-parameter monad. The two-parameter functor will accept the following monad:
type ('a, 'e) t = 'a Lwt.t let return = Lwt.return let bind = Lwt.bind
But this returns a two-parameter Seq-like type.
I notice that the
higher_kinded libraries have a similar approach of duplicating the code for each arity of the type constructor. And I think that if there was a known trick it would be used in those libraries.
Anyone has examples? Ideas?
Alternatively, explanations as to why it’s not possible?