11
我正在尋找一個更通用的解決方案,它利用monads(和monisids可能)實現 if(xs.contains(None)) None else Some(xs.flatten)
確實爲xs
類型。如果A和B是單子,如何將A [B [C]]轉換爲B [A [C]]?
我該怎麼用Scalaz做這件事?我覺得我失去了一些明顯的東西。
我正在尋找一個更通用的解決方案,它利用monads(和monisids可能)實現 if(xs.contains(None)) None else Some(xs.flatten)
確實爲xs
類型。如果A和B是單子,如何將A [B [C]]轉換爲B [A [C]]?
我該怎麼用Scalaz做這件事?我覺得我失去了一些明顯的東西。
有兩個單子既不夠(對M
)和足夠多(爲N
)哪位加起來是不夠的,當然,但如果M
有Traverse
實例和N
有Applicative
例如,您可以使用sequence
。例如:
import scalaz._, Scalaz._
def foo[A](xs: List[Option[A]]): Option[List[A]] = xs.sequence
這有你想要的語義。請注意,我使用List
而不是Seq
,因爲Scalaz 7不再爲Seq
提供必要的Traverse
實例(儘管您可以輕鬆編寫自己的實例)。
正如你已經注意到了,下面將無法編譯:
List(Some(1), Some(45)).sequence
但如果你在那裏扔None
它的罰款:
scala> List(Some(1), None, Some(45)).sequence
res0: Option[List[Int]] = None
這是因爲推斷List(Some(1), Some(45))
的類型將爲List[Some[Int]]
,我們沒有Applicative
實例Some
。
Scalaz提供了一個方便的方法some
的作品像Some.apply
但給你東西是已經輸入爲Option
,所以你可以寫:
scala> List(some(1), some(45)).sequence
res1: Option[List[Int]] = Some(List(1, 45))
沒有額外的輸入必要的。
在使用Scalaz 7的REPL中,它失敗了,因爲它找不到Seq的Traverse類型實例。也許還有別的我應該導入? –
你可以使用'List'而不是'Seq',或者爲'Seq'提供你自己的實例 - 我不確定爲什麼'Seq'實例在7中消失了。 –
謝謝,讓它工作!但是我對它的行爲感到沮喪:除了Seq問題之外,還有一個問題需要你明確指定類型:'val xs = List(Some(1),Some(45)); (xs:List [Option [Int]])。sequence' –