我应该想出一个函数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来实现这个疯狂的功能呢?感谢
答案 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
您可以看到这仅取决于x
和and xs
。这意味着我们将能够提出c
,以便折叠正确:
c x r
| x = r
| otherwise = False
r
是将and
应用于列表的其余部分的结果。但这个c
功能是什么?它只是(&&)
!
所以我们得到
and xs = foldr (&&) True xs
在每一步中,foldr
将(&&)
当前元素和折叠结果传递给列表的其余部分。
我们实际上并不需要xs
参数,所以我们可以编写
and = foldr (&&) True