20-CS-4003-001 Organization of Programming Languages Fall 2017
Expression Evaluation

Lambda calculus, Type theory, Formal semantics, Program analysis

    Prev     Next     All lectures           Code

Operators

Scheme:

   (+ 1 2 3 4)

Haskell:

   (+)
   (+ 1)
   1+2+3+4+5

Java:

   1+2+3+4+5
   numb.add(new BigInteger("10"))
 -  In Scheme all expressions have the form
   (op arg arg ...)
where op is an operator (also called a function or procedure) of some sort. This is known as prefix notation. In the example to the left + is the operator. The return value in this case is a number.

In Haskell things are different. The first expression on the left returns a procedure which takes two arguments and outputs the sum of those two numbers. It may be invoked like this:

   ((+) 2 3)
which returns 5. The second expression returns a procedure which takes one argument and outputs the sum of the argument plus 1. It may be used like this:
   ((+ 1) 2)
which returns 3. The third expression uses the + operator in infix form and always returns a number.

In Java, + is used as an infix operator on primitive types but a procedure invoked on the environment of an object of an appropriate class accomplished the desired task.

 
 

Scheme:

   (/ 3 (floor (/ 3 4)))
   

Haskell:

   2*3+4-2*3
   (2*3)+4+(-2*3)
   tail head [[10,20,30]]
   tail (head [[10,20,30]])
   tail $ head [[10,20,30]]

Java:

   2*3+4-2*3

   import java.util.*;

   public class a {
      public static void main (String args[]) {
         Vector l = new Vector();
         Vector x = new Vector();
         x.add(10);
         x.add(20);
         x.add(30);
         l.add(x);
         Vector v = (Vector)l.get(0);
         v.removeElementAt(0);
         System.out.println(v);
      }
   }
 -  In Scheme precedence and associativity is determined by parentheses. One cannot have a procedure name surrounded by white space unless it is an argument to a procedure. A nested expression such as the one to the left is evaluated from innermost parentheses out. Thus, (/ 3 4) is evaluated to 3/4 then (floor 3/4) is evaluated to 0 and (/ 3 0) raises an exception.

Operator precedence and associativity in Haskell is given by the following (partial) table.

Level    Left Assoc    Non-Assoc    Right Assoc
8 ^
7 *,/,`div`,`mod`
6 +,-
5 ++
4 ==,/=...
3 &&
2 ||
1 >>
Order can be changed with parentheses. The first two expressions on the left evaluate to 4. Function evaluation is from left to right and tokens on the right are taken as arguments as far as possible. The third expression does not compile because Haskell thinks tail is being applied to two arguments. The fourth expression evaluates to [20,30]. The $ in the fifth expression changes the order, evaluating on the right first, and evaluates to [20,30].

In Java, operator precedence is defined in a table similar to that above for Haskell but with a few changes in order. For non-primitive data types The order of evaluation is determined by method calls. The example to the left gives the same result as (tail (head [[10,20,30]])) in Haskell. This example also shows how "assignment" is considered normal in Java. This is discussed next.