I'm playing around with custom operators, infix, infixl and infixr. Now I'm confused.
I've written a custom operator for list-multiplication, and thought, that declaring it as a simple infix-operator with no directional associativity, would automatically provide both cases, nr * list and list * number, as they can be interchanged at will.
import Prelude hiding ((*))
infix 6 *
(*) :: Int -> [a] -> [a]
n * l = if n < 0 then []
else l ++ (n - 1) * l
Now, 3 * [1, 2, 3] returns [1, 2, 3, 1, 2, 3, 1, 2, 3] as expected, but [1, 2, 3] * 3 throws an error, because I never explicitly defined list * nr.
My question: What is the unique functionality of infix and why not allways use infixl or infixr instead, as it should make no difference?
I understand "no directional associativity" / infix as a synonym to "is commutative":
a + b + c has no directional associativity and is commutative and can be written as (a + b) + c, a + (b + c), b + a + c, (b + a) + c, and so on...
For my example 2 * [1, 2] * 1 is the same as 1 * (2 * [1, 2]), and all other combinations of that, so i dont really get, why there is no implicit reshaping for commutative operator declarations, even with different typed operands.
The fixity declarations only affect parsing, not the definitions of the operators.
If you use
infixl, thena * b * cis parsed as(a * b) * c.If you use
infixr, thena * b * cis parsed asa * (b * c).If you use
infix, then you are saying thata * b * ccannot be parsed; you must use parentheses to specify whether you mean(a * b) * cora * (b * c). CompareIn your case,
*is not fully associative, because the types don't line up. It can be right-associative, because3 * (6 * [])typechecks but not left-associative because(3 * 6) * []does not. Usinginfix, you disallow3 * 6 * []. If you usedinfixr, then you could write that and the parser will treat it as3 * (6 * []).Making an operator like this commutative is tricky, because at the type level they are two different operators. That's easy enough to define:
Making
*work as bothInt -> [a] -> [a]and[a] -> Int -> [a]is tricky, if not impossible. (Maybe something involving a multi-parameter type family?)
Your understanding of associativity and commutativity is incorrect. "Not associative" is not a synonym for "commutative". In fact, the two properties are orthogonal: a given operator can be both, or neither, or only one of the two.
Integer addition is associative and commutative.
Integer subtraction is neither associative nor commutative.
Matrix multiplication is associative, but not commutative. (
BAcan be different fromABor even undefined altogether.)The NAND operation (the negation of logical AND) is commutative, but not associative: