Scala编译器不能正确推断类型
我正在阅读Scala函数式编程的第6章。 我已经接近了本章的最后一个练习(即:6.11),这使我怀疑某些代码行。
这里是练习的描述:
让我们来实现一个有限状态自动机,它可以模拟一个简单的糖果分配器。 机器有两个输入:您可以插入一个硬币,或者您可以通过旋转旋钮来分配糖果。 它可以处于两种状态之一:锁定或解锁。 它还会跟踪剩余的糖果数量以及它包含的硬币数量。
方法simulateMachine
应根据输入列表操作机器并返回机器中残留的硬币和糖果的数量。 例如,如果输入机器有10个硬币和5个糖果,并且总共购买了4个糖果,则输出应该是(14,1)。
以下是我自己实施的可测试单元。
object Test extends App {
class Comparison(value: Int) {
def shouldBe(other: Int): Boolean = value == other
}
implicit def enrichIntegers(value: Int) = new Comparison(value)
val machine = Machine(locked = true, candies = 5, coins = 10)
val input = List(Coin, Turn, Coin, Turn, Coin, Turn, Coin, Turn)
val result = StateChange.simulateMachine(input)
val tuple: ((Int, Int), Machine) = result.run(machine)
val ((coins, candies), _) = tuple
(coins shouldBe 14) && (candies shouldBe 1) match {
case true => println("Ok")
case false => println("Ko")
}
}
sealed trait Input
case object Coin extends Input
case object Turn extends Input
case class Machine(locked: Boolean, candies: Int, coins: Int)
case class State[S,+A](run: S => (A, S)) {
def map[B](f: A => B): State[S, B] = State(
s => {
val (a, newState) = this.run(s)
(f(a), newState)
}
)
def map2[B,C](sb: State[S, B])(f: (A, B) => C): State[S, C] = State(
s => {
val (a, newState) = this.run(s)
val (b, finalState) = sb.run(newState)
(f(a, b), finalState)
}
)
def flatMap[B](f: A => State[S, B]): State[S, B] = State(
s => {
val (a, state): (A, S) = this.run(s)
f(a).run(state)
}
)
}
object State {
def get[S]: State[S, S] = State(s => (s, s))
def set[S](s: S): State[S, Unit] = State(_ => ((), s))
def modify[S](f: S => S): State[S, Unit] = {
for {
s <- get
_ <- set(f(s))
} yield ()
}
def unit[S, A](a: A): State[S, A] = State(s => (a,s))
def sequence[S, A](fs: List[State[S,A]]): State[S, List[A]] = {
fs.foldRight[State[S, List[A]]](State.unit(Nil))((elem, acc) => elem.map2(acc)((a,b)=>a::b))
}
}
object StateChange {
def update(i: Input)(s: Machine) = {
(i,s) match {
case (_, Machine(_,0,_)) => s
case (Coin, Machine(false,_,_)) => s
case (Turn, Machine(true,_,_)) => s
case (Coin, Machine(true,candies,coins)) => Machine(false,candies,coins+1)
case (Turn, Machine(false,candies,coins)) => Machine(true,candies-1,coins)
}
}
def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = {
import State._
val list: State[Machine, List[Unit]] = sequence(inputs.map(input => modify(update(input))))
list.flatMap((_: List[Unit]) =>
State(
s => {
val currentState: State[Machine, Machine] = get // <= my doubt is here
val (currentMachine, newState) = currentState.run(s)
((currentMachine.coins, currentMachine.candies), newState)
}
)
)
}
}
我的疑问是关于simulateMachine
定义中的以下行:
val getState: State[Machine, Machine] = get
simulateMachine
实现了一个desugared版本,我写的是为了更好地理解原来为解释练习而写的理解内容。
我的问题是:
为什么我需要显式指定currentState
的类型来编译代码? 事实上,如果没有这个State[Machine, Machine]
类型定义,上面的代码片段不能编译。
为什么编译器无法推断出实际的类型? 这只是一个类型推断限制的问题,还是我在这里错过了一些东西?
希望我的问题很清楚,谢谢!
如果你不提供类型参数来get
并且不明确指定currentState
的类型,Scala就无法知道类型。 它必须从((currentMachine.coins, currentMachine.candies), newState)
和val (currentMachine, newState) = currentState.run(s)
向后推断类型((currentMachine.coins, currentMachine.candies), newState)
但是Scala的类型推断功能不够强大。