捕获返回类型中的类型class

Capture type class in returning type

在下面的示例中,我必须重复 M 是一个 Monad 以便定义 bar 这似乎是不必要的,因为我已经按照我定义的方式告诉编译器 fnc.

import scalaz._
import scalaz.Scalaz._

object MyTest {

  // function returning a function accepting a monad as parameter
  def fnc[M[_]: Monad, T](t: T): (M[T] => T) = xs => t

  // this works
  def bar[M[_]: Monad]: (M[Double] => Double) = fnc(1.0)

  // I would like this also to work
  val foo = fnc(1.0)
}

如何使 foo 成为接受任何 M[T] 的函数?

Scala 没有多态函数——任何函数值的输入和输出类型必须是具体类型(但是,你可以有 return 函数的多态方法,并且你的 fncbar 就是这样的例子)。这意味着您的 foo 定义仅在您指定具体的单子类型时才有效:

val foo: List[Double] => Double = fnc(1.0)

Shapeless 使用对象和隐式一起实现多态函数值:

import scalaz._, Scalaz._

object foo extends shapeless.Poly1 {
  implicit def double[M[_]: Monad]: Case.Aux[M[Double], Double] = at(_ => 1.0)
}

然后:

scala> foo(List(1.0))
res0: Double = 1.0

scala> foo(Option(1.0))
res1: Double = 1.0

scala> foo(1.0: Id[Double])
res2: Double = 1.0

但不幸的是,由于语言的限制,对于如何定义这些多态函数值有很多限制(例如,很难将 1.0 部分作为参数),所以一般来说,让多态方法起作用可能会更好。