我正在UPENN Haskell Homework 6 Exercise 5工作,尝试定义ruler function
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,...
其中流中的第n个元素(假设第一个元素对应n
= 1)是最大power of 2
,它均匀地划分n
。
我想出了一个没有任何可分性测试的构建它的想法:
data Stream x = Cons x (Stream x) deriving (Eq)
streamRepeat x = Cons x (streamRepeat x)
interleaveStreams (Cons x xs) (Cons y ys) =
Cons x (Cons y (interleaveStreams xs ys))
ruler =
interleaveStreams (streamRepeat 0)
(interleaveStreams (streamRepeat 1)
(interleaveStreams (streamRepeat 2)
(interleaveStreams (streamRepeat 3) (...))
的前20个元素
ruler =
interleaveStreams (streamRepeat 0)
(interleaveStreams (streamRepeat 1)
(interleaveStreams (streamRepeat 2)
(interleaveStreams (streamRepeat 3) (streamRepeat 4))))
是
[0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2]
显然我无法手动将其定义为无限,所以我定义了infInterStream
来帮助这种无限递归定义:
infInterStream n = interleaveStreams (streamRepeat n) (infInterStream (n+1))
ruler = infInterStream 0
但现在我在ruler
中输入ghci
时遇到困难,可能会陷入无限循环。
如果懒惰的评估有效,那就不应该了。我想知道为什么延迟评估在这里失败。
帮助函数观察Stream
:
streamToList (Cons x xs) = x : streamToList xs
instance Show a => Show (Stream a) where
show = show . take 20 . streamToList
答案 0 :(得分:7)
您的交错功能太严格了。以下作品:
interleaveStreams (Cons x xs) ys = Cons x (interleaveStreams ys xs)
这也有效:
interleaveStreams (Cons x xs) ~(Cons y ys) =
Cons x (Cons y (interleaveStreams xs ys))
原始定义进入无限循环,因为interleaveStreams
要求两个参数必须是Cons
形式。 infInterStream n
计算两个流的交错,第一个可以立即评估为Cons
,但第二个也必须首先减少到Cons
,所以我们递归调用{ {1}},一直无限地呼唤自己。
如果infInterStream (n + 1)
可以返回interleaveStreams
而无需先强制使用第二个参数,Cons a _
也可以逐步构建结果。
答案 1 :(得分:1)
不需要为流提供新类型,我们可以使用Haskell的懒惰列表。正如其他人所指出的那样,interleave的定义必须足够懒,以至于在测试第二个参数是否为非空之前它可以产生输出的第一个元素。这个定义将:
interleave (x:xs) ys = x : interleave ys xs
如果您希望interleave
也适用于有限列表,则可以添加等式
interleave [] ys = ys
另请注意,使用标准前奏中的函数
ruler = interleave (repeat 0) (map (+1) ruler)
此处repeat 0
是列表[0, 0, 0, ...]
。