[英]Haskell not lazy evaluating interleaving
我正在解决一个问题(它来自一个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)不懒惰评估?
我会试着把你推向正确的方向,或者至少指出出了什么问题。 函数nthStream
永远不会评估,甚至不会评估它的第一个元素,因为它是如何用interleaveStreams
定义的。 为了给你一个例子,让我们计算出它为nthStream 0
评估的nthStream 0
(为了简洁和可读性,我将nthStream
重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
链,而不是Strm
构造函数。 我们得到了我们感兴趣的每一个,但是在评估第二个参数之前,它们永远不能从interleave
返回。 由于第二个参数总是减少为对interleave
的新调用,因此它永远不会减少。
这里有一个提示:如何递归地定义interleaveStreams
以便它只依赖于它已构造的第一个参数? 即
interleaveStreams (Stream a arest) streamB = Stream a (???)
你的问题就在于此
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)
之前不能返回任何内容 ,这将为您提供无限递归。
为了解决这个问题,你可以改变的问题行的第二个模式是有明确懒 ~
:
interleaveStreams (Stream a arest) ~(Stream b brest) = (Stream a (Stream b (interleaveStreams arest brest)))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.