为什么大多数编程语言只有二进制相等比较运算符?

时间:2010-07-08 15:11:41

标签: language-design boolean-operations

在自然语言中,我们会说“如果颜色是红色,蓝色或黄色,某些颜色是原色。”

在我看过的每种编程语言中,都转化为:

isPrimaryColor = someColor == "Red" or someColor == "Blue" or someColor == "Yellow"

为什么没有更接近匹配英语句子的语法。毕竟,如果颜色是红色,或者颜色是蓝色,或者颜色是黄色,你就不会说“某些颜色是原色”。

我只是简单地认识isPrimaryColor = someColor == ("Red" or "Blue" or "Yellow")因为它不是红蓝色和黄色,而是布尔语句,在这种情况下布尔逻辑适用,但是如下所示:

isPrimaryColor = someColor ( == "Red" or == "Blue" or == "Yellow")

作为一个额外的好处,语法可以提供更大的灵活性,比如你想看一个数字是介于1到100还是1000和2000之间,你可以说:

someNumber ((>= 1 and <=100) or (>=1000 and <=2000))

编辑:

非常有趣的答案,并指出我应该学习更多语言。在阅读完答案之后,我同意,对于严格的相等比较,类似于集合成员资格的东西是表达同一事物的清晰简洁的方式(对于具有简明内联列表或集合和测试成员资格的语言支持的语言)

出现的一个问题是,如果要比较的值是昂贵计算的结果,则需要(好的,应该)创建临时变量。另一个问题是可能需要检查不同的评估,例如“一些昂贵的计算结果应该是素数且在200到300之间”

这些场景也包含在更多功能语言中(尽管取决于语言可能不是更简洁),或者实际上任何可以将函数作为参数的语言。例如,前面的例子可能是

MeetsRequirements(GetCalculatedValue(), f(x):x > 200, f(x):x < 300, IsPrime)

24 个答案:

答案 0 :(得分:23)

我认为大多数人会考虑像

这样的东西
isPrimaryColor = ["Red", "Blue", "Yellow"].contains(someColor)

要足够清楚,他们不需要额外的语法。

答案 1 :(得分:18)

在python中你可以这样做:

color = "green"

if color in ["red", "green", "blue"]:
    print 'Yay'

它被称为in运算符,用于测试集合成员资格。

答案 2 :(得分:13)

在perl 6中,您可以使用junctions执行此操作:

if $color eq 'Red'|'Blue'|'Green' {
    doit()
}

或者,您可以使用智能匹配运算符(~~)来完成此操作。以下大致相当于python的if value in list:语法,除了~~在其他上下文中做得更多。

if ($color ~~ qw/Red Blue Green/) {
    doit()
}

parens也使其有效perl 5(&gt; = 5.10);在perl 6中,它们是可选的。

答案 3 :(得分:12)

在Haskell中,很容易定义一个函数来执行此操作:

matches x ps = foldl (||) False $  map (\ p -> p x) ps

此函数获取谓词的值列表(类型为a -> Bool),如果任何谓词与值匹配,则返回True

这可以让你这样:

isMammal m = m `matches` [(=="Dog"), (=="Cat"), (=="Human")]

好消息是,它不必只是相等,你可以使用正确类型的任何东西:

isAnimal a = a `matches` [isMammal, (=="Fish"), (=="Bird")]

答案 4 :(得分:9)

红宝石

包含在列表中:

irb(main):023:0> %w{red green blue}.include? "red"
=> true
irb(main):024:0> %w{red green blue}.include? "black"
=> false

数字范围:

irb(main):008:0> def is_valid_num(x)
irb(main):009:1>   case x
irb(main):010:2>     when 1..100, 1000..2000 then true
irb(main):011:2>     else false
irb(main):012:2>   end
irb(main):013:1> end
=> nil
irb(main):014:0> is_valid_num(1)
=> true
irb(main):015:0> is_valid_num(100)
=> true
irb(main):016:0> is_valid_num(101)
=> false
irb(main):017:0> is_valid_num(1050)
=> true

答案 5 :(得分:7)

到目前为止,还没有人提到过SQL。它有你的建议:

SELECT
    employee_id
FROM 
    employee
WHERE
    hire_date BETWEEN '2009-01-01' AND '2010-01-01' -- range of values
    AND employment_type IN ('C', 'S', 'H', 'T')     -- list of values

答案 6 :(得分:6)

COBOL使用88级别来实现命名值,命名值组 和命名的值范围。

例如:

01 COLOUR         PIC X(10).
   88 IS-PRIMARY-COLOUR VALUE 'Red', 'Blue', 'Yellow'.
...
MOVE 'Blue' TO COLOUR
IF IS-PRIMARY-COLOUR
   DISPLAY 'This is a primary colour'
END-IF

范围测试包括如下:

01 SOME-NUMBER    PIC S9(4) BINARY.
   88 IS-LESS-THAN-ZERO    VALUE -9999 THRU -1.
   88 IS-ZERO              VALUE ZERO.
   88 IS-GREATER-THAN-ZERO VALUE 1 THRU 9999.
