其他分享
首页 > 其他分享> > lazy ruler

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 调用过程不会停止

Laziness

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:

Homework 7: Laziness

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