Skip to content

Commit

Permalink
Prototyping
Browse files Browse the repository at this point in the history
  • Loading branch information
louthy committed Feb 25, 2025
1 parent dea8e26 commit 4a5719f
Show file tree
Hide file tree
Showing 31 changed files with 494 additions and 41 deletions.
13 changes: 13 additions & 0 deletions LanguageExt.Core/Deriving/Alternative.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using LanguageExt.Traits;

namespace LanguageExt;

public static partial class Deriving
{
public interface Alternative<Supertype, Subtype> :
Alternative<Supertype>,
Choice<Supertype, Subtype>,
MonoidK<Supertype, Subtype>
where Supertype : Alternative<Supertype, Subtype>
where Subtype : Alternative<Subtype>;
}
49 changes: 49 additions & 0 deletions LanguageExt.Core/Deriving/Applicative.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using LanguageExt.Async.Linq;
using LanguageExt.Traits;

namespace LanguageExt;

public static partial class Deriving
{
/// <summary>
/// Derived applicative functor implementation
/// </summary>
/// <typeparam name="Supertype">Super-type wrapper around the subtype</typeparam>
/// <typeparam name="Subtype">The subtype that the supertype type 'wraps'</typeparam>
public interface Applicative<Supertype, Subtype> :
Applicative<Supertype>,
Functor<Supertype, Subtype>
where Subtype : Applicative<Subtype>
where Supertype : Applicative<Supertype, Subtype>
{
static K<Supertype, A> Applicative<Supertype>.Pure<A>(A value) =>
Supertype.CoTransform(Subtype.Pure(value));

static K<Supertype, B> Applicative<Supertype>.Action<A, B>(K<Supertype, A> ma, K<Supertype, B> mb) =>
Supertype.CoTransform(Supertype.Transform(ma).Action(Supertype.Transform(mb)));

static K<Supertype, B> Applicative<Supertype>.Apply<A, B>(K<Supertype, Func<A, B>> mf, K<Supertype, A> ma) =>
Supertype.CoTransform(Supertype.Transform(mf).Apply(Supertype.Transform(ma)));

static K<Supertype, Func<B, C>> Applicative<Supertype>.Apply<A, B, C>(K<Supertype, Func<A, B, C>> mf, K<Supertype, A> ma) =>
Supertype.CoTransform(Supertype.Transform(mf).Apply(Supertype.Transform(ma)));

static K<Supertype, B> Applicative<Supertype>.ApplyLazy<A, B>(K<Supertype, Func<A, B>> mf, Func<K<Supertype, A>> ma) =>
Supertype.CoTransform(Supertype.Transform(mf).Apply(() => Supertype.Transform(ma())));

static K<Supertype, A> Applicative<Supertype>.Actions<A>(params K<Supertype, A>[] fas) =>
Supertype.CoTransform(fas.AsIterable().Map(Supertype.Transform).Actions());

static K<Supertype, A> Applicative<Supertype>.Actions<A>(Seq<K<Supertype, A>> fas) =>
Supertype.CoTransform(fas.Map(Supertype.Transform).Actions());

static K<Supertype, A> Applicative<Supertype>.Actions<A>(IEnumerable<K<Supertype, A>> fas) =>
Supertype.CoTransform(fas.Select(Supertype.Transform).Actions());

static K<Supertype, A> Applicative<Supertype>.Actions<A>(IAsyncEnumerable<K<Supertype, A>> fas) =>
Supertype.CoTransform(fas.Select(Supertype.Transform).Actions());
}
}
29 changes: 29 additions & 0 deletions LanguageExt.Core/Deriving/Choice.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using LanguageExt.Traits;

namespace LanguageExt;

