Skip to content

Instantly share code, notes, and snippets.

@igstan
Last active March 23, 2022 12:19
Show Gist options
  • Save igstan/1ecadd5ea5d2864446b40e65663554c4 to your computer and use it in GitHub Desktop.
Save igstan/1ecadd5ea5d2864446b40e65663554c4 to your computer and use it in GitHub Desktop.
trait SACVisitor[R] {
def c1(a: Int): R
def c2(a: R, b: R): R
}
sealed trait SAC extends Product with Serializable {
def fold[R](visitor: SACVisitor[R]): R
}
object SAC {
final case class C1(a: Int) extends SAC {
def fold[R](visitor: SACVisitor[R]): R =
visitor.c1(a)
}
final case class C2(a: SAC, b: SAC) extends SAC {
def fold[R](visitor: SACVisitor[R]): R =
// Explicit recursive calls in the "recursive points".
visitor.c2(a.fold(visitor), b.fold(visitor))
}
def sum(sac: SAC): Int =
sac.fold(new SACVisitor[Int] {
override def c1(a: Int) = a
// Recursive points have already been handled, folded, by `fold`.
override def c2(a: Int, b: Int) = a + b
})
}
// Alternatively, `fold` could be defined in the base trait using pattern matching.
trait SACVisitor[R] {
def c1(a: Int): R
def c2(a: R, b: R): R
}
sealed trait SAC extends Product with Serializable {
final def fold[R](visitor: SACVisitor[R]): R =
this match {
case SAC.C1(a) => visitor.c1(a)
case SAC.C2(a, b) => visitor.c2(a.fold(visitor), b.fold(visitor))
}
}
object SAC {
final case class C1(a: Int) extends SAC
final case class C2(a: SAC, b: SAC) extends SAC
def sum(sac: SAC): Int =
sac.fold(new SACVisitor[Int] {
override def c1(a: Int) = a
override def c2(a: Int, b: Int) = a + b
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment