简体   繁体   English

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

[英]Scala supertype of call-by-name and call-by-value

I want below code to be type-checked. 我想对下面的代码进行类型检查。

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

What should be put in "???"? 应该在“ ???”中添加什么? I have read this link and tried it. 我已阅读此链接并尝试过。

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

So I put "=> Int with Int => String" in the ???, but t(g) does not type-check. 因此,我在???中放置了“ => Int with Int => String”,但是t(g)不会进行类型检查。 I have tried "(=> Int with Int) => String" but t(f) does not type-check. 我已经尝试过“((=> Int with Int)=>字符串)”,但是t(f)没有进行类型检查。

So the question is, 所以问题是

  1. What is the meaning of "=> Int with Int => String" and why t(g) does not type-check “ => Int with Int => String”的含义是什么,为什么t(g)不进行类型检查

  2. What is the meaning of "(=> Int with Int) => String" and why t(f) does not type-check “(=> Int with Int)=>字符串”的含义是什么,为什么t(f)不进行类型检查

  3. What should be put in ??? 应该放什么???

Thanks a lot. 非常感谢。

First of all type X => Y ie Function1[X,Y] is contravariant on type parameter X so you should search least common subtype, not greatest common supertype of X and =>X 首先,类型X => YFunction1[X,Y]在类型参数X上是互变的,因此您应该搜索X最小公称子类型,而不是X最大公称父类型,并且=>X

Second - unfortunately there is not such subtype. 第二-不幸的是没有这种亚型。 More over it's very hard to define anything except function using type =>X . 而且,除使用type =>X函数外,很难定义任何东西。 Although it's known such definition desugars later to Function0[X] on typecheck level types =>X and ()=>X are not equivalent. 尽管已知此类定义稍后会在类型检查级别上对Function0[X]消减,但类型=>X()=>X并不等效。

Happily we could define complex relations between types for our needs using typeclasses. 幸运的是,我们可以使用类型类为我们的需求定义类型之间的复杂关系。

As we could use =>X only in parameter types we could define such a thing: 因为我们只能在参数类型中使用=>X ,所以我们可以定义这样的事情:

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

Which looks and works like some narrow version of contravariant functor 看起来和工作起来像收缩函子的某些狭窄版本

And provide two obvious implementations 并提供两个明显的实现

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))

Now we can generalize your t function as 现在我们可以将您的t函数推广为

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

At this point your 此时,您的

t(f)
t(g)

Should compile and run nicely 应该编译并运行良好

The problem is that Int => String and (=> Int) => String don't have useful common super type. 问题在于Int => String(=> Int) => String没有有用的通用超级类型。 Int => String is the type of a call-by-value function which takes an Int value as first parameter and returns a String . Int => String是按值调用函数的类型,该函数将Int值作为第一个参数并返回String

In contrast to that (=> Int) => String is a call-by-name function which takes an expression of type Int as the first parameter. 与此相反, (=> Int) => String是一个按名称调用函数,该函数将Int类型的表达式作为第一个参数。 Every time you access the call-by-name parameter the expression is evaluated. 每次您访问call-by-name参数时,都会对表达式进行求值。 Thus, it is effectively a zero argument function returning an Int . 因此,它实际上是一个返回Int的零参数函数。

What you can do is to convert the call-by-name function into a call-by-value function so that t(h: Int => String): String type checks also with g . 您可以执行的操作是将“按名称调用”功能转换为“按值调用”功能,以便t(h: Int => String): String类型也使用g进行检查。 You simply have to call t(g(_)) . 您只需调用t(g(_))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM