语言为什么不包含隐含逻辑运算符?


60

这可能是一个奇怪的问题,但是为什么在许多语言(Java,C,C ++,Python Haskell中没有逻辑操作符的含义),尽管最后一个用户添加了用户定义的操作符却无足轻重吗?我发现逻辑含义要清晰得多(特别是在断言或类似断言的表达式中),然后用or进行否定:

encrypt(buf, key, mode, iv = null) {
    assert (mode != ECB --> iv != null);
    assert (mode == ECB || iv != null);
    assert (implies(mode != ECB, iv != null)); // User-defined function
}

28
因为它没有放在C中;如果已经发布了,那么C ++,Java和C#就会拥有它。
m3th0dman

4
但是C却没有它,因为它不是汇编语言的通用部分。鉴于我所知道的所有指令集都包含和/或不包含,我不知道任何包含的隐含含义-毫无疑问,有人会告诉我一些晦涩难懂的指令
集会

4
也许它被认为是多余的,因为(1)它不如“ ^”,“ v”,“〜”原始,(2)由于“ A => B”等效于“〜A v B”,因此它几乎不需要输入任何内容。 。
Giorgio

4
处理逻辑结构的语言更可能具有逻辑结构。其中主要是prolog

9
我惊讶于您认为assert#1比#2更清晰。我凝视#1已经有一段时间了,但仍然看不到它的行为如何被认为是直观的。(尤其是!=在逻辑上有额外的转变)
克里斯·伯特·布朗

Answers:


61

毫无疑问,有时有时会有用。有几点反对这样的运算符:

  • 这些字符->都是有价值的,无论是孤立的还是组合的。许多语言已经使用它们来表达其他含义。(而且许多语法不能使用unicode字符集。)
  • 即使对于像逻辑家这样的人,例如程序员,暗示也非常违反直觉。四个真值表条目中的三个是true令人惊讶的事实。
  • 所有其他逻辑运算符都是对称的,这将->是正交性的一个例外。
  • 同时,有一个简单的解决方法:使用运算符!||
  • 隐含的使用频率远远低于逻辑and/ or

这可能就是为什么运营商今天很少见的原因。当然,随着新的动态语言对所有内容都使用Unicode以及运算符重载变得更加流行,它可能会变得更加普遍。


22
您的第一点只是反对使用“->”作为运算符的符号,而不是实际上拥有运算符。其他都是好点。
AShelly

14
“同时,有一个简单的解决方法:使用!和&&。”:实际上,模拟“->”(或“ =>”,在数学中更常见)的最简单方法是使用!并且||,不!&&A -> B相当于!A || B这相当于!(A && !B)
Giorgio

22
“事实表中四个条目中有三个是真实的,这使许多人感到惊讶。” 笏。我知道另一个具有相同功能且经常使用的运算符...
l0b0 2013年

9
@ l0b0,我是一名学习CS的程序员,但是很久以前。我已经忘记了“隐含”是具有两个操作数的形式运算,它们返回一个真值,因此起初我对这个问题的性质感到困惑。在日常演讲中,只有在已知第一个操作数为真时才使用“隐式”(“ X为真,因此Y必须为真”)。片刻之后,我记得形式化的“隐含”是如何工作的,但事实仍然存在,即使对于曾经研究形式化逻辑的人来说,意图也不清楚。而且,如果我从未研究过它,那么它最终将变得毫无意义。
本李

5
(a)在C中->用作运算符。没有人对此抱怨。无论如何,我都会使用=>。(b)与谁背道而驰?蕴涵的定义就是定义。(c)减法不是可交换的。没有人对此抱怨。(d)我想你的意思是!和||。由于优先级(和),通常也需要。可以对&&或||;使用相同的参数。选择。(e)也许是因为它不是大多数语言的版本。||的许多用途 可以简明扼要地(至少对我而言)以暗示的方式代替。
Theodore Norvell

54

我相信答案在于数学基础。隐含通常被认为并定义为布尔代数的派生而非基本运算。编程语言遵循此约定。

这是乔治·布尔的《思想定律的调查》(1854年)第二章的第一题:

语言的所有操作,作为推理的一种手段,都可以通过由以下要素组成的符号系统来进行,即:

1号 文字符号,如x,y和c,表示事物是我们概念的主题。

2号 运作的迹象,如+,-,×,代表思维的运作,通过这些运作,事物的概念得以组合或分解,从而形成涉及相同元素的新概念。

第三名 身份标志=。

这些逻辑符号在使用中要服从明确的定律,部分与代数科学中的相应符号的定律一致并部分不同。

布尔符号+代表了我们今天公认的布尔“ or”和集合的并集的相同“思想操作”。类似地,符号-和×对应于我们的布尔求反,集合的补码,布尔“和”以及集合的交集。


