モナドとは何かを理解するのを助けるために、誰かがJava?それらは可能ですか?
Javaプレリリースのラムダ互換JDK8をここからダウンロードする場合 http://jdk8.Java.net/lambda/
このJDKを使用したラムダの例を以下に示しますが、誰かが比較的単純なモナドを提供できますか?
public interface TransformService {
int[] transform(List<Integer> inputs);
}
public static void main(String ars[]) {
TransformService transformService = (inputs) -> {
int[] ints = new int[inputs.size()];
int i = 0;
for (Integer element : inputs) {
ints[i] = element;
}
return ints;
};
List<Integer> inputs = new ArrayList<Integer>(5) {{
add(10);
add(10);
}};
int[] results = transformService.transform(inputs);
}
参考までに:
提案された JDK8オプション クラスは、3つの モナドの法則 を満たします。 要点を示す あれです。
Monadに必要なのは、twoに適合する関数を提供することですthree法律。
2つの機能:
値をモナドコンテキストに配置する
return
/Just
Some
Option.some
Optional.of
モナドコンテキストで関数を適用する
>>=
(別名bind
)flatMap
flatMap
flatMap
Java 3つの法律のデモンストレーションについては 上記の要点 を参照してください。
注:理解すべき重要なことの1つは、モナドコンテキストに適用する関数のシグネチャです。未加工の値型を受け取り、モナド型を返します。
つまり、Optional<Integer>
のインスタンスがある場合、flatMap
メソッドに渡すことができる関数には、(Integer) -> Optional<U>
というシグネチャがあります。ここで、U
は値ですInteger
である必要のないタイプ、たとえばString
:
Optional<Integer> maybeInteger = Optional.of(1);
// Function that takes Integer and returns Optional<Integer>
Optional<Integer> maybePlusOne = maybeInteger.flatMap(n -> Optional.of(n + 1));
// Function that takes Integer and returns Optional<String>
Optional<String> maybeString = maybePlusOne.flatMap(n -> Optional.of(n.toString));
このようにコーディングしたり、このように考えたりするために、Monadインターフェースは必要ありません。 Scalaでは、Monadインターフェイスにコーディングしません(Scalazライブラリを使用している場合を除く...)。 JDK8は、このスタイルの連鎖モナド計算も使用できるようにJava人々に権限を与えるようです。
これがお役に立てば幸いです!
更新:これについてブログに書いた こちら 。
モナドはJavaで実装できますが、モナドを含む計算はすべて、ジェネリックと中括弧の乱雑な組み合わせになる運命にあります。
Javaは間違いなくnotであり、彼らの働きを説明したり、その意味と本質を研究するために使用する言語ではありません。 JavaScriptを使用するか、追加料金を支払ってHaskellを学習する方がはるかに優れています。
とにかく、新しいJava 8ラムダを使用してstateモナドを実装したことを通知します。これは間違いなくペットプロジェクトですが、重要なテストケースで動作します。
私のブログ で紹介されているかもしれませんが、ここで詳細を説明します。
状態モナドは基本的に、状態からペア(状態、内容)への関数です。通常、状態にはジェネリックタイプSを、コンテンツにはジェネリックタイプAを指定します。
Javaには特定のクラスを使用してモデル化する必要のあるペアがないため、これをScp(状態とコンテンツのペア)と呼びましょう。ジェネリック型_Scp<S,A>
_とコンストラクタnew Scp<S,A>(S state,A content)
を持ちます。それを行った後、モナド関数は型を持つと言えます
_Java.util.function.Function<S,Scp<S,A>>
_
これは_@FunctionalInterface
_です。つまり、名前を付けずにその唯一の実装メソッドを呼び出して、正しい型のラムダ式を渡すことができます。
クラス_StateMonad<S,A>
_は、主に関数のラッパーです。そのコンストラクターを呼び出すことができますと
_new StateMonad<Integer, String>(n -> new Scp<Integer, String>(n + 1, "value"));
_
状態モナドは、関数をインスタンス変数として保存します。次に、パブリックメソッドにアクセスして状態を提供する必要があります。私はそれを_s2scp
_(「状態と状態とコンテンツのペア」)と呼ぶことにしました。
モナドの定義を完了するには、nit(別名return)とbind(別名flatMap =)メソッド。個人的には、ユニットを静的として指定することを好みますが、バインドはインスタンスメンバーです。
状態モナドの場合、ユニットは以下でなければなりません:
_public static <S, A> StateMonad<S, A> unit(A a) {
return new StateMonad<S, A>((S s) -> new Scp<S, A>(s, a));
}
_
一方、バインド(インスタンスメンバーとして)は次のとおりです。
_public <B> StateMonad<S, B> bind(final Function<A, StateMonad<S, B>> famb) {
return new StateMonad<S, B>((S s) -> {
Scp<S, A> currentPair = this.s2scp(s);
return famb(currentPair.content).s2scp(currentPair.state);
});
}
_
バインドはジェネリックタイプBを導入する必要があることに注意してください。これは、異種状態モナドの連鎖を可能にし、このモナドおよび他のモナドに、計算を型から型に移動する顕著な機能を与えるメカニズムであるためです.
ここでJavaコードで停止します。複雑なものはGitHubプロジェクトにあります。以前のJavaバージョンと比較して、ラムダは中括弧の多くを削除します、しかし、構文はまだかなり複雑です。
余談ですが、他の主流言語で似た状態のモナドコードがどのように記述されるかを示しています。 Scalaの場合、bind(その場合mustを呼び出す必要がありますflatMap)
_def flatMap[A, B](famb: A => State[S, B]) = new State[S, B]((s: S) => {
val (ss: S, aa: A) = this.s2scp(s)
famb(aa).s2scp(ss)
})
_
一方、JavaScriptのバインドは私のお気に入りです。 100%機能的、無駄のない、平均的ですが、もちろんタイプレスです:
_var bind = function(famb){
return state(function(s) {
var a = this(s);
return famb(a.value)(a.state);
});
};
_
<恥知らず>ここでいくつかのコーナーをカットしていますが、詳細に興味がある場合は、WP blog。</ shameless>
モナドを理解する唯一の方法は、多数のコンビネータライブラリを記述し、結果の重複に気づき、モナドによってこの重複を除外できることを自分で発見することです。これを発見すると、誰もがモナドとは何かについて直観を構築しますが、この直観はあなたが他の誰かに直接伝えることができるようなものではありません。コンビネータライブラリの例。しかしながら
ここで、Mondasを学ぶための資料を見つけました。
あなたにも役立つことを願っています。
ここにモナドについて理解するのが難しいものがあります:モナドはパターンであり、特定のタイプではありません。モナドはシェイプであり、具体的なデータ構造であるというよりも、抽象インターフェース(Javaの意味ではない)です。 [...]モナドを理解する唯一の方法は、モナドが何であるかを見ることです:数学的構造。
モナドは比phorではない by Daniel Spiewak
Java SE 8のモナド
リストモナド
interface Person {
List<Person> parents();
default List<Person> greatGrandParents1() {
List<Person> list = new ArrayList<>();
for (Person p : parents()) {
for (Person gp : p.parents()) {
for (Person ggp : p.parents()) {
list.add(ggp);
}
}
}
return list;
}
// <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
default List<Person> greatGrandParents2() {
return Stream.of(parents())
.flatMap(p -> Stream.of(p.parents()))
.flatMap(gp -> Stream.of(gp.parents()))
.collect(toList());
}
}
たぶんモナド
interface Person {
String firstName();
String middleName();
String lastName();
default String fullName1() {
String fName = firstName();
if (fName != null) {
String mName = middleName();
if (mName != null) {
String lName = lastName();
if (lName != null) {
return fName + " " + mName + " " + lName;
}
}
}
return null;
}
// <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
default Optional<String> fullName2() {
return Optional.ofNullable(firstName())
.flatMap(fName -> Optional.ofNullable(middleName())
.flatMap(mName -> Optional.ofNullable(lastName())
.flatMap(lName -> Optional.of(fName + " " + mName + " " + lName))));
}
}
モナドは、入れ子にされた制御フローカプセル化のためのgenericパターンです。つまりネストされた命令型イディオムから再利用可能なコンポーネントを作成する方法。
モナドはflat map操作を持つ単なる一般的なラッパークラスではないことを理解することが重要です。たとえば、ArrayList
メソッドを持つflatMap
はモナドにはなりません。 モナドの法則は副作用を禁止しているためです。
モナドは形式主義です。コンテンツや意味に関係なく、構造を記述します。人々は無意味な(抽象的な)ものに関係することに苦労しています。それで、彼らはモナドではない比phorを思いつきます。
参照:会話 Erik MeijerとGilad Brachaの間。
このブログ投稿 は、JavaでMonadタイプ(インターフェース)を実装する方法の段階的な例を示しています=そして、それを使用して、実用的なアプリケーションとしてMaybeモナドを定義します。
この投稿 は、Java言語に組み込まれたモナドが1つあり、モナドがより一般的であるという点を強調していることを説明しています多くのプログラマーは考えているかもしれませんし、コーダーはしばしば 意図せずにそれらを再発明します 。
私はモナドをより数学的な(しかし非公式な)ファッションで考えるのが好きです。その後、Java 8のモナドCompletableFutureのいずれかとの関係を説明します。
まず、モナドM
はfunctorです。つまり、型を別の型に変換します。X
が型(たとえば、String
)の場合、別の型M<X>
(たとえば、List<String>
)があります。さらに、型の変換/関数X -> Y
がある場合、関数M<X> -> M<Y>
を取得する必要があります。
しかし、このようなモナドにはさらにデータがあります。 X
型ごとの関数X -> M<X>
である、いわゆるユニットがあります。言い換えると、X
の各オブジェクトは、自然な方法でモナドにラップできます。
ただし、モナドの最も特徴的なデータは、積です:各タイプX
の関数M<M<X>> -> M<X>
。
これらのデータはすべて、機能性、結合性、単位法則などのいくつかの公理を満たす必要がありますが、ここでは詳しく説明しません。また、実際の使用法についても重要ではありません。
モナドの別の操作を推論できるようになりました。これは、モナドの同等の定義としてよく使用されます。バインド操作:M<X>
の値/オブジェクトを関数X -> M<Y>
にバインドして、 M<Y>
。これをどのように達成しますか?まず、関数に機能性を適用して、関数M<X> -> M<M<Y>>
を取得します。次に、モナド積をターゲットに適用して、関数M<X> -> M<Y>
を取得します。これで、M<X>
の値をプラグインして、必要に応じてM<Y>
の値を取得できます。このバインド操作は、複数のモナド操作を連結するために使用されます。
CompletableFutureの例、つまりCompletableFuture = M
に進みましょう。 CompletableFuture<MyData>
のオブジェクトは、非同期に実行され、将来の結果としてMyData
のオブジェクトを生成する何らかの計算と考えてください。ここでのモナド演算は何ですか?
thenApply
メソッドで実現されます。最初に計算が実行され、結果が利用可能になるとすぐに、thenApply
に与えられた関数が適用され、結果が別の型に変換されますcompletedFuture
で実現されます:ドキュメントが示すように、結果の計算は既に終了しており、与えられた値を一度に生成しますCompletableFuture<CompletableFuture<MyData>>
型の計算が与えられると、その計算はCompletableFuture<MyData>
は後でMyData
に値を生成するため、両方の計算を実行してから、他の計算を実行すると合計1つの計算が生成されますthenCompose
によって実現されますご覧のとおり、計算は特別なコンテキスト、つまり非同期でラップできます。一般的な単項構造により、特定のコンテキストでこのような計算を連鎖させることができます。 CompletableFuture
は、たとえばLagomフレームワークで使用され、効率的なスレッドプールによって透過的にバックアップされる高度な非同期リクエストハンドラーを簡単に構築します(専用スレッドで各リクエストを処理する代わりに)。