【问题标题】:Thue-Morse Sequence in one Line of Haskell一行 Haskell 中的 Thue-Morse 数列
【发布时间】:2016-02-06 23:09:55
【问题描述】:

我将Thue-Morse squence 定义为Haskell 的一行中的无限整数列表:

thueMorse = 0:1:f (tail thueMorse) where f = (\(x:xs) -> x:(1 - x):f xs)

这是尝试在一行中定义序列失败的结果,仅根据 lambda 表达式及其本身,没有 let 或 where 表达式(实际上应该在两行中呈现,使上述解决方案成为两个精神上的班轮)。我一直在阅读一些关于 lambda 演算的内容,所以我想我会尝试将其作为练习。我想知道在 Haskell 中这样的事情是否可能,如果可能的话,该怎么做。

thueMorse = 0:1:(\f xs -> f f xs) (\f (x:xs) -> x:(1 - x):f f xs) ((\(_:xs) -> xs) thueMorse)

上面的表达式有点难读,所以我将其分解:

(\f xs -> f f xs)

获取一个函数和一个参数,并将该函数应用于自身和参数。 Haskell 不会计算这个表达式,因为 f 的类型是 t = t -> a -> a,这是我的问题的症结所在。

(\f (x:xs) -> x:(1 - x):f f xs)

是传递给前一个表达式的函数,它将自身和一个列表作为参数。这是递归计算 Thue-Morse 序列的部分。这也有一个无限类型t = t -> [a] -> [a]

((\(_:xs) -> xs) thueMorse)

这只是等价于(tail thueMorse),但是写成lambda表达式来满足练习的条件。

Haskell 抱怨这些表达式具有无限类型并拒绝对它们求值,我认为如果它们被求值,它们将正确生成 Thue-Morse 序列。有没有办法让解释器或编译器的手臂来评估这些表达式?有没有办法调整语句以便对其进行评估,但仍然只使用 lambda 演算中的运算符,并且在一行中?

【问题讨论】:

  • 如果你只是想看看算法是否正确(不管它的类型),你可以在代码上撒一些unsafeCoerce。不过,不要在生产环境中这样做。
  • 你需要递归,所以在某些时候你需要一个定点运算符。您可以重用标准的 (Data.Function.fix),自己定义它,或者让您的定义同时生成 thuleMorsef 而不仅仅是 thuleMorse
  • @MadameElyse,谢谢你的建议!插入unsafeCoerce 会使解释器评估表达式,结果确实是 Thule-Morse 序列!这里插入了unsafeCoercethuleMorseUnsafe = 0:1:(\f xs -> unsafeCoerce f f xs) (\f (x:xs) -> x:(1 - x):unsafeCoerce f f xs) ((\(_:xs) -> xs) thuleMorseUnsafe)。有没有更干净的方法来做到这一点?
  • @DanielWagner,是的,thuleMorse = 0:1:fix (\f (x:xs) -> x:(1 - x):f xs) (tail thuleMorse) 工作得很好,我不需要做任何令人毛骨悚然的事情来让它工作。非常感谢。
  • 是 Thue,不是 Thule

标签: haskell lambda lambda-calculus


【解决方案1】:

这是相同的算法,但没有明确的fix

thueMorse = 0 : 1 : (tail thueMorse >>= \x -> [x, 1 - x])

【讨论】:

  • 这是迄今为止最简洁的变体。
  • 它也比我的基于修复的版本略快,使用基于修复的版本获得序列的第 1 亿个元素需要 12.281 秒,使用您的版本 (ghc -e "...") 需要 11.079 秒。我的原始版本也花了超过 12 秒。
猜你喜欢
  • 2011-11-24
  • 2014-09-27
  • 1970-01-01
  • 2019-02-24
  • 2010-10-26
  • 1970-01-01
  • 2010-09-17
  • 2023-03-31
相关资源
最近更新 更多