30

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

在我见过的每一种编程语言中,它都会转化为:

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)
4

24 回答 24

23

我认为大多数人认为像

isPrimaryColor = ["Red", "Blue", "Yellow"].contains(someColor)

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

于 2010-07-08T15:14:46.010 回答
18

在 python 中,您可以执行以下操作:

color = "green"

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

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

于 2010-07-08T15:15:45.940 回答
13

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

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

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

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

括号也使它有效 perl 5 (>=5.10); 在 perl 6 中,它们是可选的。

于 2010-07-08T15:31:17.903 回答
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")]
于 2010-07-08T17:59:18.467 回答
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
于 2010-07-08T16:11:18.117 回答
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
于 2010-07-09T13:58:12.923 回答
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 应该在某种程度上模仿英语。

于 2010-07-08T15:51:51.580 回答
5

你会喜欢Perl 6,因为它有:

您可以将两者与范围相结合:

$someNumber ~~ (1..100) | (1000..2000)
于 2010-07-08T15:57:45.887 回答
4

Python 实际上使您能够很好地完成最后一件事:

>>> x=5
>>> (1<x<1000 or 2000<x<3000)
True
于 2010-07-08T15:31:41.173 回答
2

在 Python 中,你可以说...

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

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

  • 效率:这不是原因,因为没有速度改进。
  • 功能:也不是问题;在新语法中没有什么是您在旧语法中无法做到的。
  • 易读性:大多数语言都可以处理您检查多个值是否相等的情况。在其他情况下(例如,someNumber (> 1 and < 10))它可能更有用,但即便如此,它也不会给你带来太多好处(Python 允许你说1 < someNumber < 10,这更清楚)。

因此,目前尚不清楚提议的更改是否特别有用。

于 2010-07-08T15:25:35.857 回答
2

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

在大多数语言中,比较运算符返回布尔类型。在 的情况下0 < x < y,如果这被解释为(0 < x) < y没有意义,因为<比较布尔值没有意义。因此,新的编译器可以解释0 < x < ytmp:=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;
}
于 2010-07-08T15:25:41.503 回答
2

Icon有你描述的设施。

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

我更喜欢Icon的那个方面。

于 2010-07-08T16:03:33.743 回答
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;
    }
}
于 2010-10-07T17:58:01.823 回答
1

您必须深入抽象层才能找出原因。x86 的比较/跳转指令是二进制的(因为它们可以在几个时钟周期内轻松计算),事情就是这样。

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

$isPrimaryColor = in_array($someColor, array('Red', 'White', 'Blue'));
于 2010-07-08T15:19:26.763 回答
1

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

BOOL isPRimaryColour = [[NSSet setWithObjects: @"red", @"green", @"blue", nil] containsObject: someColour];
于 2010-07-08T16:33:04.927 回答
1

这个问题是合理的,我不认为这种变化是语法糖。如果要比较的值是计算的结果,最好说:

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

不如说

  国际温度;
  temp = someComplicatedExpression;
  if (temp == 1 || temp == 2 || temp == 3 || temp == 5)

特别是如果没有其他需要相关的临时变量。现代编译器可能会识别 'temp' 的短暂有用生命周期并将其优化为寄存器,并且可能识别“查看变量是否是某些常量之一”模式,但允许程序员省去编译器的麻烦。指示的语法不会在任何现有的编译器上编译,但我认为它不会比 (a+b >> c+d) 更模棱两可,其行为在语言规范中定义。

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

于 2010-07-08T16:34:49.510 回答
1

作为一名数学家,我会说颜色是原色当且仅当它是原色集合 {red, green, blue} 的成员。

这正是您在 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 的宇宙 D 中的对象,而不是写作P(X)。例如,与其说“x 是一个正实数”或“PositiveReal(x)”,不如说x ∈ ℝ⁺.

于 2010-07-08T17:12:44.380 回答
1

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

if X=3 OR 4

如果 X 是 3 或 4,我的意图就像您所描述的那样。编译器将其解释为:

if (X=3) OR (4)

也就是说,如果 X=3 为真,或者如果 4 为真。因为它将任何非零值定义为真,4 为真,任何 OR TRUE 为真,因此表达式始终为真。我花了很长时间才弄清楚那个。

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

于 2010-07-08T17:31:26.083 回答
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。对不起我不完美的英语。

于 2010-07-08T20:41:24.470 回答
0

您给出的后一个示例实际上是语法糖,它们必须评估为与较长形式相同的代码,因为在某些时候,执行的代码必须依次将您的值与每个条件进行比较。

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

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

于 2010-07-08T15:23:38.013 回答
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)))
于 2010-07-08T21:03:54.093 回答
0

两种可能

爪哇

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

Python

a = 1500
if  1 < a < 10 or  1000 < a < 2000:
     print "In range"
于 2010-07-08T21:17:34.177 回答
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- 之类的名称,以使其更具可读性。

于 2015-08-11T14:40:20.983 回答
-1

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

于 2010-07-08T16:55:49.633 回答