-
-
Save divyang4481/08dd11fcb37b125f60b3db284ef4a5b9 to your computer and use it in GitHub Desktop.
This file contains 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
// Stuff needed to make C# a kind of cluttered subtyping Haskell: | |
// - Higher kinded polymorphism (being able to pass Generic Type Definitions as type parameters) | |
// - Static interfaces & static abstract types (this gets quite perverse at the CLR level) | |
// - GADTS (easily implemented as syntactic sugar) | |
namespace HKP { | |
public static A<B> Create<A, B>() where A : <>, new() { | |
return new A<B>(); // Can't do a whole lot of useful things here, since we know little about TFn | |
} | |
// Assuming arbitrary ctor constraints get implemented | |
public static A<B> Create<A, B>(B b) where A : <>, new(B) { | |
return new A<B>(b); // much better | |
} | |
// Assuming ctor constraints and subtyping constraints on open types | |
public static A<C, B> Swap<A, B, C>(A<B, C> abc) | |
where A : <,>, ITuple<,>, new(B, C) | |
{ | |
var b = abc.Item1; | |
var c = abc.Item2; | |
var acb = new(c, b); | |
return acb; | |
} | |
} | |
public interface ITuple<T, U> { | |
T Item1 { get; } | |
U Item2 { get; } | |
} | |
} | |
namespace StaticInterfaces { | |
public static interface ILinqyMonad<T> where T : <> { | |
T<A> Create<A>(); | |
T<B> Select<A, B>(this T<A> ta, Func<A, N> f); | |
T<B> SelectMany<A, B>(this T<A> ta, Func<A, T<B>> f); | |
} | |
public static class Linq : ILinqyMonad<IEnumerable<>> { | |
public static IEnumerable<A> Create<A>() { | |
... | |
} | |
public static IEnumerable<B> Select<A, B>(this IEnumerable<A> ta, Func<A, N> f) { | |
... | |
} | |
public static IEnumerable<B> SelectMany<A, B>(this IEnumerable<A> ta, Func<A, IEnumerable<B>> f) { | |
... | |
} | |
} | |
// Static members of interfaces are only useful to constrain generic types | |
public static class UsageExample { | |
public static A<B> Foo<T, A, B>() | |
where T : ILinqyMonad<A> | |
where A : <> | |
{ | |
return T.Create<B>(); | |
} | |
public static void Main() { | |
IEnumerable<int> lst = Foo<Linq, IEnumerable, int>(); // Type inference would be nice here :( | |
} | |
} | |
} | |
// Wait, this looks like.. | |
namespace Prelude { | |
public static interface IFunctor<F> | |
where F : <> { | |
F<B> FMap<A, B>(F<A> fa, Func<A, B> f); | |
} | |
public static interface IMonad<M> : IFunctor<M> | |
where M : <> { | |
M<A> Return<A>(A a); | |
M<B> Bind<A, B>(M<A> ma, Func<A, M<B>> f); | |
} | |
public abstract static class MonadBase<M> : IMonad<M> | |
where M : <> { | |
// FMap implemented generally for all monads <3 | |
public static M<B> FMap<A, B>(this M<A> ma, Func<A, B> f) | |
{ | |
return ma.Bind(a => Return(f(a)); | |
} | |
public abstract static M<A> Return<A>(A a); | |
public abstract static M<B> Bind<A, B>(M<A> ma, Func<A, M<B>> f); | |
} | |
public data Maybe<T> { | |
Just(T t); | |
Nothing; | |
} | |
public static class Maybe : MonadBase<Maybe<>> { | |
// Specialization time | |
public static override Maybe<B> FMap<A, B>(this M<A> ma, Func<A, B> f) { | |
switch(ma) { | |
case Just(a): | |
return Just(f(b)); | |
default: | |
return Nothing; | |
} | |
} | |
public static Maybe<A> Return<A>(A a) { | |
return Just(a); | |
} | |
public static Maybe<B> Bind<A, B>(this Maybe<A> ma, Func<A, Maybe<B>> f) { | |
switch(ma) { | |
case Just(a): | |
return f(a); | |
default: | |
return Nothing; | |
} | |
} | |
} | |
} | |
public class Program { | |
using Prelude.Maybe; // imports Return, Bind and FMap | |
using Prelude.Maybe<T>; // imports Just and Nothing | |
public static void Main() { | |
Maybe<string> mfoo = Prelude.Maybe.Return<string>("Foo"); | |
Maybe<string> mbar = Prelude.Maybe.Return<string>("Bar"); | |
Maybe<string mfoobar = Prelude.Maybe.Bind<string>( | |
mfoo, | |
new Func<string, Maybe<string>>(foo => | |
Prelude.Maybe.Bind<string>( | |
mbar, | |
new Func<string, Maybe<string>>( | |
bar => | |
Prelude.Maybe<string>.Just(foo + bar))))); | |
// with type inference | |
var mx = Return(6); | |
var my = Return(3); | |
// results in z === Just(2) | |
var z = Bind(mx, x => | |
Bind(my, y => | |
Return(x / y))); | |
var x = Just(5).Bind(y => Just(y * y)) | |
.Bind(y => y > 5 ? Just(y) : Nothing) | |
.FMap(y => y.ToString()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment