由于泛函编程非常重视函数组合（function composition），任何带有副作用（side effect）的函数都无法实现函数组合，所以必须把包含外界影响（effectful）副作用不纯代码（impure code）函数中的纯代码部分（pure code）抽离出来形成独立的另一个纯函数。我们通过代码抽离把不纯代码逐步抽离向外推并在程序里形成一个纯代码核心（pure core）。这样我们就可以顺利地在这个纯代码核心中实现函数组合。IO Monad就是泛函编程处理副作用代码的一种手段。我们先用个例子来示范副作用抽离：

```1 case class Player(name: String, score: Int)
2 def printWinner(p: Player): Unit =
3     println(p.name + " is the winner!")
4 def declareWinner(p1: Player, p2: Player): Unit =
5   if (p1.score > p2.score ) printWinner(p1)
6   else printWinner(p2)```

```1 def printWinner(p: Player): Unit =
2     println(p.name + " is the winner!")
3 def winner(p1: Player, p2: Player): Player =
4   if (p1.score > p2.score) p1
5   else p2
6 def declareWinner(p1: Player, p2: Player): Unit =
7   printWinner(winner(p1, p2))```

```1 def winnerMsg(p: Player): String =
2   p.name + " is the winner!"
3 def printWinner(p: Player): Unit =
4     println(winnerMsg(p))
5 def winner(p1: Player, p2: Player): Player =
6   if (p1.score > p2.score) p1
7   else p2
8 def declareWinner(p1: Player, p2: Player): Unit =
9   printWinner(winner(p1, p2))```

1、一个纯函数：A => D, 这里D只是一个功能描述表达式

2、一个带副作用的非纯函数： D => B, 它可以被视为D的解译器（interpreter）,把描述解译成有副作用的指令

``` 1 trait IO {def run: Unit }
2 def printLine(line: String) : IO = new IO {
3     def run = println(line)
4 }
5 def printWinner(p: Player): IO =
6     printLine(winnerMsg(p))
7 case class Player(name: String, score: Int)
8 def winnerMsg(p: Player): String =
9   p.name + " is the winner!"
10 def winner(p1: Player, p2: Player): Player =
11   if (p1.score > p2.score) p1
12   else p2
13 def declareWinner(p1: Player, p2: Player): Unit =
14   printWinner(winner(p1, p2))```

```1 trait IO[+A] { self =>
2     def run: A
3     def map[B](f: A => B): IO[B] =
4       new IO[B] { def run = f(self.run)}
5     def flatMap[B](f: A => IO[B]): IO[B] =
6       new IO[B] {def run = f(self.run).run}
7 }```

```1 object IO extends Monad[IO] {
2     def unit[A](a: A) = new IO[A] {def run = a}
3     def flatMap[A,B](ma: IO[A])(f: A => IO[B]) = ma flatMap f
4     def map[A,B](ma: IO[A])(f: A => B) = ma map f
5     def apply[A](a: A) = unit(a)  //IO构建器，可以实现  IO {...}
6 }```

```1 def ReadLine: IO[String] = IO { readLine }
2 def PrintLine(msg: String): IO[Unit] = IO { println(msg) }
3 def fahrenheitToCelsius(f: Double): Double =
4   (f -32) * 5.0 / 9.0
5 def converter: IO[Unit] = for {
6     _ <- PrintLine("Enter a temperature in degrees fahrenheit:")
8     _ <- PrintLine(fahrenheitToCelsius(d).toString)
9 } yield ()```

```1 trait IO[A] {def run: A}
2 case class Pure[+A](a: A) extends IO[A]
3 case class Request[Extenal[_],I,A](expr: Extenal[I], cont: I => IO[A]) extends IO[A]```

```1 trait Runnable[A] { def run: A }
2 object Delay {
3     def apply[A](a: A) = new Runnable[A] { def run = a}
4 }
5 Delay {println("SIDE EFFECTS!!!")}```

```1 trait IO[F[_],+A] {}
2 case class Pure[F[_],+A](get: A) extends IO[F,A]
3 case class Request[F[_],I,+A](expr: F[I], cont: I => IO[F,A]) extends IO[F,A]```

```1 trait Console[A]
2 case object ReadLine extends Console[Option[String]]
3 case class PrintLine(msg: String) extends Console[Unit]```

