に変換すリストオプションのオプションのリストを使用Scalaz

StackOverflow https://stackoverflow.com/questions/2569014

  •  24-09-2019
  •  | 
  •  

質問

私たらすものに変えたいと思っている List[Option[T]]Option[List[T]].署名のタイプの機能

def lo2ol[T](lo: List[Option[T]]): Option[List[T]]

の行動は地図リストのみを含む Somes込 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ある場合には任意の要素のNoneSome[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]の(OptionListの両方を満足させるために起こる、それらの輸入によって提供される)。

Applicative[Option]のセマンティクスはListsの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にいる List1 つの要素の 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])))

この回答は、空のリスト、またはのみを含むリストという元のリクエストに基づいています。 Nones は、を返す必要があります 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"暗黙的に変換 OptionList):

Option.unless(list contains None)(list.map(_.get))
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top