I'm playing with the infixr
, infixl
and infix
declarations. I understand how infixr
and infixl
works:
-- 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)
But I don't understand how the infix
keyword works. Am I right in thinking that with infix
you always need to specify the order with parenthesis? If so, why is the numeric argument necessary considering that brackets have the highest precedence)?
Infix notation is the notation commonly used in arithmetical and logical formulae and statements. It is characterized by the placement of operators between operands—"infixed operators"—such as the plus sign in 2 + 2.
In infix form, an operator is written in between two operands. For example: An expression in the form of A * ( B + C ) / D is in infix form. This expression can be simply decoded as: “Add B and C, then multiply the result by A, and then divide it by D for the final answer.”
Infix expressions are readable and solvable by humans. We can easily distinguish the order of operators, and also can use the parenthesis to solve that part first during solving mathematical expressions.
Conversion of infix to postfixWhenever an operator will encounter, we push operator into the stack. If we encounter an operand, then we append the operand to the expression. Print the operand as they arrive. If the stack is empty or contains a left parenthesis on top, push the incoming operator on to the stack.
The r
and l
refer to the associativity, the number you specify refers to the operator precedence. When you don't specify the associativity you get an operator that can be associated only by explicit parenthesis or when the associativity is non-ambiguous.
Let's use a data structure to define operators on and understand how associativity works:
data Test = Test String deriving (Eq, Show)
It will contain the string built with the below operators.
infixr
and infixl
Now let's define right- and left- associative operators:
(>:) :: Test -> Test -> Test (Test a) >: (Test b) = Test $ "(" ++ a ++ " >: " ++ b ++ ")" (<:) :: Test -> Test -> Test (Test a) <: (Test b) = Test $ "(" ++ a ++ " <: " ++ b ++ ")" infixr 6 >: infixl 6 <:
These operator will construct the string of the resulting operator by explicitly adding the parenthesis to our associated terms.
If we test it out we see that it works correctly:
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
declaration does not specify associativity. So what should happen in those cases? Let's see:
(?:) :: Test -> Test -> Test (Test a) ?: (Test b) = Test $ "(" ++ a ++ " ?: " ++ b ++ ")" infix 6 ?:
And then let's try it:
print $ (Test "1") ?: (Test "2") ?: (Test "4")
Woops, we get:
Precedence parsing error cannot mix `?:' [infix 6] and `?:' [infix 6] in the same infix expression
As you can see the language parser noticed that we didn't specify the associativity of the operator and doesn't know what to do.
If we instead remove the last term:
print $ (Test "1") ?: (Test "2") -- Test "(1 ?: 2)"
Then the compiler doesn't complain.
To fix the original term we would need to explicitly add parenthesis; for example:
print $ (Test "1") ?: ((Test "2") ?: (Test "4")) -- Test "(1 ?: (2 ?: 4))"
Live demo
Because
1 +++ 2 < 3
works fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With