[英]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, 所以问题是
What is the meaning of "=> Int with Int => String" and why t(g) does not type-check “ => Int with Int => String”的含义是什么,为什么t(g)不进行类型检查
What is the meaning of "(=> Int with Int) => String" and why t(f) does not type-check “(=> Int with Int)=>字符串”的含义是什么,为什么t(f)不进行类型检查
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 => Y
即Function1[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.