Maybe Java りたーんず 〜 Java で Maybe を書いてみた
モナド則を満たすものがやっとできた。
定義
interface Function<T, R> { public R eval(T arg); } abstract class Monad<T, M> { public abstract <R extends M> R bind(Function<T, R> func); } abstract class Maybe<T> extends Monad<T, Maybe<?>> { public static <T> Maybe<T> unit(T value) { return new Just<T>(value); } } class Just<T> extends Maybe<T> { private final T value; public Just(T value) { this.value = value; } @Override public <R extends Maybe<?>> R bind(Function<T, R> func) { return func.eval(value); } @Override public String toString() { return String.format("Just(%s)", value); } } class Nothing extends Maybe<Object> { @Override @SuppressWarnings("unchecked") public <R extends Maybe<?>> R bind(Function<Object, R> func) { return (R) this; } @Override public String toString() { return "Nothing"; } }
用意するものは次の3個の関数。
Function<Integer, Maybe<Integer>> inc = new Function<Integer, Maybe<Integer>>() { public Maybe<Integer> eval(Integer arg) { return Maybe.unit(arg + 1); } }; Function<Integer, Maybe<String>> tostr = new Function<Integer, Maybe<String>>() { public Maybe<String> eval(Integer arg) { return Maybe.unit("num = " + arg.toString()); } }; Function<Integer, Maybe<Integer>> ret = new Function<Integer, Maybe<Integer>>() { public Maybe<Integer> eval(Integer arg) { return Maybe.unit(arg); } };
検証
モナド則を検証していく。まずは「(unit x) >>= f == f x」から。
System.out.println(ret.eval(1).bind(inc)); // #-> Just(2) System.out.println(inc.eval(1)); // #-> Just(2)
次に「m >>= unit == m」
System.out.println(ret.eval(1).bind(ret)); // #-> Just(1) System.out.println(ret.eval(1)); // #-> Just(1)
最後は「(m >>= f) >>= g == m >>= (\x -> f x >>= g)」
System.out.println(ret.eval(1).bind(inc).bind(tostr)); // #-> Just(num = 2) System.out.println(ret.eval(1).bind(new Function<Integer, Maybe<String>>() { public Maybe<String> eval(Integer arg) { return inc.eval(arg).bind(tostr); } })); // #-> Just(num = 2)