...
MOVE +358 TO SOME-NUMBER
EVALUATE TRUE
    WHEN IS-LESS-THAN-ZERO
         DISPLAY 'Negative Number'
    WHEN IS-ZERO
         DISPLAY 'Zero'
    WHEN IS-GREATER-THAN-ZERO
         DISPLAY 'Positive Number'
    WHEN OTHER
         DISPLAY 'How the heck did this happen!'
END-EVALUATE

我想这一切都发生了,因为COBOL应该模仿英语 在某种程度上。

答案 7 :(得分:5)

你会爱Perl 6,因为它有:

您可以将两者结合使用范围:

$someNumber ~~ (1..100) | (1000..2000)

答案 8 :(得分:4)

Python实际上让你能够做得最好:

>>> x=5
>>> (1<x<1000 or 2000<x<3000)
True

答案 9 :(得分:2)

在C#中:

if ("A".IsIn("A", "B", "C"))
{
}

if (myColor.IsIn(colors))
{
}

使用这些扩展程序:

public static class ObjectExtenstions
{
    public static bool IsIn(this object obj, params object [] list)
    {
        foreach (var item in list)
        {
            if (obj == item)
            {
                return true;
            }
        }

        return false;
    }

    public static bool IsIn<T>(this T obj, ICollection<T> list)
    {
        return list.Contains(obj);
    }

    public static bool IsIn<T>(this T obj, IEnumerable<T> list)
    {
        foreach (var item in list)
        {
            if (obj == item)
            {
                return true;
            }
        }

        return false;
    }
}

答案 10 :(得分:2)

在Python中你可以说......

isPrimaryColor = someColor in ('Red', 'Blue', 'Yellow')

...我觉得比你的(== "Red" or == "Blue")语法更具可读性。为语言功能添加语法支持有几个原因:

  • 效率:这里不是理由,因为没有速度提升。
  • 功能:也不是问题;你无法用新的语法做任何事情。旧的。
  • 易读性:大多数语言处理您正在检查多个值的相等性的情况。在其他情况下(例如,someNumber (> 1 and < 10))它可能更有用,但即使这样它也不会给你带来太大的帮助(Python允许你说1 < someNumber < 10,这更加清晰)。

所以不清楚提议的更改是否特别有用。

答案 11 :(得分:2)

我的猜测是语言是靠习惯设计的。早期语言只有二进制比较运算符,因为它们更容易实现。每个人都习惯说(x > 0 and x < y),直到语言设计师不再费心去支持数学中的常见形式(0 < x < y)。

在大多数语言中,比较运算符返回布尔类型。在0 < x < y的情况下,如果将其解释为(0 < x) < y,那将毫无意义,因为<对于比较布尔值没有意义。因此,新编译器可以将0 < x < y解释为tmp:=x, 0 < tmp && tmp < y,而不会破坏向后兼容性。但是,对于x == y == z,如果变量已经是布尔值,则这意味着x == y && y == z还是(x == y) == z是不明确的。

在C#中,我使用以下扩展方法,以便您可以编写someColor.IsOneOf("Red", "Blue", "Yellow")。它比直接比较效率低(如果Equals()是值类型,则与数组,循环,T调用和装箱相比),但它确实很方便。

public static bool IsOneOf<T>(this T value, params T[] set) 
{
    object value2 = value;
    for (int i = 0; i < set.Length; i++)
        if (set[i].Equals(value2))
            return true;
    return false;
}

答案 12 :(得分:2)

Icon具有您描述的功能。

if y < (x | 5) then write("y=", y)

我更喜欢Icon的那个方面。

答案 13 :(得分:1)

我还没有看到Objective-C答案。这是一个:

BOOL isPRimaryColour = [[NSSet setWithObjects: @"red", @"green", @"blue", nil] containsObject: someColour];

答案 14 :(得分:1)

这是因为编程语言尤其受到数学,逻辑和集合论的影响。布尔代数以一种不像口语自然语言那样工作的方式定义∧,∨运算符。您的示例将写为:

Let p(x) be unary relation which holds if and only if x is a primary color
p(x) ⇔ r(x) ∨ g(x) ∨ b(x)
or
p(x) ⇔ (x=red) ∨ (x=green) ∨ (x=blue)

如您所见,它与编程语言中使用的符号非常相似。由于数学提供了强大的理论基础,编程语言基于数学而不是自然语言,这总是为解释留下了很多空间。

编辑:使用集合表示法可以简化上述声明:

p(x) ⇔ x ∈ {red, green, blue}

实际上,一些编程语言,最着名的是Pascal,包括set,所以你可以输入:

type
    color = (red, green, blue, yellow, cyan, magenta, black, white);

function is_primary (x : color) : boolean;
begin
    is_primary := x in [red, green, blue]
end

但作为语言特征的集合并没有流行起来。

PS。抱歉我的英语不完美。

答案 15 :(得分:1)

