Scalaプログラマのためのバナナ,レンズ,封筒,有刺鉄線による関数型プログラミング 〜続リストバナナ編〜

前回書いた記事の補足.

tkhshyt.hatenablog.com

前回載せたプログラムが,少しばかり汚いので若干手を加える.

object List {

  def cons[A](hd: => A, tl: => List[A]): List[A] = {
    lazy val head = hd
    lazy val tail = tl

    Cons(head, thunk(tail))
  }

  def nil[A]: List[A] = Nil()
}

List のコンパニオンオブジェクトとして以上のメソッドを追加しておく.
そうすると,これ以降に書くコードが少しばかり見易くなる(?)

前回の分を含めて,list-catamorphism のコードを載せておく.

package object Lazy {

  type Thunk[A] = () => A

  def thunk[A](a: => A): () => A =
    () => a
 
  def eval[A](a: () => A): A =
    a()
}

import Lazy._

sealed trait List[A] { self =>

  import List.{cons, nil}

  def take(n: Int): List[A] =
    n > 0 match {
      case false => nil
      case true  =>
        self match {
          case Nil()       => nil
          case Cons(a, as) => cons(a, eval(as).take(n-1))
        }
    }

  def cata[B](b: => B)(f: (A, B) => B): B = self match {
    case Nil()       => b
    case Cons(a, as) => f(a, eval(as).cata(b)(f))
  }

  def length: Int =
    self.cata(0) { (a, n) => 1 + n }

  def filter(p: A => Boolean): List[A] =
    self.cata(nil[A]) { (a, as) =>
      p(a) match {
        case true  => cons(a, as)
        case false => as
      }
    }
}

case class Nil[A]() extends List[A]
case class Cons[A](a: A, as: Thunk[List[A]]) extends List[A]

object List {

  def cons[A](hd: => A, tl: => List[A]): List[A] = {
    lazy val head = hd
    lazy val tail = tl

    Cons(head, thunk(tail))
  }

  def nil[A]: List[A] = Nil()
}

もうこの段階で List から cata を分離したいけど,それは後のお話.
それと名前渡しなのに Lazy って名前はどうなのよっていう気はするけど,List を遅延リストにするためにしか使わないので御愛嬌ということで.