【发布时间】: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),自己定义它,或者让您的定义同时生成thuleMorse和f而不仅仅是thuleMorse。 -
@MadameElyse,谢谢你的建议!插入
unsafeCoerce会使解释器评估表达式,结果确实是 Thule-Morse 序列!这里插入了unsafeCoerce:thuleMorseUnsafe = 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