Functional Programming
Functional Programming
In functional programming, programs are executed by evaluating expressions Functional programming requires that functions are first-class
which means that they are treated like any other values and can be passed as arguments to other functions or be returned as a result of a function. Being first-class also means that it is possible to define and manipulate functions from within other functions.
Higher-order functions HOFs are functions that take other functions as their arguments. Higher-order functions are very useful for refactoring code and reduce the amount of repetition.
Purity Some functional languages allow expressions to yield actions in addition to return values. These actions are called side effects to emphasize that the return value is the most important outcome of a function Languages that prohibit side effects are called pure. Immutable data Purely functional programmes typically operate on immutable data. Instead of altering existing values, altered copies are created and the original is preserved. Since the unchanged parts of the structure cannot be modified, they can often be shared between the old and new copies, which saves memory.
Referential transparency Pure computations yield the same value each time they are invoked. This property is called referential transparency and makes possible to conduct equational reasoning on the code. For instance if y = f x and g = h y y then g can be written as : g = h (f x) (f x)
Lazy evaluation Since pure computations are referentially transparent they can be performed at any time and still yield the same result. This makes it possible to defer the computation of values until they are needed, that is, to compute them lazily. Lazy evaluation avoids unnecessary computations and allows, for example, infinite data structures to be defined and used.
Recursion
Recursion is the only way to iterate. A recursive function is tail recursive if the final result of the recursive call is the final result of the function itself. Tail recursive call optimisation ensure that heavy recursion does not consume excessive memory. If the result of the recursive call must be further processed it is not tail recursive.
Imperative version
void gcd ( int u, int v, int* x) { int y, t, z; z=u; y=v; While (y!=0) { t=y; y=z%y; z=t; } *x=z; }
Functional version
Imperative version
Functional version
int sum( int i, int j) { int k, temp; temp = 0; for (k = I; k<=j; k++) temp +=k; return temp; }
int sum ( int i, int j) { if( i > j ) return 0; else return (i + sum ( i + 1, j)); }
accumulating parameter
Evaluate an atom gives the value assigned that atom. Numbers are special--they always evaluate to themselves. 7 => 7 my-age => Error (variable not defined)
Assign a value to an atom with setq and/or setf (setq my-age 24) => 24 my-age => 24 Reserved: nil and T nil => nil t => t
(+3( *4 5)) (and ( = a b ) (not ( = a 0 ))) (gcd 10 35) gcd (read- char)
If elsif construct
(if ( = a 0 ) 0 (/ 1 a )) (cond (( = a 0) 0) (( = a 1) 1) (else (/ 1 a)))
Note: ; stands for comment
; if a=0 then return 0 ; else return 1/a ; if a=0 then return 0 ; elsif a=1 then return 1 ;else return 1/a