に変換すリストオプションのオプションのリストを使用Scalaz
質問
私たらすものに変えたいと思っている List[Option[T]]
入 Option[List[T]]
.署名のタイプの機能
def lo2ol[T](lo: List[Option[T]]): Option[List[T]]
の行動は地図リストのみを含む Some
s込 Some
を含むリストの要素を要素内に Some
's.一方、入力された場合はリストの少なくとも一つの None
, 期待の動作が戻っ None
.例えば:
scala> lo2ol(Some(1) :: Some(2) :: Nil)
res10: Option[List[Int]] = Some(List(1, 2))
scala> lo2ol(Some(1) :: None :: Some(2) :: Nil)
res11: Option[List[Int]] = None
scala> lo2ol(Nil : List[Option[Int]])
res12: Option[List[Int]] = Some(List())
実装例として、なく、scalazい:
def lo2ol[T](lo: List[Option[T]]): Option[List[T]] = {
lo.foldRight[Option[List[T]]](Some(Nil)){(o, ol) => (o, ol) match {
case (Some(x), Some(xs)) => Some(x :: xs);
case _ => None : Option[List[T]];
}}}
くどこかに類似例がScalaz容易にコードです。どうにかしらの利点があるのでしょうか?
少し簡潔版を使用Scala2.8 PartialFunction.condOpt
, もなくScalaz:
import PartialFunction._
def lo2ol[T](lo: List[Option[T]]): Option[List[T]] = {
lo.foldRight[Option[List[T]]](Some(Nil)){(o, ol) => condOpt(o, ol) {
case (Some(x), Some(xs)) => x :: xs
}
}}
解決
ScalazでList[Option[A]]
にOption[List[A]]
を回す機能があります。それはsequence
です。
None
ある場合には任意の要素のNone
とSome[List[A]]
ある場合にSome
を取得するには、単にこれを行うことができます
import scalaz.syntax.traverse._
import scalaz.std.list._
import scalaz.std.option._
lo.sequence
この方法は、実際F[G[A]
の実装が存在することを考えるG[F[A]]
にTraverse[F]
になり、Applicative[G]
の(Option
とList
の両方を満足させるために起こる、それらの輸入によって提供される)。
Applicative[Option]
のセマンティクスはList
sのOption
の要素のいずれかがNone
されている場合、sequence
も同様None
であろうようなものです。あなたは関係なく、他の値がSome
であるかどうかのすべてNone
値の一覧を取得したい場合は、あなたがこれを行うことができます:
lo flatMap (_.toList)
またMonad
を(Monoid
は、これらのいずれかであることを起こる)を形成することを任意のList
のためにそれを一般化することができます
import scalaz.syntax.monad._
def somes[F[_],A](x: F[Option[A]])
(implicit m: Monad[F], z: Monoid[F[A]]) =
x flatMap (o => o.fold(_.pure[F])(z.zero))
他のヒント
何らかの理由であなたは嫌いです
if (lo.exists(_ isEmpty)) None else Some(lo.map(_.get))
?これはおそらく、Scalaz を使用しない場合、Scala で最も短いものです。
一方、 Applicative[Option]
Scalaz では直接使用すると間違った動作をします MA#sequence
, を導き出すこともできます。 Applicative
から Monoid
. 。これは便利です MA#foldMapDefault
または MA#collapse
.
この場合、 Monoid[Option[List[Int]]
. 。最初に内部マップを実行します (MA#∘∘
) 個人を包みます Int
にいる List
1 つの要素の s。
(List(some(1), none[Int], some(2)) ∘∘ {(i: Int) => List(i)}).collapse assert_≟ some(List(1, 2))
(List(none[Int]) ∘∘ {(i: Int) => List(i)}).collapse assert_≟ none[List[Int]]
(List[Option[Int]]() ∘∘ {(i: Int) => List(i)}).collapse assert_≟ none[List[Int]]
からの抽象化 List
のインスタンスを持つ任意のコンテナに Traverse
, Pointed
そして Monoid
:
def co2oc[C[_], A](cs: C[Option[A]])
(implicit ct: Traverse[C], cp: Pointed[C], cam: Monoid[C[A]]): Option[C[A]] =
(cs ∘∘ {(_: A).pure[C]}).collapse
co2oc(List(some(1), none[Int], some(2))) assert_≟ some(List(1, 2))
co2oc(Stream(some(1), none[Int], some(2))) assert_≟ some(Stream(1, 2))
co2oc(List(none[Int])) assert_≟ none[List[Int]]
co2oc(List[Option[Int]]()) assert_≟ none[List[Int]]
残念ながら、現在このコードをコンパイルしようとすると、次のいずれかのトリガーが発生します。 #2741 または、コンパイラを無限ループに送ります。
アップデートリストを 2 回走査するのを避けるために、次のようにするべきでした foldMapDefault
:
(List(some(1), none[Int], some(2)) foldMapDefault (_ ∘ ((_: Int).pure[List])))
この回答は、空のリスト、またはのみを含むリストという元のリクエストに基づいています。 None
s は、を返す必要があります None
. 。ちなみに、これは次のタイプでモデル化するのが最適です。 Option[scalaz.NonEmptyList]
-- NonEmptyList
少なくとも 1 つの要素を保証します。
だけが必要な場合は、 List[Int]
, 、他の回答で示されているように、より簡単な方法がたくさんあります。言及されていない 2 つの直接的な方法:
list collect { case Some(x) => x }
list flatten
これは私のために働きました。私はこれが正しい解決策であると思います。
リストのオプションの一つは、それ以外の場合は、リストのオプションを返す[A] 、Noneの場合は、これはNoneを返します
def sequence[A](a: List[Option[A]]): Option[List[A]] = {
a.foldLeft(Option(List[A]())) {
(prev, cur) => {
for {
p <- prev if prev != None
x <- cur
} yield x :: p
}
}
}
始 Scala 2.13
, に加え、 Option::unless
ビルダーの 標準ライブラリ, バリアントへ レックスカーの回答 することはできない。
Option.unless(list contains None)(list.flatten)
// val list = List(Some(1), Some(2)) => Some(List(1, 2))
// val list = List(Some(1), None, Some(2)) => None
場合は、性能を出するために避け flatten
's"暗黙的に変換 Option
へ List
):
Option.unless(list contains None)(list.map(_.get))