Variables in Imperative Languages

• A variable in an imperative can be regarded as an abstraction of what?

Another representative from the Declarative paradigm • Assignment is ?

1 2

Variables in Imperative Languages Sequences of Instructions

Von Neumann architecture drives the imperative paradigm: • Imperative programs are sequences of instructions because to • Store: individually addressable locations. be executed they must be stored in memory in a sequence of locations, and because of the way the standard fetch/execute cycle works. • Machine language: sequences of instructions changing the contents of store locations (referred to by their addresses). • The control of such execution, involving loops of different kinds, is a common source of bugs in imperative programs. • High-level imperative languages: sequences of instructions changing the values of variables (referred to by their names).

• This influences the whole paradigm. In particular:

1. Issues around assignment. 2. Control of execution of sequences of instructions. 3 4 Assignment Referential Transparency • Referential transparency means

• There are problems with assignment and the management of – The meaning (or the effect, or the value) of an expression is the store. These relate to the same wherever (and whenever) it occurs.

• Imperative languages do not support referential transparency. • Side-effects • Trivial example: • Aliasing X := 0; • Referential transparency Write(X); X := X + 1; Write(X);

• This problem becomes even worse when parallel execution is considered. Why?

5 6

Summary The Functional Approach • Here are two examples of definitions (syntax may change!): • Imperative languages are based on standard computer architecture. fun double (n) = n+n; • The advantage of this is run-time efficiency. fun square (n) = n*n;

• A (pure) functional program is simply a collection of function definitions. • BUT… • A functional programming system allows us to store such function definitions, and then ask for specific expressions to be evaluated.

1. It facilitates errors. • Examples: 2. It makes bug-tracing difficult. 3. It makes programs hard to read and understand. # double 7; # double( square 2 ) 4. (Backus, 1978) It limits the programmer's thinking and 14 8 inhibits the problem-solving process. # map square [1, 2, 3];

7 [1, 4, 9] 8 A word on the ML language (and syntax) Functional Programming We will be using ML, a general-purpose functional programming language developed by Robin Milner et al. in the 1970s at the University of Edinburgh. • Note that a functional language is inherently declarative. http://en.wikipedia.org/wiki/ML(programming_language) http://sml-family.org/ • Such function definitions are simply statements of what our … functions are. There are many dialects and (industry adopted) languages spawn from ML! We will use a freely available, web-based, simple (Oca)ML interpreter, and from now on we will adopt its syntax: • Main operation is the application of functions to data (or other functions!), different from imperative languages, whose main http://try.ocamlpro.com/ function is manipulating the state/store, i.e. assignment.

The general syntax of ML is slightly different, e.g. • There is an analogy with Prolog. But remember that in Prolog fun double (n) = n+n; is let square n = n*n we dealt with predicates, not functions, and we achieve goals or let rec factorial n = … for recursive functions rather than evaluate expressions.

