我写了一个过滤功能:
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
怎么了?
答案 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 ]
最后一个代码段与上面的显式递归定义相对应。
另请参见