deft/blog-FP-Survey.org
Yann Esposito (Yogsototh) 4f9261e037
save
2017-12-28 00:32:14 +01:00

278 lines
9.3 KiB
Org Mode
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#+Title: Functional Programming Overview
#+Author: Yann Esposito
- Intro & Brief History Overview
- Major Principles (Theory)
- Major Languages (Practice)
* Intro
*** What is Functional Programming?
Programming paradigm. Math functions vs Procedures.
- *Immutable*: avoids changing-state and mutable data
- *Declarative programming*: expression or declarations instead of statements
- *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
- Evaluation order and timing are a separated concern from function results
- *Functions are first-class*:
- functions are treated like any other values.
- functions can be passed as arguments to other functions
- functions can returns other functions
* Brief History Overview
** 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
*** λ-Calculus, Alonzo Church & Rosser 1936
Typeless theory of functions.
A syntaxic construction can be equivalent to any Turing Machine.
Mainly re-writing rules.
*** Learn λ-Calculus in less than 1 minute
*** Definitions
- =a,b,...= are variables
- =()= parenthesis to group part of an expression
- =λ= greek letter (pronounced Lambda) and the =.= to write functions.
*** Free vs Bound
- =λ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.
*** Rules
(α) =λ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)=
(β) =(λx.(f x y))2 → (f x 2)=
(η) =λx.f x → f=
*** Resume
How does that work? Simply cut and paste! That's it.
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.
** LISP
*** LISP (McCarthy 1960)
The first functional programming language and the second oldest programming
language stil in use (after FORTRAN).
*** LISP: S-Language
- atom which are words like X or TWO
- pairing operation written as a dot
#+BEGIN_SRC elisp
((X.Y).Z)
(ONE.(TWO.(THREE.NIL)))
#+END_SRC
List, Trees, etc..
*** LISP: M-Language
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]]]=)
*** 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
Thus LISP allow meta-programming: treating program as data and vice versa
*** LISP: LISP Syntax so much parenthesis
It was intended to code use M-language in an Algol-like notation.
In practice LISPers wrote their code directly in S-expressions.
M-language became a kind of ghost... theoretically important but not used by anyone.
** History
*** 1960 → 1983
- 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/
*** Edinburgh (1969-80)
- 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/.
- ML (Meta-Language) emerged as the meta-language of Edinburgh LCF, programmable verification system
- Standard ML (Milner et al. 1990) /pattern matching/ and /type inference/ but *not pure*.
*** Miranda (1986)
- Milner type discipline:
#+BEGIN_SRC
tree * :: Leaf * | Node (tree *) (tree *)
#+END_SRC
- 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
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
** Purity
*** Function vs Procedure/Subroutines
- 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
- 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
- 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...
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)=
**** Time is Hard, purity remove time from the paradigm
Calling the same function with the same parameter twice will always results in
the same value.
*** Effects?
**** Side effects in the language
The programmer must be careful not to use impure functions in place where only
pure functions are expected.
**** 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
**** Purescript
*** Not Prod ready yet
**** Idris
**** Frege
**** Eta (Haskell 7.10 on the JVM) might be used in production but really recent
**** Clean