``` 1 trait Run[F[_]] {
2     def apply[A](expr: F[A]): (A, Run[F])
3 }
4 object IO {
5     def run[F[_],A](R: Run[F])(io: IO[F,A]): A = io match {
6         case Pure(a) => a
7         case Request(expr, cont) => R(expr) match {
8           case (a,r2) => run(r2)(cont(a))
9         }
10     }
11 }```

``` 1 trait Console[A]
2 case object ReadLine extends Console[Option[String]]
3 case class PrintLine(msg: String) extends Console[Unit]
4
5 object RunConsole extends Run[Console] {
6     def apply[A](c: Console[A]): (A, Run[Console]) = c match {
8             val r = try Some(readLine) catch { case _ => None }
9             (r, RunConsole)
10         }
11         case PrintLine(m) => (println(m),RunConsole)
12     }
13 }
14 IO.run(RunConsole)(ioprg)```

``` 1 trait IO[F[_],A] {
2  def unit(a: A) = Pure(a)
3  def flatMap[B](f: A => IO[F,B]): IO[F,B] = this match {
4      case Pure(a) => f(a)
5 //     case Request(expr,cont) => Request(expr, cont andThen (_ flatMap f))
6   case Request(expr,cont) => Request(expr, (x: Any) => cont(x) flatMap f)
7  }
8  def map[B](f: A => B): IO[F,B] = flatMap(a => Pure(f(a)))
9 }
10 case class Pure[F[_],A](get: A) extends IO[F,A]
11 case class Request[F[_],I,A](expr: F[I], cont: I => IO[F,A]) extends IO[F,A]```

```1 def ioMonad[F[_]] = new Monad[({type l[x] = IO[F, x]})#l] {
2   def unit[A](a: A) = Pure(a)
3   def flatMap[A,B](fa:IO[F,A])(f: A => IO[F,B]): IO[F,B] = fa flatMap f
4   def map[A,B](fa: IO[F,A])(f: A => B): IO[F,B] = fa map f
5
6 }```

``` 1 trait IO[F[_],A] {
2  def unit(a: A) = Pure(a)
3  def flatMap[B](f: A => IO[F,B]): IO[F,B] = this match {
4      case Pure(a) => f(a)
5 //     case Request(expr,cont) => Request(expr, cont andThen (_ flatMap f))
6   case Request(expr,cont) => Request(expr, (x: Any) => cont(x) flatMap f)
7  }
8  def map[B](f: A => B): IO[F,B] = flatMap(a => Pure(f(a)))
9  def runM[F[_],A](F: Monad[F])(io: IO[F,A]): F[A] = io match {
10       case Pure(a) => F.unit(a)
11 //      case Request(expr, cont) => F.flatMap(expr)(cont andThen (_.runM(F)(io)))
12       case Request(expr, cont) => F.flatMap(expr)(x => cont(x).runM(F)(io))
13  }
14 }
15 case class Pure[F[_],A](get: A) extends IO[F,A]
16 case class Request[F[_],I,A](expr: F[I], cont: I => IO[F,A]) extends IO[F,A]```

``` 1 trait IO[F[_],A] {
2  def unit(a: A) = Pure(a)
3  def flatMap[B](f: A => IO[F,B]): IO[F,B] = this match {
4      case Pure(a) => f(a)
5 //     case Request(expr,cont) => Request(expr, cont andThen (_ flatMap f))
6   case Request(expr,cont) => Request(expr, (x: Any) => cont(x) flatMap f)
7  }
8  def map[B](f: A => B): IO[F,B] = flatMap(a => Pure(f(a)))
9 }
10 case class Pure[F[_],A](get: A) extends IO[F,A]
11 case class Request[F[_],I,A](expr: F[I], cont: I => IO[F,A]) extends IO[F,A]
12
13 trait Trampoline[A] {
14   def unit(a: A): Trampoline[A] = Done(a)
15   def flatMap[B](f: A => Trampoline[B]): Trampoline[B] = this match {
16     case Done(a) => f(a)
17     case More(k) => k() flatMap f
18   }
19   def map[B](f: A => B): Trampoline[B] = flatMap(a => Done(f(a)))
20 }
21 case class Done[A](a: A) extends Trampoline[A]
22 case class More[A](k: () => Trampoline[A]) extends Trampoline[A] ```

