如何使用 bind (>>=) 实现一个函数

How to implement a function using bind (>>=)

我写了一个过滤函数:

f :: (a -> Bool) -> [a] -> [a]
f p xs = case xs of
         [] -> []
         x : xs' -> if p x
                    then x : f p xs'
                    else f p xs'

为了理解bind,我想用bind来实现。 我在想什么:

f p xs = xs >>= (\x xs -> if p x then x : f p xs else f p xs)

但是我得到这个错误:

* Couldn't match expected type `[a]' with actual type `[a] -> [a]'
    * The lambda expression `\ x xs -> ...' has two arguments,
      but its type `a -> [a]' has only one
      In the second argument of `(>>=)', namely
        `(\ x xs -> if p x then x : f p xs else f p xs)'
      In the expression:
        xs >>= (\ x xs -> if p x then x : f p xs else f p xs)
    * Relevant bindings include
        xs :: [a] (bound at <interactive>:104:5)
        p :: a -> Bool (bound at <interactive>:104:3)
        f :: (a -> Bool) -> [a] -> [a] (bound at <interactive>:104:1)

使用foldr成功做到了:

f p xs = foldr (\x xs -> if p x then x : f p xs else f p xs) [] xs

怎么了?

To understand bind, i want to implement this as bind.

这里没有绑定。在 do expression 的情况下添加绑定。上面不是do-expression,所以这里没有绑定

但是你可以用 bind 写这个,比如:

f p xs = xs >>= \x -> if p x then [x] else []

但这不是原始函数的文字映射,我们只是在这里使用 instance Monad [] 实现。尽管如此,你的 f 只是 filter :: (a -> Bool) -> [a] -> [a] 这里。

要理解绑定,首先实现no-op:

id_list xs   =  concat [ [x]       | x <- xs ]  =  [ y | x <- xs, y <- [x      ] ]

现在 过滤器,将其扩充为

filter p xs  =  concat [ [x | p x] | x <- xs ]  =  [ y | x <- xs, y <- [x | p x] ]

你问这段代码如何使用绑定?如果我们使用 MonadComprehensions,它会。

显式 do 表示法 re-write 很简单:

id_list xs   =  do { x <- xs ; y <- [ x      ] ; return y }
filter p xs  =  do { x <- xs ; y <- [ x | p x] ; return y }

当然,对于列表,

[x]       ==  return x
[x | p x] ==  if p x then return x else mzero
mzero     ==  []
concat    ==  join

这让我们回到了一种显式递归的方式来将 filter 编码为

filter p []     =  []
filter p (x:xs) =  [x | p x] ++ filter p xs

使用绑定,我们考虑将列表的每个元素单独地转换为列表results(none,一个或多个)对于那个输入元素。您基于 foldr 的代码打破了这一点。


所以,代码本身就是

filter_bind p xs  =  xs  >>=  (\x -> [x | p x])

因为我们有

xs >>= f  ==  join (fmap f xs) 
          ==  concat (map f xs) 
          ==  concat [ f x | x <- xs ]
          ==  foldr (++) []
                     [ f x | x <- xs ]

最后一个片段对应于上面的显式递归定义。

另见