我希望下面的代码能够进行类型检查。
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)没有打字。
所以问题是,
" =>是什么意思? Int with Int =>字符串"以及为什么t(g)不进行类型检查
"(=> Int with Int)=>是什么意思?字符串"以及为什么t(f)不进行类型检查
应该放什么???
非常感谢。
答案 0 :(得分:3)
首先,类型namespace Hachette.Common.CustomConfigSections
即X => Y
是类型参数Function1[X,Y]
的逆变量,因此您应该搜索最不常见的子类型,而不是X
和{{1}的最大常见超类型}}
第二 - 遗憾的是没有这样的子类型。除此之外,使用类型X
定义除函数之外的任何内容都非常困难。虽然众所周知,类似于=>X
=>X
和Function0[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(_))
。