scala/ScalaBook/chapter-11/src/main/scala/scalabook/iter/traverse.scala

package scalabook.iter
import java.io.File
import scalabook.file.VFile

trait Traversable[T] {
  def foreach(f: T => Unit): Unit

  def toString(mapper: T => String): String
}

trait TraversableProvider0[T] {
  def childrenOf(start: T): Traversable[T]
}

trait TraversableProvider[T] {
  def foreach(start: T, f: T => Unit): Unit
}

object FileTraversableProvider extends TraversableProvider[File] {
  def foreach(start: File, f: (File) => Unit) {
    start.listFiles match {
      case null =>
      case array =>
        array.foreach(f)
    }
  }
}

class VFileTraversableProvider[T <: VFile[T]] extends TraversableProvider[T] {
  def foreach(start: T, f: (T) => Unit) =
    start.children.foreach(f)
}

trait ToStringTraversable[T] extends Traversable[T] {
  def toString(mapper: T => String) = toString()
}

class PreOrderDFST[T](start: T, provider: TraversableProvider[T]) extends ToStringTraversable[T] {
  def foreach(f: T => Unit) = foreach(start, f)

  private def foreach(start: T, f: T => Unit) {
    f(start)
    provider.foreach(start, foreach(_, f))
  }
}

class PostOrderDFST[T](start: T, provider: TraversableProvider[T]) extends ToStringTraversable[T] {
  def foreach(f: T => Unit) = foreach(start, f)

  private def foreach(start: T, f: T => Unit) {
    provider.foreach(start, foreach(_, f))
    f(start)
  }
}