Почему большинство языков программирования имеют только операторы сравнения двоичного равенства? - PullRequest
29 голосов
/ 08 июля 2010

В естественных языках мы бы сказали, что «какой-то цвет является основным цветом, если цвет красный, синий или желтый».

На каждом языке программирования, который я видел, это выглядит примерно так:

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 ]

2 голосов
/ 07 октября 2010

В 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;
    }
}
2 голосов
/ 08 июля 2010

Я думаю, что языки создаются по привычке. Ранние языки имели бы только операторы двоичного сравнения, потому что их было проще реализовать. Все привыкли говорить (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;
}
2 голосов
/ 08 июля 2010

В Python вы можете сказать ...

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

... который я нахожу более читабельным, чем ваш (== "Red" or == "Blue") синтаксис. Есть несколько причин добавить поддержку синтаксиса для языковой функции:

  • Эффективность : здесь нет причины, так как нет улучшения скорости.
  • Функциональность : Также не проблема; в новом синтаксисе вы ничего не можете сделать, чего не можете сделать в старом.
  • Удобочитаемость : Большинство языков обрабатывают случай, когда вы проверяете равенство нескольких значений просто отлично. В других случаях (например, someNumber (> 1 and < 10)) это может быть более полезным, но даже тогда это не приносит вам большой выгоды (а Python позволяет вам сказать 1 < someNumber < 10, что еще яснее).

Так что не ясно, предложенные изменения особенно полезны.

1 голос
/ 08 июля 2010

Мне вспоминается, когда я впервые начал изучать программирование на языке Basic, и в какой-то момент я написал

if X=3 OR 4

Я задумал это так, как вы описываете, если X равен 3 или 4.Компилятор интерпретировал это как:

if (X=3) OR (4)

То есть, если X = 3 истинно или если 4 истинно.Так как он определил все ненулевое значение как истинное, 4 - это истина, все ИЛИ ИСТИНА - это истина, и поэтому выражение всегда было истинным.Я долго размышлял над этим.

Я не утверждаю, что это что-то добавляет к обсуждению.Я просто подумал, что это может быть слегка забавный анекдот.

1 голос
/ 08 июля 2010

Как математик, я бы сказал, что цвет является основным в том и только в том случае, если он является членом набора основных цветов (красный, зеленый, синий).

И это именно так, как вы могли быв 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)}

объектов в некоторой вселенной D, обладающих свойством P, вместо записи P(X).Например, вместо того, чтобы сказать «x - положительное действительное число» или «PositiveReal (x)», можно было бы сказать x ∈ ℝ⁺.

1 голос
/ 08 июля 2010

Вопрос разумный, и я бы не стал считать это изменение синтаксическим сахаром. Если сравниваемое значение является результатом вычисления, было бы лучше сказать:

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

чем сказать

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

особенно, если не было никакой другой необходимости в рассматриваемой временной переменной. Современный компилятор мог бы, вероятно, распознать короткое полезное время жизни «temp» и оптимизировать его для регистра, и, вероятно, мог бы распознать шаблон «посмотрим, является ли переменная одной из определенных констант», но не было бы вреда, если бы программист сохранить компилятор проблемы. Указанный синтаксис не будет компилироваться ни на одном существующем компиляторе, но я не думаю, что он будет более двусмысленным, чем (a + b >> c + d), поведение которого определено в спецификации языка.

Что касается того, почему никто этого не сделал, я не знаю.

1 голос
/ 08 июля 2010

Вам придется немного пройти уровень абстракции, чтобы выяснить причину. Инструкции сравнения / перехода в x86 являются двоичными (поскольку их можно легко вычислить за несколько тактов), и так оно и было.

Если хотите, многие языки предлагают абстракцию для этого. В PHP, например, вы можете использовать:

$isPrimaryColor = in_array($someColor, array('Red', 'White', 'Blue'));
1 голос
/ 09 июля 2010

Это потому, что языки программирования находятся под влиянием математики, логики и теории множеств в частности.Булева алгебра определяет операторы ∧, ∨ таким образом, что они не работают как разговорный естественный язык.Ваш пример будет записан как:

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.Извините за мой несовершенный английский.

1 голос
/ 08 июля 2010

Я пока не вижу ответа Objective-C.Вот один из них:

BOOL isPRimaryColour = [[NSSet setWithObjects: @"red", @"green", @"blue", nil] containsObject: someColour];
0 голосов
/ 11 августа 2015

Это может быть воспроизведено в 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-, чтобы сделать его еще БОЛЬШЕ читаемым.

...