Haskell Data.Stream的Monad实例的定义
Data.Stream的monad instanc是这样定义的:Haskell Data.Stream的Monad实例的定义,haskell,monads,Haskell,Monads,Data.Stream的monad instanc是这样定义的: instance Monad Stream where return = repeat xs >>= f = join (fmap f xs) where join :: Stream (Stream a) -> Stream a join ~(Cons xs xss) = Cons (head xs) (join (map tail xss)) 这意味着,join获取第
instance Monad Stream where
return = repeat
xs >>= f = join (fmap f xs)
where
join :: Stream (Stream a) -> Stream a
join ~(Cons xs xss) = Cons (head xs) (join (map tail xss))
这意味着,join
获取第一个流的第一个元素,第二个流的第二个元素等,因此生成的流可以被视为“主对角线”,丢弃所有其他元素
现在有一种方法可以通过一个无限的二维表,由Georg Cantor发现,他证明了有理数和自然数一样多:
现在我的问题是,使用沿所有次对角线的路径(访问每个流的每个元素)进行的连接是否也是有效的实现。或者这会违反单子定律吗 这会违反
return x >>= f === f x
考虑
f k = Cons k (f (k+1))
现在fmap f(return 1)
是repeat(f1)
,如果join
遍历了所有元素,在生成的流中,元素将重复
作为一个二维表,fmap f(返回1)
如下所示
1 2 3 4 ...
1 2 3 4 ...
1 2 3 4 ...
如果你沿着第二条对角线穿过它,你会得到
1 1 2 1 2 3 1 2 3 4 ...
而不是12345…
与f1
我最近为列表monad实现了类似的功能:
diagonals :: [[(Integer, Integer)]]
diagonals =
let diagonal index =
do
number <- [0..index]
return (number, index - number)
in map diagonal (enumFrom 0)
newtype Enumerable a = Enumerable { list :: [a] }
instance Monad Enumerable where
return item = Enumerable [item]
enumerable1 >>= getEnumerable2 =
let
list1 = list enumerable1
diagonalItems diagonal =
do
(index1, index2) <- diagonal
guard (containsIndex list1 index1)
let item1 = genericIndex list1 index1
let list2 = list (getEnumerable2 item1)
guard (containsIndex list2 index2)
let item2 = genericIndex list2 index2
return item2
in Enumerable (concat (takeWhile (not . null) (map diagonalItems diagonals)))
为您提供一个无限列表,其中包含第二项大于或等于1、第三项大于或等于2的所有自然数三元组
我检查了一下,如果我没有犯错误,它应该遵守所有的单子定律。它也适用于有限列表,在遇到完全为空的对角线后,它将停止尝试查找新项目
我不熟悉stream monad,所以我也无法告诉您如果您在那里做了类似的事情会发生什么。对于stream
,只有一个(合理的)monad,但是有很多comonad。详见布伦特系列。
list
(
do
item1 <- Enumerable [0..]
item2 <- Enumerable [1..]
item3 <- Enumerable [2..]
return (item1, item2, item3)
)