Functional programming as an alternative (additional) paradigm to OOP
Mikhail Smal https://mikhail.dev
Functional programming as an alternative (additional) paradigm to - - PowerPoint PPT Presentation
Functional programming as an alternative (additional) paradigm to OOP Mikhail Smal https://mikhail.dev Who are you? http://bonkersworld.net/object-world AbstractToastHeaterGeneratorFactoryInterfaceImplementer
Mikhail Smal https://mikhail.dev
http://bonkersworld.net/object-world
AbstractToastHeaterGeneratorFactoryInterfaceImplementer abstractToastHeaterGeneratorFactoryInterfaceImplementer = new AbstractToastHeaterGeneratorFactoryInterfaceImplementer( AbstractToastHeaterGeneratorFactoryInterfaceImplementer.DEFAULT_PARAMS, 0, NULL);
Émile-Auguste Chartier
Émile-Auguste Chartier
http://bonkersworld.net/object-world
Phil Karlton
William Cook, "On Understanding Data Abstraction, Revisited"
public class Ellipse public class Ellipse { public double public double SemiMajorAxis SemiMajorAxis { get; set; } { get; set; } public double public double SemiMinorAxis SemiMinorAxis { get; set; } { get; set; } } public class Circle : Ellipse public class Circle : Ellipse { { public double Radius { get; set; } public double Radius { get; set; } }
publi blic c c class lass Ell Ellips ipse { publ ublic vi ic virtu rtual al doubl double e Semi emiMajor MajorAxi Axis { get; get; se set; t; } publ ublic vi ic virtu rtual al doubl double e Semi emiMinor MinorAxi Axis { get; get; se set; t; } } publi blic c c class lass Cir Circle cle : El : Ellip lipse se { ... .. publ ublic ov ic overr erride ide doub double le Sem SemiMajo iMajorAx rAxis is { get = get => . > ... .. set = set => t > thro hrow new w new NotSu tSupport pportedE edExce xception ption(); (); } ... ... publ ublic ov ic overr erride ide doub double le Sem SemiMino iMinorAx rAxis is { ... .. }
publi blic c c class lass Ell Ellips ipse { publ ublic do ic doubl uble e SemiMa emiMajor jorAxi Axis { g { get; et; } } publ ublic do ic doubl uble e SemiMi emiMinor norAxi Axis { g { get; et; } } publ ublic El ic Ellip lipse( se(doubl double e semi emiMajor MajorAxi Axis, doubl double e semi emiMinor MinorAxi Axis) { SemiM SemiMajo ajorAx rAxis is = = sem semiMa iMajorAx jorAxis is; SemiM emiMino norAx Axis = = sem emiMi MinorAx
} ... .. } pu publi lic c class ass Cir ircle le { publ ublic do ic doubl uble R e Radius adius { { get get; } ; } publ ublic Ci ic Circl rcle(d e(double
radiu dius) s) { Radiu Radius = s = ra radius; dius; } publ ublic El ic Ellip lipse se ToEll ToEllips ipse() { { ... .. }
publi blic c c class lass Ell Ellips ipse { publ ublic do ic doubl uble e SemiMa emiMajor jorAxi Axis { g { get; et; } } publ ublic do ic doubl uble e SemiMi emiMinor norAxi Axis { g { get; et; } } publ ublic El ic Ellip lipse( se(doubl double e semi emiMajor MajorAxi Axis, doubl double e semi emiMinor MinorAxi Axis) { SemiM SemiMajo ajorAx rAxis is = = sem semiMa iMajorAx jorAxis is; SemiM emiMino norAx Axis = = sem emiMi MinorAx
} ... .. publ ublic bo ic bool
IsCircle ircle => .. ... . } pu publi lic c class ass Cir ircle le { publ ublic do ic doubl uble R e Radius adius { { get get; } ; } publ ublic Ci ic Circl rcle(d e(double
radiu dius) s) { Radiu Radius = s = ra radius; dius; } publ ublic El ic Ellip lipse se ToEll ToEllips ipse() { { ... .. }
public class Ellipse public class Ellipse { public double public double SemiMajorAxis SemiMajorAxis { get; set; } { get; set; } public double public double SemiMinorAxis SemiMinorAxis { get; set; } { get; set; } }
public class Ellipse public class Ellipse { public double public double SemiMajorAxis SemiMajorAxis { get; } { get; } public double public double SemiMinorAxis SemiMinorAxis { get; } { get; } public Ellipse(double public Ellipse(double semiMajorAxis semiMajorAxis, double , double semiMajorAxis semiMajorAxis) { SemiMajorAxis SemiMajorAxis = = semiMajorAxis semiMajorAxis; SemiMinorAxis SemiMinorAxis = = semiMinorAxis semiMinorAxis; } }
type Ellipse = type Ellipse = { { SemiMajorAxis SemiMajorAxis : float : float SemiMinorAxis SemiMinorAxis : float } : float } let ellipse = let ellipse = { { SemiMajorAxis SemiMajorAxis = 10. = 10. SemiMinorAxis SemiMinorAxis = 20. } = 20. } let let newEllipse newEllipse = { ellipse with { ellipse with SemiMinorAxis SemiMinorAxis = 30. } = 30. }
public public IConnection IConnection CreateConnection CreateConnection(Provider (Provider connectionProvider connectionProvider) { ... ...
public public Pool
edConnect
ion ConnectT ConnectTo(Pr (Provi
er ofU
pdates) { ... ...
var var numb numbers ers = [1 = [10, 3 0, 3, 7, , 7, 1, 1, 25] 25] num numbers ers.sor sort() ()
func function tion sor sorted( ted(numb numbers) ers) { { ... ... }
Simon Peyton-Jones
f(x f(x) = = expr xpressi ssion
In functional programming, programs are executed by evaluating expressions, in contrast with imperative programming where programs are composed of statements which change global state when executed. Functional programming typically avoids using mutable state.
https://wiki.haskell.org/Functional_programming
Many programming languages support programming in both functional and imperative style but the syntax and facilities
coding conventions and libraries often force the programmer towards one of the styles.
https://wiki.haskell.org/Functional_programming
int int squa square(i re(int x nt x) { { retu return x rn x * x * x; }
func function tion squ square( are(x) { x) { ret return rn x * * x }
public class Math public class Math { { public static int Square(int x) public static int Square(int x) { return x * x; return x * x; } }
squa square(X re(X) ) -> X * X * X. X.
squa square x re x = x = x * x * x squa square : re :: In : Int t -> > Int Int
▪do do ▪foreach foreach ▪for for ▪while while
fun funct ction ion f fact actor
ial(n (n) { ) { var ar re resul sult t = 1 = 1; whil hile e (n (n > > 1) 1) re resul sult t *= *= n--
retu eturn rn re resu sult; lt; }
fun funct ction ion f fact actor
ial(n (n) { ) { if ( f (n n > 1 > 1) re retur turn n n * n * f fact actor
ial(n (n - 1) 1); else lse re retur turn n 1; 1; }
fun funct ction ion f fact actor
ial(n (n) { ) { retu eturn rn ( ( n n > 1 > 1 ? ? n * n * f fact actor
ial(n (n - 1) 1) : : 1); 1); }
funct function f ion factor actorial(n ial(n) { ) { fun functi ction lo
result) { lt) { re return turn ( ( n > n > 1 1 ? l ? loop(
n - 1, 1, n * n * re resul sult) t) : r : result esult); ); } ret return urn loop loop(n, 1 (n, 1); ); }
𝒐! = ቊ𝟐, 𝒐 = 𝟏, 𝒐 − 𝟐 ! × 𝒐, 𝒐 > 𝟏.
𝑙=1 𝑜
fac factori
l n = p = produ
t [1..n ..n]
fac factori
l n = f = foldl ldl (*) (*) 1 [ 1 [1..n ..n]
f(x f(x) = = λ x • exp express ression ion
William Cook, "On Understanding Data Abstraction, Revisited"
A higher-order function is a function that takes other functions as arguments or returns a function as result.
https://wiki.haskell.org/Higher_order_function
squa square = re = fun functio ction (x n (x) { ) { ret return rn x * * x; }
squ square re = x x => x > x * x * x
squ square re = \x x -> x > x * * x
map map squa square [ re [1..1 1..100] 00]
map map (\x x -> x > x * * x) [ ) [1..1 ..100] 0]
pro product uct = = fo foldr ldr (*) *) 1
Partial application is the conversion of a polyadic function into a function taking fewer arguments by providing one or more arguments in advance.
http://raganwald.com/2013/03/07/currying-and-partial-application.html
library.Select library.Select(book => (book => book.Author book.Author) .Where(author => .Where(author => author.Age author.Age >= 50) >= 50) .Take(15) .Take(15) .Select(author => .Select(author => author.Surname author.Surname) .Select(surname => .Select(surname => surname.ToUpper surname.ToUpper()) ()) .Distinct() .Distinct() .ToList ToList() ()
$ cat sample.txt | head $ cat sample.txt | head -7 | tail 7 | tail -5
library library |> |> Seq.map Seq.map (fun b (fun b -> > b.Author b.Author) |> |> Seq.filter Seq.filter (fun a (fun a -> > a.Age a.Age >= 50) >= 50) |> |> Seq.take Seq.take 15 15 |> |> Seq.map Seq.map (fun a (fun a -> > a.Surname a.Surname) |> |> Seq.map Seq.map (fun s (fun s -> > s.ToUpper s.ToUpper()) ()) |> |> Seq.distinct Seq.distinct |> |> List.ofSeq List.ofSeq
pu public inter blic interface Stack face Stack<T> <T> { int int Dept Depth(); h(); T T T Top();
voi void Pop d Pop(); (); voi void Push(T d Push(T newTop ewTop); ); }
publi blic c c class lass Sta Stack< ck<T> : T> : Abs Abstra tract.St ct.Stack ack<T> <T> { priv private L te List st<T> T> _ite _items s = n new Li w List< t<T>( >(); publ ublic in ic int D t Dept epth() = h() => _ > _ite items.Co ms.Count unt; publ ublic T ic T Top Top() () { if (D if (Dept epth() h() == 0 == 0) thro throw n new w In Inval alidO dOperat eration
xceptio ption(); (); retur return _ n _ite items[De ms[Depth pth() () - 1]; 1]; } publ ublic vo ic void id Pop Pop() () { if (D if (Dept epth() h() == 0 == 0) thro hrow n w new ew Inval validO idOperat peration ionExc Exceptio eption(); (); _item tems.R s.Remo emoveAt veAt(Dep Depth( th() ) - 1); ); } publ public vo c void d Pus ush(T (T newT newTop) { _item tems.A s.Add dd(newTo newTop); ); } }
pu public inter blic interface Stack face Stack<T> <T> { int int Dept Depth(); h(); T T T Top();
Sta Stack<T> ck<T> Pop( Pop(); ); Sta Stack<T> Push ck<T> Push(T (T ne newTop wTop); ); }
public class public class EmptyStack EmptyStack<T> : <T> : Abstract.Stack Abstract.Stack<T> <T> { public int Depth() => 0; public int Depth() => 0; public T Top() => throw new public T Top() => throw new InvalidOperationException InvalidOperationException(); (); public void Pop() => throw new public void Pop() => throw new InvalidOperationException InvalidOperationException(); (); public void Push(T public void Push(T newTop newTop) => new ) => new NonEmptyStack NonEmptyStack<T>( <T>(newTop newTop, this); , this); }
pu publ blic i int nterfa face ce Sta tack ck<T> { int t De Depth( h(); ); T To Top( p(); Stac ack< k<T> P Pop
Stac ack< k<T> P Pus ush(T T ne newTop
) => ne new No NonE nEmpty tySt Stack(ne newTop
, this is); ); }
public class public class EmptyStack EmptyStack<T> : Stack<T> <T> : Stack<T> { public int Depth() => 0; public int Depth() => 0; public T Top() => throw new public T Top() => throw new InvalidOperationException InvalidOperationException(); (); public Stack<T> Pop() => throw new public Stack<T> Pop() => throw new InvalidOperationException InvalidOperationException(); (); }
public class public class NonEmptyStack NonEmptyStack<T> : Stack<T> <T> : Stack<T> { private T top; private T top; private Stack<T> tail; private Stack<T> tail; public public NonEmptyStack NonEmptyStack(T (T newTop newTop, Stack<T> previous) , Stack<T> previous) { top = top = newTop newTop; tail = previous; tail = previous; } public int Depth() => 1 + public int Depth() => 1 + tail.Depth tail.Depth(); (); public T Top() => top; public T Top() => top; public Stack<T> Pop() => return tail; public Stack<T> Pop() => return tail; }
va var r stac ack k = ne new w Stac ack< k<stri ring ng>(); ); st stac ack.pu push sh(“Prague”); st stac ack.pu push sh(“Berlin”);
Stack<string> Stack<string> stack = new stack = new Em EmptyStack ptyStack<string>(); <string>(); stack = stack = stack. stack.push push(“Prague”).push(“Berlin”);
pu publ blic i int nterfa face ce Sta tack ck<T> { int t De Depth( h(); ); T To Top( p(); Stac ack< k<T> P Pop
Stac ack< k<T> P Pus ush(T T ne newTop
) => ne new No NonE nEmpty tySt Stack(ne newTop
, this is); ); } wh wher ere T T : : immu muta table
In computing, a persistent data structure is a data structure that always preserves the previous version of itself when it is modified. Such data structures are effectively immutable, as their operations do not (visibly) update the structure in-place, but instead always yield a new updated structure.
https://en.wikipedia.org/wiki/Persistent_data_structure
a b b = a = a
a c c = pop = pop(a) (a)
a c c = pop = pop(a) (a)
a d d = pus = push(a, h(a, i)
Mutable Immutable Unshared Shared Shared mutable data needs synchronization Unshared mutable data needs no synchronization Unshared immutable data needs no synchronization Shared immutable data needs no synchronization
Lucius Cary
Bertrand Meyer
https://mikhail.dev
Mikhail Smal
Next talk:
Introduction to F# 22 October 2019