9.5 KiB
Functional Programming Overview
- math function vs Procedures.
- Brief History Overview
- Major Principles (Theoretical)
- Major Languages (Practical)
- Practical Examples
- Intro & Brief History Overview
- Major Principles (Theory)
- Major Languages (Practice)
math function 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 asxy
contains ay
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 2 y)
(η) λ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
((X.Y).Z)
(ONE.(TWO.(THREE.NIL)))
List, Trees, etc..
LISP: M-Language
defines computations on S-exrepssions. It has
- S-expressions
- function application (
f[a;b;...]
) with primitve functionscons
,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:
tree * :: Leaf * | Node (tree *) (tree *)
- 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.
map :: (a -> b) -> [a] -> [b]
map (+2) [1,2,3] -- ⇒ [3,4,5]
filter :: (a -> Bool) -> [a] -> [a]
filter (>2) [1,2,3] -- ⇒ [3]
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)
thenb
then(g b)
and finally(h (f a) (g b))
b
thena
then(g b)
then(f a)
and finally(h (f a) (g b))
a
andb
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 purefoo : 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
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