私が理解しているように、Scala "for"構文はHaskellのモナディック "do"構文に非常に似ています。Scalaでは、 "["構文はList
sおよびOption
s。Either
sで使用したいのですが、必要なメソッドがデフォルトのインポートに存在しません。
_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
?)どのように?独自の "モナドインスタンス"を提供したいと思います。それを行う?
動作しませんin scala 2.11以前Either
はモナドではないためです。右バイアスの話はありますが、 t内包表記で使用します。以下のように、LeftProject
または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
を右バイアスにすることを望んでいましたが、それ以外の場合は同僚によって確信されました。
この機能はインポートによって利用できますか?
はい、ただしサードパーティのインポートを介して: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からのものです。
編集:
私はあなたのこの質問を逃しました。
Eitherに独自の「モナドインスタンス」を提供したいとしたら、どうすればそれができますか?
Scala for
内包表記は、単に.map
、.flatMap
、.withFilter
、 関連するオブジェクトに対する.filter
.foreach
呼び出し。 (完全な変換スキーム here を見つけることができます。)したがって、一部のクラスに必要なメソッドがない場合は、次のコマンドを使用してクラスにaddできます暗黙の変換。
新しい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)
Scala 2.12、Either
は 現在右バイアス
ドキュメント から:
EitherはメソッドmapとflatMapを定義しているので、内包表記にも使用できます。
val right1: Right[Double, Int] = Right(1) val right2 = Right(2) val right3 = Right(3) val left23: Left[Double, Int] = Left(23.0) val left42 = Left(42.0) for ( a <- right1; b <- right2; c <- right3 ) yield a + b + c // Right(6) for ( a <- right1; b <- right2; c <- left23 ) yield a + b + c // Left(23.0) for ( a <- right1; b <- left23; c <- right2 ) yield a + b + c // Left(23.0) // It is advisable to provide the type of the “missing” value (especially the right value for `Left`) // as otherwise that type might be infered as `Nothing` without context: for ( a <- left23; b <- right1; c <- left42 // type at this position: Either[Double, Nothing] ) yield a + b + c // ^ // error: ambiguous reference to overloaded definition, // both method + in class Int of type (x: Char)Int // and method + in class Int of type (x: Byte)Int // match argument types (Nothing)