About me
 Name: Nikolay Mozgovoy (FB, LinkedIn)
 Developer in Sigma Software since 2013
and mentor since 2016
 Teacher in KhAI (Department Of Computer
Systems, Networks And Cybersecurity)
 GGJ Ukraine prizewinner (2016, 2017)
 GGJ Site organizer (Kharkiv)
 Media/Global hack weekend competitor
 MSCSD: App builder
 Caught Lisp in 2016
FP for OO adepts
Talk overview
 Functional programming fundamentals
 History
 Relevance
 Basic concepts
 Derived concepts
Paradigms in time
 Imperative
 Machine (1940s)
 Procedural (1960s – FORTRAN, ALGOL, COBOL, BASIC)
 Structured (1966-1968 ‘Go To Statement Considered Harmful’ by Dijkstra)
 Object-oriented (1967 - Simula, 1972 - Smalltalk)
 Event-driven (1970s)
 Declarative
 Functional (1958 - LISP)
 Logic (1972 - Prolog)
 Domain-specific (1974 - SQL)
 Functional reactive (1997-2000 Paul Hudak)
Lambda calculus
 Formal system in mathematical logic for expressing
computation based on function abstraction and
application using variable binding and substitution
 Turing complete
 Developed by Alonzo Church in the 1930s
 Notation:
 λx. t[x] – function that do anything with x
 λx. x^2 – x squaring function same as y=x^2
 (λx y. x + y) 1 2 = (λy. 1 + y) 2 = 1 + 2 – carrying
Functional Languages
 LISP - 1958
 Scheme - 1970
 Racket - 1994
 Common Lisp - 1984
 Clojure - 2007
 ML (Meta Language) - 1973
 Ocaml -1996
 F# - 2005
 Erlang - 1986
 Haskell - 1990
 Scala - 2004
CPU cores per year
0
4
8
12
16
20
24
28
32
2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018
Intel AMD
GPU cores per year
0
512
1024
1536
2048
2560
3072
3584
4096
4608
5120
2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018
CUDA Cores (Nvidia) Stream Processors (AMD)
RAM price ($ per Mbyte)
0.00
0.20
0.40
0.60
0.80
1.00
1.20
2000 2002 2004 2006 2008 2010 2012 2014 2016
Imperative code & parallel execution
BigInteger[] arr = Enumerable.Range(0, 10000)
.Select(x => new BigInteger(x)).ToArray();
BigInteger sum = 0;
foreach (var n in arr) sum += n; // OK
Parallel.For(0, arr.Length, n => sum += n); // Wrong result
// And if we apply lock it would degradate to de-facto single-threaded code
arr.AsParallel().Aggregate((a, b) => a + b); // OK
Functional code & parallel execution
1
3
2 43
7
10
(a, b) => a + b (a, b) => a + b
(a, b) => a + b
Basic OO concepts
 Encapsulation
 Inheritance
 Polymorphism
 Abstraction
Basic FP concepts
 Immutability
 Purity
 First-class &
Higher-order functions
 Recursion
Basic OO concepts vs Basic FP concepts
 Encapsulation
 Inheritance
 Polymorphism
 Abstraction
 Immutability
 Purity
 First-class &
Higher-order functions
 Recursion
The failure of state
public void ProcessPackage(Stream package)
{
SaveMetadataInDb(package);
package.Seek(0, SeekOrigin.Begin); // !!!
/* ... */
SaveContentInSearchEngine(package);
/* ... */
LogOperation(package);
}
Immutability
 Impossibility to change the state of the object once it was created
 Immutable objects are simpler to test, and use
 Truly immutable objects are always thread-safe
 They help to avoid temporal coupling
 Their usage is side-effect free (no defensive copies)
 Identity mutability problem is avoided
 They always have failure atomicity
 They are much easier to cache
 They prevent NULL references, which are bad
 I the Lord do not change (Malachi 3:6)
