• Funtional Programming (FP) is a Programming paradigm, that is, a methodology for how to write programs
  1. Main idea: the calculation process as far as possible into a series of reusable function calls
  2. Main features: Functions are “first class citizens” : Functions have the same status as other data types, and can be assigned to other variables, function parameters, and function return values
  • Functional programming first appeared in LISP, and most code programming languages also support functional programming to varying degrees, such as Haskell, JavaScript, Python, Swift, Kotlin, Scala, etc
  • Several commonly used concepts in functional programming
  1. Higher-order Function, Function Currying
  2. Functor, Applicatie Functor, Monad
  • References: http://www.mokacoding.com/blog/functor-applicative-monads-in-pictures/ ——————————————————————————–

FP practice – traditional writing

  • Regular writing
[(num + 3) * 5-1] % 10/2 let num = 1 func add(_ v1: Int, _ v2: Int) -> Int {v1 + v2} func sub(_ v1: Int, _ v2: Int) Int, _ v2: Int) -> Int { v1 - v2 } func multiple(_ v1: Int, _ v2: Int) -> Int { v1 * v2 } func divide(_ v1: Int, _ v2: Int) -> Int { v1 / v2 } func mod(_ v1: Int, _ v2: Int) -> Int { v1 % v2 } let result = divide(mod(sub(multiple(add(num, 3), 5), 1), 10), 2) print(result) // 4Copy the code

FP practice – functional writing

  • Currie,
func add(_ v: Int) -> (Int) -> Int { { $0 + v } }
func sub(_ v: Int) -> (Int) -> Int { { $0 - v } }
func multiple(_ v: Int) -> (Int) -> Int { { $0 * v } }
func divide(_ v: Int) -> (Int) -> Int { { $0 / v } }
func mod(_ v: Int) -> (Int) -> Int { { $0 % v } }Copy the code
  • Function synthesis
func composite(_ f1: @escaping (Int) -> Int, 
               _ f2: @escaping (Int) -> Int) -> (Int) -> Int {
        return { f2(f1($0)) }           
}
let fn = composite(add(3), multiple(5))
print(fn(num)) // 20Copy the code
  • Function composition – using symbols
infix operator >>>: AdditoinPrecedence func >>>(_ f1: @escaping (Int) -> Int, _ f2: @escaping (Int) -> Int) -> (Int) -> Int { return { f2(f1($0)) } } let fn = add(3) >>> multiple(5) print(fn(num)) // 20 Function synthesis - Using symbols - generic infix Operator >>>: AdditoinPrecedence func >>> <A, B, C>(_ F1: @escaping (A) -> B, f2: @escaping (B) -> C) -> (A) -> C { return { f2(f1($0)) } } let fn = add(3) >>> multiple(5) print(fn(num)) // 20Copy the code
let fn = add(3) >>> multiple(5) >>> sub(1) >>> mod(10) >>> divide(2)
print(fn(num)) // 4Copy the code

Higher-order functions

  • A higher-order function is one that satisfies at least one of the following conditions:
  1. Take one or more functions as input (Map, filter, reduce, etc.)
  2. Return a function
  • FP is full of higher order functions

Currying

  • Transform a function that takes many arguments into a series of functions that take only one argument
func add1(_ v1: Int, _ v2: Int) -> Int { v1 + v2 }
add1(10, 20)
func add1(_ v: Int) -> (Int) -> Int { { $0 + v } }
add1(10)(20)Copy the code
  • The Array and Optional map methods take an argument that is a Currization function
  • Three parameters are currified
func add2(_ v1: Int, _ v2: Int, v3: Int) -> Int { v1 + v2 + v3 } func add2(_ v3: Int) -> (Int) -> (Int) -> Int { // v2 == 20 return { v2 in // v1 == 10 return { v1 in return v1 + v2 + v3 } } } add2(10,  20, 30) add2(30)(20)(10)Copy the code
  • Two parameters are Currified – generic
func currying<A, B, C>(_ fn: @escaping (A, B) -> C) -> (B) -> (A) -> C {
    return { b in
        return { a in
            return fn(a, b)
        }
    }
}
currying(add1(20)(10))Copy the code
  • Two parameters are corrified – using symbols – generics
prefix func ~<A, B, C>(_ fn: @escaping (A, B) -> C) -> (B) -> (A) -> C { { b in { a in fn(a, B)}}} print ((~ sub (20) (10)) / / - 10 / / synthetic function - > generic currie, let fn = (add) ~ (3) > > > (multiple) ~ (5) > > > (sub) ~ (1) > > > (mod) ~ (10) >>> (~divide)(2) print(fn(1)) // 4Copy the code
  • The three parameters are corrified – using symbols – generics
prefix func ~<A, B, C, D>(_ fn: @escaping (A, B, C) -> D) 
                            -> (C) -> (B) -> (A) -> D { 
    { c in { b in { a in fn(a, b, c) } } }
}
print((~add2)(30)(20)(10)) // 60Copy the code

Functor

  • Types that support map operations, such as Array and Optional, are called functors
  • What kind of Type is a functor?
func map<T>(_ fn: (Inner) -> T) -> Type<T>Copy the code
  • Arrays and options are formulae that conform to functors:
func map<T>(_ fn: (Element) -> T) -> Array<T>   // [T]
func map<T>(_ fn: (Wrapped) -> T) -> Opional<T> // T?Copy the code

Applicative Functor

  • Any functor F is an applicable functor if it supports the following operation
func pure<A>(_ value: A) -> F<A>
func <*><A, B>(fn: F<(A) -> B>, value: F<A>) -> F<B>Copy the code
  • Optional can be an applicable functor
func pure<A>(_ value: A) -> A? { value } infix operator <*>: AdditionPrecedence func <*><A, B>(fn: ((A) -> B)? , value: A?) -> B? { guard let f = fn, let v = value else { return nil } return f(v) }Copy the code
var value: Int? = 10
var fn: ((Int) -> Int)? = { $0 * 2 }
// Optional
print(fn <*> value as Any)Copy the code

  • Array can be an applicable functor
func pure<A>(_ value: A) -> [A] { [value] } func <*><A, B>(fn: [(A) -> B], value: [A]) -> [B] { var arr: [B] = [] if fn.count == value.count { for i in fn.startIndex.. <fn.endIndex { arr.append(fn[i](value[i])) } } return arr }Copy the code
// [10]
print(pure(10))
var arr = [{ $0 * 2 }, { $0 + 10 }, { $0 - 5 }] <*> [1, 2, 3]
// [2, 12, -2]
print(arr)Copy the code

Monad

  • Any type F can be a Monad if it supports the following operations.
func pure<A>(_ value: A) -> F<A>
func flatMap<A, B>(_ value: F<A>, _ fn: (A) -> F<B>) -> F<B>Copy the code
  • Array and Optional are lists