Java 8 の Optional は monadのようです。
ストリームもモナドですか?
オプションのモナドのエンドファンクターと2つの自然な変換を特定できる人はいますか?
EDIT以下の回答は正しくありません (履歴のためにここに保持されます)。
はい、いずれの場合も、ファンクターはクラスとその
map
メソッドで構成され、2 つの自然な変換はof
とflatMap(identity)
です。
正解はここにありそう。
はい、java.util.stream.Stream
モナドの法則を満たしています。
前提条件は次のとおりです。
Stream
Functorである必要があります。つまり、次の関数を提供しますfmap :: (a -> b) -> M a -> M b
。ソースを調べると、すでに機能していることがわかりますStream<R> map(Function<T, R> mapper)
unit
(別名return
) 操作:が必要unit :: a -> M a
です。これは明らかです: Stream<T> of(T t)
.
次の操作が必要bind
です。 join
bind :: M a -> (a -> M b) -> M b
:Stream<R> flatMap(Function<T, Stream<R>> mapper)
join :: M (M a) -> M a
: これは には存在しませんStream
が、 から推測できbind
ます。これで、必要な関数ができました。しかし、それをモナドと呼ぶにはまだ十分ではありません! モナド則が有効であることを証明する必要があります。それらを見てみましょう:
左のアイデンティティ: (return a) bind f <=> f a
Function<String, Stream<Integer>> f = str -> str.chars().boxed();
String a = "abc";
Stream<Integer> left = Stream.of(a).flatMap(f);
Stream<Integer> right = f.apply(a);
//left should be same as right
権利のアイデンティティ: m bind unit <=> m
Stream<String> stream = Stream.of("abc", "def");
Stream<String> left = stream.flatMap(str -> Stream.of(str));
// left should be same as Stream.of("abc", "def")
結合性: (m bind f) bind g <=> m bind (\x -> f x bind g)
Function<Integer, Stream<String>> f = integer -> Arrays.stream(Integer.toHexString(integer).split(""));
Function<String, Stream<BigInteger>> g = string -> Stream.of(string).map(str -> new BigInteger(str, 16));
Stream<Integer> mLeft = Stream.of(47789, 61453);
Stream<BigInteger> left = mLeft.flatMap(f).flatMap(g);
Stream<Integer> mRight = Stream.of(47789, 61453);
Stream<BigInteger> right = mRight.flatMap(integer -> f.apply(integer).flatMap(g));
//left should be same as right
つまり、ストリームは本当にモナドのように見えます! Optional
ただし、 Monadic 法に違反する場合と同じ状況が発生する可能性があるので注意してください。parallel()
実行順序を変えられるので、使うと場合によっては違反になるのではないかと直感しています。どこで発生する可能性があるか知っている場合は、以下にコメントしてください。
Haskell を知っているなら: Java の Stream は Haskell の list モナド [] であり、Java の Optional は Haskell の Maybe モナドにほかなりません。