+1-可靠的答案。布尔代数及其所允许的逻辑简化驱动了许多编程方法。使用“隐含...”可能会干扰“无关”条件。

3
1.取决于定义。可以定义或作为a || b = !(!a && !b)(我在逻辑上遇到或作为派生运算符)。2.这样做的原因通常是为了简化归纳证明,我相信(我们知道派生运算符只是捷径,因此我们不需要为它们单独设置大小写)。@ GlenH7:什么“无关”条件?a --> b与相同!a || b
Maciej Piechotka

3
另外-我们还有其他派生运算符,例如xor(!=)nxor(==)...
Maciej Piechotka,2013年

5
实际上,您可以从NAND !(a && b)或NOR 派生所有内容!(a || b)。例如NOT a == a NAND aa AND b == NOT(a NAND b)a OR b == (NOT a) NAND (NOT b)。但是,仅提供NAND运算符会使您进入深奥的语言领域(考虑到应答者的用户名;-),这非常适合。
Stefan Majewsky

1
@Stefan:您还可以从IMPL派生所有内容。
梅森惠勒

37

更新:这个问题是我2015年11月博客的主题。感谢您提出有趣的问题!


Visual Basic 6(和VBScript)具有ImpEqv运算符。没有人使用它们。两者均已在VB.NET中删除;据我所知,没有人抱怨。

我在Visual Basic编译器团队中(作为实习生)工作了整整一年,但从未听说VB甚至拥有这些运算符。如果我不是编写VBScript编译器的人,因此必须测试它们的实现,我可能不会注意到它们。如果编译器团队的成员不了解该功能并且不使用它,那么这将告诉您有关该功能的受欢迎程度和有用性的信息。

您提到了类似C的语言。我不会讲C或C ++或Java,但可以讲C#。C#的用户建议功能列表实际上比您的手臂还要长。据我所知,还没有用户向C#团队推荐过这样的运算符,而我已经多次遍历该列表。

在一种语言中存在和未使用,而在另一种语言中从未请求过的功能不太可能成为现代编程语言的候选者。尤其是在预算中没有足够的时间,精力和金钱来制作人们确实想要的功能时。


IMP作为运营商可以追溯到GWBASIC时代。我记得它从1979
。– zarchasmpgmr

1
我读过IMPL对于代码合同非常有帮助。(没有VB。)
Mason Wheeler 2014年

3
VBScript程序员可能是最不可能使用这种运算符的群体。我现在希望PowerShell具有隐含运算符,以便我可以更轻松,更轻松地实现一些[switch]过滤器参数。
brianary

我记得DEC BASIC的IMP。我不记得了EQV。我经常希望的运算符是“而不是”,这会否定运算符之前先提升右手运算符。因此,0xABCD12345678ul ~& 0x00200000u将产生0xABCD12145678ul而不是0x12145678ul。
超级猫

19

我只能猜测,但原因可能是有些解决方法非常简单易读。让我们考虑您的示例:

if (mode != ECB) assert (iv != null);

assert (mode != ECB --> iv != null);  // <-- that's only one character shorter

如果需要表达式,可以使用大多数语言中可用的inline-if运算符(通常称为三元运算符)。当然,这不如优雅A --> B,但是用例的数量可能无法证明添加(并维护!)另一个运算符是合理的:

assert (mode != ECB ? iv != null : true);

2
至于断言-有充分的理由。第一个会(在许多实现中)产生消息“断言失败:iv!= null”,而第二个“断言失败:模式!= ECB-> iv!= null”。
Maciej Piechotka

2
+1,我将在这个问题上问同样的事情(由于我对“蕴涵”不是很熟悉,所以它永远不会出现)。if几乎每个人的陈述都清晰得多。
Izkata

12

埃菲尔有牵连

实际上,它还有更多。它既有严格的半严格运算符。

程序员不使用此类事物的原因是,他们从未受过培训,以致他们无法准确地知道它们是什么,如何使用它们,何时使用它们以及如何使用它们进行设计。因为他们从未接受过培训,所以他们从不向编译器编写者提出要求,这就是为什么编译器人员不会费心将此类机制放入编译器中的原因。当计算机科学专业的学生和Shade-tree程序员开始接受更全面的教育时,编译器将开始追赶。

事实证明,一旦您拥有具有此类布尔运算符的语言,并且知道如何使用它们进行设计和使用,便可以使用它们。

在Eiffel中,“隐含”关键字的使用由于基于合同的设计而非常突出,这是由于合同断言的布尔重性质。有些合同只能使用“隐含”运算符正确且有效地编写。然后,这引起了这样的评论:没有合同的语言会进一步发展,而无需考虑,训练和实施暗示的使用。

