为什么“和[]”为真,“或[]”为假

时间:2014-08-21 13:27:38

标签: haskell monoids

为什么空列表中的“和”返回true,是否表示空列表为True?对不起,但我无法正确阅读和理解,所以请纠正我。感谢。

Prelude> and []
True
Prelude> or []
False

7 个答案:

答案 0 :(得分:37)

在数学中,谈论二元操作通常很有用,例如&&||+*等等。 身份。标识是值e,以便以下属性适用于某些通用二进制操作<>

e <> x = x
x <> e = x

对于我上面列出的运算符,它们是可交换的,这意味着所有x <> y = y <> xx的{​​{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)

andor只是折叠,而在空列表中调用的折叠将产生其起始参数,分别为TrueFalse

只有在加载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,请注意andall是可以确定的。如果您有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是对象的一个​​点Me : 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, ||)

然后sumproductandor是相应的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)

考虑TrueFalse的一种方式是False < True排序lattice的元素。可以将&&||视为此晶格的二进制“满足”(最大下限)和“连接”(最小上限)操作。类似地,andor是一般的有限会合和有限连接操作。什么是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