具有Lambda表达式的复杂Scala类型推断
我正在为一个我在
Scala中构建的实验库工作的DSL,我遇到了Scala类型推断的一些棘手的特性,因为它与lambda表达式参数有关,这些参数似乎没有在
Programming In Scala中讨论过. .
在我的库中,我有一个特性,Effect [-T],用于表示可以应用于类型T的对象的临时修饰符.我有一个对象myEffects,它有一个名为=的方法接受一个参数效果类型[PlayerCharacter].最后,我有一个泛型方法,当[T]时,用于通过接受条件表达式和另一个效果作为参数来构造条件效果.签名如下: def when[T](condition : T => Boolean) (effect : Effect[T]) : Effect[T] 当我使用上述签名调用“when”方法时,将其结果传递给=方法,它无法推断lambda表达式的参数类型. myEffects += when(_.hpLow()) (applyModifierEffect) //<-- Compiler error 如果我将“when”的参数组合到一个参数列表中,Scala能够很好地推断lambda表达式的类型. def when[T](condition : T => Boolean,effect : Effect[T]) : Effect[T] /* Snip */ myEffects += when(_.hpLow(),applyModifierEffect) //This works fine! 如果我完全删除第二个参数,它也可以工作. def when[T](condition : T => Boolean) : Effect[T] /* Snip */ myEffects += when(_.hpLow()) //This works too! 但是,出于美观原因,我真的希望将参数作为单独的参数列表传递给“when”方法. 我在Programming in Scala第16.10节中的理解是,编译器首先查看方法类型是否已知,如果是,则使用它来推断它的参数的预期类型.在这种情况下,最外层的方法调用是=,它接受Effect [PlayerCharacter]类型的参数.由于when [T]的返回类型是Effect [T],并且传递结果的方法需要Effect [PlayerCharacter]类型的参数,它可以推断T是PlayerCharacter,因此lambda的类型表达式作为第一个参数传递给“when”是PlayerCharacter =>布尔.这似乎是在一个参数列表中提供参数时它是如何工作的,那么为什么将参数分成两个参数列表呢? 解决方法
我自己对Scala比较陌生,而且我没有很多关于类型推理如何工作的详细技术知识.所以最好带上一粒盐.
我认为不同之处在于编译器无法证明两个Ts的条件相同:T =>布尔和效果:效果[T],在双参数列表版本中. 我相信当你有多个参数列表时(因为Scala将其视为定义一个返回消耗下一个参数列表的函数的方法),编译器会一次处理一个参数列表,而不是像单个参数列表版本一样. 所以在这种情况下: def when[T](condition : T => Boolean,applyModifierEffect) //This works fine! applyModifierEffect的类型和myEffects =的必需参数类型可以帮助约束_.hpLow()的参数类型;所有的Ts必须是PlayerCharacter.但在以下内容中: myEffects += when(_.hpLow()) (applyModifierEffect) 编译器必须独立地计算出when(_.hpLow())的类型,以便它可以检查将它应用于applyModifierEffect是否有效.并且就其自身而言,_.hpLow()没有为编译器提供足够的信息来推断这是[PlayerCharacter](_.hpLow())的时候,所以它不知道返回类型是函数type Effect [PlayerCharacter] =>效果[PlayerCharacter],因此它不知道在该上下文中应用该函数是有效的.我的猜测是类型推断只是没有连接点,并发现只有一种类型可以避免类型错误. 至于其他有效的案例: def when[T](condition : T => Boolean) : Effect[T] /* Snip */ myEffects += when(_.hpLow()) //This works too! 这里返回类型的when和它的参数类型更直接连接,而不经过参数类型和currying创建的额外函数的返回类型.由于myEffects =需要Effect [PlayerCharacter],因此T必须是具有hpLow方法的PlayerCharacter,并且编译器已完成. 希望有更多知识渊博的人可以纠正我的细节,或者指出我是否完全咆哮了错误的树! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |