Closed youthyJJ closed 1 year ago
However, this code encounters compilation issues.
What is the compilation issue?
First, I created a class (Functor\<T>):
internal class Functor<T>
{
public readonly T t;
public Functor(T t) { this.t = t; }
}
Then, I added some extension functions to Functor\<T>:
// Pure
private static Functor<T> Pure<T>(T t) => new Functor<T>(t);
// Select
private static Functor<T2> Select<T1, T2>(
this Functor<T1> functor,
Func<T1, T2> f
) => Pure(f(functor.t));
Then I treated Functor\<Functor\<T>> as a Monad\<T> and added some extension functions to it:
// Flatten
private static Functor<T> Flatten<T>(this Functor<Functor<T>> monad) => monad.t;
// SelectMany
private static Functor<T2> SelectMany<T1, T2>(
this Functor<T1> functor,
Func<T1, Functor<T2>> f
) => functor.Select(f).Flatten();
Finally, I attempted to implement the Compose method:
private static Func<T, Functor<Functor<T2>>> Compose<T, T1, T2>(
this Func<T, Functor<Functor<T1>>> action1,
Func<T1, Functor<Functor<T2>>> action2
) => x => action1(x).SelectMany(action2);
My IDE (Rider) is giving me an error for SelectMany(action2)
in the code:
The type arguments for method 'Functor
SelectMany<T1,T2>(this Functor , Func<T1,Functor >)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
I had to change the code to the following form to avoid the error:
private static Func<T, Functor<Functor<T2>>> Compose<T, T1, T2>(
this Func<T, Functor<Functor<T1>>> action1,
Func<T1, Functor<Functor<T2>>> action2
) => x => action1(x) .SelectMany(f => f.SelectMany(action2) );
private static Func<T, Functor<Functor<T2>>> Compose<T, T1, T2>( this Func<T, Functor<Functor<T1>>> action1, Func<T1, Functor<Functor<T2>>> action2 ) => x => action1(x).SelectMany(action2);
You have nested functors there...
Oh! I see, I misunderstood!
After reading Flatting, I mistakenly thought that Monad
is just nested Functor
, so I used Functor<Functor<T>>
as Monad<T,>
which caused this issue.
I apologize for the inconvenience.
By the way, I feel that reading C# extension methods can be a bit cumbersome. I tried using Kotlin to express it, and writing example code with it is not only intuitive but also very concise 🤩 !
data class Monad<T>(val t: T)
fun <T> `return`(t: T) = Monad(t)
fun <T> Monad<T>.flatten() = t
fun <A, B> Monad<A>.flatMap(f: (A) -> Monad<B>): Monad<B> = f(flatten())
fun <A, B> Monad<A>.apply(f: Monad<(A) -> B>): Monad<B> = f.flatMap { `return`(it(t)) }
fun <A, B> Monad<A>.fmap(f: (A) -> B): Monad<B> = apply(`return`(f))
fun <T, T1, T2> ((T) -> Monad<T1>).compose(
f: (T1) -> Monad<T2>
): (T) -> Monad<T2> = { x -> this(x).flatMap(f) }
In Kleisli composition, the implementation of the
Compose
method seems to have a problem:The original code is as follows:
However, this code encounters compilation issues. I modified it to the following to make it compile successfully:
This modification allowed it to pass compilation.