我正在解决一个问题(它来自UPenn类,但我没有接受它(只是通过它来学习Haskell)),重点是构造一个Stream(定义如下),定义由"统治者" (标尺!! n = 2的最高幂的指数,它将除以n)。问题在于我认为下面标尺的定义应该懒惰地评估,但它似乎是严格评估并且无限运行。如果我通过添加类似" nthStream 10 = streamRepeat 10"的终端案例来限制它。它运行并生成输出到我想要的点。
data Stream a = Stream a (Stream a)
streamToList :: Stream a -> [a]
streamToList (Stream a rest) = [a] ++ streamToList rest
instance Show a => Show (Stream a) where
show s = show $ take 100 $ streamToList s
streamRepeat :: a -> Stream a
streamRepeat a = Stream a (streamRepeat a)
interleaveStreams :: Stream a -> Stream a -> Stream a
interleaveStreams (Stream a arest) (Stream b brest) = (Stream a (Stream b (interleaveStreams arest brest)))
nthStream :: Integer -> Stream Integer
nthStream n = interleaveStreams (streamRepeat n) (nthStream (n+1))
ruler :: Stream Integer
ruler = nthStream 0
任何人都可以解释为什么统治者(和nthStream)没有懒惰地评估?
答案 0 :(得分:5)
我会试着把你推向正确的方向,或者至少指出出了什么问题。函数nthStream
永远不会评估,甚至不会评估它的第一个元素,因为它是用interleaveStreams
定义的。为了给你一个例子,让我们弄清楚它为nthStream 0
评估的内容(为了简洁和可读性,我将nthStream
重命名为nth
,interleaveStream
改为interleave
},streamRepeat
到repeat
,Stream
到Strm
):
nth 0 = interleave (repeat 0) (nth 1)
= interleave (Strm 0 _0) (interleave (repeat 1) (nth 2))
= interleave (Strm 0 _0) (interleave (Strm 1 _1) (nth 2))
= interleave (Strm 0 _0) (interleave (Strm 1 _1) (interleave (repeat 2) (nth 3)))
= interleave (Strm 0 _0) (interleave (Strm 1 _1) (interleave (Strm 2 _2) (nth 3)))
我选择将repeat
返回的每个流的尾部表示为_N
,其中N
是重复的数字。这些目前是thunk,因为我们还没有要求他们的价值观。请注意正在构建的是interleave
s链,而不是Strm
构造函数链。我们得到了我们感兴趣的每个人,但他们永远不会从interleave
返回,直到评估第二个参数。由于第二个参数总是减少为对interleave
的新调用,因此它永远不会减少。
这是一个提示:如何递归定义{{1}},以便它只取决于它已经构造的第一个参数?即。
interleaveStreams
答案 1 :(得分:5)
你的问题就在这一行
interleaveStreams (Stream a arest) (Stream b brest) = (Stream a (Stream b (interleaveStreams arest brest)))
为了使该函数甚至返回结果的开头,必须评估其参数的两个,因为您直接在其构造函数上进行模式匹配。但是你在
中使用它nthStream n = interleaveStreams (streamRepeat n) (nthStream (n+1))
这意味着nthStream n
在评估nthStream (n+1)
之前无法返回任何,这会为您提供无限递归。
要解决此问题,您可以使用~
将问题行中的第二个模式更改为显式 lazy :
interleaveStreams (Stream a arest) ~(Stream b brest) = (Stream a (Stream b (interleaveStreams arest brest)))