Perry
Perry

Reputation: 528

typedef for map from M<A> to M<B>

I'm working on a learning library for Dart called "dfunct" and trying to convey a function that takes a Wrapped A (Ma) and returns a Wrapped B (Mb) after applying a function from A to B while ensuring that the type of wrapper is the same.

These two examples would be well suited I think but both trigger warnings.

typedef R Func1<T, R>(T input); // <-- included for completeness but not related

typedef M<B> Lift<M extends Monad, A, B>(M<A> source, Func1<A, B> map);
typedef Mb Lift<M extends Monad, Ma extends M<A>, A, Mb extends M<B>, B>(Ma source, Func1<A, B> map);

-- I'm making due with a less expressive variant in the mean time but it lacks any type guards against say 'M of B' being provided as the source and also doesn't guard the result of 'M of B' in the implementation:

typedef M Lift<M extends Monad, A, B>(M source, Func1<A, B> map);

-- Wondering if there is another way to express this that I'm missing... ?

Upvotes: 0

Views: 316

Answers (1)

Both of these are incorrect:

typedef M<B> Lift<M extends Monad, A, B>(M<A> source, Func1<A, B> map);
typedef Mb Lift<M extends Monad, Ma extends M<A>, A, Mb extends M<B>, B>(Ma source, Func1<A, B> map);

The problem is that you're saying that M is a type variable, and type variables take no type arguments. So you cannot write:

M<A>

Why is that? The short answer is that the actual value of M might be a subclass of Monad that doesn't have type parameters (or has more type parameters than Monad).

So the "best" type you can express is:

typedef R Lift<A, B, M extends Monad<A>, R extends Monad<B>>(M source, Func1<A, B> map);

My recommendation is to not attempt this. This would be much easier to use:

typedef Monad<B> Lift<A, B>(Monad<A> source, Func1<A, B> map);

Notice that the type rules in Dart are sufficiently lax that this will allow you to use any subclass of Monad.

Upvotes: 1

Related Questions