9

我正在尝试>=>在 Scala 中使用(Kleisli 箭头)。据我了解,它由返回单子的函数组成。现在我尝试如下:

scala> val f = {i:Int => Some(i + 1)}
f: Int => Some[Int] = <function1>

scala> val g = {i:Int => Some(i.toString)}
g: Int => Some[String] = <function1>

scala> val h = f >=> g
<console>:15: error: value >=> is not a member of Int => Some[Int]
       val h = f >=> g
                 ^

为什么不编译?如何作曲fg搭配>=>

4

1 回答 1

11

这里有两个问题。首先是您的函数的推断类型过于具体。Option是一个单子,但Some不是。在像 Haskell 这样的语言中,等价物Some甚至不是类型——它只是一个构造函数——但由于代数数据类型在 Scala 中的编码方式,你必须注意这个问题。有两个简单的修复——要么明确地提供更通用的类型:

scala> val f: Int => Option[Int] = i => Some(i + 1)
f: Int => Option[Int] = <function1>

scala> val g: Int => Option[String] = i => Some(i.toString)
g: Int => Option[String] = <function1>

或者使用Scalaz的handy some,它返回一个适当类型的Some

scala> val f = (i: Int) => some(i + 1)
f: Int => Option[Int] = <function1>

scala> val g = (i: Int) => some(i.toString)
g: Int => Option[String] = <function1>

第二个问题是>=>Scalaz 中没有为普通的旧 monadic 函数提供它——您需要使用Kleisli包装器:

scala> val h = Kleisli(f) >=> Kleisli(g)
h: scalaz.Kleisli[Option,Int,String] = Kleisli(<function1>)

这正是你想要的——只是h.run用来展开。

于 2014-02-09T15:02:55.210 回答