Refer to the tutorials/docs on the web site! 9 10 (also http://caml.inria.fr/pub/docs/manual-ocaml/ )

The Functional Approach The Functional Approach

• A program consists of a collection of function definitions, and a `run' amounts to an evaluation of an expression involving these functions • Programs in functional languages are generally shorter, easier to over input data. understand, design, debug, and maintain, than imperative counterpart.

• Function are first class objects (higher order functions), e.g. map. • The intention is to focus on the computations which are to be done, not on how to fit them to the structure of the machine. • Typically recursion is used in functional programming languages, iteration is used in imperative languages. • Assignment is not a part of this paradigm, nor is the idea of a sequence of instructions. • Modern functional languages are • Under this paradigm: – are strongly typed (most type errors detected statically by the , no type errors at runtime) – provide type inference. 1. Side-effects can be completely avoided. 2. Aliasing is not possible. • (Pure) functional programs are stateless – (good news?) 3. Referential transparency can be supported.

11 12 FP in the Real World

List of functional programming languages from homepages.inf.ed.ac.uk/wadler/realworld/ :

• Industrial – Erlang, an e-commerce database, Partial evaluator for airline • Many functional languages, … scheduling, Combinators for financial derivatives • … and imperative ones that support forms of functional usage. • , Interpreters and Partial Evaluators, Syntax and Analysis Tools • Theorem Provers and Reasoning Assistants • http://en.wikipedia.org/wiki/ • Network Toolkits and Applications, Web, HTML, XML, XSLT List_of_programming_languages_by_type#Functional_languages • Natural Language Processing and Speech Recognition (pure and impure) • Numerically Based Applications, Computer Algebra – MC-SYM - computes 3D shape of nucleic acid, FFTW - Fastest Fourier Transform in the West, BlurFit - model focal plane imaging • Pure: Charity Clean Curry Haskell Hope Miranda Idris • Database Systems • Impure: # Erlang F#, Java (since version 8) Lisp Clojure Scheme • Operating Systems Mathematica ML OCaml R Scala Python • Light and sound • There are more impure languages! – Lula: a system for theather lighting, Scheme Score

14

1. Programs 2. Data Structures

• A program consists of a collection of function definitions: • Lists are the main basic data structure. • Careful with types! inOcaML + is int * int -> int +. is float * float -> float • Notations (ML):

let double(n) = n +. n [2;6;4;5] is a list let square(n) = n *. n [ ] is an empty list let avg(x,y) = (x +. y) /. 2.0 List.hd [2;6;4;5] is 2 (an integer) let sqAvg(x,y) = avg(square(x),square(y)) List.tl [2;6;4;5] is [6;4;5] (a list) • The the following can be evaluated: h :: t 2 :: [6;4;5] is …

square( double(6.0) ) • Example function involving lists (more later): sqAvg( 5.0 , 7.0 ) let rec length l = match l with • In each case the system would respond with the value, respectively | [ ] -> 0 144 and 37. | _ -> 1 + length( List.tl l) 15 16 3. Program Control 4. Pattern-Matching • Two equivalent definitions: • We have composition of functions: – apply one function to some value(s), and then apply another let isEmpty( l ) = if l = [ ] then true else false function to the result. (Like SqAvg above). let isEmpty( l ) = match l with • There is no notion of program loop, so recursion is essential | [ ] -> true (see the Length function above). | h :: t -> false

• Functional programming also has an `if' construct, to distinguish • When we ask to evaluate (say) isEmpty([4,1,7]), a matching cases. process takes place, and as a result the second line of the definition is used. • Example: • (See also the length function above.) let max (x, y) = if x >= y then x else y;

let isEmpty ( l ) = if l = [ ] then true else false;

17 18

More Pattern Matching Further Pattern Matching Examples

let rec isM x l = if l = [ ] then false let rec addUpTo n = match n with | 0 -> 0 | n when n>0 -> n + addUpTo (n -1);; else if x = List.hd( l ) then true

else isMember x (List.tl l) let rec factorial n = match n with | 0 -> 1 | _ -> n * factorial (n - 1);; is equivalent to let rec listAsFarAs x l = match l with | [ ] -> [ ] | h :: t when h = x -> [x] let rec isM m l = match l with | h :: t -> h :: listAsFarAs x t;; | [ ] -> false | n :: t when n = m -> true let rec doubleList l = match l with | [ ] -> [ ] | n :: t when n <> m -> isM m t | h :: t -> double(h) :: doubleList t;;

let rec sumList l = match l with | [x] -> x

| h :: t -> h +. sumList t ;; The word pattern here refers to the formal structure of an expression ([ ] and h :: t are patterns). Pattern-matching is an essential part of functional let listAvg l = sumList l /. (float_of_int) (length l) ;; languages. (As it is also with Prolog*.) *actually: unification 19 20 5. Evaluation 6. Higher-order Functions

• A functional programming system simply allows evaluation of expressions. An actual evaluation is done by a process called reduction or rewriting. • In functional languages there is the possibility to define functions Here is how it works. which have functions as parameters, or which return functions as results. This is what is meant by higher-order functions. • Say we wish to evaluate listAvg([3,7,2]). • Avoids repetition of code.

listAvg([3.0,7.0,2.0]) • E.g. We have a function to traverse a list and add all the sumList([3.0,7.0,2.0]) /. (float_of_int) length([3.0,7.0,2.0]) elements up. We also have a function to traverse a list and (3.0 +. SumList([7.0,2.0])) /. (float_of_int) (1 + Length([7.0,2.0])) multiply all the elements together. Why not have a function to traverse a list and apply some action, and make the action (3.0 +. (7.0 +. SumList([2.0]))) /. (float_of_int) (1 + (1 + Length([2]))) (function) a parameter? (3.0 + (7.0 + 2.0)) /. (float_of_int) (1 + (1 + (1 + Length(nil)))) (3.0 + 9.0) /. (float_of_int) (1 + (1 + (1 + 0))) • This is a natural feature of functional languages. 12.0 /. (float_of_int) (1 + (1 + 1)) • Functions can have functions as parameters. 12.0 /. (float_of_int) (1 + 2) 12.0 /. 3.0 4.0 21 22

6. Higher-Order Functions (continued) 7. Types

• Example (The simplistic story) let rec doubleList l = match l with | [ ] -> [ ] | h :: t -> double(h) :: doubleList t;; Static Types:

• All variables and parameters must have their types declared in let rec squareList l = match l with | [ ] -> [ ] the program, so that they can be checked by the compiler. | h :: t -> square (h) :: squareList t;;

• We can generalise this and consider functions as parameters, obtaining Dynamic Types: function of functions (HOFs) • The types of program entities are not constrained at all in advance of run-time information. let rec listApply f l = match l with | [ ] -> [ ] | h :: t -> f h :: listApply f t;; • Example:

ListApply(Double,[3,1,4]) ListApply(Square,[3,1,4]) 23 24 Best of Both? 8. Strong Typing and Type Inference

• Security of compile-time type checking • Strong typing: all expressions have a well defined type.

• Flexibility of dynamic typing / freedom from type • Most functional languages other than LISP have strong typing. They have a type-checking system which infers types declarations for all objects for which a type is not specified, and checks for inconsistencies. • Make the system infer types itself! • It seems to give the best of both worlds: – security against errors, provided by type-checking, – freedom from the necessity to specify types.

25 26

Type Inference Type Inference (continued)

• Example: • Here is another example:

let sum1To(n) = n*(n+1) / 2 let rec addToList a l = match l with | [ ] -> [ ] • n must be such that +1 and * and div are appropriate operations | h :: t -> if (h < 0) then (a + h) :: addToList a t • Sum1To must return a corresponding numerical result else h :: addToList a t

• The function Sum1To thus must have type ? • The type of AddToList is ?

27 28 Type Inference (continued) 9. Polymorphism

let rec length l = match l with Another example: | [ ] -> 0 | _ -> 1 + length( List.tl l) let isEmpty ( l ) = if l = [ ] then true else false; • The type of h may be anything. We could use this function to find the length of a list of numbers, a list of Booleans, a list of strings, a list of lists, ... • It is clear that this function acts on a list and returns a Boolean result. (why?) • And the value returned will be an integer (because ?).

• What kind of list? • The type of Length would be inferred as • ... Any kind of list. ('a list) -> int ML uses the notation 'a to represent types which are unconstrained in this way. • It is polymorphic . . . • What is the type of isEmpty above?

29 30

10. Lazy Evaluation

• Simply, this means that parameters are not evaluated until they • But laziness also brings other possibilities: are required. let rec countFrom n = n :: CountFrom(n+1) • The opposite of lazy is strict. • An infinite list? • Of functional languages, LISP and ML are strict, whereas Miranda and Haskell are lazy. • Consider

• Laziness has an efficiency advantage: parameter values which sumList ( listAsFarAs 10 countFrom(1) ) are not in fact needed will not be evaluated.

What is used in the evaluation?

31 32 11. Abstract Data Types Abstract Data Types (continued)

• The only means of building data structures so far has been the • Values of the type (int tree) would be expressions such as list. empty • Most functional programming languages include a facility for the node(4,empty,empty) user to build tailor-made data types, specific to current needs, node(4,empty,node(6,empty,empty)) using abstract data types. • A binary tree either is empty, or consists of a root (at which is stored a data item) and two subtrees. • Example (ML): datatype 'a tree = empty • That is exactly what we are constructing here. | node of ('a * ('a tree) * ('a tree)); • Note that the only mechanism used to build this structure is the • This is a definition of a binary tree type. Here, 'a is a type (formal) application of functions. variable (and the * separates types).

33 34

Abstract Data Types (continued) Summary

Example (ML): • Here are the aspects of functional languages that we have considered:

datatype 'a stack = new_stack 1. Composition of functions. | push of ('a * ('a stack)); 2. Data structures (lists). 3. Distinguishing cases using if. • Values are expressions like 4. Pattern matching. new_stack push(3,new_stack) 5. Evaluation by reduction/rewriting. push(7,push(3,new_stack)) 6. Static/dynamic typing. 7. Higher-order functions. • Standard operations include: 8. Strong typing and type inference.

exception top_err: 9. Polymorphism. fun top(new_stack) = raise top_err; 10. Lazy evaluation. | top(push(a,b)) = a; 11. Data structures (abstract data types).

(Note the mechanism for dealing with error situations.) 35 36