# 函数式编程与并行计算

### 并行计算的方式

• 进程
• 线程
• 协程(coroutine)/纤程(fiber)
• Future/Task
• Async/Await
• Actor
• … …

Oh, no! 我该怎么选？

From Akka:

We believe that writing correct concurrent & distributed, resilient and elastic applications is too hard. Most of the time it’s because we are using the wrong tools and the wrong level of abstraction.

### Functor可以简单视作对于map的抽象

Formally, a functor is a type F[A] with an operation map with type (A => B) => F[B].

trait Functor[F[_]]:
extension [A, B](x: F[A])
def map(f: A => B): F[B]


Functor Laws:

Functors guarantee the same semantics whether we sequence many small operations one by one, or combine them into a larger function before mapping. To ensure this is the case the following laws must hold:

• Identity: calling map with the identity function is the same as doing nothing:

fa.map(a => a) == fa

• Composition: mapping with two functions f and g is the same as mapping with f and then mapping with g:

fa.map(g(f(_))) == fa.map(f).map(g)

map之外，当然还有flatMap

### 一个单子(Monad)说白了不过就是自函子范畴上的一个幺半群而已(🐶

Monadic behaviour is formally captured in two operations: pure and flatMap:

trait Monad[F[_]] extends Functor[F]:

def pure[A](x: A): F[A]

extension [A, B](x: F[A])
def flatMap(f: A => F[B]): F[B]

def map(f: A => B): F[B] = x.flatMap(f.andThen(pure))


Monad Laws:

pure and flatMap must obey a set of laws that allow us to sequence operations freely without unintended glitches and side-effects:

• Left identity: calling pure and transforming the result with func is the same as calling func:

pure(a).flatMap(func) == func(a)

• Right identity: passing pure to flatMap is the same as doing nothing:

m.flatMap(pure) == m

• Associativity: flatMapping over two functions f and g is the same as flatMapping over f and then flatMapping over g:

m.flatMap(f).flatMap(g) == m.flatMap(x => f(x).flatMap(g))