我想知道是否有方法將List[Kleisli[Option, Int, Int]]
轉換爲Kleisli[Option, Int, List[Int]]
。列表中的Kleisli到Kleisli列表
特別是我有這樣形成kleisli名單:
我要做的就是以下
Kleisli[Option, Int, List[Int]](m => kList.map(_.run(m)).sequence)
這是非常凌亂,沒有表現,需要大量的人工勞動。
有沒有更好的方法?
我想知道是否有方法將List[Kleisli[Option, Int, Int]]
轉換爲Kleisli[Option, Int, List[Int]]
。列表中的Kleisli到Kleisli列表
特別是我有這樣形成kleisli名單:
我要做的就是以下
Kleisli[Option, Int, List[Int]](m => kList.map(_.run(m)).sequence)
這是非常凌亂,沒有表現,需要大量的人工勞動。
有沒有更好的方法?
是的,你可以使用traverse
這樣做。如果您使用cats
< = 0.9.0,您可以使用下面的代碼:
import cats.data._
import cats.instances.list._
import cats.instances.option._
import cats.syntax.traverse._
// ...
def k(a: String) = Kleisli[Option, Int, Int](m => Some(a.length * m))
val result: Kleisli[Option, Int, List[Int] = List("hi", "hello").traverseU(k)
如果你使用Scala的2.11.9+,加入scalacOptions += "-Ypartial-unification"
您build.sbt
文件,你可以只使用traverse
在traverseU
的地方。此外,從版本1.0.0開始,traverseU
和sequenceU
將不再存在。
請注意,如果您使用的是Scala < 2.11.9但> = 2.10.6,您仍然可以通過將this plugin添加到您的版本來啓用部分統一。
,你可以做最簡單的就是有partial-unification
啓用並使用traverse
:
import cats.implicits._
List("hi", "hello").traverse(k)
這是一樣的對你kList
運行sequence
,爲traverse
相當於map
然後sequence
。
啓用partial-unification
的最簡單方法是添加sbt-partial-unification
plugin。從cats
隊
scalacOptions += "-Ypartial-unification"
我們強烈建議您有此標誌在任何時候使用時:
如果你在斯卡拉2.11.9或更新的版本,你也可以簡單地添加了編譯器標誌貓,因爲它使一切變得容易很多。
使用TraverseOps.sequence
我們可以將List[A[B]]
到A[List[B]]
,其中
A = ({type λ[α] = Kleisli[Option, Int, α]})#λ
B = Int
所以答案是:
def transform(x: List[Kleisli[Option, Int, Int]]) =
x.sequence[({type λ[α] = Kleisli[Option, Int, α]})#λ, Int]
下面的代碼是完整的解決方案:
import scalaz._
import Scalaz._
import scalaz.Kleisli._
def transform(x: List[Kleisli[Option, Int, Int]]) = x.sequence[({type λ[α] = Kleisli[Option, Int, α]})#λ, Int]
def k(a: String) = Kleisli[Option, Int, Int](m => Some(a.length * m))
val kList = List("hi", "hello").map(k)
val res = transform(kList)
res.run(10)
除了下面的很好的答案之外,我想強調一個事實,即「序列映射」(即序列映射)做'map'然後做'sequence')在一般情況下等價於'遍歷'。這可能會幫助你重構你的代碼庫的其他幾個部分;) –