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

я играю с 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 вам всегда нужно указывать порядок в скобках? Если да,то почему числовой аргумент необходим, учитывая, что скобки имеют самый высокий приоритет)?

2 ответов


tl; dr

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

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

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

data Test = Test String deriving (Eq, Show)

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

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

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

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

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

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

infix 6 ?:

и тогда давайте попробуем:

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

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

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

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

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

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

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

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

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

Live demo


, потому что

1 +++ 2 < 3

работает нормально.