我想知道是否有方法将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')在一般情况下等价于'遍历'。这可能会帮助你重构你的代码库的其他几个部分;) –