|
| 1 | +package ch02 |
| 2 | + |
| 3 | +/* |
| 4 | +Structural corecursion works by considering all the possible outputs, which are the constructors of |
| 5 | +the algebraic data type, and then working out the conditions under which we’d call each constructor. |
| 6 | +
|
| 7 | +We could abstract structural corecursion as an unfold. |
| 8 | + */ |
| 9 | +enum MyList[A]: |
| 10 | + case Empty() |
| 11 | + case Pair(_head: A, _tail: MyList[A]) |
| 12 | + |
| 13 | + def map[B](f: A => B): MyList[B] = |
| 14 | +// this match |
| 15 | +// case Empty() => Empty() |
| 16 | +// case Pair(head, tail) => Pair(f(head), tail.map(f)) |
| 17 | + MyList.unfold(this)(_.isEmpty, a => f(a.head), _.tail) |
| 18 | + |
| 19 | + def isEmpty: Boolean = |
| 20 | + this match |
| 21 | + case Empty() => true |
| 22 | + case _ => false |
| 23 | + |
| 24 | + def head: A = |
| 25 | + this match |
| 26 | + case Pair(head, _) => head |
| 27 | + case _ => scala.sys.error("empty list") |
| 28 | + |
| 29 | + def tail: MyList[A] = |
| 30 | + this match |
| 31 | + case Pair(_, tail) => tail |
| 32 | + case _ => scala.sys.error("empty list") |
| 33 | + |
| 34 | + def fold[B](zero: B)(f: (A, B) => B): B = |
| 35 | + this match |
| 36 | + case Empty() => zero |
| 37 | + case Pair(head, tail) => f(head, tail.fold(zero)(f)) |
| 38 | + |
| 39 | + def toSeq: Seq[A] = fold(Seq.empty)(_ +: _) |
| 40 | + |
| 41 | +object MyList: |
| 42 | + /* |
| 43 | + Types inferred for one method parameter cannot be used for other method parameters in the same parameter list. |
| 44 | + However, types inferred for one method parameter list can be used in subsequent lists. |
| 45 | + */ |
| 46 | + def unfold[A, B](seed: A)(stop: A => Boolean, f: A => B, next: A => A): MyList[B] = |
| 47 | + if stop(seed) then MyList.Empty() |
| 48 | + else MyList.Pair(f(seed), unfold(next(seed))(stop, f, next)) |
| 49 | + |
| 50 | + def fill[A](n: Int)(elem: => A): MyList[A] = |
| 51 | + unfold(0)(_ == n, _ => elem, _ + 1) |
| 52 | + |
| 53 | + def iterate[A](start: A, len: Int)(f: A => A): MyList[A] = |
| 54 | + unfold((0, start))(_._1 == len, _._2, (i, a) => (i + 1, f(a))) |
0 commit comments