【问题标题】:Definition of the Monad Instance of Data.StreamData.Stream 的 Monad 实例的定义
【发布时间】:2012-07-27 09:07:46
【问题描述】:

Data.Stream 的 monad 实例是这样定义的:

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 发现,他证明有理数与自然数一样多:http://www.jcu.edu/math/vignettes/infinity.htm

现在我的问题是join 使用沿所有次对角线的路径(访问每个流的每个元素)是否也是有效的实现。或者这会违反单子定律之一吗?

【问题讨论】:

  • Stream 只有一个(合理的)单子,但有很多共单子。详情见布伦特系列Themes on Streams

标签: haskell monads


【解决方案1】:

会违反

return x >>= f === f x

考虑

f k = Cons k (f (k+1))

现在fmap f (return 1)repeat (f 1),如果join 遍历所有元素,在生成的Stream 中,元素会重复。

作为一个二维表,fmap f (return 1) 看起来像

1 2 3 4 ...
1 2 3 4 ...
1 2 3 4 ...

如果你沿着次对角线遍历它,你会得到

1 1 2 1 2 3 1 2 3 4 ...

而不是 1 2 3 4 5 ...f 1

【讨论】:

    【解决方案2】:

    我最近为 list 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)))
    

    不幸的是,您必须做一些newtype 的恶作剧,因为您不能声明Monad [] 的另一个实例,但除此之外,它工作正常。类似的东西

    list
    (
        do
            item1 <- Enumerable [0..]
            item2 <- Enumerable [1..]
            item3 <- Enumerable [2..]
            return (item1, item2, item3)
    )
    

    为您提供第二项大于或等于 1 且第三项大于或等于 2 的所有自然数三元组的无限列表。

    我检查了,如果我没有犯错,它应该遵守所有的单子定律。它也适用于有限列表,在遇到完全空的对角线后,它将停止尝试查找新项目。

    我不熟悉流单子,所以我不能告诉你如果你在那里做类似的事情会发生什么。

    【讨论】:

      猜你喜欢
      • 2021-03-09
      • 1970-01-01
      • 2013-09-27
      • 1970-01-01
      • 2019-06-30
      • 2011-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多