, , - :
// WON'T WORK
def flatten[T <: SpecialList](parentList: T): List[Exp] = parentList.elements flatMap {
case x:T => x.elements
case somethingElse => List(somethingElse)
}
, , :
def flatten[T <: SpecialList](parentList: T): List[Exp] = parentList.elements flatMap {
case x:SpecialList if x.getClass == parentList.getClass => x.elements
case somethingElse => List(somethingElse)
}
, , , , ListA ListB, , ListC.
, flatten (ListA (...)) ListA (...) - , . :
abstract class SpecialList {
val elements: List[Exp]
def flatten: SpecialList = createAnother(elements flatMap {
case x: SpecialList => {
val flattenX = x.flatten
if (flattenX.getClass == this.getClass) flattenX.elements else List(flattenX)
}
case somethingElse => List(somethingElse)
})
def createAnother(elements: List[Exp]): SpecialList
}
case class ListA(elements: List[Exp]) extends SpecialList {
override def toString: String = "ListA("+elements.mkString(",")+")"
def createAnother(elements: List[Exp]) = ListA(elements)
}
case class ListB(elements: List[Exp]) extends SpecialList {
override def toString: String = "ListB("+elements.mkString(",")+")"
def createAnother(elements: List[Exp]) = ListB(elements)
}
The problem in this case is that the bit createAnotheris a clean pattern. On the other hand, this version supports the generality of the above solution.
The third suggestion, which may include refactoring your code a bit more, is to completely abandon the ListA and ListB types, since it seems to me that their goal is to provide a tag to the Exp list. Therefore, consider this solution:
case class SpecialList(tag: Tag, elements: List[Exp]) extends Exp {
def flatten: SpecialList = {
val newElems = elements flatMap {
case x: SpecialList => {
val flattenX = x.flatten
if (flattenX.tag == this.tag) flattenX.elements else List(flattenX)
}
case somethingElse => List(somethingElse)
}
SpecialList(tag, newElems)
}
override def toString = tag.toString ++ "(" + elements.mkString(",") + ")"
}
sealed abstract class Tag {
def apply(elements: Exp*): SpecialList = SpecialList(this, elements.toList)
}
object ListA extends Tag { override val toString = "ListA" }
object ListB extends Tag { override val toString = "ListB" }
From a syntactic point of view, this is almost the same as you have
val x = ListA(Element(A), Element(B), ListA(Element(C), Element(D)), ListB(Element(E),Element(F), ListA(Element(C), ListA(Element(D)))))
x.flatten => ListA(Element(A),Element(B),Element(C),Element(D),ListB(Element(E),Element(F),ListA(Element(C),Element(D))))
This may not correspond to your problem, however, I'm sorry if I left the rails a bit.