如何使用bind(>> =)实现功能

时间:2019-07-19 09:56:52

标签: list haskell monads

我写了一个过滤功能:

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'

要了解绑定,我想使用绑定实现此功能。 我在想什么:

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

怎么了?

2 个答案:

答案 0 :(得分:5)

  

要了解绑定,我想将其实现为绑定。

这里没有绑定。如果是do expression,则添加绑定。上面的代码不是do-expression,因此这里没有绑定。

不过,您可以使用bind编写此代码,例如:

Select 
TicketNo,
CreatedBy,
`Date and Time`,
    Datediff(second,`Date and Time`,lag(`Date and Time`)
      Over (partition by TicketNo order by `Date and Time` asc)) as SecDiff
From Table

但这不是原始函数的文字映射,我们在这里仅使用f p xs = xs >>= \x -> if p x then [x] else []实现。不过,您的instance Monad []只是filter :: (a -> Bool) -> [a] -> [a]

答案 1 :(得分:2)

要了解绑定,请首先实现 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-符号重写很简单:

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

对于bind,我们考虑将列表的每个每个元素分别转换为到结果列表(无,一个,或几个)。您基于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 ]

最后一个代码段与上面的显式递归定义相对应。

另请参见