``` 1 trait Free[F[_],A] {
2  private case class FlatMap[B](a: Free[F,A], f: A => Free[F,B]) extends Free[F,B]
3  def unit(a: A): Free[F,A] = Return(a)
4  def flatMap[B](f: A => Free[F,B])(implicit F: Functor[F]): Free[F,B] = this match {
5      case Return(a) => f(a)
6      case Suspend(k) => Suspend(F.map(k)(a => a flatMap f))
7      case FlatMap(b,g) => FlatMap(b, g andThen (_ flatMap f))
8  }
9  def map[B](f: A => B)(implicit F: Functor[F]): Free[F,B] = flatMap(a => Return(f(a)))
10 }
11 case class Return[F[_],A](a: A) extends Free[F,A]
12 case class Suspend[F[_],A](ffa: F[Free[F,A]]) extends Free[F,A]```

``` 1 trait Free[F[_],A] {
2  private case class FlatMap[B](a: Free[F,A], f: A => Free[F,B]) extends Free[F,B]
3  def unit(a: A): Free[F,A] = Return(a)
4  def flatMap[B](f: A => Free[F,B])(implicit F: Functor[F]): Free[F,B] = this match {
5      case Return(a) => f(a)
6      case Suspend(k) => Suspend(F.map(k)(a => a flatMap f))
7   case FlatMap(b,g) => FlatMap(b, g andThen (_ flatMap f))
8  }
9
10  def map[B](f: A => B)(implicit F: Functor[F]): Free[F,B] = flatMap(a => Return(f(a)))
11  def resume(implicit F: Functor[F]): Either[F[Free[F,A]],A] = this match {
12      case Return(a) => Right(a)
13      case Suspend(k) => Left(k)
14      case FlatMap(a,f) => a match {
15          case Return(b) => f(b).resume
16          case Suspend(k) => Left(F.map(k)(_ flatMap f))
17          case FlatMap(b,g) => FlatMap(b, g andThen (_ flatMap f)).resume
18      }
19  }
20  def liftF(fa: F[A])(implicit F: Functor[F]): Free[F,A] =
21    Suspend(F.map(fa)(Return(_)))
22 }
23 case class Return[F[_],A](a: A) extends Free[F,A]
24 case class Suspend[F[_],A](ffa: F[Free[F,A]]) extends Free[F,A] ```

``` 1 trait Console[A]
2 case class GetLine[A](next: A) extends Console[A]
3 case class PutLine[A](msg: String, next: A) extends Console[A]
4 implicit val consoleFunctor = new Functor[Console]{
5     def map[A,B](ca: Console[A])(f: A => B): Console[B] = ca match {
6         case GetLine(a) => GetLine(f(a))
7         case PutLine(m,a) => PutLine(m,f(a))
8     }
9 }                                                 //> consoleFunctor  : ch13.ex3.Functor[ch13.ex3.Console] = ch13.ex3\$\$anonfun\$ma
10                                                   //| in\$1\$\$anon\$1@53e25b76
11 type ConsoleIO[A] = Free[Console,A]
12 implicit def liftConsole[A](ca: Console[A]) = Free.liftF(ca)
13                                                   //> liftConsole: [A](ca: ch13.ex3.Console[A])ch13.ex3.Free[ch13.ex3.Console,A]
14 def putLine(msg: String) = PutLine(msg,())        //> putLine: (msg: String)ch13.ex3.PutLine[Unit]
15 def getLine = GetLine(())                         //> getLine: => ch13.ex3.GetLine[Unit]
16 val ioprg:ConsoleIO[Unit] = for {
17  _ <- putLine("What is your first name ?")
18  first <- getLine
19  _ <- putLine("What is your last name ?")
20  last <- getLine
21  _ <- putLine(s"Hello, \$first \$last !")
22 } yield()                                         //> ioprg  : ch13.ex3.Free[ch13.ex3.Console,Unit] = Suspend(PutLine(What is you
23                                                   //| r first name ?,Suspend(GetLine(Suspend(PutLine(What is your last name ?,Sus
24                                                   //| pend(GetLine(Suspend(PutLine(Hello, () () !,Return(())))))))))))```