除此之外,大多数程序员对数学和逻辑的理解都是“软弱的”。即使您在数学和逻辑方面的工作量很大,但是当人们选择一种语言时,并没有实现诸如暗示之类的结构,那么人们往往会认为这样的事情是不必要的或无用的。很少有人问这门语言,并进入一个回声室:“好吧编译器人员看不到需求”和“好吧程序员看不到需求”-无休止的恶性循环。

取而代之的是,编译人员需要支持该理论,编写一种由该理论提出或暗示的语言表示法(例如,面向对象的理论),而不管程序员的想法或要求如何。从那里,教授,老师和其他专业人员需要根据原始理论而不是“通过语言的透镜理论”来专业地训练年轻的思想家。当这种情况发生时,人们会突然醒来,意识到自己所缺少的和所施加的。

现在-那里有太多的理论伪装成面向对象的,但仅仅是一种“玻璃”(通过您选择的语言)的面向对象。人们无法阅读有关OO的大多数“理论”书,因为他们想通过某种语言来解释理论。完全错误和不正确。这就像教我基于计算器的数学运算或我的计算尺一样。否-人们可以让现实教给自己一个关于自己的东西,然后使用一种符号来描述人们所观察到的东西-这就是所谓的“科学”。另一个称为OO-based-on-language-X的混搭太偏斜以至于几乎不能代表现实。

因此,远离语言,看一下原始理论,然后重新开始。不要让语言的局限性,局限性和绘画技巧告诉您理论是什么。只需让理论的实际情况决定其本身的符号,然后从那里转移到制定一种语言即可。

从那里,您将开始领会暗示和“暗示”不仅有用,而且优雅而又非常酷!

有一个很棒的!


7

Python具有某种隐藏方式的隐含运算符。

小于等于运算符被重载以接受布尔值。结果,可以将其用作蕴涵运算符。

示例验证(Python代码):

print (False <= False) # This will print True.
print (False <= True)  # This will print True.
print (True <= False)  # This will print False.
print (True <= True)   # This will print True.

回忆蕴涵运算符的真值表是:

LEFT RIGHT RESULT
F    F     T
F    T     T
T    F     F
T    T     T

2
这很棒,但不幸的是,它的严格性属性有误:f() implies g()不应评估is g()是否f()False,但在这种情况下<=会评估g()
乔恩·普迪

2
@Jon Purdy-严格来说,短路评估是二进制运算符的可选功能。因此,从技术上讲,这是蕴涵运算符的完全合法的实现。话虽这么说,我真的怀疑Guido van Rossum甚至打算把它当作一个隐含操作者。这只是比较布尔值的一个怪癖。
Mackenzie 2014年

当然,我是说这是一个有趣的观察,但不是您应该在实际程序中使用的东西,因为它不会短路,如果他们期望did_all_possible_stuff = x.do_required_stuff() and (x.supports_optional_stuff() <= x.do_optional_stuff())工作,可能会使某些人感到惊讶。
乔恩·普迪

2
这也适用于C和C ++。
Ben Voigt,2015年

5

Eiffel有一个“隐含”运算符,非常适合编写前置条件和后置条件。它使代码更具可读性,不幸的是,这从来都不是像C这样的语言的基本意图,而且很少人使用eiffel,因此众所周知“隐含”作为运算符的美妙之处。


2

对我来说,隐含的最大问题是初始条件为假时。例如:“如果太阳是绿色的,那么我就是果蝠。” 真正!

在形式逻辑中,当不满足隐含条件时,它只是为值赋“ True”。但是在编程中,这可能会导致违反直觉和令人惊讶的结果。

我实际上认为@Heinzi的示例在上面:

if (sun.color() == "green") then assert(me.species() == "fruitbat")

易于理解,并且由于误解逻辑而不太容易出错。

在测试的上下文中,我只是在我的假设变为假的时候就停止了:

assert(sun.color() == "green")
assert(me.species() == "fruitbat")

因此,就@Eric Lippert而言,作为程序员,我不知道何时使用隐式运算符。“错误为真”行为在数学形式逻辑的上下文中似乎很有用,但可能导致程序逻辑中出乎意料的结果。

...

没有人提到常见的“?” 运算符,其中“ A?B:true”与“ implies”相同。但是,尽管形式逻辑将true赋予“ else”条件,但“?” 让开发人员明确分配。

在形式逻辑中,使用“ true”是可行的,但是在编程中,如果条件为false,则更好的答案更像是“ null”或“ void”或“ skip”,甚至可能是false。

我认为有人必须弄清楚为什么“隐含”比“?”或“ if”语句或常规程序流更有用。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.