2017-12-27 23:32:14 +00:00
|
|
|
|
#+Title: Functional Programming Overview
|
2017-12-07 15:44:09 +00:00
|
|
|
|
#+Author: Yann Esposito
|
2017-08-24 18:58:13 +00:00
|
|
|
|
|
2017-12-27 23:32:14 +00:00
|
|
|
|
- Intro & Brief History Overview
|
|
|
|
|
- Major Principles (Theory)
|
|
|
|
|
- Major Languages (Practice)
|
|
|
|
|
|
2018-02-17 11:34:40 +00:00
|
|
|
|
* math function vs Procedures.
|
2017-12-27 23:32:14 +00:00
|
|
|
|
|
|
|
|
|
- *Immutable*: avoids changing-state and mutable data
|
|
|
|
|
- *Declarative programming*: expression or declarations instead of statements
|
2017-12-07 15:44:09 +00:00
|
|
|
|
- *Pure*:
|
|
|
|
|
- Output value of a function depends *only* on the arguments that are input to the function
|
|
|
|
|
- Eliminating side-effects, easier to reason about code and predict behavior
|
2017-12-27 23:32:14 +00:00
|
|
|
|
- Evaluation order and timing are a separated concern from function results
|
|
|
|
|
- *Functions are first-class*:
|
2017-12-07 15:44:09 +00:00
|
|
|
|
- functions are treated like any other values.
|
|
|
|
|
- functions can be passed as arguments to other functions
|
|
|
|
|
- functions can returns other functions
|
2017-12-27 23:32:14 +00:00
|
|
|
|
|
|
|
|
|
* Brief History Overview
|
2017-12-07 15:44:09 +00:00
|
|
|
|
** Short
|
|
|
|
|
- λ-Calculus, Alonzo Church & Rosser 1936
|
|
|
|
|
- LISP (McCarthy 1960)
|
|
|
|
|
- Algol 60 (Naur et al 1963)
|
|
|
|
|
- ISWIM (Landin 1966)
|
|
|
|
|
- PAL (Evans 1968)
|
|
|
|
|
- SASL (1973-83)
|
|
|
|
|
- Edinburgh (1969-80) NLP, early ML, HOPE
|
|
|
|
|
- Miranda (1986)
|
|
|
|
|
- Haskell (1992‥)
|
|
|
|
|
** λ-Calculus
|
2017-08-24 18:58:13 +00:00
|
|
|
|
*** λ-Calculus, Alonzo Church & Rosser 1936
|
|
|
|
|
Typeless theory of functions.
|
|
|
|
|
|
|
|
|
|
A syntaxic construction can be equivalent to any Turing Machine.
|
|
|
|
|
Mainly re-writing rules.
|
2017-12-07 15:44:09 +00:00
|
|
|
|
*** Learn λ-Calculus in less than 1 minute
|
|
|
|
|
*** Definitions
|
2017-08-24 18:58:13 +00:00
|
|
|
|
- =a,b,...= are variables
|
|
|
|
|
- =()= parenthesis to group part of an expression
|
|
|
|
|
- =λ= greek letter (pronounced Lambda) and the =.= to write functions.
|
2017-12-07 15:44:09 +00:00
|
|
|
|
*** Free vs Bound
|
2017-08-24 18:58:13 +00:00
|
|
|
|
- =λx.xy= the expression is open as =xy= contains a =y= and there is no =λy= that bound it.
|
|
|
|
|
- =λx.λy.xy= is said to be bound.
|
|
|
|
|
|
|
|
|
|
Bound expressions represent functions.
|
2017-12-07 15:44:09 +00:00
|
|
|
|
*** Rules
|
2017-12-27 23:32:14 +00:00
|
|
|
|
(α) =λx.A → λy.[y/x]A=
|
|
|
|
|
(β) =(λx.A)B → [B/x]A=
|
|
|
|
|
(η) =λx.Ax → A= if =x= not free in =A=
|
|
|
|
|
|
|
|
|
|
Where =[B/x]A= means substitue =B= for free occurrences of =x= in =A=.
|
|
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
|
|
|
|
|
|
(α) =λx.(f x z x) → λy.(f y z y)=
|
2018-02-17 11:34:40 +00:00
|
|
|
|
(β) =(λx.(f x y))2 → (f 2 y)=
|
2017-12-27 23:32:14 +00:00
|
|
|
|
(η) =λx.f x → f=
|
2017-08-24 18:58:13 +00:00
|
|
|
|
|
2017-12-07 15:44:09 +00:00
|
|
|
|
*** Resume
|
|
|
|
|
How does that work? Simply cut and paste! That's it.
|
2017-08-24 18:58:13 +00:00
|
|
|
|
|
|
|
|
|
Example: =(λy.x(yz))(ab)=
|
|
|
|
|
|
|
|
|
|
So =(ab)= is an expression we apply to the function =(λy.x(yz))=.
|
|
|
|
|
So replace =y= by =ab= and we get: =x(abz)=.
|
|
|
|
|
|
|
|
|
|
And...
|
|
|
|
|
|
|
|
|
|
That's it.
|
2017-12-07 15:44:09 +00:00
|
|
|
|
** LISP
|
2017-08-24 18:58:13 +00:00
|
|
|
|
*** LISP (McCarthy 1960)
|
|
|
|
|
The first functional programming language and the second oldest programming
|
|
|
|
|
language stil in use (after FORTRAN).
|
|
|
|
|
|
2017-12-07 15:44:09 +00:00
|
|
|
|
*** LISP: S-Language
|
2017-08-24 18:58:13 +00:00
|
|
|
|
- atom which are words like X or TWO
|
|
|
|
|
- pairing operation written as a dot
|
|
|
|
|
|
2017-12-07 15:44:09 +00:00
|
|
|
|
#+BEGIN_SRC elisp
|
|
|
|
|
((X.Y).Z)
|
|
|
|
|
(ONE.(TWO.(THREE.NIL)))
|
|
|
|
|
#+END_SRC
|
2017-08-24 18:58:13 +00:00
|
|
|
|
|
|
|
|
|
List, Trees, etc..
|
|
|
|
|
|
2017-12-07 15:44:09 +00:00
|
|
|
|
*** LISP: M-Language
|
2017-08-24 18:58:13 +00:00
|
|
|
|
defines computations on S-exrepssions. It has
|
|
|
|
|
- S-expressions
|
|
|
|
|
- function application (=f[a;b;...]=) with primitve functions =cons=, =car=, =cdr=, =atom=, =eq=
|
|
|
|
|
- conditional expressions (=[ test1 -> result1 ; test2 -> result2 ; ... ]=)
|
|
|
|
|
- ability to define recursive functions (=first[x] = [atom [x] -> x ; T -> first[car[x]]]=)
|
|
|
|
|
|
2017-12-07 15:44:09 +00:00
|
|
|
|
*** LISP: Encode M-Language exprs as S-Expressions
|
|
|
|
|
|
|
|
|
|
Encoding M-Language expressions and functions as S-Expressions:
|
|
|
|
|
|
|
|
|
|
Define M-language functions =eval= and =apply= that correctly interpret these
|
|
|
|
|
S-expressions
|
2017-08-24 18:58:13 +00:00
|
|
|
|
|
|
|
|
|
Thus LISP allow meta-programming: treating program as data and vice versa
|
|
|
|
|
|
2017-12-07 15:44:09 +00:00
|
|
|
|
*** LISP: LISP Syntax so much parenthesis
|
2017-08-24 18:58:13 +00:00
|
|
|
|
|
|
|
|
|
It was intended to code use M-language in an Algol-like notation.
|
2017-12-07 15:44:09 +00:00
|
|
|
|
In practice LISPers wrote their code directly in S-expressions.
|
2017-08-24 18:58:13 +00:00
|
|
|
|
M-language became a kind of ghost... theoretically important but not used by anyone.
|
|
|
|
|
|
2017-12-07 15:44:09 +00:00
|
|
|
|
** History
|
|
|
|
|
*** 1960 → 1983
|
2017-12-27 23:32:14 +00:00
|
|
|
|
- Algol 60 (Naur et al 1963) -- /no I/O facilities/
|
|
|
|
|
- ISWIM (Landin 1966) -- /If you See What I Mean/
|
|
|
|
|
- PAL (Evans 1968) -- /Pedagogic Algorithmic Language/
|
|
|
|
|
- SASL (1973-83) -- /St Andrews Static Language/
|
2017-12-07 15:44:09 +00:00
|
|
|
|
*** Edinburgh (1969-80)
|
2017-12-27 23:32:14 +00:00
|
|
|
|
- NLP /strongly typed/ but no polymorphisms, call-by-value
|
|
|
|
|
- NLP evolved into HOPE: higher order, /strongly typed/ with explicit types and
|
|
|
|
|
/polymorphic type variables/, /purely functional/.
|
2017-08-24 18:58:13 +00:00
|
|
|
|
- ML (Meta-Language) emerged as the meta-language of Edinburgh LCF, programmable verification system
|
2017-12-27 23:32:14 +00:00
|
|
|
|
- Standard ML (Milner et al. 1990) /pattern matching/ and /type inference/ but *not pure*.
|
2017-08-24 18:58:13 +00:00
|
|
|
|
*** Miranda (1986)
|
2017-12-27 23:32:14 +00:00
|
|
|
|
- Milner type discipline:
|
|
|
|
|
|
|
|
|
|
#+BEGIN_SRC
|
|
|
|
|
tree * :: Leaf * | Node (tree *) (tree *)
|
|
|
|
|
#+END_SRC
|
|
|
|
|
|
2017-08-24 18:58:13 +00:00
|
|
|
|
- Use of =*=, =**=, =***=, ... syntax as type variables from original ML
|
|
|
|
|
*** Haskell (1992...)
|
|
|
|
|
Similar to Miranda but richer and more redundant syntax.
|
|
|
|
|
+ type classes
|
|
|
|
|
+ monadic IO
|
|
|
|
|
+ module system
|
|
|
|
|
|
|
|
|
|
* Major Principles (Theoretical)
|
|
|
|
|
** Higher-order functions
|
2017-12-07 15:44:09 +00:00
|
|
|
|
|
|
|
|
|
A function can take another function as parameter.
|
|
|
|
|
|
|
|
|
|
#+BEGIN_SRC haskell
|
|
|
|
|
map :: (a -> b) -> [a] -> [b]
|
|
|
|
|
map (+2) [1,2,3] -- ⇒ [3,4,5]
|
|
|
|
|
|
|
|
|
|
filter :: (a -> Bool) -> [a] -> [a]
|
|
|
|
|
filter (>2) [1,2,3] -- ⇒ [3]
|
|
|
|
|
#+END_SRC
|
|
|
|
|
|
2017-08-24 18:58:13 +00:00
|
|
|
|
** Purity
|
|
|
|
|
*** Function vs Procedure/Subroutines
|
2017-12-07 15:44:09 +00:00
|
|
|
|
- A Function is something that doesn't have any effect.
|
|
|
|
|
- A Procedure/subroutine is something that can interleave effects during
|
|
|
|
|
evaluation
|
|
|
|
|
*** Referential Transparency vs Referential Opacity
|
2017-08-24 18:58:13 +00:00
|
|
|
|
- Ability to copy/paste without changing result vs impossible
|
|
|
|
|
- Help the programmer but also the compiler!
|
|
|
|
|
- Help in proving correctness
|
|
|
|
|
- Help simplifying algorithms, better linters
|
2017-12-07 15:44:09 +00:00
|
|
|
|
- Optimizing by:
|
|
|
|
|
- memoization
|
|
|
|
|
- common subexpression elimination
|
|
|
|
|
- lazy evaluation
|
|
|
|
|
- parallelization
|
|
|
|
|
*** Extremely Easy to Parallelze
|
|
|
|
|
**** Evaluation strategies:
|
|
|
|
|
=(h (f a) (g b))= We can evaluate:
|
|
|
|
|
|
|
|
|
|
- =a= then =(f a)= then =b= then =(g b)= and finally =(h (f a) (g b))=
|
|
|
|
|
- =b= then =a= then =(g b)= then =(f a)= and finally =(h (f a) (g b))=
|
|
|
|
|
- =a= and =b= in parallel then =(f a)= and =(g b)= in parallel and finally
|
|
|
|
|
=(h (f a) (g b))=
|
|
|
|
|
- =h= and then evaluate =(f a)= only if needed and then =(g b)= only if needed...
|
2017-08-24 18:58:13 +00:00
|
|
|
|
That's called non-strict evaluation (sometime lazy evaluation)
|
|
|
|
|
For example if: =(def h (λx.λy.(+ x x)))= we don't need to evaluate =y=, in our case =(g b)=
|
2017-12-07 15:44:09 +00:00
|
|
|
|
|
2017-08-24 18:58:13 +00:00
|
|
|
|
**** Time is Hard, purity remove time from the paradigm
|
2017-12-07 15:44:09 +00:00
|
|
|
|
Calling the same function with the same parameter twice will always results in
|
|
|
|
|
the same value.
|
2017-08-24 18:58:13 +00:00
|
|
|
|
*** Effects?
|
|
|
|
|
**** Side effects in the language
|
2017-12-07 15:44:09 +00:00
|
|
|
|
The programmer must be careful not to use impure functions in place where only
|
|
|
|
|
pure functions are expected.
|
2017-08-24 18:58:13 +00:00
|
|
|
|
**** Split impurity using a flag (generaly a type)
|
|
|
|
|
- =foo : Int -> String= declared as pure
|
|
|
|
|
- =foo : Int -> IO String= declared as impure (IO)
|
|
|
|
|
*** Exceptions / Errors?
|
|
|
|
|
We can't avoid the fact real world has limits! Space limit, maybe time limit,
|
|
|
|
|
maybe access limitations...
|
|
|
|
|
** Tail Recursion
|
|
|
|
|
Recursion is heavily used in functional programming. Functional language will
|
|
|
|
|
often include *tail call optimisation* to ensure that heavy recursion does not
|
|
|
|
|
consume excessive memory.
|
|
|
|
|
** Functional Programming Style and Grey area Languages
|
|
|
|
|
|
|
|
|
|
Functional Style can be achieved in most languages. For example in Perl, PHP,
|
|
|
|
|
C++11, Java 8 and C# 3.0. all added features to facilitate the functional style.
|
|
|
|
|
|
|
|
|
|
Scala is special as it is frequently written in a functional style but the
|
|
|
|
|
presence of side effects and mutable state place it in a grey area.
|
|
|
|
|
|
|
|
|
|
*** A Hole in purity, and all great properties of functional programming fall appart
|
|
|
|
|
|
|
|
|
|
This is a major point. You cannot compromise with purity without losing
|
|
|
|
|
everything. Extremely well explained in the SICP when he introduce the =set!=
|
|
|
|
|
ability to *mutate* the value associated to a variable.
|
|
|
|
|
|
|
|
|
|
*** Grey Area Languages
|
|
|
|
|
**** XSLT
|
|
|
|
|
**** R, J, K and Q
|
|
|
|
|
**** SQL (declarative)
|
|
|
|
|
**** Lex/Yacc a bit
|
|
|
|
|
|
|
|
|
|
** Meta-Programming and Macros!
|
|
|
|
|
|
|
|
|
|
If you really want to have the next power level, you can write macros, or what
|
|
|
|
|
is mostly called meta-programming.
|
|
|
|
|
|
|
|
|
|
A notable thing to know about are LISP Macros.
|
|
|
|
|
|
|
|
|
|
** Type System
|
|
|
|
|
First, If when I say static typing you think C, C++, Java... No, that's NOT THAT AT ALL!
|
|
|
|
|
|
|
|
|
|
Type Theory is a vast mathematical field, with lot of hard and incredible work.
|
|
|
|
|
|
|
|
|
|
Some language don't need type system at all. Typically most LISP are very close to a raw lambda calculus.
|
|
|
|
|
|
|
|
|
|
But there is a problem with untyped languages: ⊥
|
|
|
|
|
|
|
|
|
|
Even we provided purity, you can imagine a system that help you reason about
|
|
|
|
|
your code even further by adding more meta informations.
|
|
|
|
|
|
|
|
|
|
Different type systems: Hindley Milner, Martin/Lof, HoTT
|
|
|
|
|
|
|
|
|
|
- Basic Types (same as in Java)
|
|
|
|
|
- Parametric Types ⇒ many different polymorphisms to choose
|
|
|
|
|
- ADT! ⇒ Algebraic Data Types (type with algebraic properties FTW!)
|
|
|
|
|
- GADT! ⇒ Generalized Algebraic Data Types
|
|
|
|
|
- Generic Programming (be able to understand that two data structure share the same underlying structure)
|
|
|
|
|
- Typeclasses ⇒ Incredible ability to abstraction (Monoids, Functor, Applicative, Monads, Traversables...)
|
|
|
|
|
|
|
|
|
|
* Major Languages (Practical)
|
|
|
|
|
|
|
|
|
|
- We only talk about General purpose languages (not domain specific languages)
|
|
|
|
|
- Prod ready or not is only regarding our current knowledge. And by prod ready
|
|
|
|
|
it won't be enough to name less than 5 company using it for small project.
|
|
|
|
|
- Prod ready mean used at 100% by a company earning money for some years, and
|
|
|
|
|
used partially (more than 10%) by more than 10 company or having a big
|
|
|
|
|
production project
|
|
|
|
|
** Not Pure
|
|
|
|
|
*** Can be used in modern production env
|
|
|
|
|
**** LISP Family
|
|
|
|
|
***** Common Lisp
|
|
|
|
|
***** Clojure (Generally pure as default data structure are pure)
|
|
|
|
|
**** Not LISP & General Purpose Languages
|
|
|
|
|
***** Erlang
|
|
|
|
|
***** Mathematica
|
|
|
|
|
***** OCaml
|
|
|
|
|
***** F#
|
|
|
|
|
*** Not suitable for production yet
|
|
|
|
|
**** LISP Family
|
|
|
|
|
***** Scheme
|
|
|
|
|
***** Racket
|
|
|
|
|
**** Not LISP, General Purpose Languages
|
|
|
|
|
***** Erlang
|
|
|
|
|
***** ML, Caml
|
|
|
|
|
** Pure
|
|
|
|
|
*** Prod ready
|
|
|
|
|
**** Haskell
|
|
|
|
|
**** Elm
|
2017-12-07 15:44:09 +00:00
|
|
|
|
**** Purescript
|
2017-08-24 18:58:13 +00:00
|
|
|
|
*** Not Prod ready yet
|
|
|
|
|
**** Idris
|
|
|
|
|
**** Frege
|
|
|
|
|
**** Eta (Haskell 7.10 on the JVM) might be used in production but really recent
|
|
|
|
|
**** Clean
|
2018-02-17 11:34:40 +00:00
|
|
|
|
* Practical Examples
|
|
|
|
|
** Bug 1 - Parallelization / pureté
|
|
|
|
|
- =map=
|
|
|
|
|
- =pmap=
|
|
|
|
|
** Bug 2 - Waiting icon
|
|
|
|
|
Waiting icon
|
|
|
|
|
** Bug 3 - Null Pointer Exception
|
|
|
|
|
No NPE with Maybe
|
|
|
|
|
** Helper - Non deterministic programming
|
|
|
|
|
- for (for (for .... ))) pyramid of hell
|
|
|
|
|
List monad
|