I have the following ADT for Formulas. (shortened to the important ones)
sealed trait Formula case class Variable(id: String) extends Formula case class Negation(f: Formula) extends Formula abstract class BinaryConnective(val f0: Formula, val f1: Formula) extends Formula Note that the following methods are defined in an implicit class for formulas.
Let's say i want to get all variables from a formula.
My first approach was:
Solution 1
def variables: Set[Variable] = formula match { case v: Variable => HashSet(v) case Negation(f) => f.variables case BinaryConnective(f0, f1) => f0.variables ++ f1.variables case _ => HashSet.empty } This approach is very simple to understand, but not tailrecursive. So I wanted to try something different. I implemented a foreach on my tree-like formulas.
Solution 2
def foreach(func: Formula => Unit) = { @tailrec def foreach(list: List[Formula]): Unit = list match { case Nil => case _ => foreach(list.foldLeft(List.empty[Formula])((next, formula) => { func(formula) formula match { case Negation(f) => f :: next case BinaryConnective(f0, f1) => f0 :: f1 :: next case _ => next } })) } foreach(List(formula)) } Now I can implement many methods with the help of the foreach.
def variables2 = { val builder = Set.newBuilder[Variable] formula.foreach { case v: Variable => builder += v case _ => } builder.result } Now finally to the question. Which solution is preferable in terms of efficieny? At least I find my simple first solution more aesthetic.