Scala可以在参数中允许自由类型参数(Scala类型参数是一等公民?)?

时间:2009-07-16 18:05:27

标签: scala type-parameter

我有一些Scala代码可以使用两个不同版本的类型参数化函数来执行某些操作。我已经从我的应用程序中简化了很多,但最后我的代码充满了w(f[Int],f[Double])形式的调用,其中w()是我的神奇方法。我希望有一个像z(f) = w(f[Int],f[Double])这样更神奇的方法 - 但是我不能得到像z(f[Z]:Z->Z)这样的语法来工作,因为它看起来(对我来说)函数参数不能有自己的类型参数。这是Scala代码段的问题。

有什么想法吗?宏可以做到,但我不认为它们是Scala的一部分。

object TypeExample {
  def main(args: Array[String]):Unit = {
    def f[X](x:X):X = x              // parameterize fn
    def v(f:Int=>Int):Unit = { }     // function that operates on an Int to Int function
    v(f)                             // applied, types correct
    v(f[Int])                        // appplied, types correct
    def w[Z](f:Z=>Z,g:Double=>Double):Unit = {} // function that operates on two functions
    w(f[Int],f[Double])              // works
// want something like this:  def z[Z](f[Z]:Z=>Z) = w(f[Int],f[Double])
// a type parameterized function that takes a single type-parameterized function as an  
// argument and then speicalizes the the argument-function to two different types,  
// i.e. a single-argument version of w() (or wrapper)
  }
}

3 个答案:

答案 0 :(得分:6)

你可以这样做:

trait Forall {
  def f[Z] : Z=>Z
}

def z(u : Forall) = w(u.f[Int], u.f[Double])

或使用结构类型:

def z(u : {def f[Z] : Z=>Z}) = w(u.f[Int], u.f[Double])

但这会比第一个版本慢,因为它使用反射。

编辑:这是您使用第二个版本的方式:

scala> object f1 {def f[Z] : Z=>Z = x => x}
defined module f1

scala> def z(u : {def f[Z] : Z=>Z}) = (u.f[Int](0), u.f[Double](0.0))
z: (AnyRef{def f[Z]: (Z) => Z})(Int, Double)

scala> z(f1)
res0: (Int, Double) = (0,0.0)

对于第一个版本,添加f1 extends Forall或简单地

scala> z(new Forall{def f[Z] : Z=>Z = x => x})

答案 1 :(得分:6)

如果你很好奇,你在这里谈论的是“rank-k多态性”。 See wikipedia。在你的情况下,k = 2.一些翻译:

写作时

f[X](x : X) : X = ... 

然后你说f的类型为“forall X.X - > X”

你想要的z是“(forall Z.Z - > Z) - >>单位”。额外的一对括号是一个很大的区别。就维基百科文章而言,它将forall限定符放在2个箭头而不是1个之前。类型变量不能仅实例化一次并且可以执行,它可能必须实例化为许多不同类型。 (这里“实例化”并不意味着对象构造,它意味着将类型赋值给类型变量进行类型检查)。

正如alexy_r的回答所示,这可以使用对象而不是直接函数类型在Scala中编码,基本上使用类/特征作为parens。虽然他似乎让你在插入原始代码方面有点悬而未决,所以这就是:

//这是你的代码

object TypeExample {
  def main(args: Array[String]):Unit = {
    def f[X](x:X):X = x              // parameterize fn
    def v(f:Int=>Int):Unit = { }     // function that operates on an Int to Int function
    v(f)                             // applied, types correct
    v(f[Int])                        // appplied, types correct
    def w[Z](f:Z=>Z,g:Double=>Double):Unit = {} // function that operates on two functions
    w(f[Int],f[Double])              // works

//这是新代码

    trait ForAll {
      def g[X](x : X) : X
    }

    def z(forall : ForAll) = w(forall.g[Int], forall.g[Double])
    z(new ForAll{def g[X](x : X) = f(x)})
  }
}

答案 2 :(得分:2)

我不认为你想做什么是可能的。

修改

我之前的版本存在缺陷。这确实有效:

scala> def z(f: Int => Int, g: Double => Double) = w(f, g)
z: (f: (Int) => Int,g: (Double) => Double)Unit

scala> z(f, f)

但是,当然,它几乎就是你所拥有的。

我认为它甚至不可能工作,因为类型参数仅在编译时存在。在运行时没有这样的事情。因此,传递参数化函数对我来说没有意义,而不是使用Scala推断出的类型参数的函数。

而且,不,Scala没有宏系统。