Scala:#:::和+&#x2B之间的区别与拉齐主义者
我希望#:::和++在两个操作数都是Lazylist时的行为相同。实际上,随着以下代码键入VS代码 /金属工作表:
LazyList.from(0) ++ LazyList.from(0)
LazyList.from(0) #::: LazyList.from(0)
两者都评估lazylist [int] = lazylist(&lt;未计算&gt;)< / code>。完全有道理。如果我这样做:
def countFrom(initial: LazyList[Int]): LazyList[Int] =
LazyList(initial.head) #::: countFrom(LazyList(initial.head + 1))
val m1 = countFrom(LazyList(0))
VS代码显示M1评估:lazylist [int] = lazylist(&lt;未计算&gt;)
,这对我来说又是完全有意义的。没有人要求任何元素,所以什么都不应计算。但是,如果我按以下内容更改#::: to ++:
def countFrom(initial: LazyList[Int]): LazyList[Int] =
LazyList(initial.head) ++ countFrom(LazyList(initial.head + 1))
val m1 = countFrom(LazyList(0))
那么,VS代码在评估从调用count Count Count等的count等的同时,VS代码无法评估M1。这是一个我正在研究的项目的简化,它正在构建更有趣的lazylists
。 ,但它是由我(怪异的)从方法中暴露出来的。谁能解释这里发生了什么?
[在路易斯·米格尔·梅吉亚·苏阿雷斯(Luis MiguelMejíaSuárez)的评论之后]
感谢路易斯·米格尔·梅吉亚·苏阿雷斯(Luis MiguelMejíaSuárez如果我遇到了问题,可以随意修复我!)。在表达式x#::: y
中为什么在Scala文档中命名为#::: :::
的参数前缀
)。由于#:::
是在deferrer
上定义的,因此这会导致y
(lazylist)的隐式转换为deferrer ,将
和y
包装到thunk(nullary函数)中。 x#::: y
然后变成x lazyappendedall todeferrer(y)()()
。然后,我想关键是lazyAppendedAll
是通过名称的第二个参数,因此todeferrer(y)()()
在需要之前实际上无法实际评估。现在,至于++
,我在lazylist源中没有看到++的定义,因此我想它已继承并且具有更简单的定义,其中使用x ++ y << /code>,
此x
是y
是参数,y
是按值传递的,因此评估进入++
。由于y
是lazylist
,因此未计算元素,但必须将y
评估为lazylist
本身,这就是无限递归产生的地方。
I would expect #::: and ++ to behave identically when both operands are LazyLists. Indeed, with the following code typed into a VS Code / Metals worksheet:
LazyList.from(0) ++ LazyList.from(0)
LazyList.from(0) #::: LazyList.from(0)
both evaluate to LazyList[Int] = LazyList(<not computed>)
. Makes perfect sense. And if I do this:
def countFrom(initial: LazyList[Int]): LazyList[Int] =
LazyList(initial.head) #::: countFrom(LazyList(initial.head + 1))
val m1 = countFrom(LazyList(0))
VS Code shows that m1 evaluates to: LazyList[Int] = LazyList(<not computed>)
which again makes perfect sense to me. No one asked for any elements, so nothing should be computed yet. But if I change the #::: to ++ as per the following:
def countFrom(initial: LazyList[Int]): LazyList[Int] =
LazyList(initial.head) ++ countFrom(LazyList(initial.head + 1))
val m1 = countFrom(LazyList(0))
then VS Code cannot evaluate m1 due to a stack overflow error while evaluating countFrom calling countFrom calling countFrom, etc. (Btw, yes, this is bizarre, contrived code. It's a simplification of code from a project I was working on that was constructing more interesting LazyLists.)
So apparently there IS a difference between ++ and #::: which is not exposed when concatenating LazyLists generated via the built-in from method, but which IS exposed by my (weird) countFrom method. Can anyone explain what's going on here?
[added after Luis Miguel Mejía Suárez's comment]
Thanks to Luis Miguel Mejía Suárez, I think I get it now, so I'm going to try to explain the details after having looked at the LazyList source (feel free to fix me if I get something wrong!). In the expression X #::: Y
, Y
is this
, and X
is the argument (which is why the parameter to #:::
is named prefix
in the scala docs). Since #:::
is defined on Deferrer
, this causes an implicit conversion of Y
(a LazyList) into a Deferrer
, which wraps Y
into a thunk (nullary function). X #::: Y
then becomes X lazyAppendedAll toDeferrer(Y)()
. Then, I guess the key is that the second parameter to lazyAppendedAll
is pass-by-name, so toDeferrer(Y)()
is not actually evaluated until it is needed. Now as for ++
, I did not see a definition of ++ in the LazyList source, so I guess it gets inherited and has a much simpler definition where, with X ++ Y
, X
is this
and Y
is the argument and Y
is passed by value, and is thus evaluated on entry to ++
. Since Y
is a LazyList
, the elements are not calculated, but Y
must be evaluated down to the LazyList
itself, and that's where the infinite recursion results.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论