public static partial class Deriving
{
/// <summary>
/// A semigroup on applicative functors
/// </summary>
public interface Choice<Supertype, Subtype> :
Choice<Supertype>,
Applicative<Supertype, Subtype>,
SemigroupK<Supertype, Subtype>
where Supertype : Choice<Supertype, Subtype>
where Subtype : Choice<Subtype>
{
/// <summary>
/// Where `Supertype` defines some notion of failure or choice, this function picks
/// the first argument that succeeds. So, if `fa` succeeds, then `fa` is returned;
/// if it fails, then `fb` is returned.
/// </summary>
/// <param name="fa">First structure to test</param>
/// <param name="fb">Second structure to return if the first one fails</param>
/// <typeparam name="A">Bound value type</typeparam>
/// <returns>First argument to succeed</returns>
static K<Supertype, A> Choice<Supertype>.Choose<A>(K<Supertype, A> fa, K<Supertype, A> fb) =>
Supertype.CoTransform(Supertype.Transform(fa).Choose(Supertype.Transform(fb)));
}
}
58 changes: 58 additions & 0 deletions LanguageExt.Core/Deriving/Fallible.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;
using LanguageExt.Common;
using LanguageExt.Traits;

namespace LanguageExt;

public static partial class Deriving
{
/// <summary>
/// Trait for higher-kinded structures that have a failure state `E`
/// </summary>
public interface Fallible<E, Supertype, Subtype> :
Traits.Fallible<E, Supertype>
where Supertype :
Fallible<E, Supertype, Subtype>,
Traits.Fallible<E, Supertype>,
Natural<Supertype, Subtype>,
CoNatural<Supertype, Subtype>
where Subtype : Traits.Fallible<E, Subtype>
{
/// <summary>
/// Raise a failure state in the `Fallible` structure `F`
/// </summary>
/// <param name="error">Error value</param>
/// <typeparam name="A">Bound value type</typeparam>
/// <returns></returns>
static K<Supertype, A> Traits.Fallible<E, Supertype>.Fail<A>(E error) =>
Supertype.CoTransform(Subtype.Fail<A>(error));

/// <summary>
/// Run the `Fallible` structure. If in a failed state, test the failure value
/// against the predicate. If, it returns `true`, run the `Fail` function with
/// the failure value.
/// </summary>
/// <param name="fa">`Fallible` structure</param>
/// <param name="Predicate">Predicate to test any failure values</param>
/// <param name="Fail">Handler when in failed state</param>
/// <typeparam name="A">Bound value type</typeparam>
/// <returns>Either `fa` or the result of `Fail` if `fa` is in a failed state and the
/// predicate returns true for the failure value</returns>
static K<Supertype, A> Traits.Fallible<E, Supertype>.Catch<A>(
K<Supertype, A> fa,
Func<E, bool> Predicate,
Func<E, K<Supertype, A>> Fail) =>
Supertype.CoTransform(Supertype.Transform(fa).Catch(Predicate, e => Supertype.Transform(Fail(e))));
}

/// <summary>
/// Trait for higher-kinded structures that have a failure state `E`
/// </summary>
public interface Fallible<Supertype, Subtype> :
Fallible<Error, Supertype, Subtype>
where Supertype :
Fallible<Error, Supertype, Subtype>,
Natural<Supertype, Subtype>,
CoNatural<Supertype, Subtype>
where Subtype : Traits.Fallible<Error, Subtype>;
}
31 changes: 31 additions & 0 deletions LanguageExt.Core/Deriving/Functor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using LanguageExt.Traits;

namespace LanguageExt;

public static partial class Deriving
{
/// <summary>
/// Derived functor implementation
/// </summary>
/// <typeparam name="Supertype">Super-type wrapper around the subtype</typeparam>
/// <typeparam name="Subtype">The subtype that the supertype type 'wraps'</typeparam>
public interface Functor<Supertype, Subtype> :
Functor<Supertype>,
Natural<Supertype, Subtype>,
CoNatural<Supertype, Subtype>
where Subtype : Functor<Subtype>
where Supertype : Functor<Supertype, Subtype>
{
/// <summary>
/// Functor map operation
/// </summary>
/// <param name="f">Mapping function</param>
/// <param name="ma">Functor structure to map</param>
/// <typeparam name="A">Input bound value type</typeparam>
/// <typeparam name="B">Output bound value type</typeparam>
/// <returns>Mapped functor</returns>
static K<Supertype, B> Functor<Supertype>.Map<A, B>(Func<A, B> f, K<Supertype, A> ma) =>
Supertype.CoTransform(Supertype.Transform(ma).Map(f));
}
}
31 changes: 31 additions & 0 deletions LanguageExt.Core/Deriving/Monad.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using LanguageExt.Traits;