我想起了我第一次开始学习编程的时候,在Basic中,有一次我写了

if X=3 OR 4

如果X是3或4,我打算像你所描述的那样。编译器将其解释为:

if (X=3) OR (4)

即,如果X = 3为真,或者如果4为真。因为它将非零定义为真,4为真,任何OR TRUE都为真,因此表达式始终为真。我花了很长时间想出那个。

我不认为这会增加讨论的内容。我只是觉得这可能是一个有趣的轶事。

答案 16 :(得分:1)

作为一名数学家,我会说,当且仅当它是原色{红色,绿色,蓝色}的成员时,颜色才是主要颜色。

这正是你在Delphi中所说的:

isPrimary := Colour in [clRed, clGreen, clBlue]

事实上,我经常使用这种技术。上次是三天前。我写了

,实现了我自己的脚本语言解释器
const
  LOOPS = [pntRepeat, pntDoWhile, pntFor];

然后,几行,

if Nodes[x].Type in LOOPS then

问题的哲学部分

@supercat等(“至于为什么没有人这样做,我不知道。”):

可能是因为编程语言的设计者是数学家(或者至少是数学上倾向的)。如果数学家需要陈述两个对象的相等性,她会说

X = Y,

自然。但是如果X可以是A,B,C ......之类的东西之一,那么她会定义这些东西的集合S = {A, B, C, ...}并写下

X ∈ S.

事实上,你(数学家)写X ∈ S,其中S是集

非常普遍
S = {x ∈ D; P(x)}

具有属性P的某些Universe D中的对象,而不是写P(X)。例如,不是说“x是正实数”或“PositiveReal(x)”,而是说x ∈ ℝ⁺

答案 17 :(得分:1)

这个问题是合理的,我不认为这种改变是语法糖。如果被比较的值是计算的结果,那么可以更好地说:

  if (someComplicatedExpression ?== 1 : 2 : 3 : 5)

而不是说

  int temp;
  temp = someComplicatedExpression;
  if (temp == 1 || temp == 2 || temp == 3 || temp == 5)

特别是如果没有其他需要的temp变量。现代编译器可能会识别'temp'的短暂使用寿命并将其优化为寄存器,并且可能识别出“看看变量是否是某个常量之一”模式,但允许程序员使用它并没有什么坏处保存编译器的麻烦。指示的语法不会在任何现有的编译器上编译,但我认为它不会比(a + b&gt;&gt; c + d)更加模糊,其行为是在语言规范中定义的。

至于为什么没有人这样做,我不知道。

答案 18 :(得分:1)

你必须在抽象层上稍微找一下原因。 x86的比较/跳转指令是二进制的(因为它们可以在几个时钟周期内轻松计算),这就是事情的发展方式。

如果你愿意,许多语言都提供了抽象。例如,在PHP中,您可以使用:

$isPrimaryColor = in_array($someColor, array('Red', 'White', 'Blue'));

答案 19 :(得分:0)

只是添加语言示例

<强>方案

(define (isPrimaryColor color)
  (cond ((member color '(red blue yellow)) #t)
        (else #f)))

(define (someNumberTest x)
  (cond ((or (and (>= x 1) (<= x 100)) (and (>= x 10000 (<= x 2000))) #t)
        (else #f)))

答案 20 :(得分:0)

两种可能性

爪哇

boolean isPrimary = Arrays.asList("red", "blue", "yellow").contains(someColor);

的Python

a = 1500
if  1 < a < 10 or  1000 < a < 2000:
     print "In range"

答案 21 :(得分:0)

你给出的后一个例子是有效的语法糖,他们必须评估与更长形式相同的代码,因为在某些时候执行的代码必须依次将你的值与每个条件进行比较。

数组比较语法,在这里以几种形式给出,更接近,我怀疑还有其他语言更接近。

使语法更接近自然语言的主要问题是后者不仅含糊不清,而且含糊不清。即使将模糊性保持在最低限度,我们仍然设法在我们的应用程序中引入错误,你能想象如果用自然英语编程会是什么样的吗?!

答案 22 :(得分:0)

这可以在Lua中用一些可以理解的魔法复制:D

local function operator(func)
    return setmetatable({},
        {__sub = function(a, _)
            return setmetatable({a},
                {__sub = function(self, b)
                    return f(self[1], b)
                end}
            )
        end}
    )
end


local smartOr = operator(function(a, b)
    for i = 1, #b do
        if a == b[i] then
            return true
        end
    end
    return false
end)


local isPrimaryColor = someColor -smartOr- {"Red", "Blue", "Either"}

注意:您可以将-smartOr-的名称更改为-isEither-,以使其更具可读性。

答案 23 :(得分:-1)

计算机上的语言比较为二进制,因为它们都是使用二进制来表示信息的机器。它们使用类似的逻辑和大致相似的目标设计。英语不是逻辑设计的,旨在描述算法,人脑(它运行的硬件)不是基于二进制。它们是专为不同任务而设计的工具。