Functional Language

Why Funcational Language?

  • 單核程式不夠用
  • Multithreading Program 的困難
    • 每個存取到的共享變數都要 synchronize
    • 操作必須注意 Atomic
    • 要有策略可以避免 Deadlock
    • 每個用到的 library 都要滿足以上三點
    • Synchronize 太多了,都是 blocking thread,程式同時間可能只有一個 thread 在跑

Mutable shared state

Forget Everything you know

Functional Language 

  • Erlang
  • Clojure
  • Scala
  • F#,
  • Haskell

Purity

  • Pure functions
    • Pure Functions are very simple functions. They only operate on their input parameters.
var z = 10;
function add(x, y) {
  return x + y;
}

Pure Functions

  • Most useful Pure Functions must take at least one parameter.
  • All useful Pure Functions must return something.
  • Pure Functions will always produce the same output given the same inputs.
function justTen() {
    return 10;
}

function addNoReturn(x, y) {
    var z = x + y
}


function add(x, y) {
    return x + y;
}
console.log(add(1, 2)); // prints 3
console.log(add(1, 2)); // still prints 3
console.log(add(1, 2)); // WILL ALWAYS print 3

Immutability

  • Functional Programming deals with changes to values in a record by making a copy of the record with the values changed. It does this efficiently without having to copy all parts of the record by using data structures that makes this possible.
addOneToSum y z =
    let
        x = 1
    in
        x + y + z

Recursion

  • Functional Programming uses recursion to do looping.
// simple loop construct
var acc = 0;
for (var i = 1; i <= 10; ++i)
    acc += i;
console.log(acc); // prints 55


// without loop construct or variables (recursion)
function sumRange(start, end, acc) {
    if (start > end)
        return acc;
    return sumRange(start + 1, end, acc + start)
}
console.log(sumRange(1, 10, 0)); // prints 55

Higher-Order Function 

  • In Functional Programming, a function is a first-class citizen of the language. In other words, a function is just another value.
  • Higher-order Functions either take functions as parameters, return functions or both.

Why we need Higher-Order Function?

function validateSsn(ssn) {
    if (/^\d{3}-\d{2}-\d{4}$/.exec(ssn))
        console.log('Valid SSN');
    else
        console.log('Invalid SSN');
}
function validatePhone(phone) {
    if (/^\(\d{3}\)\d{3}-\d{4}$/.exec(phone))
        console.log('Valid Phone Number');
    else
        console.log('Invalid Phone Number');
}

Why we need Higher-Order Function?

function validateSsn(ssn) {
    if (/^\d{3}-\d{2}-\d{4}$/.exec(ssn))
        console.log('Valid SSN');
    else
        console.log('Invalid SSN');
}
function validatePhone(phone) {
    if (/^\(\d{3}\)\d{3}-\d{4}$/.exec(phone))
        console.log('Valid Phone Number');
    else
        console.log('Invalid Phone Number');
}
function validateValue(value, regex, type) {
    if (regex.exec(value))
        console.log('Invalid ' + type);
    else
        console.log('Valid ' + type);
}

Why we need Higher-Order Function?

function validateAddress(address) {
    if (parseAddress(address))
        console.log('Valid Address');
    else
        console.log('Invalid Address');
}
function validateName(name) {
    if (parseFullName(name))
        console.log('Valid Name');
    else
        console.log('Invalid Name');
}
function validateValueWithFunc(value, parseFunc, type) {
    if (parseFunc(value))
        console.log('Invalid ' + type);
    else
        console.log('Valid ' + type);
}

Higher-Order Function

