Έχουν δημοσιευτεί
Κυριακή, 25 Οκτωβρίου 2009 5:34 μμ
από το μέλος
PALLADIN
Τον τελευταίο καιρό ψάχνω κάποιο φορμαλισμό (σε C#) ώστε να μπορέσω να έχω έναν generic-reusable ορισμό ενός Monad.
Αυτό που λείπει από τα .Net generics είναι η δυνατότητα να έχω abstraction σε επίπεδο Type Constructor.
Σαν παράδειγμα της συγκεκριμένης αφαίρεσης, παρουσιάζω τον generic ορισμό ενός Monad μέσα από δυο αγαπημένες μου γλώσσες.
Haskell
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
Scala
class Monad[M[_]] {
def unit[T](a: T): M[T]
def bind[T, K](m: M[T], f: T => M[K]): M[K]
}
Μετά από αρκετό πειραματισμό και μελέτη, κατέληξα στον παρακάτω κώδικα.
abstract class Monad<T, M> where M : MonadDef<M> { }
abstract class MonadDef<M> where M : MonadDef<M>
{
public abstract Monad<T, M> Unit<T>(T value);
public abstract Monad<S, M> Bind<T, S>(Monad<T, M> monad, Func<T, Monad<S, M>> func);
public Monad<S, M> Then<T, S>(Monad<T, M> first, Monad<S, M> second)
{
return Bind(first, _ => second);
}
public Monad<S, M> Map<T, S>(Monad<T, M> monad, Func<T, S> f)
{
return Bind(monad, value => Unit(f(value)));
}
public Monad<T, M> Join<T>(Monad<Monad<T, M>, M> monad)
{
return Bind(monad, value => value);
}
}
// Maybe Monad implementation
abstract class Maybe<T> : Monad<T, MaybeDef>
{
}
sealed class Just<T> : Maybe<T>
{
public T Value { private set; get; }
public Just(T value) { Value = value; }
}
sealed class Nothing<T> : Maybe<T> { }
static class MaybeMonadExtensions
{
public static Maybe<T> ToMaybe<T>(this Monad<T, MaybeDef> monad)
{
return (Maybe<T>)monad;
}
}
sealed class MaybeDef : MonadDef<MaybeDef>
{
public override Monad<T, MaybeDef> Unit<T>(T value)
{
return new Just<T>(value);
}
public override Monad<S, MaybeDef> Bind<T, S>(Monad<T, MaybeDef> monad, Func<T, Monad<S, MaybeDef>> f)
{
Just<T> just = monad as Just<T>;
if (just != null)
return f(just.Value);
else
return new Nothing<S>();
}
}
static void Main(string[] args)
{
var def = new MaybeDef();
Maybe<string> result = def.Bind(def.Unit(42), value => def.Unit(value.ToString())).ToMaybe();
}