Traverse/fold a nested case class in Scala without boilerplate code -
i have case classes mix of sum , product types:
sealed trait leaf case class goodleaf(value: int) extends leaf case object badleaf extends leaf case class middle(left: leaf, right: leaf) case class container(leaf: leaf) case class top(middle : middle, container: container, extraleaves : list[leaf]) i want fold-like operations top structure. examples include:
- count occurrences of
badleaf - sum values in
goodleafs
here code operations:
object top { def fold[t](accu: t)(f : (t, leaf) => t)(top: top) = { val allleaves = top.container.leaf :: top.middle.left :: top.middle.right :: top.extraleaves allleaves.foldleft(accu)(f) } private def countbadleaf(count: int, leaf : leaf) = leaf match { case badleaf => count + 1 case _ => count } def countbad(top: top): int = fold(0)(countbadleaf)(top) private def sumgoodleaf(count: int, leaf : leaf) = leaf match { case goodleaf(v) => count + v case _ => count } def sumgoodvalues(top: top) = fold(0)(sumgoodleaf)(top) } the real life structure dealing more complicated example made up. there techniques me avoid writing lots of boilerplate code?
i have cats library dependency, solution uses lib preferred. open including new dependencies in order solve problem.
for particular example, definition not recursive, i'd interested in seeing solution works recursive definitions also.
you create function returning leaves top, did allleaves, can work list[leaf] (with existing fold , other functions scala library, cats, etc provide).
for example :
def topleaves(top: top): list[leaf] = top.container.leaf :: top.middle.left :: top.middle.right :: top.extraleaves val isbadleaf: leaf => boolean = { case badleaf => true case _ => false } val leafvalue: leaf => int = { case goodleaf(v) => v case _ => 0 } which use as
import cats.implicits._ // or // import cats.instances.int._ // import cats.instances.list._ // import cats.syntax.foldable._ val leaves = topleaves(sometop) val badcount = leaves.count(isbadleaf) val badandgood = leaves.partition(isbadleaf) // (list[leaf], list[leaf]) val sumleaves = leaves.foldmap(leafvalue) i not sure if helps actual use case ? in general heterogeneous structure (like top) want convert somehow more homogeneous (like list[leaf] or tree[leaf]) can fold over.
if have recursive structure @ talks recursion schemes (with matryoshka library in scala).
Comments
Post a Comment