validateValueWithFunc('123-45-6789', /^\d{3}-\d{2}-\d{4}$/.exec, 'SSN');
validateValueWithFunc('(123)456-7890', /^\(\d{3}\)\d{3}-\d{4}$/.exec, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');
function validateValueWithFunc(value, parseFunc, type) {
    if (parseFunc(value))
        console.log('Invalid ' + type);
    else
        console.log('Valid ' + type);
}
var parseSsn = /^\d{3}-\d{2}-\d{4}$/.exec;
var parsePhone = /^\(\d{3}\)\d{3}-\d{4}$/.exec;
validateValueWithFunc('123-45-6789', parseSsn, 'SSN');
validateValueWithFunc('(123)456-7890', parsePhone, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');

Higher-Order Function

validateValueWithFunc('123-45-6789', /^\d{3}-\d{2}-\d{4}$/.exec, 'SSN');
validateValueWithFunc('(123)456-7890', /^\(\d{3}\)\d{3}-\d{4}$/.exec, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');
function validateValueWithFunc(value, parseFunc, type) {
    if (parseFunc(value))
        console.log('Invalid ' + type);
    else
        console.log('Valid ' + type);
}
function makeRegexParser(regex) {
    return regex.exec;
}
var parseSsn = makeRegexParser(/^\d{3}-\d{2}-\d{4}$/);
var parsePhone = makeRegexParser(/^\(\d{3}\)\d{3}-\d{4}$/);
validateValueWithFunc('123-45-6789', parseSsn, 'SSN');
validateValueWithFunc('(123)456-7890', parsePhone, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');

Closures

function makeAdder(constantValue) {
    return function adder(value) {
        return constantValue + value;
    };
}

var add10 = makeAdder(10);
console.log(add10(20)); // prints 30
console.log(add10(30)); // prints 40
console.log(add10(40)); // prints 50

Closures

function grandParent(g1, g2) {
    var g3 = 3;
    return function parent(p1, p2) {
        var p3 = 33;
        return function child(c1, c2) {
            var c3 = 333;
            return g1 + g2 + g3 + p1 + p2 + p3 + c1 + c2 + c3;
        };
    };
}

A closure is a function’s scope that’s kept alive by a reference to that function.

Function Composition

Code reuse sounds great but is difficult to achieve.

Make the code too specific and you can’t reuse it. Make it too general and it can be too difficult to use in the first place.

var add10 = function(value) {
    return value + 10;
};
var mult5 = function(value) {
    return value * 5;
};
var add10 = value => value + 10;
var mult5 = value => value * 5;
var mult5AfterAdd10 = value => 5 * (value + 10) 
var mult5AfterAdd10 = value => mult5(add10(value));

Point-Free Notation

  • There is a style of writing functions without having to specify the parameters called Point-Free Notation
  • If not a point-free notation, what will happened ?
var add10 = (x, y) => x + y;
var mult5 = value => value * 5;
var mult5AfterAdd10 = y => mult5(add(10, y));

No longer just combining functions!

Curry

  • A Curried Function is a function that only takes a single parameter at a time.
var add = x => y => x + y;
var compose = (f, g) => x => f(g(x));
var mult5AfterAdd10 = compose(mult5, add(10));

Referential Transparency

  • Referential Transparency is a fancy term to describe that a pure function can safely be replaced by its expression. An example will help illustrate this.
quote str =
    "'" ++ str ++ "'"
findError key =
    "Unable to find " ++ (quote key)
findError key =
   "Unable to find " ++ ("'" ++ str ++ "'")

Common Functional Functions

Common Functional Functions

var things = [1, 2, 3, 4];
for (var i = 0; i < things.length; ++i) {
    things[i] = things[i] * 10; // MUTATION ALERT !!!!
}
console.log(things); // [10, 20, 30, 40]
var things = [1, 2, 3, 4];
var newThings = [];
for (var i = 0; i < things.length; ++i) {
    newThings[i] = things[i] * 10;
}
console.log(newThings); // [10, 20, 30, 40]
var map = (f, array) => {
    var newArray = [];
    for (var i = 0; i < array.length; ++i) {
        newArray[i] = f(array[i]);
    }
    return newArray;
};

var newThings = map(v => v * 10, things);

Execution Order

1. Get out the bread
2. Put 2 slices into the toaster
3. Select darkness
4. Push down the lever
5. Wait for toast to pop up
6. Remove toast
7. Get out the butter
8. Get a butter knife
9. Butter toast
Thread 1
--------
1. Get out the bread
2. Put 2 slices into the toaster
3. Select darkness
4. Push down the lever
5. Wait for toast to pop up
6. Remove toast
Thread 2
--------
1. Get out the butter
2. Get a butter knife
3. Wait for Thread 1 to complete
4. Butter toast

Execution Order

  • First, they must be pure functions.
  • The second thing that must be true for independence is that the output of one function is not used as the input of the other.

The order of execution in a Pure Functional Language can be determined by the compiler.

buildMessage message value =
    let
        upperMessage =
            String.toUpper message
        quotedValue =
            "'" ++ value "'"
    in
        upperMessage ++ ": " ++ value

Type Annotations

private final Map<Integer, String> getPerson(Map<String, String> people, Integer personId) {
   // ...
}
var getPerson = function(people, personId) {
    // ...
};
add : Int -> Int -> Int
add x y =
    x + y

Functional JS

  • Immutability - const
  • Currying and Composition
  • Ramda.js
const a = {
    x: 1,
    y: 2
};
a.x = 2; // NO EXCEPTION!
a = {}; // this will throw a TypeError


#curry

const f = a => b => c => d => a + b + c + d

Function language

By Stanney Yen

Function language

Function Language intro

  • 274