残念ながら C# の型システムには高カインド多相(高階多相)が備わっていないため表現することができません。
ですので、C# に似た架空の言語で実装してみます。(Kotlin や Scala からも連想しています。)
型クラスに相当するのがトレートです。
lang
1trait Functor<F<_>>
2{
3 F<S> Map<T, S>(Func<T, S> f, F<T> a);
4}
5
6trait Applicative<F<_>> : Functor<F<_>>
7{
8 F<S> App<T, S>(F<Func<T, S>> f, F<T> a);
9 F<T> Pure<T>(T a);
10}
11
12trait Monad<F<_>> : Applicative<F<_>>
13{
14 F<S> Bind<T, S>(F<T> a, Func<T, F<S>> f);
15}
下記のような Maybe
型を考えてみましょう。
lang
1abstract class Maybe<T>
2{
3 public sealed class Just (T value) : Maybe<T> {}
4
5 public sealed class Nothing : Maybe<T> {}
6}
これを先のトレートのインスタンスにしていきます。
lang
1instance Functor<Maybe<_>>
2{
3 Maybe<S> Map<T, S>(Func<T, S> f, Maybe<T> ma) =>
4 ma switch {
5 Maybe<T>.Just (var a) => new Maybe<S>.Just(f(a)),
6 Maybe<T>.Nothing => new Maybe<S>.Nothing()
7 };
8}
9
10instance Applicative<Maybe<_>>
11{
12 Maybe<S> App<T, S>(Maybe<Func<T, S>> mf, Maybe<T> ma) =>
13 (mf, ma) switch {
14 (Maybe<Func<T, S>>.Just (var f), Maybe<T>.Just (var a)) => new Maybe<S>.Just(f(a)),
15 (Maybe<Func<T, S>>.Nothing, _) => new Maybe<S>.Nothing(),
16 (_, Maybe<T>.Nothing) => new Maybe<S>.Nothing()
17 };
18
19 Maybe<T> Pure<T>(T a) => new Maybe<T>.Just(a);
20}
21
22instance Monad<Maybe<_>>
23{
24 Maybe<S> Bind<T, S>(Maybe<T> ma, Func<T, Maybe<S>> f) =>
25 ma switch {
26 Maybe<T>.Just (var a) => f(a),
27 Maybe<T>.Nothing => Maybe<S>.Nothing
28 };
29}
使用する場合はこのようなコードを想定しています。
lang
1/// 名前から関数を探す関数
2/// 見付からなければ Nothing
3Maybe<Func<int, int>> FindFunction(string name) { … }
4
5/// ユーザーの入力が整数ならその値
6/// そうでなければ Nothing
7Maybe<int> InputInt() { … }
8
9Monad<Maybe<_>>.Bind<Func<int, int>, string>(
10 FindFunction("minus"),
11 f => // FindFunction で見付かった関数が代入されるのが f
12 // f の型は Func<int, int>
13 Monad<Maybe<_>>.Bind<int, string>(
14 InputInt(),
15 i => // ユーザーの入力した整数値が代入されるのが i
16 Applicative<Maybe<_>>.Pure<string>(i.ToString())
17 )
18);
19// 全体の値は、
20// minus 関数が見付からなければ Nothing
21// ユーザーの入力が整数値でなければ Nothing
22// それ以外ならば、ユーザーの入力が 10 とすると "-10" という文字列が Just に包まれたもの
23
24// 型推論がバリバリ効いて型引数を書かなくていいなら下記のように書けます
25Monad.Bind(
26 FindFunction("minus"),
27 f =>
28 Monad.Bind(
29 InputInt(),
30 i => Applicative.Pure(i.ToString())
31 )
32);
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/03/22 01:23 編集
2019/03/22 00:29
2019/03/22 01:34 編集