如何使用map / filter实现这一点

时间:2014-10-21 05:17:25

标签: haskell higher-order-functions

我应该想出一个函数and::[Bool]->Bool,只有当xs不包含False元素时,(and xs)才为真。

我完全能够使用递归来编写它。我甚至尝试使用map,但是地图总是返回一个列表,这与我的返回类型冲突。

这是我使用递归的代码:(它工作得很好)

isTrue::[Bool]->Bool
isTrue []       =True
isTrue (x:xs)
 | (x == True)  =isTrue(xs)
 | otherwise    =False

我尝试用map执行此操作:(这将无法工作)

and::[Bool]->Bool
and xs = map (True ==) xs

那么我在世界上如何使用map,filter或foldr来实现这个疯狂的功能呢?感谢

3 个答案:

答案 0 :(得分:3)

以与过滤器类似的方式考虑takeWhile,但在遇到第一个False时停止过滤,如下所示,

and' :: [Bool] -> Bool
and' xs = xs == takeWhile (== True) xs

答案 1 :(得分:2)

过滤True值并检查结果是否为空列表:

and' :: [Bool] -> Bool
and' = null . filter (== False)

使用foldr的更经典方法:

and'' :: [Bool] -> Bool
and'' = foldr (&&) True

答案 2 :(得分:2)

foldr是要走的路:

有各种方法可以解决这个问题。第一种是考虑折叠为在元素对之间插入二元运算:

foldr c n [x1,x2,x3,...,xn] =
    x1 `c` (x2 `c` (x3 `c` (... `c` (xn `c` n))))

所以在这种情况下,

foldr (&&) True [x1,x2,x3,...,xn] =
    x1 && x2 && x3 && ... && xn && True

请注意,&&是正确关联的,因此我们不需要括号。

另一种方法是弄清楚如何将您提供的递归形式转换为折叠。一般来看,这一点看看格雷厄姆赫顿的“关于普遍性和折叠表现力的教程”。

从递归表单开始:

and::[Bool]->Bool
and []       =True
and (x:xs)
 | (x == True)  = and (xs)
 | otherwise    = False

现在没有理由问x==True是否因为它实际上与直接测试x相同。并且函数参数周围不需要额外的括号。所以我们可以像这样重写:

and []        = True
and (x:xs)
  | x         = and xs
  | otherwise = False

现在让我们看看我们是否可以将其写成折叠:

and xs = foldr c n xs

因为and [] = True我们知道n = True

and xs = foldr c True xs

现在看一下递归案例:

and (x:xs)
  | x         = and xs
  | otherwise = False

您可以看到这仅取决于xand xs。这意味着我们能够提出c,以便折叠正确:

c x r
  | x         = r
  | otherwise = False

r是将and应用于列表的其余部分的结果。但这个c功能是什么?它只是(&&)

所以我们得到

and xs = foldr (&&) True xs

在每一步中,foldr(&&)当前元素和折叠结果传递给列表的其余部分。

我们实际上并不需要xs参数,所以我们可以编写

and = foldr (&&) True