Trying to understand more about operator associativity in OCaml - ocaml

I got quite confusioned about associativity in OCaml.
Let's have some examples first.
1. Is + left associative or right?
I think it is left associative. which means if we have a + b + c + d, then it is ((a+b)+c)+d.
But what if we do f1 1 + f2 2? Will it throw an error? because it should be ((f1 1)+f2) 2, right?
2. :: is right associative, but what if used with ,?
If we do 4,3::[], then we have [4,3]. it will create a tuple (4,3), then :: into [].
then why doesn't 4,3::5,6::[] work?
3. functions
Say we have let f x y = y x 5, so y is a function taking two parameters.
If we do f 1 + 2, because + is actually a function taking two parameters, why won't f 1 + 2 work? Why doesn't + become a parameter of f?
4. right associativity
How to create a infix function with right associativity?
Basically, I guess I haven't understood the whole associative / precedence thing in OCaml.
I know there are tables like this http://caml.inria.fr/pub/docs/manual-caml-light/node4.9.html out there. But can someone explain more to me?

Operator associativity determines how to parse an expression when there are multiple operators with the same precedence. For example, a + b + c has two operators with the same precedence (+ and +), so the associativity determines how to parse that expression: the operator is left-associative, so the expression is equivalent to (a + b) + c.
In the expression f1 1 + f2 2, juxtaposition (f1 1 and f2 2) has higher precedence than +, so the expression is equivalent to (f1 1) + (f2 2). There aren't two or more operators at the same precedence level, so associativity doesn't matter.
Your statement about 4,3::[] is wrong: :: has higher precedence than ,, so it is parsed as 4, (3::[]), not (4,3)::[]. The result is a pair whose second element is a list. Read the type error for 4,3::5,6::[]: it is equivalent to (4, (3::5), (6::[])), thus the compiler complains that 5 has type int but the context (due to the :: operator) requires a list.
When you write f 1 + 2, it is parsed as (f 1) + 2. The function f is applied to an integer argument; since f expects two arguments, the result is a function (waiting for the second argument), but the + operator wants an integer, so the expression is ill-typed. + isn't a parameter of f because + by itself is not an expression, and the argument of a function is an expression.
I don't know what you mean by “infix function with right associative”. The associativity and precedence of operators in Ocaml is determined by the first character of the operator as indicated in the table you link to.
These are all standard concepts in parsing, applicable to almost every programming language out there. I recommend reading any textbook with a chapter on programming language syntax or parsing, or start with the Wikipedia articles on associativity and precedence.

Related

Order of commutative mathematical operations

