问题描述
我正在使用 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,index: Int)) =>
^
error: type mismatch;
found : Any
required: Int
在这个项目中编写折叠时我已经处理过很多次这样的东西(第一个在 Scala 中),我总是找到一种不同的方法来使它工作,但也许如果我理解它,我将不再碰这堵墙.
解决方法
因为您需要使用 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
方法需要一个关联二元运算作为它的第二个参数,即一些满足 f(_,_)
的运算
f(x,f(y,z)) = f(f(x,y),z)
您的折叠函数 f
结合了 Int
和 (Int,Int)
。
它不能是关联的,因为 f(x,z))
和 f(f(x,z)
不可能同时进行类型检查:
- 如果
f(x,z))
类型检查,则x: Int
和f(y,z): (Int,Int)
, - 但是,
f
的返回类型必须是(Int,Int)
, - 但是,
f(f(x,z)
无法进行类型检查,因为它在第一个参数中得到(Int,Int)
,其中需要Int
。
因此,在这里谈论结合性没有意义:该声明甚至都不是错误的,它根本无法首先陈述。
由于操作不是关联的,你不能简单地让语言来决定以什么顺序处理元素;你必须选择一个折叠方向,即决定它是否是
f(...f(f(f(a0,x1),x2),x3)...)
(foldLeft)
或
f(...f(x(n-3),f(x(n-2),f(x(n-1),a0))...)))))
(foldRight)
就您而言,它必须是 foldLeft
。
类型 Any
被推断为 Int
和 (Int,Int)
之间的最小上限,因为编译器试图将 f
解释为关联操作,其中,必然有两个相同类型的参数。