Lazy evaluation steps : filtering a list
我对scala中的懒惰评估有一些问题。这是示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | val people=List(("Mark", 32), ("Bob", 22), ("Jane", 8), ("Jill", 21), ("nick", 50), ("Nancy", 42), ("Mike", 19), ("Sara", 12), ("Paula", 42), ("John", 21)) def isOlderThan17(person: (String,Int)) = { println(s"isOlderThan 17 called for $person") val(_,age) = person age > 17 } def nameStartsWithJ(person: (String, Int)) = { println(s"isNameStartsWithJ called for $person") val (name,_) = person name.startsWith("J") } println(people.view.filter(p => isOlderThan17(p)) .filter(p => nameStartsWithJ(p)) .last) |
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | isOlderThan 17 called for (Mark,32) isNameStartsWithJ called for (Mark,32) isOlderThan 17 called for (Bob,22) isNameStartsWithJ called for (Bob,22) isOlderThan 17 called for (Jane,8) isOlderThan 17 called for (Jill,21) isNameStartsWithJ called for (Jill,21) isOlderThan 17 called for (Mark,32) //Here is the problem. isNameStartsWithJ called for (Mark,32) isOlderThan 17 called for (Bob,22) isNameStartsWithJ called for (Bob,22) isOlderThan 17 called for (Jane,8) isOlderThan 17 called for (Jill,21) isNameStartsWithJ called for (Jill,21) isOlderThan 17 called for (nick,50) isNameStartsWithJ called for (nick,50) isOlderThan 17 called for (Nancy,42) isNameStartsWithJ called for (Nancy,42) isOlderThan 17 called for (Mike,19) isNameStartsWithJ called for (Mike,19) isOlderThan 17 called for (Sara,12) isOlderThan 17 called for (Paula,42) isNameStartsWithJ called for (Paula,42) isOlderThan 17 called for (John,21) isNameStartsWithJ called for (John,21) (John,21) |
为什么在找到"jill"后必须重新开始评估(再次从"mark"返回)?为什么不继续评估,直到清单结束?
这似乎与
1 2 3 4 | people.view .filter(isOlderThan17(_)) .filter(nameStartsWithJ(_)) .fold(None)((x, y) => Some(y)) |
看起来
更新
这是
第一个元素确实被访问了两次。
Why did the evaluation have to be restarted (back again from"Mark")
after"Jill" had been found?
因为每个
1 2 3 4 | println(people.toStream .filter(p => isOlderThan17(p)) .filter(p => nameStartsWithJ(p)) .last) |
从流vs视图vs迭代器
Stream is a lazy list indeed. In fact, in Scala, a Stream is a List
whose tail is a lazy val. Once computed, a value stays computed and is
reused. Or, as you say, the values are cached.
在这种情况下,您只需要组成过滤器,所以您也可以将两个谓词组合起来,只进行一次过滤:
1 2 | println(people.filter(p => isOlderThan17(p) && nameStartsWithJ(p)) .last) |