'infix' 是如何工作的?

How does the 'infix' work?

我正在研究 infixrinfixlinfix 声明。我了解 infixrinfixl 的工作原理:

-- 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 +++ 2 < 3

工作正常。

tl;博士

rl指的是结合律,你指定的数字指的是运算符的优先级。当您不指定关联性时,您会得到一个运算符,该运算符只能通过显式括号关联,或者当关联性明确时。

我们的测试数据结构

让我们使用数据结构来定义运算符并了解关联性的工作原理:

data Test = Test String deriving (Eq, Show)

它将包含使用以下运算符构建的字符串。

infixrinfixl

的关联性

现在让我们定义右结合运算符和左结合运算符:

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

"Associativity" 与 infix

infix 声明没有指定关联性。那么在这些情况下会发生什么?让我们看看:

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

infix 6 ?:

然后让我们试试:

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

糟糕,我们得到:

Precedence parsing error cannot mix `?:' [infix 6] and `?:' [infix 6] in the same infix expression

如您所见,语言解析器注意到我们没有指定运算符的结合性,因此不知道该怎么做。

如果我们改为删除最后一项:

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

那么编译器就不会报错了。

要修复原始术语,我们需要明确添加括号;例如:

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

Live demo