繁体   English   中英

Haskell不是懒惰的评估交错

[英]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 (为了简洁和可读性,我将nthStreamnthStreamnthinterleaveStream重新interleavestreamRepeat repeatStreamStrm ):

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM