我正在尝试在Scala中使用>=>
(Kleisli箭头)。据我所知,它组成了返回monad的函数。现在我尝试如下:
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 ^
为什么不编译?如何使用f
撰写g
和>=>
?
答案 0 :(得分:11)
这里有两个问题。首先,您推断的函数类型过于具体。 Option
是monad,但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的方便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
来解包。