You can do this quite cleanly with a recursive function that traverses the tree and expands the ambiguities:
sealed trait Term case class App(f: Term, x: Term) extends Term case class Var(s: String) extends Term case class Amb(a: Term, b: Term) extends Term def det(term: Term): Stream[Term] = term match { case v: Var => Stream(v) case App(f, x) => det(f).flatMap(detf => det(x).map(App(detf, _))) case Amb(a, b) => det(a) ++ det(b) }
Note that I use a sealed slash instead of an abstract class to take advantage of the compiler's ability to check for completeness.
It works as expected:
scala> val app = App(Var("f"), Amb(Var("x"), Amb(Var("y"), Var("z")))) app: App = App(Var(f),Amb(Var(x),Amb(Var(y),Var(z)))) scala> det(app) foreach println App(Var(f),Var(x)) App(Var(f),Var(y)) App(Var(f),Var(z))
If you can change the Term API, you can more or less equivalently add def det: Stream[Term] .
source share