Fail to define an infinite stream

巧了我就是萌 提交于 2021-01-27 12:50:48

问题


I'm working on UPENN Haskell Homework 6 Exercise 5, trying to define a ruler function

0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,...

where the nth element in the stream (assuming the first element corresponds to n = 1) is the largest power of 2 which evenly divides n.

I just came up with an idea to build it without any divisibility testing:

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) (...))

where first 20 element of

ruler =
    interleaveStreams (streamRepeat 0)
        (interleaveStreams (streamRepeat 1)
            (interleaveStreams (streamRepeat 2)
                (interleaveStreams (streamRepeat 3) (streamRepeat 4))))

is

[0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2]

Obviously I couldn't define it manually to infinite so I defined a infInterStream to help such infinite recursion definition:

infInterStream n = interleaveStreams (streamRepeat n) (infInterStream (n+1))

ruler = infInterStream 0

But now I get stuck when typing in ruler in ghci, it probably falls into infinite loop.

It shouldn't be if lazy evaluation works. I want to know why lazy evaluation fails here.


Helper function to observe Stream:

streamToList (Cons x xs) = x : streamToList xs

instance Show a => Show (Stream a) where
    show = show . take 20 . streamToList

回答1:


Your interleaving function is too strict. The following works:

interleaveStreams (Cons x xs) ys = Cons x (interleaveStreams ys xs)

This also works:

interleaveStreams (Cons x xs) ~(Cons y ys) = 
    Cons x (Cons y (interleaveStreams xs ys))

The original definition goes into infinite loop because interleaveStreams demands that both arguments must be of Cons forms. infInterStream n evaluates to the the interleaving of two streams, and the first one can be immediately evaluated to Cons, but the second one must also be reduced first to Cons, so we recursively call infInterStream (n + 1), which keeps calling itself ad infinitum.

If interleaveStreams can return a Cons a _ without first having to force the second argument, infInterStream can also incrementally build the result.




回答2:


There's no need for a new type for streams, and we can just use Haskell's lazy lists instead. As others have noted, the definition of interleave must be sufficiently lazy that it can produce the first element of the output before testing whether the second argument is non-empty. This definition will do:

interleave (x:xs) ys = x : interleave ys xs

If you want interleave to work also for finite lists, you can add the equation

interleave [] ys = ys

Note also that, using functions from the standard prelude,

ruler = interleave (repeat 0) (map (+1) ruler)

Here repeat 0 is the list [0, 0, 0, ...].



来源:https://stackoverflow.com/questions/39327656/fail-to-define-an-infinite-stream

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!