在 Scala 中,是否可以 "curry" 键入 def 的参数?

In Scala, is it possible to "curry" type parameters of a def?

假设我有一个带有多个类型参数的 def:

def foo[A, B, C](b: B, c: C)(implicit ev: Writer[A])

但是,预期用途是应该推断类型参数 BC(基于传入的参数)。并且调用者只需要真正明确地指定 A (例如,让编译器选择适当的隐式)。不幸的是,Scala 只允许调用者指定所有或 none 类型参数。从某种意义上说,我希望对类型参数进行柯里化:

def foo[A][B, C]...

在 Scala 中有什么技巧可以做到这一点吗?

(如果我的具体示例没有完全说明问题,我很乐意提出建议来改进它。)

我能够做到这一点的最好方法是定义一个 class 来保存柯里化类型信息,然后使用 apply 方法来模拟函数调用。

我在这里写过这个 - http://caryrobbins.com/dev/scala-type-curry/

对于您的具体示例,您需要将 implicit ev: Writes[A] 放入 apply 的签名中,将 而不是 放入 [= 的签名中16=]。这是因为它会导致显式传递隐式参数或隐式调用 apply 方法之间存在歧义。

这是您的示例的示例实现 -

object Example {
  def foo[A]: _Foo[A] = _foo.asInstanceOf[_Foo[A]]

  final class _Foo[A] private[Example] {
    def apply[B, C](b: B, c: C)(implicit ev: Writes[A]): Unit = ???
  }

  private lazy val _foo = new _Foo[Nothing]
}

然后您可以提供您希望柯里化的类型参数,然后将推断传递给 apply 方法的以下参数。

Example.foo[Int]("bar", new Object)

如果你最终需要指定其他类型参数,你可以通过显式调用 apply;虽然,我还没有看到需要这样做。

Example.foo[Int].apply[String, Object]("bar", new Object)

如果您不想使用中间类型,您也可以使用 结构类型,我在前面提到的 post 中对此进行了讨论;但是,这需要 reflectiveCalls 和推断的类型签名,我希望避免这两者。