我正在阅读红皮书,在检查我的练习答案时,我发现其中一个练习 (6.11) 的解决方案完全不同(并且比我自己的解决方案更优雅和神秘)。
这是代码:
object Candy {
def update: Input => Machine => Machine = (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, candy, coin)) =>
Machine(false, candy, coin + 1)
case (Turn, Machine(false, candy, coin)) =>
Machine(true, candy - 1, coin)
}
def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = for {
_ <- State.sequence(inputs map (modify[Machine] _ compose update))
s <- get
} yield (s.coins, s.candies)
def modify[S](f: S => S): State[S, Unit] = for {
s <- get // Gets the current state and assigns it to `s`.
_ <- set(f(s)) // Sets the new state to `f` applied to `s`.
} yield ()
def get[S]: State[S, S] = State(s => (s, s))
def set[S](s: S): State[S, Unit] = State(_ => ((), s))
Run Code Online (Sandbox Code Playgroud)
我不确定的是这一行:
inputs map (modify[Machine] _ compose update)
我了解 compose 的工作原理,但这种特殊的语法确实让我陷入了循环。有没有一种方法可以重写它,而不是那么紧凑以帮助菜鸟理解?
提前致谢。
对于其他试图更好地理解此代码如何工作的人,我发现这篇文章很有帮助。
这里使用了几个语法特性:
Scala 允许消息发送使用空格而不是句点作为消息发送操作符,即
foo.bar(baz, quux)
Run Code Online (Sandbox Code Playgroud)
也可以写成
foo bar(baz, quux)
Run Code Online (Sandbox Code Playgroud)
当使用带有单个参数的单个参数列表的运算符语法时,括号可以省略,即
foo bar(baz)
Run Code Online (Sandbox Code Playgroud)
也可以写成
foo bar baz
Run Code Online (Sandbox Code Playgroud)
Scala 中的匿名函数可以使用下划线_作为参数的占位符来编写。粗略地说,每个下划线都被最接近的词法封闭匿名函数的每个参数替换,按照在源文本中出现的顺序,即
val adder: (Int, Int) => Int = (x, y) => x + y
Run Code Online (Sandbox Code Playgroud)
也可以写成
val adder: (Int, Int) => Int = _ + _
Run Code Online (Sandbox Code Playgroud)
下划线_在 Scala 中有很多用途,所以有时如果你不够仔细,你可能会混淆不同的用法。在这种情况下,粗略一看,似乎下划线_可能意味着modify? 扩展为方法值,但事实并非如此。下划线_是匿名函数参数占位符。
因此,如果我们将上述三个语法特征放在一起,则有问题的代码段将脱糖为
inputs.map(
// ? Operator Syntax
(
f => modify[Machine](f)
// ? Placeholder Syntax ?
).compose(update)
// ? Operator Syntax
)
Run Code Online (Sandbox Code Playgroud)
如果你有什么特定的代码方式的语法,你可以打印出Scala编译器或斯卡拉REPL /“解释”在使用的各个阶段的内部状态的疑虑-Xprint:<name-of-phase>命令行选项scala。例如,这是-Xprint:parser相关代码段的打印内容:
inputs.map((modify[Machine]: (() => <empty>)).compose(update))
Run Code Online (Sandbox Code Playgroud)
这是-Xprint:typer:
inputs.map[this.State[this.Machine, Unit]](
(
(f: this.Machine => this.Machine) => $anon.this.State.modify[this.Machine](f)
).compose[this.Input](Candy.this.update)
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
95 次 |
| 最近记录: |