对于2013年homework,我试图将2个Streams相乘。
xStream :: Stream Integer
xStream = Cons 0 (Cons 1 $ streamRepeat 0)
instance Num (Stream Integer) where
fromInteger x = Cons x $ streamRepeat 0
negate = streamMap (* (-1))
(+) xs ys = combineStreams (+) xs ys
(*) xs ys = multStreams xs ys
abs = streamMap abs
以下是教授对如何实现上述流的乘法的帮助:
Multiplication is a bit trickier. Suppose A = a0 + xA` and B = b0 +
xB0 are two generating functions we wish to multiply. We reason as
follows: AB = (a0 + xA`)B
= a0B + xA`B
= a0(b0 + xB0) + xA`B
= a0b0 + x(a0B0 + A`B)
这是我的尝试:
multStreams :: Stream Integer -> Stream Integer -> Stream Integer
multStreams (Cons x xs) b@(Cons y ys) = addXY + rest
where addXY = Cons (x + y) $ streamRepeat 0
rest = (xStream *) $ (streamMap (*x) ys + (xs * b))
具有以下定义:
data Stream a = Cons a (Stream a)
streamRepeat :: a -> Stream a
streamRepeat x = Cons x (streamRepeat x)
streamMap :: (a -> b) -> Stream a -> Stream b
streamMap f (Cons x xs) = Cons (f x) rest
where rest = streamMap f xs
combineStreams :: (a -> b -> c) -> Stream a -> Stream b -> Stream c
combineStreams f (Cons x xs) (Cons y ys) = Cons (f x y) rest
where rest = combineStreams f xs ys
请注意,xStream
与此related question的x
相同。
当我尝试上述实现时,我对multStreams
的调用不会终止。
请帮助我了解上述multStream
功能的错误 - 在实施中以及我是否正确实施了教授对乘法的解释。
答案 0 :(得分:4)
根本问题是,multStreams
的定义在(*)
的定义中直接使用Stream
上的rest
,这不是给定推理的意图
如果你考虑等式AB = a0b0 + x(a0B0 + A'B)
,它会告诉你AB
的第一项应该是什么:a0b0
是常数,即第一项的一部分,以及其他每一项流中的术语乘以x
,即不是第一个术语的一部分。
它还告诉您AB
的剩余条款来自a0B0 + A'B
- 因为将其与Cons
一起移动相当于multipltying x
。
与您所做的完全不同的是,输出流的第一个元素可以在不对(*)
进行任何递归调用的情况下构建,即使其余元素使用一个。
所以这样的事情应该有效:
multStreams :: Stream Integer -> Stream Integer -> Stream Integer
multStreams (Cons x xs) b@(Cons y ys) =
Cons (x * y) (streamMap (*x) ys + multStreams xs b)