Hi. I am new to scala and I would like to get to know that language. Now I am implementing a little program that should be able to dump table of contents. A TOC can be seen as a tree, therefore I start with:
case class Tree(name: String, children: List[Tree] = List()) extends Traversable[Tree] {
override def foreach[U](f: Tree => U): Unit = {
f(this)
children.foreach(_.foreach(f))
}
override def toString: String = name
}
Fine. I can initialize a TOC, e.g.
val t = Tree("Introduction", List(
Tree("Technical Background"),
Tree("Methods", List(
Tree("One Method"),
Tree("Another Method"),
Tree("Yet another Method"),
)),
Tree("Results"),
Tree("Conclusion")
))
… and simply dump it
t.foreach(println)
But here comes the tricky part: when printing, I would like to have automated numbering and indentation. This would not be much of a problem, but I would like to seperate a) the logic of counting and b) the final output format from my tree. So I implemented a simple Counter:
case class Counter(count: List[Int] = List(1), depth: Int = 0) {
def down: Counter = copy(count = transformLastElement(count, last => last + 1))
def up: Counter = copy(count = transformLastElement(count, last => last - 1))
def in: Counter = copy(count = count :+ 1, depth = depth + 1)
def out: Counter = copy(count = count.dropRight(1), depth = depth - 1)
private def transformLastElement(list: List[Int], f: Int => Int): List[Int] = list match {
case Nil => Nil
case xs :+ x => xs :+ f(x)
}
}
and some Formatter objects:
object SimpleFormatter extends Formatter {
def format(counter: Counter): String = f"${indent(counter)}${concatCount(counter)}"
}
object VerboseFormatter extends Formatter {
override def format(counter: Counter): String = counter.count match {
case _ :: Nil => f"${indent(counter)}Chapter ${concatCount(counter)}"
case _ :: _ :: Nil => f"${indent(counter)}Section ${concatCount(counter)}"
case _ :: _ :: _ :: Nil => f"${indent(counter)}Subsection ${concatCount(counter)}"
case _ => f"${indent(counter)}${concatCount(counter)}"
}
}
Apparently, I can use my counter like this:
val f: Formatter = SimpleFormatter
println(f.format(Counter()))
println(f.format(Counter().in))
println(f.format(Counter().in.in.in.in.out.out))
println(f.format(Counter().down.down.down.in.in.in.in.out))
Now when initializing my tree, I would like to wrap some Object around it like this:
val t = ENUMERATED(Tree("Introduction", List(
Tree("Technical Background"),
Tree("Methods", List(
Tree("One Method"),
Tree("Another Method"),
Tree("Yet another Method"),
)),
Tree("Results"),
Tree("Conclusion")
)))
I would like to solve two problems here: first, the ENUMERATED object should automatically be wrapped around each child object of tree. Second, it should override foreach in some way such that it yields both, the current numbering (accessing a private val counter) and the current caption of my TOC. The foreach should therefore look somehow similiar to this (for trees):
override def foreach[U](f: T => U): Unit = {
counter.down
f(this)
if (children.nonEmpty) {
counter.in
children.foreach(_.foreach(f))
counter.out
}
}
But I can’t get my head around a suitable solution. Is there any way to solve that? Yes, I know I could simply use inheritance but I like the thought that my ENUMERATED wrapper fits to any traversable in some way … I even think about generalizing it in such a way that it might count anything else than just integers, but one thing after the other
Any ideas?