对此的上下文非常简单.我的假设是基于Odersky的书"Scala编程,第2版",第8.5节描述"占位符语法".
我有一个List [List [Boolean]](即一个矩形位图),我试图计算值"true"的总出现次数.这是定义执行正常的数据的REPL行:
val rowsByColumns =
List( List(false, true, false)
, List(true, true, true)
, List(false, true, false)
)
Run Code Online (Sandbox Code Playgroud)
接下来,我尝试使用以下行计算"true"的出现次数.而不是执行,我收到一个错误:
val marks = (for(row <- rowsByColumns)
yield {row.foldLeft[Int](0)(_ + (if (_) 1 else 0))}).sum
<console>:8: error: wrong number of parameters; expected = 2
val marks = (for(row <- rowsByColumns) yield {row.foldLeft[Int](0)(_ + (i
f (_) 1 else 0))}).sum
^
Run Code Online (Sandbox Code Playgroud)
我不理解错误,因为我有两个下划线代表函数的参数.所以,我通过写这个执行得很好的函数使函数更加明确:
val marks = (for(row <- rowsByColumns)
yield {row.foldLeft[Int](0)((sum, marked) => sum + (if (marked) 1 else 0))}
).sum
Run Code Online (Sandbox Code Playgroud)
我的问题是这样的:为什么我收到错误并且不太明确的情况,但是当我通过减少"简化"来映射函数时,它是否正确执行?
感谢您提供有关此问题的任何见解.
Tra*_*own 13
Scala的占位符语法对匿名函数的限制可能非常混乱(至少对我来说).一条经验法则是下划线被绑定到它们最近的括号中,但这是一个近似值 - 请参阅Scala规范的第6.23节中的详细信息:
如果以下两个条件成立,则句法类别的表达式e
Expr绑定下划线部分u:(1)e正确包含u,以及(2)没有其他句法类别的表达式,Expr它正确包含在e中并且其本身正确包含ü.
在这种情况下,编译器不会将第二个下划线视为第二个参数.这可能看起来很奇怪,因为它_ + _被正确地视为具有两个参数,并且if (_) x else y等效于z => if (z) x else y(其中z是新标识符),但嵌套这两个参数不起作用.
确实,编译器理论上可以确定两个下划线应该是您的同一个匿名函数的参数foldLeft,但不是,例如,在下面,第二个下划线确实需要单独绑定:
rowsByColumns.map(_.map(!_))
Run Code Online (Sandbox Code Playgroud)
但是,这需要编译器方面的许多额外的聪明才智,并且Scala语言设计者已经确定它不值得 - 只需要为没有嵌套表达式的一些相当简单的情况提供占位符语法.
幸运的是,在这种情况下你可以写rowsByColumns.flatten.count(identity).flatten这里连接子列表给出一个单独的List[Boolean].然后,我们想知道该列表中有多少值true.count获取谓词并告诉您集合中有多少值满足该谓词.例如,这是计算1到10(含)之间的偶数的一种方法:
val isEven: Int => Boolean = _ % 2 == 0
(1 to 10) count isEven
Run Code Online (Sandbox Code Playgroud)
但是,在您的情况下,我们已经有了布尔值,因此谓词不需要做任何工作 - 它只能是身份函数x => x.正如dhg在评论中指出的那样,Scala的Predef对象提供了这个名为的方法identity,我在这里使用它.rowsByColumns.flatten.count(x => x)但是,如果你发现更清楚的话,你可以轻松地写出来.
| 归档时间: |
|
| 查看次数: |
974 次 |
| 最近记录: |