对Kleisli的不同输入类型的`then`?

时间:2017-09-20 13:13:08

标签: scala scalaz

假设:

import scalaz._, Scalaz._
import scalaz.concurrent.Task

case class AppConfig(x: Int, y: String)

val x = Kleisli[Task, Int, Boolean] { 
   case i: Int => if (i === 42) Task.now(true) else Task.now(false)
}

val y = Kleisli[Task, String, Unit] { 
    case s: String => Task.delay { println(s"$s was here") } 
}

由于编译失败,我无法调用x >> y

scala> x >> y
<console>:21: error: type mismatch;
 found   : scalaz.Kleisli[scalaz.concurrent.Task,String,Unit]
 required: scalaz.Kleisli[scalaz.concurrent.Task,Int,?]
       x >> y
            ^

因此,将xy的类型从Kleisli[Task, Int, Boolean]Kleisli[Task, String, Boolean]更改为Kleisli[Task, AppConfig, Boolean]是否合理?

如果没有,请提出更好的选择和理由。

2 个答案:

答案 0 :(得分:2)

我认为你在寻找的是

x *** y

会给你Kleisli[Task, (Int, String), (Boolean, Unit)]

***来自Arrow语法,表示并行合成(与>>=>>的顺序合成相对)。

答案 1 :(得分:1)

以下是发生的事情:因为在Scalaz中Kleisli[M, A, B]可以解释为Scala函数A => M[B],所以它有内置的阅读器monad实例,在这种情况下使用。读取器monad是在从固定类型R => M[A]读取的函数R上定义的。因此,您需要匹配Kleisli箭头的输入类型才能使用它,但实际情况并非如此。 Kleisli组合>=>也不可用:它需要第一个Kleisli(签名中为B)的结果类型来匹配第二个的输入类型A。您可以提供参数并向下移动到Task级别:

x(42) >> y("abc")

或者,如果你想保持Kleisli级别,你可能想要使用平行箭头组合,如其他答案中所述:

import scalaz.syntax.arrow._ // if you're not importing whole Scalaz
import Function.const
(x *** y).map(const()) // use map to ignore result

请注意,这也意味着您最终需要在以后提供参数。