私はモナドとは何か、そしてそれらの使い方を知っています。 whatがOption
をモナドにしたとしましょう。
Haskellでは、モナドMaybe
はモナドです。これは、Monad
クラスからインスタンス化されているためです(クラスには、return
とbind
があり、クラスMonad
、実際にはモナドになります)。
しかし、Scalaにはこれがあります:
sealed abstract class Option[+A] extends Product with Serializable { ... }
trait Product extends Any with Equals { ... }
モナドに関連するものはありません。
Scalaで独自のクラスを作成すると、デフォルトでモナドになりますか?何故なの?
Monad
は、データの構成方法を単純に定義する概念であり、抽象インターフェースです。
Option
は、flatMap
による構成をサポートします。これが、「モナドバッジ」の着用に必要なほとんどすべての機能です。
理論的な観点から、次のことも行う必要があります。
unit
操作(Haskell用語ではreturn
)をサポートして、裸の値からモナドを作成します。これは、Option
の場合はSome
コンストラクタです。しかし、これはScalaによって厳密に強制されているわけではありません。
scalaのモナドは、Haskellの場合よりもはるかに緩やかな概念であり、アプローチがより実用的です。言語の観点から、モナドが関連するのは、forで使用される機能だけです。 -理解。
flatMap
は基本的な要件であり、オプションでmap
、withFilter
、foreach
を指定できます。
ただし、HaskellのようにMonad
型クラスに厳密に準拠するようなものはありません。
次に例を示します。独自のモナドを定義しましょう。
class MyMonad[A](value: A) {
def map[B](f: A => B) = new MyMonad(f(value))
def flatMap[B](f: A => MyMonad[B]) = f(value)
override def toString = value.toString
}
ご覧のとおり、map
とflatMap
だけを実装しています(まあ、toString
を商品として)。おめでとう、モナドができました!試してみましょう:
scala> for {
a <- new MyMonad(2)
b <- new MyMonad(3)
} yield a + b
// res1: MyMonad[Int] = 5
いいね!フィルタリングは行わないため、withFilter
を実装する必要はありません。また、値を生成しているので、foreach
も必要ありません。基本的に、厳密な要件なしに、サポートしたいものをすべて実装します。 for内包でフィルターをかけようとしていて、withFilter
を実装していない場合は、コンパイル時エラーが発生します。
FilterMonadic
トレイトがダックタイピングによって(部分的に)実装されるものはすべて、Scalaのモナドと見なされます。これは、Haskellでモナドを表現する方法、または Monad
scalazのtypeclass とは異なります。ただし、Scalaのfor
内包構文糖度を利用するには、オブジェクトがFilterMonadic
特性で定義されているメソッドの一部を公開する必要があります。
また、Scalaでは、Haskellのreturn
関数に相当するものは、yield
内包から値を生成するために使用されるfor
キーワードです。 yield
の脱糖は、「モナド」のmap
メソッドの呼び出しです。
私の言い方では、モナドの間には設計パターンとファーストクラスの抽象化の違いが浮上しています。 HaskellにはMonad
型クラスの形式で後者があります。しかし、モナド演算を持ち(または実装できる)型があり、法則に従う場合、それもモナドです。
最近では、モナドをJava 8's librariesの設計パターンとして見ることができます。Optional
とStream
はJava 8には、Haskell of
に対応する静的return
メソッドとflatMap
メソッドがありますが、Monad
タイプはありません。
Ionuț G. Stanの回答が示すように、あなたの間のどこかに「アヒル型」アプローチがあります。 C#にもこれがあります。LINQ構文は特定の型に関連付けられていませんが、特定のメソッドを実装する任意のクラスで使用できます。