Skip to content

Instantly share code, notes, and snippets.

@alphaKAI
Last active September 26, 2016 03:21
Show Gist options
  • Select an option

  • Save alphaKAI/21c1254357d66ae8ac08e66b24077a96 to your computer and use it in GitHub Desktop.

Select an option

Save alphaKAI/21c1254357d66ae8ac08e66b24077a96 to your computer and use it in GitHub Desktop.
Maybe Monad in D(I'm studying Haskell thus this code might have a lots of misunderstandings)
import std.traits,
std.conv;
/*
class Functor F where
fmap :: (A -> B) -> FA -> FB
*/
interface Functor(F) {
F fmap(AB = typeof((A _) => B.init), A, B)(AB, F);
}
/*
class Functor f => Applicative (f :: * -> *) where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
<*> is ap
*/
interface Applicative(F) : Functor!(Applicative!F) {
ReturnType!F _pure(A)(A);
F ap(AB = typeof((A _) => B.init), A, B)(AB, F);
}
enum MaybeState {
Nothing,
Just
}
/**
instance Functor Maybe where
fmap func (Just val) = Just (func val)
fmap func Nothing = Nothing
*/
class Maybe : Functor!Maybe, Applicative!Maybe {
MaybeState state;
this (MaybeState state) { this.state = state; }
// Is this code needed?
auto fmap(F)(F func) {
static if (this.state == MaybeState.Just) {
return cast(Just!(Parameters!F[0]))(this).fmap(func);
} else {
return cast(Nothing)(this).fmap(func);
}
}
static Just!T _pure(T)(T t) {
return new Just!T(t);
}
}
auto _pure(F, A)(A a) {
return F._pure(a);
}
A _pure(A)(A a) {
return a;
}
class Just(T) : Maybe, Applicative!(Just!T) {
T val;
this(T t) {
val = t;
super(MaybeState.Just);
}
Just!(ReturnType!F) fmap(F)(F func) { return new Just!(ReturnType!F)(func(this.val)); }
override string toString() { return "(Just!" ~ T.stringof ~ " " ~ val.to!string ~ ")"; }
// Applicative
auto ap(J: Just!X, X)(J just) if (isCallable!T) {
return new Just!(ReturnType!val)(val(just.val));
}
}
class Nothing : Maybe {
this() { super(MaybeState.Nothing); }
Nothing fmap(F)(F func) { return new Nothing; }
override string toString() { return "Nothing"; }
}
class Func(F) : Functor!F {
F f;
this(F f) { this.f = f; }
typeof (
(Parameters!R[0] x) => f(ReturnType!R.init)
) fmap(G: Func!R, R)(G g) {
return (Parameters!R[0] x) => f(g.f(x));
}
// Applicative
Just!(ReturnType!F) fmap(J: Just!E, E)(J j) {
return new Just!(ReturnType!F)(f(j.val));
}
override string toString() {
return Parameters!F[0].stringof ~ " -> " ~ ReturnType!F.stringof;
}
}
auto func(F)(F func) if (isCallable!F) {
return new Func!F(func);
}
// Utility Class(inspired from underscore.js)
static class _ {
static N delegate(N) plus(N)(N n) if (isNumeric!N) {
return (N m) => m + n;
}
static N delegate(N) mul(N)(N n) if (isNumeric!N) {
return (N m) => m * n;
}
}
// Helper Functions
auto just(T)(T t) { return new Just!T(t); }
auto nothing() { return new Nothing; }
/*
import Data.Char
import Control.Monad
numUpper x y s = do
guard $ length s == x + y
euard $ length (filter isDigit $ take x s) == x
guard $ length (filter isUpper $ drop x s) == y
Just s
*/
Maybe numUpper(int x, int y, string s) {
if (!(s.length == x + y)) {
return nothing;
}
import std.algorithm, std.range, std.ascii;
if (!((s.take(x).filter!(isDigit)).array.length == x)) {
return nothing;
}
if (!((s.drop(x).filter!(isUpper)).array.length == y)) {
return nothing;
}
return just(s);
}
class List(T) : Functor!(List!T) {
T[] list;
this(T[] list) { this.list = list; }
import std.algorithm, std.array, std.range;
auto fmap(F)(F func) if (isCallable!F && arity!func == 1) {
return new List!(ReturnType!F)(list.map!(x => func(x)).array);
}
auto ap(L: List!X, X)(L _list) if (isCallable!T && is(X == Parameters!T[0])) {
return new List!(ReturnType!T)(this.fmap(((T fun) => _list.fmap(fun))).list.map!(x => x.list).join);
}
override string toString() {
static if (isCallable!T) {
return "[" ~ list.map!(x => T.stringof).join(", ") ~ "]";
} else {
return "[" ~ list.map!(x => x.to!string).join(", ") ~ "]";
}
}
}
auto list(T...)() {
alias E = typeof(T[0]);
E[] _list;
foreach (e; T) {
_list ~= e;
}
return new List!E(_list);
}
// demo
import std.stdio;
void main() {
// The equivalent Haskell code is : fmap (+3) (Just 2)
just(2).fmap(_.plus(3)).writeln;
// ditto : fmap (+3) Nothing
nothing.fmap(_.plus(3)).writeln;
// ditto : :type (+3)
func(_.plus(3)).writeln;
// ditto : fmap (+3) (+2) $ 10
func(_.plus(3)).fmap(func(_.plus(2)))(10).writeln;
/*
print $ numUpper 3 2 "123AB"
print $ numUpper 3 2 "123ABC"
print $ numUpper 3 2 "12ABC"
*/
writeln(numUpper(3, 2, "123AB"));
writeln(numUpper(3, 2, "123ABC"));
writeln(numUpper(3, 2, "12ABC"));
// Applicative
// ditto : Just (+3) <*> Just 2
just(_.plus(3)).ap(just(2)).writeln;
// ditto : fmap (+3) [1, 2, 3]
list!(1, 2, 3).fmap(_.plus(3)).writeln;
// ditto : [(*2), (+3)] <*> [1, 2, 3]
list!((int x) => x * 2, (int x) => x + 3).ap(list!(1, 2, 3)).writeln;
// ditto : <$> (Just 5)
func((int x) => (int y) => x + y).fmap(just(5)).writeln;
// ditto : Just (+5) <*> (Just 3)
func((int x) => (int y) => x + y).fmap(just(5)).ap(just(3)).writeln;
}
@ncaq
Copy link

ncaq commented Sep 25, 2016

Maybeまでなら書いたことがあります(Functorは実装してません).
どこにも公開してなかったので,ここに供養(不法投棄?)しようと思います.
ご迷惑じゃなければ参考にしてください.

import std.stdio;

interface Maybe(T) {
    T fromMaybe(T x);
}

class Nothing(T) : Maybe!(T) {
    override T fromMaybe(T x) {
        return x;
    }
}

class Just(T) : Maybe!(T) {
    this(T x) {
        a = x;
    }
    override T fromMaybe(T x) {
        return a;
    }
    T a;
}

Maybe!(T) safeDiv(T)(T x, T y) {
    if(y == 0) {
        return new Nothing!(T)();
    }
    else {
        return new Just!(T)(x / y);
    }
}

void main() {
    writeln(safeDiv(1.0, 2.0).fromMaybe(0));
    writeln(safeDiv(1.0, 0.0).fromMaybe(0));
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment