List Monad的两个实现在文献中绑定:为什么它们是等价的?

时间:2017-04-03 10:53:54

标签: haskell

阅读“Haskell编程”第2版中的Monad章节。来自Graham Hutton,我在第167页找到了这个例子来说明List Monad的行为:

pairs :: [a] -> [b] -> [(a,b)]
pairs xs ys = do x <- xs
                 y <- ys
                 return (x,y)

对象定义如下:

instance Monad [] where
   -- (>>=) :: [a] -> (a -> [b]) -> [b]
   xs >>= f = [y | x <- xs, y <- f x]

这个bind的实现:

...
   xs >>= f = concat (fmap f xs)

我试着用铅笔和纸来理解这个例子是如何解决的,但是没有得到它。

然后我发现,在其他书中,绑定操作的定义不同:

{{1}}

通过这个定义,我理解为什么这个例子有效。 但第一个定义是我在前奏中发现的hackage,所以我相信它是正确的。

我的问题

  • 任何人都可以解释为什么第一个定义等同于第二个定义? (concat-stuff在第一个发生在哪里?)

2 个答案:

答案 0 :(得分:2)

列表理解只是语法糖。基本上,[f x y | x<-l, y<-m]是糖的

concatMap (\x -> concatMap (\y -> return $ f x y) m) l

或等效

concat $ fmap (\x -> concat $ fmap (\y -> return $ f x y) m) l

因此,这两个实现确实等同于按照定义

无论如何,您当然可以使用“直观集合理解”评估手动评估基于理解的定义中的示例:

pairs [1,2] [3,4]
 ≡ do { x <- [1,2]; y <- [3,4]; return (x,y) }
 ≡ [1,2] >>= \x -> [3,4] >>= \y -> return (x,y)
 ≡ [p | x<-[1,2], p <- (\ξ -> [3,4] >>= \y -> return (ξ,y)) x]
 ≡ [p | x<-[1,2], p <- ([3,4] >>= \y -> return (x,y))]
 ≡ [p | x<-[1,2], p <- [q | y<-[3,4], q <- (\υ -> return (x,υ)) y]]
 ≡ [p | x<-[1,2], p <- [q | y<-[3,4], q <- return (x,y)]]
 ≡ [p | x<-[1,2], p <- [q | y<-[3,4], q <- [(x,y)]]]
 ≡ [p | x<-[1,2], p <- [(x,3), (x,4)]]
 ≡ [(1,3), (1,4)] ++ [(2,3), (2,4)]
 ≡ [(1,3), (1,4), (2,3), (2,4)]

答案 1 :(得分:0)

[y | x <- xs, y <- f x]逐个接受x中的所有xs

  1. f应用于他们,这是一个monadic操作a -> [a],因此结果是一个值列表([a]
  2. 理解继续y逐一解决每个f x
  3. 每个y都会发送到输出列表
  4. 这相当于首先在输入列表的每个元素上映射f,从而生成嵌套列表的列表,然后将其连接起来。请注意,列表中fmapmap,您可以使用concatMap f xs作为xs >>= f的定义。