Last active
September 26, 2025 15:34
-
-
Save micmarsh/812184999bcbbc10bac989504c1d30c5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Requires LanguageExt V5 | |
| using LanguageExt; | |
| using LanguageExt.Traits; | |
| namespace Kleisli; | |
| public readonly record struct Kleisli<M, A, B>(Func<A, K<M, B>> Invoke) : K<Kleisli<M, A>, B>, K<CoKleisli<M, B>, A> | |
| where M : Monad<M> | |
| { | |
| public Kleisli<M, A, C> ComposeK<C>(Kleisli<M, B, C> next) | |
| { | |
| var self = this; | |
| return new (a => self.Invoke(a).Bind(next.Invoke)); | |
| } | |
| public Kleisli<M, A, C> ComposeK<C>(Func<B, K<M, C>> next) | |
| { | |
| var self = this; | |
| return new (a => self.Invoke(a).Bind(next)); | |
| } | |
| public static Kleisli<M, A, B> operator >> (Kleisli<M, A, B> lhs, Kleisli<M, B, B> rhs) => | |
| lhs.ComposeK(rhs); | |
| public static Kleisli<M, A, B> operator >> (Kleisli<M, A, B> lhs, Func<B, K<M, B>> rhs) => | |
| lhs.ComposeK(rhs); | |
| public Kleisli<M, A, C> Map<C>(Func<B, C> f) | |
| { | |
| var ma = this; | |
| return new Kleisli<M, A, C>(a => ma.Invoke(a).Map(f)); | |
| } | |
| public static Kleisli<M, A, B> Pure(B value) => new Kleisli<M, A, B>(_ => M.Pure(value)); | |
| public Kleisli<M, A, C> Apply<C>(Kleisli<M, A, Func<B, C>> mf) | |
| { | |
| var ma = this; | |
| return new Kleisli<M, A, C>(a => mf.Invoke(a).Apply(ma.Invoke(a))); | |
| } | |
| public Kleisli<M, A, C> Bind<C>(Func<B, Kleisli<M, A, C>> f) | |
| { | |
| var ma = this; | |
| return new Kleisli<M, A, C>(a => ma.Invoke(a).Bind(a1 => f(a1).Invoke(a))); | |
| } | |
| public Kleisli<M, C, B> Comap<C>(Func<C, A> f) | |
| { | |
| var ma = this; | |
| return new Kleisli<M, C, B>(c => ma.Invoke(f(c))); | |
| } | |
| } | |
| public static class KleisliExt | |
| { | |
| public static Kleisli<M, A, B> As<M, A, B>(this K<Kleisli<M, A>, B> ma) | |
| where M : Monad<M> | |
| => (Kleisli<M, A, B>)ma; | |
| public static Kleisli<M, A, B> As<M, A, B>(this K<CoKleisli<M, B>, A> ma) | |
| where M : Monad<M> | |
| => (Kleisli<M, A, B>)ma; | |
| public static K<Kleisli<M, A>, B> Kind<M, A, B>(this Kleisli<M, A, B> ma) where M : Monad<M> => ma; | |
| public static K<CoKleisli<M, B>, A> Co<M, A, B>(this Kleisli<M, A, B> ma) where M : Monad<M> => ma; | |
| public static K<CoKleisli<M, B>, A> Co<M, A, B>(this K<Kleisli<M, A>, B> ma) where M : Monad<M> => ma.As(); | |
| public static Kleisli<M, A, C> ComposeK<M, A, B, C>(this Func<A, K<M, B>> fb, Func<B, K<M, C>> fc) | |
| where M : Monad<M> => | |
| new Kleisli<M, A, B>(fb).ComposeK(fc); | |
| public static Kleisli<M, A, C> ComposeK<M, A, B, C>(this Func<A, K<M, B>> fb, Kleisli<M, B, C> fc) | |
| where M : Monad<M> => | |
| new Kleisli<M, A, B>(fb).ComposeK(fc); | |
| } | |
| public class Kleisli<M, A> : Monad<Kleisli<M, A>> | |
| where M : Monad<M> | |
| { | |
| public static K<Kleisli<M, A>, C> Map<B, C>(Func<B, C> f, K<Kleisli<M, A>, B> ma) => ma.As().Map(f); | |
| public static K<Kleisli<M, A>, B> Pure<B>(B value) => Kleisli<M, A, B>.Pure(value); | |
| public static K<Kleisli<M, A>, C> Apply<B, C>(K<Kleisli<M, A>, Func<B, C>> mf, K<Kleisli<M, A>, B> ma) => | |
| ma.As().Apply(mf.As()); | |
| public static K<Kleisli<M, A>, C> Bind<B, C>(K<Kleisli<M, A>, B> ma, Func<B, K<Kleisli<M, A>, C>> f) => | |
| ma.As().Bind(a => f(a).As()); | |
| } | |
| public class CoKleisli<M, B> : Cofunctor<CoKleisli<M, B>> | |
| where M : Monad<M> | |
| { | |
| public static K<CoKleisli<M, B>, A> Comap<A, C>(Func<A, C> f, K<CoKleisli<M, B>, C> fb) => fb.As().Comap(f); | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment