【问题标题】:How to implement a function using bind (>>=)如何使用绑定(>>=)实现函数
【发布时间】:2019-07-19 09:56:52
【问题描述】:

我写了一个过滤函数:

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

怎么了?

【问题讨论】:

  • 这不是do 块,所以这里没有使用绑定。
  • 列表绑定 &gt;&gt;=concatMap,而不是 foldr

标签: list haskell monads


【解决方案1】:

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

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

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

f p xs = xs &gt;&gt;= \x -&gt; if p x then [x] else []

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

【讨论】:

    【解决方案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-notation 重写很简单:

    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
    

    使用绑定,我们考虑将列表中的每个元素单独转换为结果列表(无,一,或多个)用于该一个输入元素。您基于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 ]
    

    最后一个 sn-p 对应于上面的显式递归定义。

    另见

    【讨论】:

      猜你喜欢
      • 2019-06-03
      • 1970-01-01
      • 2011-01-08
      • 2023-03-19
      • 1970-01-01
      • 2023-03-11
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多