如何使用 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 ]
最后一个片段对应于上面的显式递归定义。
另见
我写了一个过滤函数:
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 ]
最后一个片段对应于上面的显式递归定义。
另见