42

私が理解しているように、Scala の「for」構文は、Haskell のモナドの「do」構文に非常に似ています。ListScala では、 s とsに "for" 構文がよく使用されますOption。sで使いたいEitherのですが、必要なメソッドがデフォルトのインポートにありません。

for {
  foo <- Right(1)
  bar <- Left("nope")
} yield (foo + bar)

// expected result: Left("nope")
// instead I get "error: value flatMap is not a member..."

この機能は、何らかのインポートを通じて利用できますか?

少し問題があります。

for {
  foo <- Right(1)
  if foo > 3
} yield foo
// expected result: Left(???)

リストの場合は になりますList()。の場合Option、 になりますNone。Scala 標準ライブラリはこれに対する解決策を提供しますか? (またはおそらくscalaz?)どのように?独自の「モナド インスタンス」を提供したいとします。

4

3 に答える 3

55

はモナドではないため、scala 2.11 以前では機能しません。Either右バイアスの話がありますが、for 内包表記では使用できません。以下のようにLeftProjectorを取得する必要があります。RightProjection

for {
  foo <- Right[String,Int](1).right
  bar <- Left[String,Int]("nope").right
} yield (foo + bar)

ちなみに、それは を返しますLeft("nope")

Scalaz では、 に置き換えEitherますValidation。おもしろい事実:Eitherのオリジナルの作者は、Scalaz の作者の 1 人である Tony Morris です。Either彼は右寄りになりたかったのですが、同僚からそうではないと説得されました。

于 2012-06-02T23:56:05.940 に答える
16

この機能はインポートを通じて利用できますか?

はい。ただし、サードパーティのインポートを介して:ScalazはのMonadインスタンスを提供しますEither

import scalaz._, Scalaz._

scala> for {
     |   foo <- 1.right[String]
     |   bar <- "nope".left[Int]
     | } yield (foo.toString + bar)
res39: Either[String,java.lang.String] = Left(nope)

現在if、-guardは単調な操作ではありません。したがって、if-guardを使用しようとすると、期待どおりにコンパイラエラーが発生します。

scala> for {
     |   foo <- 1.right[String]
     |   if foo > 3
     | } yield foo
<console>:18: error: value withFilter is not a member of Either[String,Int]
                foo <- 1.right[String]
                              ^

上記で使用されている便利なメソッド-.rightおよび.left-もScalazからのものです。

編集:

私はあなたのこの質問を逃しました。

どちらかに独自の「モナドインスタンス」を提供したいとします。どうすればよいでしょうか。

Scalaのfor内包表記は、単純に、、、に変換され、.map関連するオブジェクトを呼び出します。(完全な変換スキームはここにあります。)したがって、一部のクラスに必要なメソッドがない場合は、暗黙的な変換を使用してそれらをクラスに追加できます。.flatMap.withFilter.filter .foreach

以下の新しいREPLセッション。

scala> implicit def eitherW[A, B](e: Either[A, B]) = new {
     |   def map[B1](f: B => B1) = e.right map f
     |   def flatMap[B1](f: B => Either[A, B1]) = e.right flatMap f
     | }
eitherW: [A, B](e: Either[A,B])java.lang.Object{def map[B1](f: B => B1): Product 
with Either[A,B1] with Serializable; def flatMap[B1](f: B => Either[A,B1]):
Either[A,B1]}

scala> for {
     |   foo <- Right(1): Either[String, Int]
     |   bar <- Left("nope") : Either[String, Int]
     | } yield (foo.toString + bar)
res0: Either[String,java.lang.String] = Left(nope)
于 2012-06-03T04:43:43.090 に答える