在上节我们介绍了Trampoline。它主要是为了解决堆栈溢出（StackOverflow）错误而设计的。Trampoline类型是一种数据结构，它的设计思路是以heap换stack：对应传统递归算法运行时在堆栈上寄存程序状态，用Trampoline进行递归算法时程序状态是保存在Trampoline的数据结构里的。数据结构是在heap上的，所以可以实现以heap换stack的效果。这种以数据结构代替函数调用来解决问题的方式又为泛函编程提供了更广阔的发展空间。

```1 def transfer(amount: Double, from: Account, to: Account, user: User,
2   context: Authorization with Logger with ErrorHandler with Storage): Unit```

`1 def transfer(amount: Double, from: Account, to: Account, user: User）： List[Instruction]`

```1 trait Interact[A] //交互数据类型
2 //提问，等待返回String类型答案
3 case class Ask(prompt: String) extends Interact[String]
4 //告知，没有返回结果
5 case class Tell(msg: String) extends Interact[Unit]```

```1  val prg = List(Ask("What's your first name?"),
3                  Tell("Hello ??? ???"))```

```1 for {
4     _ <- Tell(s"Hello \$y \$x!")
5 } yield () ```

```1 trait Free[F[_],A]
2 case class Return[F[_],A](a: A) extends Free[F,A]
3 case class Bind[F[_],I,A](a: F[I], f: I => Free[F,A]) extends Free[F,A]```

``` 1 trait Free[F[_],A] {
2  def unit(a: A) = Return(a)
3  def flatMap[B](f: A => Free[F,B]): Free[F,B] = this match {
4        case Return(a) => f(a)
5 //还记得Trampoline  FlatMap(FlatMap(b,g),f) == FlatMap(b, (x: Any) => FlatMap(g(x),f))
6        case Bind(fa,g) => Bind(fa, (x: Any) => g(x) flatMap f)
7 //下面采用了函数组合方式。具备同样功能
8 //   case Bind(fa,g) => Bind(fa, g andThen (_ flatMap f))
9  }
10  def map[B](f: A => B): Free[F,B] = flatMap(a => Return(f(a)))
11
12 }
13 case class Return[F[_],A](a: A) extends Free[F,A]
14 case class Bind[F[_],I,A](a: F[I], f: I => Free[F,A]) extends Free[F,A]```

```1 implicit def lift[F[_],A](fa: F[A]): Free[F,A] = Bind(fa, (a: A) => Return(a))
2                                                   //> lift: [F[_], A](fa: F[A])ch13.ex6.Free[F,A]```

``` 1 trait Interact[A] //交互数据类型
2 //提问，等待返回String类型答案
3 case class Ask(prompt: String) extends Interact[String]
4 //告知，没有返回结果
5 case class Tell(msg: String) extends Interact[Unit]
6
7 implicit def lift[F[_],A](fa: F[A]): Free[F,A] = Bind(fa, (a: A) => Return(a))
8                                                   //> lift: [F[_], A](fa: F[A])ch13.ex6.Free[F,A]
9 for {
12     _ <- Tell(s"Hello \$y \$x!")
13 } yield ()                                        //> res0: ch13.ex6.Free[ch13.ex6.Interact,Unit] = Bind(Ask(What's your first nam
14                                                   //| e?),<function1>)```

```1 trait ~>[F[_],G[_]] {
2     def apply[A](fa: F[A]): G[A]
3 }```

```1 def foldMap[G[_]: Monad](f: F ~> G): G[A] = this match {
3           case Bind(b,g) => Monad[G].flatMap(f(b))(a => g(a).foldMap(f))
4  }```

``` 1 ype Id[A] = A
3     def unit[A](a: A) = a
4     def flatMap[A,B](fa: A)(f: A => B): B = f(fa)
6                                                   //| 530c12
7 object Console extends (Interact ~> Id) {
8     def apply[A](i: Interact[A]): A = i match {
10           println(prompt)
12         }
13         case Tell(msg) => println(msg)
14     }
15 }```

```1 val prg = for {
4     _ <- Tell(s"Hello \$y \$x!")
5 } yield ()                                        //> prg  : ch13.ex6.Free[ch13.ex6.Interact,Unit] = Bind(Ask(What's your first n
6                                                   //| ame?),<function1>)
7
8 prg.foldMap(Console)```

``` 1 type Tester[A] = Map[String, String] => (List[String], A)
3     def unit[A](a: A) = (_ => (List(),a))
4     def flatMap[A,B](ta: Tester[A])(f: A => Tester[B]): Tester[B] = {
5         m => {
6             val (l1,a) = ta(m)
7             val (l2,b) = f(a)(m)
8             (l1 ++ l2,b)
9         }
10     }
12                                                   //| g,String] => (List[Nothing], A)} = ch13.ex6\$\$anonfun\$main\$1\$\$anon\$2@5b464ce
13                                                   //| 8
14 object TestConsole extends (Interact ~> Tester) {
15     def apply[A](i: Interact[A]): Tester[A] = i match {
16       case Ask(prompt) => m => (List(), m(prompt))
17       case Tell(msg) => _ => (List(msg),())
18     }
19 }```

```1 val prg = for {
4     _ <- Tell(s"Hello \$y \$x!")
5 } yield ()                                        //> prg  : ch13.ex6.Free[ch13.ex6.Interact,Unit] = Bind(Ask(What's your first n
6                                                   //| ame?),<function1>)
7
8 prg.foldMap(TestConsole)```

0 条评论

## 相关文章

### python源码阅读笔记之GC（一）

python源码阅读： 参考书籍：《python源码剖析》 摘要：写这个系列的目的呢，是想为python的学习画上一个暂时的句号，接下来的重点应该是scala这...

1032

2716

3217

2339

782

### 51Nod 1016 水仙花数 V2(组合数学,枚举打表法)

1016 水仙花数 V2 基准时间限制：1 秒 空间限制：131072 KB 分值: 160         难度：6级算法题 水仙花数是指一个 n 位数 ...

2707

2854

48211

### Springboot中使用Scala开发使用SB與Scala

https://github.com/LightSwordSpringBoot/lightsword

1541

2039