I've into curious question (asking it myself while reading a crude piece of code). Let's look at expression:
double a = c*d*e*2/3*f;
where c, d, e, f are initialized variables of type double. Does standard guarantee that it would be treated as c*d*e*2 (double result) then divided by 3 and multiplied by f (or some similar behavior). Obviously, 2/3 being calculated to 0 is undesirable.
Which paragraph of standard defines that?
Based on the standard
[intro.abstract] - Note 7 (non-normative):
Operators can be regrouped according to the usual mathematical rules
only where the operators really are associative or commutative.
Mathematical rule for MDAS is from left to right (considering the associativity and precedence of operators). So it is evaluated as follows:
(((((c * d) * e) * 2) / 3) * f)
In a word - yes.
The property you're looking for is called operator associativity. It defines how operators of the same precedence (such as * and /) are grouped and ordered when parenthesis aren't present.
In your case, both * and / have the same precedence, and are both left-associative - i.e., they are evaluated from left to right. Which means c would be multiplied by d, then the result by e, then the result by 2 (which would be done with floating point arithmetic, since you're multiplying a double by an int literal), then divided by 3 (again, using floating point arithmetic) and finally multiplied by f.
See this cppreference page for additional information.
Both * and / have the same precedence, and are left-to-right associative, this means that
a*b*c*d
is parsed as
((a*b)*c)*d
and the same is true if you replace any of the * with /.
Source: http://en.cppreference.com/w/cpp/language/operator_precedence

Understanding operator precedence from the table

I was going over the following link and it states
Operators between dashed lines have the same "precedence level", of
which you will note that there are 18
Now my question is what does the above statement mean. For instance if two operators are between the dashed lines like -> comes before [] does this mean -> has higher precedence than [] ?
Yes .. you are right.. also note that in case like when * and / comes in an expression,that's where associativity is considered... in such a case you have to evaluate from left to right...
In a * b / c, the operation a * b is evaluated first and then / is evaluated.
In a / b * c, the operation a / b is evaluated first and then * is evaluated.
For instance if two operators are between the dashed lines like -> comes before [] does this mean -> has higher precedence than [] ?
Yes, both are at same precedence level but because of Left to right associativite for example:
a->b[i];
is parsed or equivalent as (a->b)[i];. This is useful when a is a pointer to structure and b is a array member of struct.
And an expression like:
a[i]->b;
same as (a[i])->b;. This is useful when a is an array of structure's pointers.
You don't need parenthesis.
For *, ., ->, and [] operators you can read this answer "Pointer to structure".

Who defines C operator precedence and associativity?

Introduction
In every textbook on C/C++, you'll find an operator precedence and associativity table such as the following:
http://en.cppreference.com/w/cpp/language/operator_precedence
One of the questions on StackOverflow asked something like this:
What order do the following functions execute:
f1() * f2() + f3();
f1() + f2() * f3();
Referring to the previous chart I confidently replied that functions have left-to-right associativity so in the previous statements the are evaluated like this in both cases:
f1() -> f2() -> f3()
After the functions are evaluated you finish the evaluation like this:
(a1 * a2) + a3
a1 + (a2 * a3)
To my surprise, many people told me I was flat out wrong. Determined to prove them wrong, I decided to turn to the ANSI C11 standard. I was once again surprised to find out that very little is mentioned on operator precedence and associativity.
Questions
If my belief that functions are always evaluated from left-to-right is wrong, what does the table referring to function precedence and associativity really mean?
Who defines operator precedence and associativity if it's not ANSI? If it is ANSI who makes the definition, why is little mentioned about operator precedence and associativity? Is operator precedence and associativity inferred from the ANSI C standard or is it defined in Mathematics?
Operator precedence is defined in the appropriate standard. The standards for C and C++ are the One True Definition of what exactly C and C++ are. So if you look closely, the details are there. In fact, the details are in the grammar of the language. For example, take a look at the grammar production rule for + and - in C++ (collectively, additive-expressions):
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
As you can see, a multiplicative-expression is a subrule of an additive-expression. This means that if you have something like x + y * z, the y * z expression is a subexpression of x + y * z. This defines the precedence between these two operators.
We can also see that the left operand of an additive-expression expands to another additive-expression, which means that with x + y + z, x + y is a subexpression of it. This defines the associativity.
Associativity determines how adjacent uses of the same operator will be grouped. For example, + is left-to-right associative, which means that x + y + z will be grouped like so: (x + y) + z.
Don't mistake this for order of evaluation. There is absolutely no reason why the value of z could not be computed before x + y is. What matters is that it is x + y that is computed and not y + z.
For the function call operator, left-to-right associativity means that f()() (which could happen if f returned a function pointer, for example) is grouped like so: (f())() (of course, the other direction wouldn't make any sense).
Now let's consider the example you were looking at:
f1() + f2() * f3()
The * operator has higher precedence than the + operator, so the expressions are grouped like so:
f1() + (f2() * f3())
We don't even have to consider associativity here, because we don't have any of the same operator adjacent to each other.
Evaluation of the functions call expressions is, however, completely unsequenced. There's no reason f3 couldn't be called first, then f1, and then f2. The only requirement in this case is that operands of an operator are evaluated before the operator is. So that would mean f2 and f3 have to be called before the * is evaluated and the * must be evaluated and f1 must be called before the + is evaluated.
Some operators do, however, impose a sequencing on the evaluation of their operands. For example, in x || y, x is always evaluated before y. This allows for short-circuiting, where y does not need to be evaluated if x is known already to be true.
The order of evaluation was previously defined in C and C++ with the use of sequence points, and both have changed terminology to define things in terms of a sequenced before relationship. For more information, see Undefined Behaviour and Sequence Points.
The precedence of operators in the C Standard is indicated by the syntax.
(C99, 6.5p3) "The grouping of operators and operands is indicated by the syntax. 74)"
74) "The syntax specifies the precedence of operators in the evaluation of an expression"
C99 Rationale also says
"The rules of precedence are encoded into the syntactic rules for each operator."
and
"The rules of associativity are similarly encoded into the syntactic rules."
Also note that associativity has nothing to do with evaluation order. In:
f1() * f2() + f3()
function calls are evaluated in any order. The C syntactic rules says that f1() * f2() + f3() means (f1() * f2()) + f3() but the evaluation order of the operands in the expression is unspecified.
One way to think about precedence and associativity is to imagine that the language only allows statements containing an assignment and one operator, rather than multiple operators. So a statement like:
a = f1() * f2() + f3();
would not be allowed, since it has 5 operators: 3 function calls, multiplication, and addition. In this simplified language, you would have to assign everything to temporaries and then combine them:
temp1 = f1();
temp2 = f2();
temp3 = temp1 * temp2;
temp4 = f3();
a = temp3 + temp4;
Associativity and precedence specify that the last two statements must be performed in that order, since multiplication has higher precedence than addition. But it doesn't specify the relative order of the first 3 statements; it would be just as valid to do:
temp4 = f3();
temp2 = f2();
temp1 = f1();
temp3 = temp1 * temp2;
a = temp3 + temp4;
sftrabbit gave an example where associativity of function call operators is relevant:
a = f()();
When simplifying it as above, this becomes:
temp = f();
a = temp();
Precedence and associativity are defined in the standard, and they decide how to build the syntax tree. Precedence works by operator type(1+2*3 is 1+(2*3) and not (1+2)*3) and associativity works by operator position(1+2+3 is (1+2)+3 and not 1+(2+3)).
Order of evaluation is different - it does not define how to build the syntax tree - it defines how to evaluate the nodes of operators in the syntax tree. Order of evaluation is defined not to be defined - you can never rely on it because compilers are free to choose any order they see fit. This is done so compilers could try to optimize the code. The idea is that programmers write code that shouldn't be affected by order of evaluation, and yield the same results no matter the order.
Left-to-right associativity means that f() - g() - h() means (f() - g()) - h(), nothing more. Suppose f returns 1. Suppose g returns 2. Suppose h returns 3. Left-to-right associativity means the result is (1 - 2) - 3, or -4: a compiler is still permitted to first call g and h, that has nothing to do with associativity, but it is not allowed to give a result of 1 - (2 - 3), which would be something completely different.

How is this Precedence operators working?

I know this is silly question but I don't know which step I'm missing to count so can't understand why the output is that of this code.
int i=2;
int c;
c = 2 * - ++ i << 1;
cout<< c;
I have trouble to understanding this line in this code:
c = 2 * - ++ i <<1;
I'm getting result -12. But I'm unable to get it how is precedence of operator is working here?
Have a look at the C++ Operator Precedence table.
The ++i is being evaluated, yielding 3.
The unary - is being evaluated, yielding -3.
The multiplication is being done1, yielding -6.
The bit shift is evaluated (shifting left by 1 is effectively multiplying by two) yielding -12.
The result -12 is being assigned to the variable c.
If you used parentheses to see what operator precedence was doing, you'd get
c = ((2 * (-(++i))) << 1);
Plus that expression is a bit misleading due to the weird spacing between operators. It would be better to write it c = 2 * -++i << 1;
1 Note that this is not the unary *, which dereferences a pointer. This is the multiplication operator, which is a binary operator.
Operator precedence defined the grouping between the operators and their operands. In your example the grouping is as follows
c = ((2 * (-(++i))) << 1);
That's how "precedence of operator is working here" and that's the only thing it does.
The result of this expression is -6 shifted one bit to the left. This happens to be -12 on your platform.
According to your comment in another answer, you mistakenly believe that operator precedence somehow controls what is executed "first" and what is executed "next". This is totally incorrect. Operator precedence has absolutely nothing to do with the order of execution. The only thing operator precedence does, once again, is define the grouping between the operators and their operands. No more, no less.
The order of execution is a totally different thing entirely independent from operator precedence. In fact, C++ language does not define any "order of execution" for expressions containing no sequence points inside (the above one included).

operators computing direction

I encountered something that I can't understand.
I have this code:
cout << "f1 * f1 + f2 * f1 - f1 / f2 is: "<< f1 * f1 + f2 * f1 - f1 / f2 << endl;
All the "f"s are objects, and all the operators are overloaded.
The weird this is that the first computation is of the / operator,
then the second * and then the first *; after that, the operator + and at last, operator -.
So basically, the / and * worked from right to left,
and the + and - operators worked from left to right.
I made another test...
I checked this code:
cout << "f1 * f1 / f2 is: " << f1 * f1 / f2 << endl;
Now, the first operator was * and only then operator /.
So now, it worked from left to right.
Can someone help me understand why is there difference in the directions?
10X!
This is yet again a question of the order of evaluation of function parameters - C++ does not specify such an order. Your code is equivalent to:
(f1 * f1) + (f2 * f1) - (f1 / f2)
The three multiply and divide operations can be evaluated in any order. This is perhaps cleraer for named functions:
add(f1*f2,f2*f1)).minus(f1/f2);
The bottom line is that associativity and precedence have nothing to say about the order of evaluation of function parameters and/or sub-expressions. Given the simple expression:
a + b
the C++ (and C) compiler is free to evaluate a first, then b, or b first then a, whether or not the '+' is overloaded.
It is unspecified in what sequence operator arguments will be calculated.
C++ Standard 5/4:
Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual
expressions, and the order in which side effects take place, is unspecified.
Your expression is equivalent to (* and / are operators too, but leave them as is):
operator-( operator+(f1*f1, f2*f1), f1/f2 )
Operator precedence defines the order of operators that have different precedence, so that, e.g., * and / always evaluate before + and -. Then there is the left-to right rule when multiple operators of the same precedence are concatenated.
However, there is (with the exception of logical and ternary operators) no rule about which of an operator's arguments should be evaluated first. The compiler is free to perform the multiplicative operations in any order in pleases before passing them to the additive operators.
In fact, with the expression f() + g() + h(), the compiler is free to call the functions in reverse order, h(), then g(), then f(), then add together the result of f() and g(), and finally add the result of h(). That wouldn't be a very sensible thing to do in most cases, but it's perfectly legal.
User defined operators use the same precedence and associativity rule than buil-in ones.
Rule of precedence state that operators with higher precedence should be executed before those with lower precedence when adjacent in an expression (separated by a single operator).
Associativity rule state in wich order operators should be executed when an expression contains adjacent operators of same precedence.
In your first exemple precedence rule apply, but as associativity is only about adjacent operators the compiler choose in which order he will execute multiply and divide.
In Your second exemple the asociativity rule applies.
Rule of thumb to avoid problems with this kind of rules (that can be somewhat complex):
if unsure use parenthesis or local variables to force order.
avoid side effect when you call function (or user defined operators) because result could be surprising
when redefining operators try to be consistent with maths
http://www.cppreference.com/wiki/operator_precedence
strange behavior, indeed.
But what i would say is that this should not matter, because a * b / c should be equal to a / c * b if you implemented them mathematical-wise
This just looks like simple operator precedence at work.
In your first example, all the multiplication and division must be done before the addition and subtraction. Since the results of the multiplications and divisions are independent, it really doesn't matter what order they're performed, just that the results are used from left to right in the addition and subtraction.
In the second example, the multiplication and division are not independent and must be performed left to right.
You're always getting the correct results based upon operator precedence. THat's all that really matters. The compiler does not guarantee anything about the order of evaluation other than that operator precedence is honored.
Neil is right .
It is matter of operator associativity and precedence.
The expression is evaluated as (f1 * f1) + (f2 * f1) - (f1 / f2) as per the rules suggests and after that it is left to right in second pass . lastly addition and sub. takes place.
second example is simple. * and / have same precedence so we evaluate the expression as per the associativity rules which is left to right hence the order.