Scala超类型的呼叫名称和按值调用

时间:2015-10-19 08:03:48

标签: scala types

我希望下面的代码能够进行类型检查。

val f: Int => String = x => "a"
val g: (=> Int) => String = x => "b"
def t(h: ???): String = h(42)
t(f)
t(g)

应该放什么" ???"? 我看过thread as well并试了一下。

t[Int => String, (=> Int) => String].common
res4s: reflect.runtime.universe.TypeTag[=> Int with Int => String] = TypeTag[=> Int with Int => String]

所以我把" => Int with Int =>字符串"在???中,但t(g)不进行类型检查。 我试过"(=> Int with Int)=>字符串"但是t(f)没有打字。

所以问题是,

  1. " =>是什么意思? Int with Int =>字符串"以及为什么t(g)不进行类型检查

  2. "(=> Int with Int)=>是什么意思?字符串"以及为什么t(f)不进行类型检查

  3. 应该放什么???

  4. 非常感谢。

2 个答案:

答案 0 :(得分:3)

首先,类型namespace Hachette.Common.CustomConfigSections X => Y是类型参数Function1[X,Y]的逆变量,因此您应该搜索最不常见的子类型,而不是X和{{1}的最大常见超类型}}

第二 - 遗憾的是没有这样的子类型。除此之外,使用类型X定义除函数之外的任何内容都非常困难。虽然众所周知,类似于=>X =>XFunction0[X] =>X的{​​{1}}之类的定义desugars并不等同。

令人高兴的是,我们可以使用类型类来定义类型之间的复杂关系。

由于我们只能在参数类型中使用()=>X,我们可以定义这样的事情:

=>X

其外观和工作方式类似于逆变函数的一些窄版本

并提供两个明显的实现

case class ParamConvertible[X, Y, T](apply: ((Y => T) => X => T))

现在我们可以将您的implicit def idParamConvertible[X, T] = ParamConvertible((f: X => T) => (x: X) => f(x)) implicit def byNameParamConvertible[X, T] = ParamConvertible((f: (=> X) => T) => (x: X) => f(x)) 功能概括为

t

此时你的

def t[T](h: T => String)
        (implicit conv: ParamConvertible[Int, T, String]): String =
  conv.apply(h)(42)

应该编译并运行良好

答案 1 :(得分:1)

问题是Int => String(=> Int) => String没有有用的常见超类型。 Int => String是call-by-value函数的类型,它将Int值作为第一个参数并返回String

与此相反,(=> Int) => String是一个名为call-by-name的函数,它将类型Int的表达式作为第一个参数。每次访问call-by-name参数时,都会计算表达式。因此,它实际上是一个返回Int的零参数函数。

您可以做的是将按名称调用的函数转换为按值调用的函数,以便t(h: Int => String): String类型也可以使用g进行检查。您只需致电t(g(_))