Skip to content

Instantly share code, notes, and snippets.

@jedws
Last active July 4, 2016 12:53
Show Gist options
  • Save jedws/1059553 to your computer and use it in GitHub Desktop.
Save jedws/1059553 to your computer and use it in GitHub Desktop.
Pattern vs Catamorphism? an exercise in different approaches to implementing a simple data-structure
import com.atlassian.util.scala.concurrent.Atomic //https://bitbucket.org/jwesleysmith/atlassian-util-scala/src/tip/src/main/scala/com/atlassian/util/scala/concurrent/Atomic.scala
package patterns {
final class TreiberStack[A] {
private[this] val head = Atomic[Node[A]](End)
@annotation.tailrec
def pop: Option[A] = head.value match {
case l @ Link(a, prev) => if (head.compareAndSet(l, prev)) Some(a) else pop
case _ => None
}
def peek: Option[A] = head.value match {
case Link(a, _) => Some(a)
case _ => None
}
def push(a: A) = head.value = new Link(a, _)
}
sealed trait Node[+A]
case class Link[A](a: A, prev: Node[A]) extends Node[A]
case object End extends Node[Nothing]
}
package catamorphism {
class TreiberStack[A] {
private[this] val head = Atomic[Node[A]](End())
def pop: Option[A] = head.value.fold(None, l => if (head.compareAndSet(l, l.prev)) Some(l.a) else pop)
def peek: Option[A] = head.value.fold(None, l => Some(l.a))
def push(a: A) = head.value = new Link(a, _)
}
sealed trait Node[A] {
def fold(zero: => Option[A], f: Link[A] => Option[A]): Option[A]
}
case class Link[A](a: A, prev: Node[A]) extends Node[A] {
override def fold(zero: => Option[A], f: Link[A] => Option[A]) = f(this)
}
case class End[A]() extends Node[A] {
override def fold(zero: => Option[A], f: Link[A] => Option[A]) = zero
}
}
package listmap {
// list based, flatMap
final class TreiberStack[A] {
private[this] val head = Atomic[List[A]](Nil)
def pop = head.map { l => l.headOption flatMap { h => if (head.compareAndSet(l, l.tail)) Some(h) else pop } }
def peek: Option[A] = head.value.headOption
def push(a: A) = head.value = a :: _
}
}
package listpattern {
// list based, pattern matching version
final class TreiberStack[A] {
private[this] val head = Atomic[List[A]](Nil)
@annotation.tailrec
def pop: Option[A] = head.value match {
case Nil => None
case l @ h :: xs if (head.compareAndSet(l, xs)) => Some(h)
case _ => pop
}
def peek: Option[A] = head.value.headOption
def push(a: A) = head.value = a :: _
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment