- Funtional Programming (FP) is a Programming paradigm, that is, a methodology for how to write programs
- Main idea: the calculation process as far as possible into a series of reusable function calls
- 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
- Higher-order Function, Function Currying
- 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:
- Take one or more functions as input (Map, filter, reduce, etc.)
- 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