Immutability example
; LISP
(define animals (list 'dog 'cat 'fish))
(cons 'horse animals) ; returns a new list of animals, not changing existing one
// F#
let animals = ["dog";"cat";"rat"]
let moreAnimals = List.append animals ["horse"] // returns a new list
// C#
var animals = new ReadOnlyCollection<string>(new[] { "dog", "cat", "fish" });
var moreAnimals = animals.Append("horse"); // returns new Enumerable
The sin of impurity
public async Task HookNextBuild(IProject project, Task buildFinished) {
var buildStarted = SyncEvents.VsBuildStarted(this.VsPid).ToTask(); // IPC
await Task.WhenAny(buildStarted, buildFinished).ConfigureAwait(false);
if (this.recentAnalysisCompletion != null) {
await this.recentAnalysisCompletion;
this.recentAnalysisCompletion = null;
this.recentCompletionTime = DateTime.Now; // Time
}
var analysisCompletion = await this.LaunchAnalysisAsync(project);
this.recentAnalysisCompletion = analysisCompletion;
}
Purity
 The property of functions not to have side-effects and any dependence from
external state or time
 Function is considered pure when:
 The function always evaluates the same result value given the same
argument value(s)
 Evaluation of the result does not cause any side effect
 Application:
 Simplifies testing
 Simplifies parallel computing
 Allows memoization
Purity example
// in F#
let inc x = x + 1 // pure function
let mutable i = 0
let badInc () = i <- i + 1 // impure function
; in LISP
(define (inc x) (+ x 1)) ; pure function
(define i 1)
(define (bad-inc!) (set! i (+ i 1)))
// in C#
Math.Pow(2, 8); // pure function
Path.GetTempFileName() ; // impure function
DateTime.Now; // impure function
First-class and Higher-order functions
 First-class functions is a property of programming language to treat functions
as a standard datatype
 Function is considered higher-order function when it does at least one of the
following:
 takes one or more functions as arguments
 returns a function as its result
First-class and Higher-order functions
// C#
// toUpper is first-class function
Func<string, string> toUpper = str => str.ToUpper();
// Select is higher-order function
new[] { "dog", "cat" }.Select(toUpper);
// F#
// fun x -> -x is first-class function & Seq.sortBy is higher-order function
[22;31;1;5;7] |> Seq.sortBy(fun x -> -x)
// >> is a higher-order function, it returns a composition of the functions
(add1 >> add1) 1 // 3
Recursion
 Recursion is idiomatic way to perform iterations or lopping in functional
programming languages
 Tail recursion usually can be recognized and optimized by a compiler
 Mutual recursion may require trampoline to handle it
 To iterate is human, to recurse, divine (L. Peter Deutsch)
Recursion example (LISP)
; mutual recursion
(define (r1 i)
(if (< i 0) 1 (r2 (- i 1))))
(define (r2 i)
(if (< i 0) 1 (r1 (- i 1))))
(r1 1000000)
; tail recursion
(define (factorial x)
(if (< x 2)
1
(* x (factorial (- x 1)))))
Recursion example (F#)
// mutual recursion
let rec r1 i =
if i < 0
then 1
else r2(i - 1)
and r2 i =
if i < 0
then 1
else r1(i - 1)
// tail recursion
let rec factorial x =
if x < 2
then 1
else x * factorial(x - 1)
Derived FP concepts
 Closures
 Partial application
 Lazy evaluation
First-class &
Higher-order functions
Closures
 A data structure containing a lambda expression, and an environment to be
used when that lambda expression is applied to arguments
 Closures are used to:
 bind together data and behavior (just like objects in OOP)
 emulate state
 emulate object system
function
environment
in which
function got
created
closure
object
Closure example in F# (simple and artificial)
// creates a function that raises y to a power of x
let makePowerFn x =
(fun y -> pown y x) // this lambda is a closure itself (because of reference to x)
let pow2 = makePowerFn 2
pow2 3 // 9
let pow3 = makePowerFn 3
pow3 3 // 27
Closure example: pure recursive data structures
type Seq = { value: int; next: (unit -> Seq) }
let rec initSeq next value : Seq = {
value = value; // return current value
next = (fun () -> initSeq next (next value)) // create a new sequence with the next value
}
let pow2Seq = initSeq (fun x -> x * 2) 2 // sequence of powers of 2
pow2Seq.value // 2
pow2Seq.next().next().value // 8
// doesn’t it look like enumerator.MoveNext().MoveNext().Current in C#?
Closure example: trampoline (in JavaScript)
function factorial (n) {
return n < 2
? 1
: n * factorial(n -1);
}
factorial(3); // 6
/* maximum call stack
size exceeded */
factorial(100000);
function trampoline (fn) {
while (
typeof fn === 'function') {
fn = fn();
}
return fn;
}
function factorial (n, acc = 1) {
return function () {
return (n < 2)
? acc
: factorial(n - 1, n * acc);
}
}
/* no errors */
trampoline(factorial(100000));
Partial application
 Process of breaking a single function into a multiple ones of smaller arity
 Often conflated/mixed with currying witch is a process of breaking a function of
n arguments to a chain of n functions of 1 argument each
 Motivation is that very often the functions obtained by supplying some but not
all of the required arguments
 papply: (((a × b) → c) × a) → (b → c) = λ(f, x). λy. f (x, y)
 curry: ((a × b) → c) → (a → (b → c)) = λf. λx. λy. f (x, y)
 uncurry: (a → (b → c)) → ((a × b) → c) = λf. λ(x, y). f x y
Partial application example (simple & artificial)
// F#
let add1 x = x + 1
// traditional definition vs application
let add1 = (+) 1
let sortAsc = List.sortWith
(fun x y -> x - y)
let sortDsc = List.sortWith
(fun x y -> y - x)
// C#
Func<string, Claim> newClaim =
value => new Claim(
"group", value, "String", “sigma.software ");
/*…*/
var groups = RetrieveGroups();
// { "Management", "Accountants“ };
var groupClaims = groups.Select(newClaim);
Partial application (C#)
public class Package {
private readonly IContentReader contentReader;
private readonly IChecksumGenerator checksumGenerator;
private readonly IChecksumFormatter checksumFormatter;
public Package(
string name,
IContentReader contentReader,
IChecksumGenerator checksumGenerator,
IChecksumFormatter checksumFormatter) {
this.Name = name;
this.contentReader = contentReader;
this.checksumGenerator = checksumGenerator;
this.checksumFormatter = checksumFormatter; }
public string Name { get; }
public string GetChecksumStr(Encoding encoding) =>
this.checksumFormatter.Format(
this.checksumGenerator.Generate(contentReader.Read()),
encoding);
}
public interface IContentReader {
Stream Read();
}
public interface IChecksumGenerator {
byte[] Generate(Stream dataStream);
}
public interface IChecksumFormatter {
string Format(
byte[] checksum,
Encoding encoding);
}
Partial application (F#)
type Package = {
name: string;
getChecksumStr: (Encoding -> string) }
let initPackage
(name: string)
(content: (unit -> Stream))
(generateChecksum: ((unit -> Stream) -> byte[]))
(formatChecksum:(byte[] -> Encoding -> string)) : Package = {
name = name;
getChecksumStr = content |> generateChecksum |> formatChecksum
}
Lazy evaluation
 Lazy evaluation is a way of computing in which values are not calculated until
they are required
 Lazy evaluation can be accomplished:
 By language itself (Haskell)
 Using special data structures
 The opposite of lazy evaluation called eager evaluation
 Application:
 Infinite data structures
 Memory footprint optimization
 Startup speed optimization
 Often combined with memorization
Lazy evaluation example (simple & artificial - F#)
// F#
let lazyVal = lazy (10 * 10)
lazyVal // Lazy<int> Value is not created.
lazyVal.Force() // 100
let nat = Seq.initInfinite(fun n -> n + 1)
// seq<int> = seq [1; 2; 3; 4; ...]
Seq.skip 10 nat |> Seq.take 10
// seq<int> = seq [11; 12; 13; 14; ...]
Lazy evaluation example (F#)
type Package = {
name: string;
getChecksumStr: (Encoding -> string) }
let initPackage
(name: string)
(content: (unit -> Stream))
(generateChecksum: ((unit -> Stream) -> byte[]))
(formatChecksum:(byte[] -> Encoding -> string)) : Package =
let checksum = lazy (content |> generateChecksum)
{
name = name;
getChecksumStr = checksum.Value |> formatChecksum
}
Pattern matching
 Language feature that allows to choose the following instruction set based on
the match of given data with one of the declared patterns:
 Constants
 Predicates (functions that return Boolean values)
 Data type
 Anything else supported by a particular language
Pattern matching example
// F#
let ReadFromFile reader : StreamReader) =
match reader.ReadLine() with
| null -> printfn "n"; false
| line -> printfn "%s" line;
true
// C#
public static double ComputeArea (object shape)
{
switch (shape)
{
case Square s:
return s.Side * s.Side;
case Circle c:
return c.Radius * c.Radius * Math.PI;
case Rectangle r:
return r.Height * r.Length;
default: throw new ArgumentException();
}
}
Concepts comparison
Goal OOP FP
Binding data & behavior Class -> Object Closure
Passing dependencies Constructor Partial application
Decoupling from concrete
implementation
Interface Function signature
Controlling execution flow Switch statement Pattern matching
Summary
 Fundamentals concepts:
 Immutability
 Simplifies reasoning & testing; Increases scalability & reliability;
 Purity
 Simplifies reasoning and testing; Increases scalability & reliability;
 First-class, higher-order functions
 Closures
 Functional way to bind data and behavior
 Partial application
 Functional way to have constructors
 Lazy evaluation
 Speed ups initialization
What’s next?
 State management
 The problem of state
 Approaches of managing the state and side-effects
 Continuations
 Promises
 Monads
 FRP
Books
 Structure and interpretation of computer programs
 MIT course 6.037
 Introduction to Functional Programming
 Cambridge CS department
 Hackers and painters
 Google Play Books
 Amazon
Articles
 Rich Hickey – Simple made Easy
 https://github.com/matthiasn/talk-
transcripts/blob/master/Hickey_Rich/SimpleMadeEasy.md
 Vladimir Khorikov - Functional C#
 https://github.com/vkhorikov/CSharpFunctionalExtensions
 Robert Martin – FP vs OO
 http://blog.cleancoder.com/uncle-bob/2014/11/24/FPvsOO.html
 Why Functional Programming matters
 https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf
 Me - LISP: back to the future (a tribute to 60th anniversary):
 https://sigma.software/about/media/lisp-back-future-tribute-60th-
anniversary
Credits
 Penrose triangle © Tobias R. – Metoc [CC BY-SA 2.5] / Wikimedia Commons
 Six petal lotus © Christopher J. Fynn [CC BY-SA 3.0] / Wikimedia Commons
 Two intersecting Archimedean spirals of opposite directions © Nevit Dilmen
[GFDL, CC-BY-SA-3.0 or CC BY-SA 2.5] / Wikimedia Commons
 Objects should be immutable © Yegor Bugayenko
 Scheme: An interpreter for extended lambda calculus © Sussman and Steele

Столпы функционального программирования для адептов ООП, Николай Мозговой

  • 2.
    About me  Name:Nikolay Mozgovoy (FB, LinkedIn)  Developer in Sigma Software since 2013 and mentor since 2016  Teacher in KhAI (Department Of Computer Systems, Networks And Cybersecurity)  GGJ Ukraine prizewinner (2016, 2017)  GGJ Site organizer (Kharkiv)  Media/Global hack weekend competitor  MSCSD: App builder  Caught Lisp in 2016
  • 3.
    FP for OOadepts
  • 4.
    Talk overview  Functionalprogramming fundamentals  History  Relevance  Basic concepts  Derived concepts
  • 5.
    Paradigms in time Imperative  Machine (1940s)  Procedural (1960s – FORTRAN, ALGOL, COBOL, BASIC)  Structured (1966-1968 ‘Go To Statement Considered Harmful’ by Dijkstra)  Object-oriented (1967 - Simula, 1972 - Smalltalk)  Event-driven (1970s)  Declarative  Functional (1958 - LISP)  Logic (1972 - Prolog)  Domain-specific (1974 - SQL)  Functional reactive (1997-2000 Paul Hudak)
  • 6.
    Lambda calculus  Formalsystem in mathematical logic for expressing computation based on function abstraction and application using variable binding and substitution  Turing complete  Developed by Alonzo Church in the 1930s  Notation:  λx. t[x] – function that do anything with x  λx. x^2 – x squaring function same as y=x^2  (λx y. x + y) 1 2 = (λy. 1 + y) 2 = 1 + 2 – carrying
  • 7.
    Functional Languages  LISP- 1958  Scheme - 1970  Racket - 1994  Common Lisp - 1984  Clojure - 2007  ML (Meta Language) - 1973  Ocaml -1996  F# - 2005  Erlang - 1986  Haskell - 1990  Scala - 2004
  • 8.
    CPU cores peryear 0 4 8 12 16 20 24 28 32 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 Intel AMD
  • 9.
    GPU cores peryear 0 512 1024 1536 2048 2560 3072 3584 4096 4608 5120 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 CUDA Cores (Nvidia) Stream Processors (AMD)
  • 10.
    RAM price ($per Mbyte) 0.00 0.20 0.40 0.60 0.80 1.00 1.20 2000 2002 2004 2006 2008 2010 2012 2014 2016
  • 11.
    Imperative code &parallel execution BigInteger[] arr = Enumerable.Range(0, 10000) .Select(x => new BigInteger(x)).ToArray(); BigInteger sum = 0; foreach (var n in arr) sum += n; // OK Parallel.For(0, arr.Length, n => sum += n); // Wrong result // And if we apply lock it would degradate to de-facto single-threaded code arr.AsParallel().Aggregate((a, b) => a + b); // OK
  • 12.
    Functional code &parallel execution 1 3 2 43 7 10 (a, b) => a + b (a, b) => a + b (a, b) => a + b
  • 13.
    Basic OO concepts Encapsulation  Inheritance  Polymorphism  Abstraction
  • 14.
    Basic FP concepts Immutability  Purity  First-class & Higher-order functions  Recursion
  • 15.
    Basic OO conceptsvs Basic FP concepts  Encapsulation  Inheritance  Polymorphism  Abstraction  Immutability  Purity  First-class & Higher-order functions  Recursion
  • 16.
    The failure ofstate public void ProcessPackage(Stream package) { SaveMetadataInDb(package); package.Seek(0, SeekOrigin.Begin); // !!! /* ... */ SaveContentInSearchEngine(package); /* ... */ LogOperation(package); }
  • 17.
    Immutability  Impossibility tochange the state of the object once it was created  Immutable objects are simpler to test, and use  Truly immutable objects are always thread-safe  They help to avoid temporal coupling  Their usage is side-effect free (no defensive copies)  Identity mutability problem is avoided  They always have failure atomicity  They are much easier to cache  They prevent NULL references, which are bad  I the Lord do not change (Malachi 3:6)
  • 18.
    Immutability example ; LISP (defineanimals (list 'dog 'cat 'fish)) (cons 'horse animals) ; returns a new list of animals, not changing existing one // F# let animals = ["dog";"cat";"rat"] let moreAnimals = List.append animals ["horse"] // returns a new list // C# var animals = new ReadOnlyCollection<string>(new[] { "dog", "cat", "fish" }); var moreAnimals = animals.Append("horse"); // returns new Enumerable
  • 19.
    The sin ofimpurity public async Task HookNextBuild(IProject project, Task buildFinished) { var buildStarted = SyncEvents.VsBuildStarted(this.VsPid).ToTask(); // IPC await Task.WhenAny(buildStarted, buildFinished).ConfigureAwait(false); if (this.recentAnalysisCompletion != null) { await this.recentAnalysisCompletion; this.recentAnalysisCompletion = null; this.recentCompletionTime = DateTime.Now; // Time } var analysisCompletion = await this.LaunchAnalysisAsync(project); this.recentAnalysisCompletion = analysisCompletion; }
  • 20.
    Purity  The propertyof functions not to have side-effects and any dependence from external state or time  Function is considered pure when:  The function always evaluates the same result value given the same argument value(s)  Evaluation of the result does not cause any side effect  Application:  Simplifies testing  Simplifies parallel computing  Allows memoization
  • 21.
    Purity example // inF# let inc x = x + 1 // pure function let mutable i = 0 let badInc () = i <- i + 1 // impure function ; in LISP (define (inc x) (+ x 1)) ; pure function (define i 1) (define (bad-inc!) (set! i (+ i 1))) // in C# Math.Pow(2, 8); // pure function Path.GetTempFileName() ; // impure function DateTime.Now; // impure function
  • 22.
    First-class and Higher-orderfunctions  First-class functions is a property of programming language to treat functions as a standard datatype  Function is considered higher-order function when it does at least one of the following:  takes one or more functions as arguments  returns a function as its result
  • 23.
    First-class and Higher-orderfunctions // C# // toUpper is first-class function Func<string, string> toUpper = str => str.ToUpper(); // Select is higher-order function new[] { "dog", "cat" }.Select(toUpper); // F# // fun x -> -x is first-class function & Seq.sortBy is higher-order function [22;31;1;5;7] |> Seq.sortBy(fun x -> -x) // >> is a higher-order function, it returns a composition of the functions (add1 >> add1) 1 // 3
  • 24.
    Recursion  Recursion isidiomatic way to perform iterations or lopping in functional programming languages  Tail recursion usually can be recognized and optimized by a compiler  Mutual recursion may require trampoline to handle it  To iterate is human, to recurse, divine (L. Peter Deutsch)
  • 25.
    Recursion example (LISP) ;mutual recursion (define (r1 i) (if (< i 0) 1 (r2 (- i 1)))) (define (r2 i) (if (< i 0) 1 (r1 (- i 1)))) (r1 1000000) ; tail recursion (define (factorial x) (if (< x 2) 1 (* x (factorial (- x 1)))))
  • 26.
    Recursion example (F#) //mutual recursion let rec r1 i = if i < 0 then 1 else r2(i - 1) and r2 i = if i < 0 then 1 else r1(i - 1) // tail recursion let rec factorial x = if x < 2 then 1 else x * factorial(x - 1)
  • 27.
    Derived FP concepts Closures  Partial application  Lazy evaluation First-class & Higher-order functions
  • 28.
    Closures  A datastructure containing a lambda expression, and an environment to be used when that lambda expression is applied to arguments  Closures are used to:  bind together data and behavior (just like objects in OOP)  emulate state  emulate object system function environment in which function got created closure object
  • 29.
    Closure example inF# (simple and artificial) // creates a function that raises y to a power of x let makePowerFn x = (fun y -> pown y x) // this lambda is a closure itself (because of reference to x) let pow2 = makePowerFn 2 pow2 3 // 9 let pow3 = makePowerFn 3 pow3 3 // 27
  • 30.
    Closure example: purerecursive data structures type Seq = { value: int; next: (unit -> Seq) } let rec initSeq next value : Seq = { value = value; // return current value next = (fun () -> initSeq next (next value)) // create a new sequence with the next value } let pow2Seq = initSeq (fun x -> x * 2) 2 // sequence of powers of 2 pow2Seq.value // 2 pow2Seq.next().next().value // 8 // doesn’t it look like enumerator.MoveNext().MoveNext().Current in C#?
  • 31.
    Closure example: trampoline(in JavaScript) function factorial (n) { return n < 2 ? 1 : n * factorial(n -1); } factorial(3); // 6 /* maximum call stack size exceeded */ factorial(100000); function trampoline (fn) { while ( typeof fn === 'function') { fn = fn(); } return fn; } function factorial (n, acc = 1) { return function () { return (n < 2) ? acc : factorial(n - 1, n * acc); } } /* no errors */ trampoline(factorial(100000));
  • 32.
    Partial application  Processof breaking a single function into a multiple ones of smaller arity  Often conflated/mixed with currying witch is a process of breaking a function of n arguments to a chain of n functions of 1 argument each  Motivation is that very often the functions obtained by supplying some but not all of the required arguments  papply: (((a × b) → c) × a) → (b → c) = λ(f, x). λy. f (x, y)  curry: ((a × b) → c) → (a → (b → c)) = λf. λx. λy. f (x, y)  uncurry: (a → (b → c)) → ((a × b) → c) = λf. λ(x, y). f x y
  • 33.
    Partial application example(simple & artificial) // F# let add1 x = x + 1 // traditional definition vs application let add1 = (+) 1 let sortAsc = List.sortWith (fun x y -> x - y) let sortDsc = List.sortWith (fun x y -> y - x) // C# Func<string, Claim> newClaim = value => new Claim( "group", value, "String", “sigma.software "); /*…*/ var groups = RetrieveGroups(); // { "Management", "Accountants“ }; var groupClaims = groups.Select(newClaim);
  • 34.
    Partial application (C#) publicclass Package { private readonly IContentReader contentReader; private readonly IChecksumGenerator checksumGenerator; private readonly IChecksumFormatter checksumFormatter; public Package( string name, IContentReader contentReader, IChecksumGenerator checksumGenerator, IChecksumFormatter checksumFormatter) { this.Name = name; this.contentReader = contentReader; this.checksumGenerator = checksumGenerator; this.checksumFormatter = checksumFormatter; } public string Name { get; } public string GetChecksumStr(Encoding encoding) => this.checksumFormatter.Format( this.checksumGenerator.Generate(contentReader.Read()), encoding); } public interface IContentReader { Stream Read(); } public interface IChecksumGenerator { byte[] Generate(Stream dataStream); } public interface IChecksumFormatter { string Format( byte[] checksum, Encoding encoding); }
  • 35.
    Partial application (F#) typePackage = { name: string; getChecksumStr: (Encoding -> string) } let initPackage (name: string) (content: (unit -> Stream)) (generateChecksum: ((unit -> Stream) -> byte[])) (formatChecksum:(byte[] -> Encoding -> string)) : Package = { name = name; getChecksumStr = content |> generateChecksum |> formatChecksum }
  • 36.
    Lazy evaluation  Lazyevaluation is a way of computing in which values are not calculated until they are required  Lazy evaluation can be accomplished:  By language itself (Haskell)  Using special data structures  The opposite of lazy evaluation called eager evaluation  Application:  Infinite data structures  Memory footprint optimization  Startup speed optimization  Often combined with memorization
  • 37.
    Lazy evaluation example(simple & artificial - F#) // F# let lazyVal = lazy (10 * 10) lazyVal // Lazy<int> Value is not created. lazyVal.Force() // 100 let nat = Seq.initInfinite(fun n -> n + 1) // seq<int> = seq [1; 2; 3; 4; ...] Seq.skip 10 nat |> Seq.take 10 // seq<int> = seq [11; 12; 13; 14; ...]
  • 38.
    Lazy evaluation example(F#) type Package = { name: string; getChecksumStr: (Encoding -> string) } let initPackage (name: string) (content: (unit -> Stream)) (generateChecksum: ((unit -> Stream) -> byte[])) (formatChecksum:(byte[] -> Encoding -> string)) : Package = let checksum = lazy (content |> generateChecksum) { name = name; getChecksumStr = checksum.Value |> formatChecksum }
  • 39.
    Pattern matching  Languagefeature that allows to choose the following instruction set based on the match of given data with one of the declared patterns:  Constants  Predicates (functions that return Boolean values)  Data type  Anything else supported by a particular language
  • 40.
    Pattern matching example //F# let ReadFromFile reader : StreamReader) = match reader.ReadLine() with | null -> printfn "n"; false | line -> printfn "%s" line; true // C# public static double ComputeArea (object shape) { switch (shape) { case Square s: return s.Side * s.Side; case Circle c: return c.Radius * c.Radius * Math.PI; case Rectangle r: return r.Height * r.Length; default: throw new ArgumentException(); } }
  • 41.
    Concepts comparison Goal OOPFP Binding data & behavior Class -> Object Closure Passing dependencies Constructor Partial application Decoupling from concrete implementation Interface Function signature Controlling execution flow Switch statement Pattern matching
  • 42.
    Summary  Fundamentals concepts: Immutability  Simplifies reasoning & testing; Increases scalability & reliability;  Purity  Simplifies reasoning and testing; Increases scalability & reliability;  First-class, higher-order functions  Closures  Functional way to bind data and behavior  Partial application  Functional way to have constructors  Lazy evaluation  Speed ups initialization
  • 43.
    What’s next?  Statemanagement  The problem of state  Approaches of managing the state and side-effects  Continuations  Promises  Monads  FRP
  • 44.
    Books  Structure andinterpretation of computer programs  MIT course 6.037  Introduction to Functional Programming  Cambridge CS department  Hackers and painters  Google Play Books  Amazon
  • 45.
    Articles  Rich Hickey– Simple made Easy  https://github.com/matthiasn/talk- transcripts/blob/master/Hickey_Rich/SimpleMadeEasy.md  Vladimir Khorikov - Functional C#  https://github.com/vkhorikov/CSharpFunctionalExtensions  Robert Martin – FP vs OO  http://blog.cleancoder.com/uncle-bob/2014/11/24/FPvsOO.html  Why Functional Programming matters  https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf  Me - LISP: back to the future (a tribute to 60th anniversary):  https://sigma.software/about/media/lisp-back-future-tribute-60th- anniversary
  • 46.
    Credits  Penrose triangle© Tobias R. – Metoc [CC BY-SA 2.5] / Wikimedia Commons  Six petal lotus © Christopher J. Fynn [CC BY-SA 3.0] / Wikimedia Commons  Two intersecting Archimedean spirals of opposite directions © Nevit Dilmen [GFDL, CC-BY-SA-3.0 or CC BY-SA 2.5] / Wikimedia Commons  Objects should be immutable © Yegor Bugayenko  Scheme: An interpreter for extended lambda calculus © Sussman and Steele

Editor's Notes

  • #6 Любопытно что функциональная парадигма появилась так давно. Раньше чем структурное и чем GOTO стал considered harmful. LISP – Первый функциональный и второй высокоуровневый язык –после FORTRAN, до сих пор наголову превосходит большинство языков общего назначения по своим возможностям. Первый язык с IF, garbage collection, функции как базовый тип данных, возможности метапрограммирования
  • #7 Что интересно что Джон Маккарти (автор LISP и термина Искусственный интеллект) сам признавал что не понял работу Алонзо Чёрча
  • #8 Выписал основные языки. Тут важно отметить 2 семейства которые повлияли на все остальные: LISP & ML
  • #9 Интерес к древней функциональной парадигме, в значительной мере пропорционален изменению наших вычислительных возможностей. Ядер становится всё больше при том что тактовая частота не сильно поменялась со средины нулевых
  • #10 Заметим, что кроме центрального процессора мы имеет графический, который отличается наличием ТЫСЯЧ ядер, которые могут выполнять параллельные вычисления (пусть и узкоспециализированные)
  • #11 И вот последний важный момент связанный с ограничениями железа, цена на оперативную память радикально (экспоненциально), аргумент против «более прожорливых» функциональных языков более не актуален.
  • #12 Сразу к примеру, почему императивный подход оказался нерабочим в новых условиях
  • #13 Каждая операция не зависит друг от друга, может выполнятся поралельно
  • #14 Прежде чем перейти к основным понятиям функционального программирования интересно напомнить ОО
  • #16 Прежде чем перейти к основным понятиям функционального программирования интересно напомнить ОО/ Мне кажется очень удобно подойти к этому вопросу также как мы подходим к ОО. Здесть тоже можно выделить 4 принципа. При этом что важно все присущие ОО свойства кроме наследования остаются в силе и в рамках ФП
  • #18 То что на первый взгляд кажется ограничением, в реальности крайне полезное свойство избавляющее разработчика от множества дефектов
  • #19 Здесь возникает вопрос, не расточительно ли создавать каждый раз новые объекты, вместо того что бы изменять существующие?
  • #20 Опять совершенное реальный пример, с реального проекта. Очень важная функция совершенно не тестируема, а результат её работы не воспроизводим. Она явным образом совершает 2 вещи которые нарушают свойство её «чистоты»: Ждёт сигналов от других процессов Зависит от реального времени (DateTime.Now)
  • #21 Кошерный код в данном контексте приобретает весьма определённое значение
  • #22 Кошерный код в данном контексте приобретает весьма определённое значение
  • #25 Помним, что в функциональный языках нельзя менять состояние объектов. По этому цикл for int i = 0; i<10;i++ не катит
  • #31 Очень похоже на enumerator в C#, но здесь состояние только эмулируется. Всё это чистые функции
  • #32 Элегантный костыль для языков с фиксированным стеком вызовов
  • #33 Керрирование названо в честь Хаскеля Карри
  • #35 Реальный пример, реального проекта. Чексумма вычисляется только при необходимости Но причём тут частично применение?
  • #36 Реальный пример, реального проекта. Чексумма вычисляется только при необходимости Но причём тут частично применение?
  • #39 Реальный пример, реального проекта. Чексумма вычисляется только при необходимости Но причём тут частично применение?
  • #42 Если всё так похоже почему так получилось что мы пользуем ООП?
  • #43 Что важно. Это парадигма, это не конкретный язык. Как минимум принципам неизменяемости и чистоты вы можете следовать в любом языке
  • #45 Introduction to Functional Programming (1996/7) - John Harrison