在 Scala 中,泛型类型参数可以与 *function* 定义一起使用吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15264838/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:02:20  来源:igfitidea点击:

In Scala, can generic type parameters be used with *function* definitions?

scalagenerics

提问by erich2k8

Is there a syntax to allow generic type parameters on function literals? I know I could wrap it in a method such as:

是否有允许在函数文字上使用泛型类型参数的语法?我知道我可以用一种方法来包装它,例如:

def createLongStringFunction[T](): (T) => Boolean = {
  (obj: T) => obj.toString.length > 7
}

but then I end up needing to invoke the method for every type T and getting a new function. I looked through the language reference, and while I see that the function literal syntax is translated by the compiler to an instance of a Functionnobject that itself has generic input types, it looks like the compiler magic realizes those parameters at the time of creation. I haven't found any syntax that allows me to, in effect, "leave one or more of the type parameters of Functionnunbound". What I would prefer is something along the lines of:

但后来我最终需要为每个类型 T 调用该方法并获得一个新函数。我查看了语言参考,虽然我看到函数文字语法被编译器翻译成一个Functionn对象的实例,它本身具有通用输入类型,但看起来编译器魔术在创建时实现了这些参数。我还没有找到任何允许我实际上“使Functionn 的一个或多个类型参数未绑定”的语法。我更喜欢的是:

// doesn't compile
val longStringFunction: [T](T) => Boolean = (obj: T) => obj.toString.length > 7

Does any such thing exist? Or for that matter, what is the explicit type of an eta-expansion function when the method being expanded has generic parameters?

有没有这样的东西?或者就此而言,当被扩展的方法具有泛型参数时,eta 扩展函数的显式类型是什么?

This is a purely contrived and useless example. Of course I could just make the function use Any here.

这是一个纯粹人为的和无用的例子。当然,我可以让函数在这里使用 Any 。

采纳答案by Kipton Barros

No, type parameters only apply to methods and not function objects. For example,

不,类型参数仅适用于方法而不适用于函数对象。例如,

def f[T](x: T) = x     //> f: [T](x: T)T
val g = f _            //> g: Nothing => Nothing = <function1>
// g(2)                // error
val h: Int=>Int = f _  //> h  : Int => Int = <function2>
h(2)                   //> res0: Int = 2

The method fcannot be converted to a polymorphic function object g. As you can see, the inferred type of gis actually Function1[Nothing, Nothing], which is useless. However, with a type hint we can construct h: Function1[Int,Int]that works as expected for Intargument.

该方法f无法转换为多态函数对象g。如您所见,推断出的类型g实际上是Function1[Nothing, Nothing],这是无用的。但是,使用类型提示,我们可以构造h: Function1[Int,Int]按预期工作的Int参数。

回答by Impredicative

As you say, in your example all you're requiring is the toStringmethod and so Anywould be the usual solution. However, there is call for being able to use higher-rank types in situations such as applying a type constructor such as Listto every element in a tuple.

正如您所说,在您的示例中,您需要的只是toString方法,Any通常的解决方案也是如此。但是,在诸如将类型构造函数应用于List元组中的每个元素等情况下,需要能够使用更高级别的类型。

As the other answers have mentioned, there's no direct support for this, but there's a relatively nice way to encode it:

正如其他答案所提到的,对此没有直接支持,但是有一种相对不错的编码方式:

trait ~>[A[_],B[_]] {
  def apply[X](a : A[X]) : B[X]
}

type Id[A] = A //necessary hack

object newList extends (Id ~> List) {
  def apply[X](a : Id[X]) = List(a)
}

def tupleize[A,B, F[_]](f : Id ~> F, a : A, b : B) = (f(a), f(b))

tupleize(newList, 1, "Hello") // (List(1), List(Hello))

回答by ievgen.garkusha

In scala, Function values are parametrically monomorphic(while methods are polymorphic)

在 Scala 中,函数值在参数上是单态的(而方法是多态的)

Shapeless library introduces polymorphic function values which may be mapped over HLists and many more other features.

Shapeless 库引入了可以映射到 HList 和更多其他功能的多态函数值。

Please consider the following refs: http://www.chuusai.com/2012/04/27/shapeless-polymorphic-function-values-1/http://www.chuusai.com/2012/05/10/shapeless-polymorphic-function-values-2/

请考虑以下参考文献:http: //www.chuusai.com/2012/04/27/shapeless-polymorphic-function-values-1/ http://www.chuusai.com/2012/05/10/shapeless-多态函数值-2/

回答by Eastsun

Since longStringFunctiondefined as followed is a value, which must have some given type.

由于longStringFunction定义如下是一个,它必须具有某种给定的类型

val longStringFunction: (T) => Boolean = (obj: T) => obj.toString.length > 7

However, you can reuse a function object with a method:

但是,您可以使用方法重用函数对象:

scala> val funObj: Any => Boolean = _.toString.size > 7
funObj: Any => Boolean = <function1>

scala> def typedFunction[T]: T => Boolean = funObj
typedFunction: [T]=> T => Boolean

scala> val f1 = typedFunction[String]
f1: String => Boolean = <function1>

scala> val f2 = typedFunction[Int]
f2: Int => Boolean = <function1>

scala> f1 eq f2
res0: Boolean = true

This works because trait Function1[-T1, +R]is contravariantof type T1.

这是有效的,因为它trait Function1[-T1, +R]是type 的逆变T1