namespace LanguageExt;

public static partial class Deriving
{
/// <summary>
/// Derived monad implementation
/// </summary>
/// <typeparam name="Supertype">Super-type wrapper around the subtype</typeparam>
/// <typeparam name="Subtype">The subtype that the supertype type 'wraps'</typeparam>
public interface Monad<Supertype, Subtype> :
MonadIO<Supertype, Subtype>,
Applicative<Supertype, Subtype>,
Monad<Supertype>
where Subtype : Monad<Subtype>
where Supertype : Monad<Supertype, Subtype>
{
/// <summary>
/// Monad bind operation. Chains two operations together in sequence.
/// </summary>
/// <param name="ma">First monad to run</param>
/// <param name="f">Bind function that yields the second monad to run</param>
/// <typeparam name="A">Input bound value type</typeparam>
/// <typeparam name="B">Output bound value type</typeparam>
/// <returns>Composed chained monad operation</returns>
static K<Supertype, B> Monad<Supertype>.Bind<A, B>(K<Supertype, A> ma, Func<A, K<Supertype, B>> f) =>
Supertype.CoTransform(Supertype.Transform(ma).Bind(x => Supertype.Transform(f(x))));
}
}
68 changes: 68 additions & 0 deletions LanguageExt.Core/Deriving/MonadIO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using LanguageExt.Common;
using LanguageExt.Traits;

namespace LanguageExt;

public static partial class Deriving
{
/// <summary>
/// Derived `MonadIO` implementation
/// </summary>
/// <typeparam name="Supertype">Super-type wrapper around the subtype</typeparam>
/// <typeparam name="Subtype">The subtype that the supertype type 'wraps'</typeparam>
public interface MonadIO<Supertype, Subtype> :
MonadIO<Supertype>,
Natural<Supertype, Subtype>,
CoNatural<Supertype, Subtype>
where Subtype : MonadIO<Subtype>, Monad<Subtype>
where Supertype : MonadIO<Supertype, Subtype>, Monad<Supertype>
{
/// <summary>
/// Lift an IO operation into the `Self` monad
/// </summary>
/// <param name="ma">IO structure to lift</param>
/// <typeparam name="A">Bound value type</typeparam>
/// <returns>Monad with an `IO` structure lifted into it</returns>
/// <exception cref="ExceptionalException">If this method isn't overloaded in
/// the inner monad or any monad in the stack on the way to the inner monad
/// then it will throw an exception.</exception>
static K<Supertype, A> MonadIO<Supertype>.LiftIO<A>(K<IO, A> ma) =>
Supertype.CoTransform(Subtype.LiftIO(ma));

/// <summary>
/// Lift an IO operation into the `Self` monad
/// </summary>
/// <param name="ma">IO structure to lift</param>
/// <typeparam name="A">Bound value type</typeparam>
/// <returns>Monad with an `IO` structure lifted into it</returns>
/// <exception cref="ExceptionalException">If this method isn't overloaded in
/// the inner monad or any monad in the stack on the way to the inner monad
/// then it will throw an exception.</exception>
static K<Supertype, A> MonadIO<Supertype>.LiftIO<A>(IO<A> ma) =>
Supertype.CoTransform(Subtype.LiftIO(ma));

/// <summary>
/// Extract the inner `IO` monad from the `Self` structure provided
/// </summary>
/// <param name="ma">`Self` structure to extract the `IO` monad from</param>
/// <typeparam name="A">Bound value type</typeparam>
/// <returns>`Self` structure with the `IO` structure as the bound value</returns>
static K<Supertype, IO<A>> MonadIO<Supertype>.ToIO<A>(K<Supertype, A> ma) =>
Supertype.CoTransform(Supertype.Transform(ma).ToIO());

/// <summary>
/// Map the inner `IO` monad within the `Self` structure provided
/// </summary>
/// <param name="ma">`Self` structure to extract the `IO` monad from</param>
/// <param name="f">`IO` structure mapping function</param>
/// <typeparam name="A">Input bound value type</typeparam>
/// <typeparam name="B">Output bound value type</typeparam>
/// <returns>`Self` structure that has had its inner `IO` monad mapped</returns>
/// <exception cref="ExceptionalException">If this method isn't overloaded in
/// the inner monad or any monad in the stack on the way to the inner monad
/// then it will throw an exception.</exception>
static K<Supertype, B> MonadIO<Supertype>.MapIO<A, B>(K<Supertype, A> ma, Func<IO<A>, IO<B>> f) =>
Supertype.CoTransform(Supertype.Transform(ma).MapIO(f));
}
}
24 changes: 24 additions & 0 deletions LanguageExt.Core/Deriving/MonoidK.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using LanguageExt.Traits;

