Elements of Programming
September 11, 2012
Elements of Programming
Every non-trivial programming language provides:
primitive expressions representing the simplest elements ways to combine expressions ways to abstract expressions, which introduce a name for an expression by which it can then be referred to.
The Read-Eval-Print Loop
Functional programming is a bit like using a calculator An interactive shell (or REPL, for Read-Eval-Print-Loop) lets one write expressions and responds with their value. The Scala REPL can be started by simply typing
> scala
Expressions
Here are some simple interactions with the REPL
scala> 87 + 145 232
Functional programming languages are more than simple calcululators because they let one dene values and functions:
scala> def size = 2 size: => Int scala> 5 * size 10
Evaluation
A non-primitive expression is evaluated as follows. 1. Take the leftmost operator 2. Evaluate its operands (left before right) 3. Apply the operator to the operands A name is evaluated by replacing it with the right hand side of its denition The evaluation process stops once it results in a value A value is a number (for the moment) Later on we will consider also other kinds of values
Example
Here is the evaluation of an arithmetic expression:
(2 * pi) * radius
Example
Here is the evaluation of an arithmetic expression:
(2 * pi) * radius (2 * 3.14159) * radius
Example
Here is the evaluation of an arithmetic expression:
(2 * pi) * radius (2 * 3.14159) * radius 6.28318 * radius
Example
Here is the evaluation of an arithmetic expression:
(2 * pi) * radius (2 * 3.14159) * radius 6.28318 * radius 6.28318 * 10
Example
Here is the evaluation of an arithmetic expression:
(2 * pi) * radius (2 * 3.14159) * radius 6.28318 * radius 6.28318 * 10 62.8318
Parameters
Denitions can have parameters. For instance:
scala> def square(x: Double) = x * x square: (Double)Double scala> square(2) 4.0 scala> square(5 + 4) 81.0 scala> square(square(4)) 256.0 def sumOfSquares(x: Double, y: Double) = square(x) + square(y) sumOfSquares: (Double,Double)Double
Parameter and Return Types
Function parameters come with their type, which is given after a colon
def power(x: Double, y: Int): Double = ...
If a return type is given, it follows the parameter list. Primitive types are as in Java, but are written capitalized, e.g:
Int Double Boolean
32-bit integers 64-bit oating point numbers boolean values true and false
Evaluation of Function Applications
Applications of parameterized functions are evaluated in a similar way as operators: 1. Evaluate all function arguments, from left to right 2. Replace the function application by the functions right-hand side, and, at the same time 3. Replace the formal parameters of the function by the actual arguments.
Example
sumOfSquares(3, 2+2)
Example
sumOfSquares(3, 2+2) sumOfSquares(3, 4)
Example
sumOfSquares(3, 2+2) sumOfSquares(3, 4) square(3) + square(4)
Example
sumOfSquares(3, 2+2) sumOfSquares(3, 4) square(3) + square(4) 3 * 3 + square(4)
Example
sumOfSquares(3, 2+2) sumOfSquares(3, 4) square(3) + square(4) 3 * 3 + square(4) 9 + square(4)
Example
sumOfSquares(3, 2+2) sumOfSquares(3, 4) square(3) + square(4) 3 * 3 + square(4) 9 + square(4) 9 + 4 * 4
Example
sumOfSquares(3, 2+2) sumOfSquares(3, 4) square(3) + square(4) 3 * 3 + square(4) 9 + square(4) 9 + 4 * 4 9 + 16
Example
sumOfSquares(3, 2+2) sumOfSquares(3, 4) square(3) + square(4) 3 * 3 + square(4) 9 + square(4) 9 + 4 * 4 9 + 16 25
The substitution model
This scheme of expression evaluation is called the substitution model. The idea underlying this model is that all evaluation does is reduce an expression to a value. It can be applied to all expressions, as long as they have no side eects. The substitution model is formalized in the -calculus, which gives a foundation for functional programming.
Termination
Does every expression reduce to a value (in a nite number of steps)?
Termination
Does every expression reduce to a value (in a nite number of steps)? No. Here is a counter-example
def loop: Int = loop loop
Changing the evaluation strategy
The interpreter reduces function arguments to values before rewriting the function application. One could alternatively apply the function to unreduced arguments. For instance:
sumOfSquares(3, 2+2)
Changing the evaluation strategy
The interpreter reduces function arguments to values before rewriting the function application. One could alternatively apply the function to unreduced arguments. For instance:
sumOfSquares(3, 2+2) square(3) + square(2+2)
Changing the evaluation strategy
The interpreter reduces function arguments to values before rewriting the function application. One could alternatively apply the function to unreduced arguments. For instance:
sumOfSquares(3, 2+2) square(3) + square(2+2) 3 * 3 + square(2+2)
Changing the evaluation strategy
The interpreter reduces function arguments to values before rewriting the function application. One could alternatively apply the function to unreduced arguments. For instance:
sumOfSquares(3, 2+2) square(3) + square(2+2) 3 * 3 + square(2+2) 9 + square(2+2)
Changing the evaluation strategy
The interpreter reduces function arguments to values before rewriting the function application. One could alternatively apply the function to unreduced arguments. For instance:
sumOfSquares(3, 2+2) square(3) + square(2+2) 3 * 3 + square(2+2) 9 + square(2+2) 9 + (2+2) * (2+2)
Changing the evaluation strategy
The interpreter reduces function arguments to values before rewriting the function application. One could alternatively apply the function to unreduced arguments. For instance:
sumOfSquares(3, 2+2) square(3) + square(2+2) 3 * 3 + square(2+2) 9 + square(2+2) 9 + (2+2) * (2+2) 9 + 4 * (2+2)
Changing the evaluation strategy
The interpreter reduces function arguments to values before rewriting the function application. One could alternatively apply the function to unreduced arguments. For instance:
sumOfSquares(3, 2+2) square(3) + square(2+2) 3 * 3 + square(2+2) 9 + square(2+2) 9 + (2+2) * (2+2) 9 + 4 * (2+2) 9 + 4 * 4
Changing the evaluation strategy
The interpreter reduces function arguments to values before rewriting the function application. One could alternatively apply the function to unreduced arguments. For instance:
sumOfSquares(3, 2+2) square(3) + square(2+2) 3 * 3 + square(2+2) 9 + square(2+2) 9 + (2+2) * (2+2) 9 + 4 * (2+2) 9 + 4 * 4 25
Call-by-name and call-by-value
The rst evaluation strategy is known as call-by-value, the second is is known as call-by-name. Both strategies reduce to the same nal values as long as
the reduced expression consists of pure functions, and both evaluations terminate.
Call-by-value has the advantage that it evaluates every function argument only once. Call-by-name has the advantage that a function argument is not evaluated if the corresponding parameter is unused in the evaluation of the function body.
Call-by-name vs call-by-value
Question: Say you are given the following function denition:
def test(x: Int, y: Int) = x * x
For each of the following function applications, indicate which evaluation strategy is fastest (has the fewest reduction steps)
CBV fastest O O O O CBN fastest O O O O same #steps O O O O test(2, 3) test(3+4, 8) test(7, 2*4) test(3+4, 2*4)
Call-by-name vs call-by-value
def test(x: Int, y: Int) = x * x test(2, 3) test(3+4, 8) test(7, 2*4) test(3+4, 2*4)