来自 Scala,CoffeeScript 中缺少阴影似乎很奇怪。我写了一个演示。
object ZekeDemo extends App {
val filterAll = (arr: Seq[String]) => {
val saved = ArrayBuffer[String]()
val removed = ArrayBuffer[String]()
val filterDo = (arr: Seq[String]) => {
val saved = for {item <- arr if item != "do"} yield item
val removed = for {item <- arr if item == "do"} yield item
(saved, removed)
}
val filterSo = (arr: Seq[String]) => {
val saved = for {item <- arr if item != "so"} yield item
val removed = for {item <- arr if item == "so"} yield item
(saved, removed)
}
val addRemoved = (item: String) => removedBuff += item
val addSaved = (item: String) => savedBuff += item
for {item <- filterDo(arr)._1} { addSaved(item)}
for {item <- filterDo(arr)._2} { addRemoved(item)}
for {item <- filterSo(arr)._1} { addSaved(item)}
for {item <- filterSo(arr)._2} { addRemoved(item)}
(saved, removed)
}
val song = Seq("do", "re", "mi", "fa", "so")
val s = filterAll(song)._1
val r = filterAll(song)._2
println("saved: %s, removed: %s".format(s.mkString(","), r.mkString(",")))
}
现在这是 CoffeeScript 中的相同程序:
filterAll = (arr) ->
saved = []
removed = []
filterDo = (arr) ->
saved = ->
item for item in arr when item != "do"
removed = ->
item for item in arr when item == "do"
{"saved":saved(), "removed":removed()}
filterSo = (arr) ->
saved = ->
item for item in arr when item != "so"
removed = ->
item for item in arr when item == "so"
{"saved":saved(), "removed":removed()}
addRemoved = (item) ->
saved[saved.length] = item
addSaved = (item) ->
removed[removed.length] = item
addRemoved item for item in filterDo(arr)["removed"]
addSaved item for item in filterDo(arr)["saved"]
addRemoved item for item in filterSo(arr)["removed"]
addSaved item for item in filterSo(arr)["saved"]
{"saved":saved, "removed":removed}
song = ["do", "re", "mi", "fa", "so"]
s = filterAll(song)["saved"]
r = filterAll(song)["removed"]
alert("saved: " + s + ", removed: " + r)
声明为数组的“已保存”被引用 for 理解的“已保存”覆盖。更改变量名称会产生预期的输出。
这对我来说似乎很奇怪。函数式语言之美的很大一部分是不需要了解外部作用域。如果我在另一个上下文(类|函数|文件)中编写我的“filterDo”函数,我相信我应该能够将它放到它是有效语法的任何其他上下文中,而不必担心它是否会踩到来自的值一个外部范围。
要求开发人员知道当前范围之外的范围内的所有变量名称的语言会阻止其开发人员进行封装。我可以通过将 filterDo 和 filterSo 移到外部范围来修复这个错误。但这会污染该作用域的命名空间,并不必要地增加界面的表面积。
CoffeeScript 没有为隐藏变量提供特殊语法的论点是,您根本不应该做这种事情。清楚地命名你的变量。因为即使允许使用阴影,如果有两个具有两种不同含义的变量具有相同的名称,一个在内部范围内,一个在封闭范围内,这将是非常令人困惑的。
我原则上喜欢这个想法,但在实践中,我不相信语言应该表现出如此难以根据如此微妙的规则追踪和解决的行为。变量命名是编码风格的反映,风格选择不应该改变程序的行为。