namespace LanguageExt;

public static partial class Deriving
{
/// <summary>
/// A monoid for higher-kinds
/// </summary>
/// <typeparam name="M">Higher kind</typeparam>
public interface MonoidK<Supertype, Subtype> :
MonoidK<Supertype>,
SemigroupK<Supertype, Subtype>
where Supertype : MonoidK<Supertype, Subtype>
where Subtype : MonoidK<Subtype>
{
/// <summary>
/// Identity
/// </summary>
static K<Supertype, A> MonoidK<Supertype>.Empty<A>() =>
Supertype.CoTransform(Subtype.Empty<A>());
}
}

30 changes: 30 additions & 0 deletions LanguageExt.Core/Deriving/Readable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using LanguageExt.Traits;

namespace LanguageExt;

public static partial class Deriving
{
/// <summary>
/// Derived `Readable` implementation
/// </summary>
/// <typeparam name="Supertype">Super-type wrapper around the subtype</typeparam>
/// <typeparam name="Env">Reader environment</typeparam>
/// <typeparam name="Subtype">The subtype that the supertype type 'wraps'</typeparam>
public interface Readable<Supertype, Env, Subtype> :
Readable<Supertype, Env>,
Natural<Supertype, Subtype>,
CoNatural<Supertype, Subtype>
where Supertype : Readable<Supertype, Env, Subtype>, Readable<Supertype, Env>
where Subtype : Readable<Subtype, Env>
{
static K<Supertype, Env> Readable<Supertype, Env>.Ask =>
Supertype.CoTransform(Subtype.Ask);

static K<Supertype, A> Readable<Supertype, Env>.Asks<A>(Func<Env, A> f) =>
Supertype.CoTransform(Subtype.Asks(f));

static K<Supertype, A> Readable<Supertype, Env>.Local<A>(Func<Env, Env> f, K<Supertype, A> ma) =>
Supertype.CoTransform(Supertype.Transform(ma).Local(f));
}
}
27 changes: 27 additions & 0 deletions LanguageExt.Core/Deriving/SemigroupK.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using LanguageExt.Traits;

namespace LanguageExt;

public static partial class Deriving
{
/// <summary>
/// Derived equivalent of semigroups for working with higher-kinded types
/// </summary>
public interface SemigroupK<Supertype, Subtype> :
SemigroupK<Supertype>,
Natural<Supertype, Subtype>,
CoNatural<Supertype, Subtype>
where Supertype : SemigroupK<Supertype, Subtype>
where Subtype : SemigroupK<Subtype>
{
/// <summary>
/// An associative binary operation.
/// </summary>
/// <param name="lhs">The first operand to the operation</param>
/// <param name="rhs">The second operand to the operation</param>
/// <returns>The result of the operation</returns>
static K<Supertype, A> SemigroupK<Supertype>.Combine<A>(K<Supertype, A> lhs, K<Supertype, A> rhs) =>
Supertype.CoTransform(Supertype.Transform(lhs).Combine(Supertype.Transform(rhs)));
}
}

3 changes: 3 additions & 0 deletions LanguageExt.Core/Effects/Eff/Eff no runtime/Eff.Monad.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,7 @@ static K<Eff, A> Fallible<Error, Eff>.Catch<A>(
K<Eff, A> fa, Func<Error, bool> Predicate,
Func<Error, K<Eff, A>> Fail) =>
new Eff<A>(fa.As().effect.Catch(Predicate, e => Fail(e).As().effect).As());

static K<Eff, A> SemigroupK<Eff>.Combine<A>(K<Eff, A> lhs, K<Eff, A> rhs) =>
lhs.Choose(rhs);
}
Loading

0 comments on commit 4a5719f

Please sign in to comment.