lazy ruler
作者:互联网
lazy ruler
streamRepeat :: a -> Stream a
streamRepeat a = Cons a (streamRepeat a)
streamToList :: Stream a -> [a]
streamToList (Cons a xs) = a : streamToList xs
instance Functor Stream where
fmap f (Cons a b) = Cons (f a) (fmap f b)
streamMap :: (a -> b) -> Stream a -> Stream b
streamMap = fmap
streamIterate :: (a -> a) -> a -> Stream a
streamIterate f init = Cons init (streamIterate f (f init))
streamInterleave :: Stream a -> Stream a -> Stream a
-- Error! ***stackoverflow***
-- streamInterleave (Cons a b) (Cons c d) = Cons a (Cons c (streamInterleave b d))
streamInterleave (Cons a b) c = Cons a (streamInterleave c b)
nats = streamIterate (+1) 0
ruler :: Stream Integer
求 ruler
是无限 Stream
,值为 1, 2, 3, 4, 5, ...
的二进制位的最低位 1 的位数
前一些项为:
1 0
10 1
11 0
100 2
101 0
110 1
111 0
1000 3
1001 0
1010 1
1011 0
1100 2
1101 0
1110 1
1111 0
10000 4
10001 0
10010 1
10011 0
10100 2
10101 0
10110 1
10111 0
11000 3
11001 0
11010 1
11011 0
11100 2
11101 0
11110 1
11111 0
100000 5
100001 0
100010 1
100011 0
100100 2
100101 0
100110 1
100111 0
101000 3
101001 0
101010 1
101011 0
101100 2
101101 0
101110 1
101111 0
110000 4
110001 0
110010 1
110011 0
...
观察数据可以发现:
ruler = i
(r 0)
(i
(r 1)
(i
(r 2)
(i
(r 3)
...
where
i = streamInterleave
r = streamRepeat
于是写个函数无限嵌套调用就行。之前定义的工具函数似乎没有能帮忙递归的。
ruler :: Stream Integer
ruler = tmp 0 where
tmp :: a -> Stream a
tmp n = streamInterleave (streamRepeat n) (tmp (n+1))
或者
ruler = tmp streamInterleave (streamMap streamRepeat nats) where
tmp :: (Stream a -> Stream a -> Stream a) -> Stream (Stream a) -> Stream a
tmp f (Cons fn b) = f fn (tmp f b)
然而发现并不会停止,过一段时间后栈溢出,说明有无限递归(但 haskell 里面只有递归,好像是句屁话)
最终发现问题出在 streamInterleave
的定义上
streamInterleave :: Stream a -> Stream a -> Stream a
-- Error! ***stackoverflow***
streamInterleave (Cons a b) (Cons c d) = Cons a (Cons c (streamInterleave b d))
-- Correct
streamInterleave (Cons a b) c = Cons a (streamInterleave c b)
原因是上面的实现在模式匹配时需要将第二个参数展开,而第二个参数实际上永远会依赖于子递归,这使得 ruler 调用过程不会停止
The other important thing to note is that thunks are evaluated only enough to allow a pattern match to proceed, and no further!
haskell 由模式匹配驱动惰性求值
做完才看到题目下面有 hint:
Do you see why you had to make streamInterleave lazy in its second parameter?
真是好题
标签:tmp,lazy,Cons,Stream,ruler,streamInterleave,streamRepeat 来源: https://www.cnblogs.com/human-in-human/p/16367299.html