【问题标题】:How does the `randoms` function in Haskell work?Haskell 中的 `randoms` 函数是如何工作的?
【发布时间】:2017-11-27 13:22:23
【问题描述】:

我正在关注 Learn You A Haskell 这本书来学习 Haskell,但我无法理解 randoms 函数。书中将函数定义为:

randoms' :: (RandomGen g, Random a) => g -> [a]  
randoms' gen = let (value, newGen) = random gen in value:randoms' newGen    

现在我看到这个函数的方式是它递归地调用自己并将返回值附加到列表value。我不明白的是函数是如何返回的,因为每次它只是用一个新的随机种子调用自己!

【问题讨论】:

  • 不,因为懒惰,尾巴在你需要之前评估。
  • 不记得具体的函数,但如果它创建了一个惰性无限随机数列表,您可以从无限列表中 take 获取一些元素。请注意,该函数不会一次全部评估;它只根据需要产生值。查看repeat 函数以查看另一个示例。
  • @1-_- 你想得太严格了。你知道 Python 生成器是什么吗?
  • @1-_- 好的,很好。我只是想说,在使用无限列表时,您可以认为它的值是一次一个 yielded,而不是一次返回整个列表。我强烈建议深入研究并习惯懒惰,因为 Haskell 广泛使用它。
  • @1-_- 我不知道我是否可以写一个很好的解释,因为我使用 Haskell 已经有一段时间了,而且这是一个很难深入研究的话题。这只是最好的比较,可能有助于改变你的观点。

标签: haskell


【解决方案1】:

我认为令人困惑的部分可能是在返回值中使用了:

value:randoms' newGen 

这是一个列表,第一项为value,列表的其余部分是递归调用randoms' newGen返回的内容。

我不明白这个函数是如何返回的,因为每次它只是用一个新的随机种子调用自己!

由于懒惰,它只会在您尝试访问返回列表的第二个(或以后)项目时调用自己。此列表不会,也不能立即出现在内存中。 Haskell 中的列表更像是食谱……在您尝试访问一个元素之前,Haskell 不会尝试找出它是什么。

【讨论】:

    【解决方案2】:

    作为一个粗略的比较,与其尝试考虑如何返回无限列表,不如考虑 Python 生成器如何能够“返回”无限列表:yield一次一个元素,因为它们'是必需的。

    整个列表不会立即返回。每个元素都根据需要进行评估,并且该函数仅在需要时递归。

    请注意,我并不是说 Haskell 的惰性与 Python 的生成器的工作方式相同,但在考虑此类函数时,记住它可能是一个有用的比较。

    请参阅其他答案以了解为什么会发生这种情况。

    【讨论】:

    • 对我来说一个相关的、有用的见解是 Haskell 中的列表在用作 data 结构时并不是很好(如果你想存储一系列元素,@987654322 @ 或其他东西可能更好)但它们是出色的 控制 结构,其行为或多或少类似于其他语言中的(记忆的)迭代器和生成器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    • 2012-04-23
    • 1970-01-01
    相关资源
    最近更新 更多