Подтвердить что ты не робот

Почему в большинстве языков программирования есть только бинарные операторы сравнения равенства?

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

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

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

Edit:

Очень интересные ответы и точка зрения, что я должен выучить больше языков. Прочитав ответы, я согласен с тем, что для строгого сравнения сравнений нечто подобное заданному членству является ясным и сжатым способом выражения одного и того же (для языков, которые поддерживают язык для кратких встроенных списков или наборов и тестирования членства)

Одна из проблем, которые возникли, заключается в том, что если значение для сравнения является результатом дорогостоящего расчета, то временная переменная должна быть (ну, должно быть) создана. Другая проблема заключается в том, что могут быть разные оценки, которые необходимо проверить, например, "результат какого-то дорогостоящего расчета должен быть простым и от 200 до 300"

Эти сценарии также охватываются более функциональными языками (хотя в зависимости от языка может быть не более кратким) или действительно любого языка, который может принимать функцию в качестве параметра. Например, предыдущий пример может быть

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

Ответ 1

В 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")]

Ответ 2

Я думаю, что большинство людей считают что-то вроде

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

достаточно ясно, что для этого не требуется дополнительный синтаксис.

Ответ 3

В python вы можете сделать что-то вроде этого:

color = "green"

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

Он называется in оператор, который проверяет наличие набора.

Ответ 4

В perl 6 вы можете сделать это с помощью junctions:

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

В качестве альтернативы вы можете сделать это с помощью оператора smart match (~~). Следующий пример примерно эквивалентен синтаксису python if value in list:, за исключением того, что ~~ делает гораздо больше в других контекстах.

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

Параны также делают его действительным perl 5 ( >= 5.10); в perl 6 они необязательны.

Ответ 5

рубин

Содержится в списке:

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

Ответ 6

До сих пор никто не упоминал 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

Ответ 7

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 должен был подражать английскому языку в некоторой степени.

Ответ 8

Вам понравится Perl 6, поскольку он имеет:

И вы можете комбинировать оба с диапазонами:

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

Ответ 9

Python на самом деле дает вам возможность делать последнее очень хорошо:

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

Ответ 10

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

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

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

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

Поэтому неясно, какое предлагаемое изменение особенно полезно.

Ответ 11

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

В С# я использую следующий метод расширения, чтобы вы могли написать 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

Icon содержит объект, который вы описываете.

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

Мне нравится этот аспект Icon.

Ответ 13

В С#:

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;
    }
}

Ответ 14

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

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

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

Ответ 15

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

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

Ответ 16

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

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

чем сказать

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

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

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

Ответ 17

Как математик, я бы сказал, что цвет является первичным тогда и только тогда, когда он является членом набора {красного, зеленого, синего} основных цветов.

И именно так вы можете сказать в 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 ∈ ℝ⁺.

Ответ 18

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

if X=3 OR 4

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

if (X=3) OR (4)

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

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

Ответ 19

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

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)

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

EDIT: вышеуказанный оператор можно упростить, используя обозначение набора:

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

Ответ 20

Последние примеры, которые вы даете, являются синтаксическим сахаром, они должны были бы оценить тот же код, что и более длинная форма, так как в какой-то момент исполняемый код должен сравнить ваше значение с каждым из условий в свою очередь.

Синтаксис сравнения массива, приведенный в нескольких формах здесь, ближе, и я подозреваю, что есть другие языки, которые становятся еще ближе.

Основная проблема с приближением синтаксиса к естественному языку состоит в том, что последнее не просто двусмысленно, оно ужасно неоднозначно. Даже сохраняя неопределенность до минимума, нам все еще удается вводить ошибки в наши приложения, можете ли вы представить, каково это было бы, если бы вы запрограммировали естественный английский?!

Ответ 21

Просто добавьте примеры языков

Схема

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

Ответ 22

Две возможности

Java

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

Python

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

Ответ 23

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

Ответ 24

Языки на компьютерах сравниваются как двоичные, потому что все они предназначены для машины, которая использует двоичную информацию для представления информации. Они были разработаны с использованием аналогичной логики и с аналогичными целями. Английский язык не был разработан логически, предназначен для описания алгоритмов, а человеческий мозг (аппаратное обеспечение, на котором он работает) не основан на двоичном. Это инструменты, предназначенные для различных задач.