4

Scalaでの障害処理についてかなりの数の質問を投稿しましたが、本当にありがとうございました。

どちらかとScalazまたは理解のためのを扱うときの私の選択肢を理解しています、そして私は別の(最後の?)質問があります:

操作がDBのような外部の非機能的な世界を処理しているときに、フェイルファストの一連の操作を実行するにはどうすればよいですか?


私はそのような方法を持っていることを意味します:

def insertItem(item: Item): Either[Error,Item]

どちらかとこれらの答えのおかげで、私はどちらかでそれを行う方法を知っています:理解とモナドのために、ScalaでのEitherと メソッドパラメーターの検証を使用したメソッド呼び出しの連鎖

しかし、私のケースクラスは不変であり、呼び出し元がすでに値を持っているため、Itemそれをaとして返すことは実際には意味がありません。Right

したがって、どうすれば同じ種類のことを次のように行うことができますか?

def insertItem(item: Item): Option[Error]

私のアプリケーションでは、ユーザーが作成されるときに、そのユーザーのためにいくつかのアイテムも作成します。アイテムの作成に失敗した場合は、プロセス全体を停止する必要があります。

理解のために直接使用するOption[Error]と、期待した結果が得られないと思います。

私はそのようなことをするのが理にかなっていると思います:

for {
  _ <- insertItem(item1).toLeft("???").right
  _ <- insertItem(item2).toLeft("???").right
  _ <- insertItem(item3).toLeft("???").right
}

しかし、値として「???」私は自分の権利を入れることは決して有用ではありません、私は決して使用されない権利を作成することを含まないエレガントな解決策を見逃していると思います。

結果が出たときだけ理解し続けるものを探していると思いますNoneが、実際の操作ではなく、次の操作を続けたいだけなので、ちょっと変ですmap

ちなみに、可能であれば、Scalaz以外のソリューションとScalazソリューションの両方が欲しいです。Scalazがそのようなことを処理するかどうかはわかりません。これは、実際の関数型プログラミングに重点が置かれているようで、おそらく私のユースケースのような副作用動作のコードを提供していないためです。

4

4 に答える 4

8

このような場合に使用しないという原則的な理由はわかりませんEither[Error, Unit](または、少なくとも私はそれを実行しましたが、それについては罪を感じません)。次のものがあるとします。

def launch(thing: String): Either[String, Unit] = Either.cond(
  thing.nonEmpty,
  println("Launching the " + thing),
  "Need something to launch!"
)

正しい射影モナドが適切に怠惰であることを示すことができます。

scala> for {
     |   _ <- launch("flowers").right
     |   _ <- launch("").right
     |   r <- launch("MISSILES").right
     | } yield r
Launching the flowers
res1: Either[String,Unit] = Left(Need something to launch!)

必要に応じて、ミサイルは発射されません。


Optionの代わりにを使用する場合、説明している操作は、(加算操作がちょうどである)Eitherの「最初の」モノイドインスタンスに与えられた合計にすぎないことに注意してください。たとえば、Scalaz7で次のように書くことができます。OptionorElse

import scalaz._, Scalaz._

def fst[A](x: Option[A]): Option[A] @@ Tags.First = Tag(x)

def launch(thing: String): Option[String] = if (thing.isEmpty) Some(
  "Need something to launch!"
) else {
  println("Launching the " + thing)
  None
}

そして今:

scala> val r: Option[String] = fst(launch("flowers")) |+| fst(
     |   launch("")) |+| fst(launch("MISSILES"))
Launching the flowers
r: Option[String] = Some(Need something to launch!)

繰り返しますが、ミサイルはありません。

于 2012-10-22T19:17:25.880 に答える
3

これは慣用的なscalazではありませんが、scalazを使用してメッセージ送信で迅速に失敗する場合と同様のことを行います。

def insertItem(item: Item): Validation[Error, Unit]

val result = for {
  _ <- insertItem(item1)
  _ <- insertItem(item2)
  _ <- insertItem(item3)
} yield Unit
于 2012-10-22T19:21:42.673 に答える
1

を含むメソッドを連鎖させて、がでOption[Error]ある場合にのみ次のステップを実行する場合OptionNone、そのために使用できますorElse

于 2012-10-22T19:05:33.047 に答える
0

最初の失敗のみに関心がある場合は、次Iteratorの選択肢があります。

case class Item(i: Int)

case class Error(i: Item)

val items = Iterator(1,3,7,-5,-2,0) map Item

def insertItem(item: Item): Option[Error] =
  if (item.i < 0) Some(Error(item)) else None

scala> val error = (items map insertItem find (_.isDefined)).flatten
error: Option[Error] = Some(Error(Item(-5)))

が唯一のメソッドではない場合insertItemは、値で区切って呼び出すことができます。

val items = Iterator(
  () => insertItem(i1),
  () => deleteItem(i2),
  () => insertItem(i3),
  () => updateItem(i4))
于 2012-10-22T17:21:07.407 に答える