为啥折叠推断任何?
Posted
技术标签:
【中文标题】为啥折叠推断任何?【英文标题】:Why fold infers Any?为什么折叠推断任何? 【发布时间】:2021-06-17 03:24:04 【问题描述】:我正在使用 Scala 2.11.12 和此声明进行编译:
import scala.collection.mutable.Stack
def stackToInt(stack: Stack[Int]): Int =
stack.zipWithIndex.fold(0) case (z: Int, (piece: Int, index: Int)) =>
piece match
case 1 => (1 << index) + z
case _ => z
给予:
stack.zipWithIndex.fold(0) case (z: Int, (piece: Int, index: Int)) =>
^
error: type mismatch;
found : Any
required: Int
在这个项目(Scala 中的第一个)中编写折叠时,我一直在处理类似的事情很多次,我总是找到一种不同的方法来使它工作,但也许如果我理解它,我将不再碰壁.
【问题讨论】:
相关***.com/questions/16111440/scala-fold-vs-foldleft 【参考方案1】:fold
方法需要一个关联二元运算作为它的第二个参数,即满足某些运算 f(_, _)
f(x, f(y, z)) = f(f(x, y), z)
您的折叠函数f
结合了Int
和(Int, Int)
。
它不能是关联的,因为 f(x, f(y, z))
和 f(f(x, y), z)
不可能同时进行类型检查:
f(x, f(y, z))
类型检查,则x: Int
和f(y, z): (Int, Int)
,
但是,f
的返回类型必须是(Int, Int)
,
但是,f(f(x, y), z)
无法进行类型检查,因为它在第一个参数中获得了 (Int, Int)
,而这里应该是 Int
。
因此,在这里谈论关联性是没有意义的:这种说法甚至不是错误的,它根本就不能放在首位。
由于操作不是关联的,你不能简单地让语言来决定以什么顺序处理元素;您必须选择折叠方向,即决定是否是
f(...f(f(f(a0, x1), x2), x3)...)
(左折叠)
或
f(...f(x(n-3), f(x(n-2), f(x(n-1), a0))...)))))
(右折叠)
在你的情况下,它必须是foldLeft
。
Any
类型被推断为Int
和(Int, Int)
之间的最小上限,因为编译器试图将f
解释为关联操作,它必然具有两个相同的参数输入。
【讨论】:
【参考方案2】:因为你需要使用foldLeft
而不是折叠:
import scala.collection.mutable.Stack
def stackToInt(stack: Stack[Int]): Int =
stack.zipWithIndex.foldLeft(0) case (z: Int, (piece: Int, index: Int)) =>
piece match
case 1 => (1 << index) + z
case _ => z
斯卡蒂:https://scastie.scala-lang.org/VzfKqHZ5QJyNPfwpLVGwSw
fold
不起作用,因为它是语义的:fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1
- 因此在你的情况下,zipWithIndex
给出了(Int, Int)
类型而不是预期的Int
,并且函数内部返回Int
- 所以最后推断类型你看 Any
- (Int, Int)
和 Int
之间的共同祖先。
而foldLeft[Z](zero: Z)
推断出Int
因为你给了0
【讨论】:
最好解释一下fold
和foldLeft
之间的区别以及为什么会导致Any
类型。
@LuisMiguelMejíaSuárez 几乎完成了,谢谢!以上是关于为啥折叠推断任何?的主要内容,如果未能解决你的问题,请参考以下文章