我有这些功能的代码:
- 从给定的流中创建一个无限列表;
- 为给定的迭代函数和起始流元素(种子)创建一个流;
- 将两个流合并为一个,以便它们的元素交错。
代码如下:
data Stream a = Cons a (Stream a)
streamToList :: Stream a -> [a]
streamToList (Cons x xs) = x : streamToList xs
streamIterate :: (a -> a) -> a -> Stream a
streamIterate f x = Cons x (streamIterate f (f x))
streamIterLeave :: Stream a -> Stream a -> Stream a
streamIterLeave (Cons x xs) ys = Cons x (streamIterLeave ys xs)
现在我遇到的问题是我不知道如何在 ghci 上检查这段代码。更具体地说,如何将流输入命令行?
例如,我尝试了 streamToList [1,2,3]
; streamToList (1,2,3)
; streamToList 1,2,3
但它们似乎都不起作用。
非常感谢您的帮助!
最佳答案
几种方式。最简单的就是使用 undefined
:
> take 2 $ streamToList $ Cons 1 $ Cons 2 undefined
[1,2]
您可以在提示符下定义命名流,
> let { one = Cons 1 two ; two = Cons 2 one }
或者多行输入,
> :{
| one = Cons 1 two
| two = Cons 2 one
| :}
> take 5 $ streamToList one
[1,2,1,2,1]
您可以使用您的 streamIterate
,如评论中所示,或使用 foldr
从列表中创建您的流,
> take 5 $ streamToList $ streamIterate (+1) 0
[0,1,2,3,4]
> listToStream xs = foldr Cons undefined xs
> intS = listToStream [1..]
> take 5 $ streamToList intS
[1,2,3,4,5]
定义了listToStream
,你可以进一步轻松定义
> mapStream f s = listToStream . map f . streamToList $ s
> intsStream = x where { x = Cons 1 $ mapStream (1+) x }
> take 5 $ streamToList intsStream
[1,2,3,4,5]
> zipStr s1 s2 = listToStream $ zip (streamToList s1) (streamToList s2)
> zipStrWith f s1 s2 = mapStream (uncurry f) (zipStr s1 s2)
> addStreams s1 s2 = zipStrWith (+) s1 s2
> fibS = let {a = Cons 0 b; b = Cons 1 c; c = addStreams a b} in a
> take 15 $ streamToList fibS
[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377]
等等等等等
作为dfeuer在评论中提到,上面的 listToStream
有点虚假——它允许将无效(即有限)列表作为其参数。可以在 REPL 上玩它,但一般情况下不行。
通过定义
> :{
| (+++) :: [a] -> Stream a -> Stream a
| xs +++ ys = foldr Cons ys xs
| :}
允许我们定义流
> good = [1..] +++ undefined
> bad = [1..10] +++ undefined
问题在哪里(如果存在)会更加明显。
关于Haskell 需要帮助理解流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70317203/