``` 1 trait ~>[F[_],G[_]]{
2     def apply[A](fa: F[A]): G[A]
3 }
4 trait Free[F[_],A] {
5  private case class FlatMap[B](a: Free[F,A], f: A => Free[F,B]) extends Free[F,B]
6  def unit(a: A): Free[F,A] = Return(a)
7  def flatMap[B](f: A => Free[F,B])(implicit F: Functor[F]): Free[F,B] = this match {
8      case Return(a) => f(a)
9      case Suspend(k) => Suspend(F.map(k)(a => a flatMap f))
10   case FlatMap(b,g) => FlatMap(b, g andThen (_ flatMap f))
11  }
12
13  def map[B](f: A => B)(implicit F: Functor[F]): Free[F,B] = flatMap(a => Return(f(a)))
14  def resume(implicit F: Functor[F]): Either[F[Free[F,A]],A] = this match {
15      case Return(a) => Right(a)
16      case Suspend(k) => Left(k)
17      case FlatMap(a,f) => a match {
18          case Return(b) => f(b).resume
19          case Suspend(k) => Left(F.map(k)(_ flatMap f))
20          case FlatMap(b,g) => FlatMap(b, g andThen (_ flatMap f)).resume
21      }
22  }
23  def foldMap[G[_]](f: (F ~> G))(implicit F: Functor[F], G: Monad[G]): G[A] = resume match {
24        case Right(a) => G.unit(a)
25        case Left(k) => G.flatMap(f(k))(_ foldMap f)
26  }
27 }
28 case class Return[F[_],A](a: A) extends Free[F,A]
29 case class Suspend[F[_],A](ffa: F[Free[F,A]]) extends Free[F,A]
30 object Free {
31  def liftF[F[_],A](fa: F[A])(implicit F: Functor[F]): Free[F,A] =
32    Suspend(F.map(fa)(Return(_)))
33
34 }```

``` 1 type Id[A] = A
3     def unit[A](a: A): A = a
4     def flatMap[A,B](fa: A)(f: A => B): B = f(fa)
5 }
6 object ConsoleEffect extends (Console ~> Id) {
7     def apply[A](c: Console[A]): A = c match {
8         case GetLine(n) => readLine ; n
9         case PutLine(m,n) => println(m); n
10     }
11 }
12 ioprg.foldMap(ConsoleEffect)```

``` 1 case class InOutLog(inLog: List[String], outLog: List[String])
2 case class Logger[A](runLogger: InOutLog => (A, InOutLog))
3 object MockConsole extends (Console ~> Logger) {
4     def apply[A](c: Console[A]): Logger[A] = Logger[A](
5       s => (c, s) match {
6           case (GetLine(n), InOutLog(in,out)) => (in.head, InOutLog(in.tail,out))
7           case (PutLine(l,n), InOutLog(in,out)) => ((), InOutLog(in, l :: out))
8       }
9     )
10 }
11
12 val s = ioprg.foldMap(MockConsole)
13 s.runLogger(InOutLog(List("Tiger","Chan"),Nil))```

``` 1 object NonBlockingIO extends(Console ~> Future) {
2     def apply[A](c: Console[A]): Future[A] = c match {
3         case GetLine(n) => Future.unit {
4             try Some(readLine) catch {case _: Exception => None}
5         }
6         case PutLine(n,l) => Future.unit{
7             println(l)
8         }
9     }
10 }```

207 篇文章55 人订阅

0 条评论

## 相关文章

3335

### 2018年7月25日python中将程序中的数据存储到文件中的具体代码实现

#将程序中的数据可以分别以二进制和字符串的形式存储到文件中 #首先引用pickle和json模块，实际应用中只需要引用一个就行

804

3379

1364

3276

### SpringBoot ( 十一 ) ：SpringBoot 中 mongodb 的使用

mongodb是最早热门非关系数据库的之一，使用也比较普遍，一般会用做离线数据分析来使用，放到内网的居多。由于很多公司使用了云服务，服务器默认都开放了外网地址，...

992

4158

### angularjs directive学习心得

transclude有三个选项，true, false, 和object.如果不显示指明的话，默认为false. 当为false的时候，则那个directiv...

851