简体   繁体   English

列表Kleisli to Kleisli列表

[英]List of Kleisli to Kleisli of list

I was wondering if there is a way to turn List[Kleisli[Option, Int, Int]] to Kleisli[Option, Int, List[Int]] . 我想知道是否有办法将List[Kleisli[Option, Int, Int]]Kleisli[Option, Int, List[Int]]

In particular I have the list of kleisli formed like this: 特别是我有像这样形成的kleisli列表:

def k(a: String) = Kleisli[Option, Int, Int](m => Some(a.length * m))
val kList = List("hi", "hello").map(k)

What I do is the following 我所做的是以下内容

Kleisli[Option, Int, List[Int]](m => kList.map(_.run(m)).sequence)

which is very messy, not expressive and requires a lot of manual work. 这是非常混乱,没有表现力,需要大量的手工工作。

Is there a better way? 有没有更好的办法?

Yes, you can use traverse which does just that. 是的,你可以使用traverse来做到这一点。 If you're using cats <= 0.9.0 you can use the following code: 如果你使用的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)

If you're using Scala 2.11.9+, by adding scalacOptions += "-Ypartial-unification" to your build.sbt file, you can just use traverse in place of traverseU . 如果您正在使用Scala 2.11.9 scalacOptions += "-Ypartial-unification" ,通过在build.sbt文件中添加scalacOptions += "-Ypartial-unification" ,您可以使用traverse代替traverseU Also, starting from version 1.0.0, traverseU and sequenceU will no longer exist. 此外,从版本1.0.0开始, traverseUsequenceU将不再存在。

Note that, if you're using Scala < 2.11.9 but >= 2.10.6 you can still enable partial unification by adding this plugin to your build. 请注意,如果您使用Scala <2.11.9但> = 2.10.6,您仍然可以通过将此插件添加到构建中来启用部分统一。

The simplest you can do is to have partial-unification enabled and using traverse : 您最简单的方法是启用partial-unification并使用traverse

import cats.implicits._

List("hi", "hello").traverse(k)

This is the same as running sequence on your kList , as traverse is equivalent to map and then sequence . 这与kList上的运行sequence相同,因为traverse相当于map ,然后是sequence

The easiest way to enable partial-unification , is to add the sbt-partial-unification plugin . 启用partial-unification的最简单方法是添加sbt-partial-unification 插件

If you're on Scala 2.11.9 or newer, you can also simply add the compiler flag: 如果你使用的是Scala 2.11.9或更高版本,你也可以简单地添加编译器标志:

scalacOptions += "-Ypartial-unification"

We from the cats team strongly encourage you to have this flag on at all times when using cats, as it makes everything just a lot easier. 来自cats队的我们强烈建议您在使用猫时始终使用此标志,因为它使一切变得更加容易。

Using TraverseOps.sequence we can transform List[A[B]] to A[List[B]] , where 使用TraverseOps.sequence我们可以将List[A[B]]变换为A[List[B]] ,其中

A = ({type λ[α] = Kleisli[Option, Int, α]})#λ
B = Int

So the answer is: 所以答案是:

def transform(x: List[Kleisli[Option, Int, Int]]) =
  x.sequence[({type λ[α] = Kleisli[Option, Int, α]})#λ, Int]

Following code is complete solution: 以下代码是完整解决方案:

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)

https://scastie.scala-lang.org/2uZvWWb1ScOHNA55QOcWQA https://scastie.scala-lang.org/2uZvWWb1ScOHNA55QOcWQA

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM