Как работает "инфикс"?

Я играю с объявлениями infixr, infixl и infix. Я понимаю, как работают infixr и infixl:

-- Test expression: 40 +++ 20 +++ 50 +++ 10 * 10

-- infixr 8 +++ -- Calculated as: (40 +++ (20 +++ (50 +++ 10))) * 10. Result: 630.
-- infixl 8 +++ -- Calculated as: (((40 +++ 20) +++ 50) +++ 10) * 10. Result: 800.

-- infixr 6 +++ -- Calculated as: 40 +++ (20 +++ (50 +++ (10 * 10))). Result: 75.
-- infixl 6 +++ -- Calculated as: ((40 +++ 20) +++ 50) +++ (10 * 10). Result: 125.

(+++) :: Int -> Int -> Int
a +++ b = a + (b `div` 2)

Но я не понимаю, как работает ключевое слово infix. Правильно ли я думаю, что при infix вам всегда нужно указывать порядок с круглыми скобками? Если да, то почему требуется числовой аргумент, учитывая, что скобки имеют самый высокий приоритет)?

Ответ 1

ТЛ; др

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

Наша тестовая структура данных

Давайте используем структуру данных, чтобы определить операторы и понять, как работает ассоциативность:

data Test = Test String deriving (Eq, Show)

Он будет содержать строку, созданную с помощью следующих операторов.

Ассоциативность с infixr и infixl

Теперь давайте определим ассоциативные операторы right- и left-:

(>:) :: Test -> Test -> Test
(Test a) >: (Test b) = Test $ "(" ++ a ++ " >: " ++ b ++ ")"

(<:) :: Test -> Test -> Test
(Test a) <: (Test b) = Test $ "(" ++ a ++ " <: " ++ b ++ ")"

infixr 6 >:
infixl 6 <:

Эти операторы создадут строку результирующего оператора, явно добавив скобки к нашим связанным терминам.

Если мы проверим это, мы увидим, что это работает правильно:

print $ (Test "1") >: (Test "2") >: (Test "4")
-- Test "(1 >: (2 >: 4))"

print $ (Test "1") <: (Test "2") <: (Test "4")
-- Test "((1 <: 2) <: 4)"

"Ассоциативность" с infix

Объявление infix не определяет ассоциативность. Так что же должно произойти в этих случаях? Давай посмотрим:

(?:) :: Test -> Test -> Test
(Test a) ?: (Test b) = Test $ "(" ++ a ++ " ?: " ++ b ++ ")"

infix 6 ?:

А потом давай попробуем это:

print $ (Test "1") ?: (Test "2") ?: (Test "4")

Woops, мы получаем:

Ошибка разбора приоритета не может смешивать '?:' [Infix 6] и '?:' [Infix 6] в одном и том же выражении infix

Как видите, анализатор языка заметил, что мы не указали ассоциативность оператора и не знаем, что делать.

Если вместо этого мы удалим последний член:

print $ (Test "1") ?: (Test "2")
-- Test "(1 ?: 2)"

Тогда компилятор не жалуется.

Чтобы исправить первоначальный термин, нам нужно явно добавить скобки; например:

print $ (Test "1") ?: ((Test "2") ?: (Test "4"))
-- Test "(1 ?: (2 ?: 4))"

Live demo

Ответ 2

Поскольку

1 +++ 2 < 3

отлично работает.