scala - 使用 Lambda 表达式的复杂 Scala 类型推断

标签 scala type-inference lambda

我正在为我在 Scala 中构建的实验库开发 DSL,我遇到了 Scala 类型推断的一些令人烦恼的特性,因为它与 Programming In Scala 书中似乎没有涵盖的 lambda 表达式参数有关.

在我的库中,我有一个特征 Effect[-T],用于表示可应用于 T 类型对象的临时修饰符。我有一个对象 myEffects,它有一个名为 += 的方法,它接受一个Effect[PlayerCharacter] 类型的参数。最后,我有一个通用方法 when[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 => Boolean。当参数在一个参数列表中提供时,这似乎是它的工作原理,那么为什么将参数分成两个参数列表会破坏它呢?

最佳答案

我自己对 Scala 比较陌生,而且我对类型推断的工作原理没有很多详细的技术知识。所以最好把这个和一粒盐一起吃。

我认为不同之处在于编译器无法向自己证明这两个 T condition : T => Boolean 中的 s 相同和 effect : Effect[T] , 在双参数列表版本中。

我相信当您有多个参数列表时(因为 Scala 将其视为定义一个返回使用下一个参数列表的函数的方法)编译器一次处理一个参数列表,而不是像在单个参数列表版本中那样全部一起处理。

所以在这种情况下:

def when[T](condition : T => Boolean, effect : Effect[T]) : Effect[T]

/* Snip */

myEffects += when(_.hpLow(), applyModifierEffect) //This works fine!
applyModifierEffect的类型以及所需的参数类型myEffects +=可以帮助约束_.hpLow()的参数类型;所有T s 必须是 PlayerCharacter .但在下面:
myEffects += when(_.hpLow()) (applyModifierEffect)

编译器必须找出 when(_.hpLow()) 的类型独立,以便它可以检查将其应用于 applyModifierEffect 是否有效.就其本身而言,_.hpLow()没有为编译器提供足够的信息来推断这是 when[PlayerCharacter](_.hpLow()) , 所以它不知道返回类型是 Effect[PlayerCharacter] => Effect[PlayerCharacter] 类型的函数,因此它不知道在该上下文中应用该函数是否有效。我的猜测是,类型推断只是没有连接点,并找出恰好有一种类型可以避免类型错误。

至于另一种有效的情况:
def when[T](condition : T => Boolean) : Effect[T]

/* Snip */

myEffects += when(_.hpLow()) //This works too!

这里返回类型when和它的参数类型更直接相连,不需要经过currying创建的额外函数的参数类型和返回类型。由于myEffects +=需要 Effect[PlayerCharacter] , T必须是 PlayerCharacter ,其中有 hpLow方法,编译完成。

希望有更多知识的人可以纠正我的细节,或者指出我是否完全吠错了树!

关于scala - 使用 Lambda 表达式的复杂 Scala 类型推断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7655818/

相关文章:

java - Java 类型推断何时产生无限类型?

C# 类型推断因包含默认参数的方法而失败

java - Scala/Java 中是否存在并发可变数组(或任何其他索引随机访问)?

java - Play JSON : How to use string as proper json

Scala可堆叠特征

scala - 为什么表达式的值取决于分配给它的变量?

python - "merging"使用 lambda 和 map 的字典

C++0x 和 lambda

Java 8 - 如何通过 groupingBy 和 summingInt 使用 lambda 并使用按位运算符

scala - 如何从 build.sbt 运行主类?