为什么空列表中的“和”返回true,是否表示空列表为True?对不起,但我无法正确阅读和理解,所以请纠正我。感谢。
Prelude> and []
True
Prelude> or []
False
答案 0 :(得分:37)
在数学中,谈论二元操作通常很有用,例如&&
,||
,+
,*
等等。 身份。标识是值e
,以便以下属性适用于某些通用二进制操作<>
e <> x = x
x <> e = x
对于我上面列出的运算符,它们是可交换的,这意味着所有x <> y = y <> x
和x
的{{1}},所以我们只需要检查其中一个以上属性。对于y
,有问题的二元运算符为and
,对于&&
,二元运算符为or
。如果我们为这些操作制作Cayley table,它看起来像
||
正如您所看到的,对于&& | False | True
------+-------+------
False | False | False
True | False | True
|| | False | True
------+-------+------
False | False | True
True | True | True
,如果您有&&
和True && False
,答案始终是True && True
的第二个参数。对于&&
,如果您有||
和False || False
,则答案始终是第二个参数,因此每个参数的第一个参数必须是这些运算符下的标识元素。简单地说:
False || True
因此,当没有要执行运算符的元素时,首选答案是每个操作的标识元素。
考虑True && x = x
x && True = x
False || x = x
x || False = x
和+
的身份元素可能会有所帮助,分别是*
和0
:
1
您还可以将此扩展到列表连接(x + 0 = x = 0 + x
x * 1 = x = 1 * x
和++
)等操作,[]
类型函数的函数组合(a -> a
(.)
),以及许多其他人。由于这开始看起来像一个模式,你可能会问这是否已经是Haskell中的一个东西,事实确实如此。模块id
定义了抽象此模式的Data.Monoid
类型类,它的最小定义是
Monoid
它甚至将class Monoid a where
mempty :: a -- The identity
mappend :: a -> a -> a -- The binary operator
别名为mappend
以便于使用(我在上面为一般二元运算符选择它并不是偶然的)。我鼓励您查看该模块并使用其定义。源代码非常易于阅读并具有启发性。
答案 1 :(得分:12)
and
和or
只是折叠,而在空列表中调用的折叠将产生其起始参数,分别为True
或False
。
只有在加载Prelude
时才使用折叠实现它们,否则它们是使用显式递归实现的,尽管实际上没有使用foldr
或{{1},但它本身仍然是折叠的}。通过检查来源,它们的行为仍然与我们看到的相同:
foldl
Here是实施的链接。
清除注释中的混淆:fold是一个函数,它接受二进制函数和起始值(通常称为累加器)并遍历列表直到它为空。当在空列表上调用时,折叠将返回累加器,如果列表已经遍历则无关紧要。这是and [] = True
and (x:xs) = x && and xs
or [] = False
or (x:xs) = x || or xs
的示例实现:
foldr
foldr _ acc [] = acc
foldr f acc (x:xs) = f x (foldr f acc xs)
只是
and
使and = foldr (&&) True
评估为and []
。
答案 2 :(得分:7)
优秀的答案,但我认为值得提供更直观的治疗方法。但是,让我们看看and :: [Bool] -> Bool
,而不是all :: (a -> Bool) -> [Bool] -> Bool
。你可以这样想到all
。将谓词(a -> Bool
参数)描述为关于列表元素的假设。然后all
返回False
当且仅当列表包含至少一个反例时才会出现假设。如果列表为空,则没有反例,因此很容易确认。
要将其恢复为and
,请注意and
和all
是可以确定的。如果您有and
,则可以通过以下方式定义all
:
all :: (a -> Bool) -> [a] -> Bool
all pred = and . map pred
反之亦然,如果您已经all
,则可以从中定义and
:
and :: [Bool] -> Bool
and = all id
答案 3 :(得分:5)
除了@bheklilr回答之外,让我们回想起Monoid是一个元组(M,e,<>)
,其中M
是一个对象(你可以把它想象成一个类型),e
是对象的一个点M
(e : M
- 类型的元素)和<>
是一个二元操作,它是关联的并且具有e
作为标识:
<> : M -> M -> M
e <> x = x
x <> e = x
(x <> y) <> z = x <> (y <> z)
一些幺半群之间存在幺半群同态。有一个自由的幺半群 - 与其他任何一个同态的幺半群。这样的免费monoid是一个列表:([a], [], ++)
可以映射到任何其他monoid。例如:
([Int], [], ++) => (Int, 0, +)
([Int], [], ++) => (Int, 1, *)
([Bool], [], ++) => (Bool, True, &&)
([Bool], [], ++) => (Bool, False, ||)
然后sum
,product
,and
,or
是相应的monoid同态,映射了[Int]
和[Bool]
类型的元素。通过monoid同态的定义,幺半群的映射h
以任何列表x++y
映射到点h(x ++ y) == (h x) <> (h y)
的方式执行 - 例如and (x++[]) == (and x) && (and [])
}。从后一个示例可以清楚地看出,自x++[] == x
以来,(and x) && (and []) == and x
因此and []
映射到(Bool, True, &&)
的标识元素。
答案 4 :(得分:4)
考虑True
和False
的一种方式是False < True
排序lattice的元素。可以将&&
和||
视为此晶格的二进制“满足”(最大下限)和“连接”(最小上限)操作。类似地,and
和or
是一般的有限会合和有限连接操作。什么是and []
?这是[]
的最大下限。但True
(空)小于或等于[]
的每个元素,因此它是[]
的下限,(当然)它比任何其他下限(其他是False
),所以and [] = True
。代数观(考虑幺半群等)结果完全等同于秩序理论观点,但我认为秩序理论提供了更多的视觉直觉。
答案 5 :(得分:2)
and
的逻辑是找到列表中的第一个条目False
。如果未找到该条目,则结果为True
。例如:
and $ map even [2..]
不会遍历整个无限列表,但会停在3
并返回False
。空列表中没有False
元素,因此我们默认为True
。
对于or
,它类似:它会尝试找到第一个True
,然后停止,否则它会False
。
答案 6 :(得分:0)
and
的意思是:“所有内容都在True
吗?”。当它为空时,其中的所有内容(不是很多)都是真实的,因此是肯定的(True
)。
or
的意思是:“ True
里面有东西吗?”。当那里什么都没有时,那里什么也没有。 (False
)