I have an interface,
trait Heap[E, H <: Heap[E, H]] { implicit def ord: Ordering[E] def empty: H def isEmpty: Boolean def insert(x: E): H def merge(b: H): H def findMin: E def deleteMin: H def toList: List[E] = if (isEmpty) Nil else findMin :: deleteMin.toList }
This is common, since we need H
define โa Heap
the same typeโ because def merge(b: H): H
usually defined in terms of merging a heap of the same internal structure.
This works well for "normal" heaps, i.e. heaps that themselves manage their internal structures:
class LazyPairingHeap[E](val h: Repr[E] = Empty) (implicit val ord: Ordering[E]) extends Heap[E, LazyPairingHeap[E]] { import okasaki.heaps.LazyPairingHeap._ override def empty = new LazyPairingHeap[E](Empty) override def isEmpty: Boolean = h == Empty // etc.
and even for some heaps built on top of other heaps:
class SizedHeap[E, H <: Heap[E, H]](val s: Int, val h: H) extends Heap[E, SizedHeap[E, H]] { override implicit def ord: Ordering[E] = h.ord override def empty = new SizedHeap[E, H](0, h.empty) override def isEmpty = s == 0 override def insert(e: E) = new SizedHeap[E, H](s + 1, h.insert(e)) override def merge(o: SizedHeap[E, H]) = new SizedHeap[E, H](s + os, h.merge(oh)) override def findMin: E = h.findMin override def deleteMin = new SizedHeap[E, H](s - 1, h.deleteMin) }
The problem arises when instead of simply packing the original heap, we need to weave it into our representation:
object BootstrappedHeap { sealed trait BSHeap[+A, +H[_]] object Empty extends BSHeap[Nothing, Nothing] { override def toString = "Empty" } case class H[A, BH[_]](x: A, bsh: BH[BSHeap[A, BH]]) extends BSHeap[A, BH] { override def toString = s"H($x, $bsh)" } } abstract class BootstrappedHeap[E, BaseHeap[X] <: Heap[X, BaseHeap[X]], This <: BootstrappedHeap[E, BaseHeap, This]] (val h: BSHeap[E, BaseHeap] = Empty) (implicit ord: Ordering[E]) extends Heap[E, This] { implicit val hord: Ordering[BSHeap[E, BaseHeap]] = Ordering.by { case Empty => None case H(x, _) => Some(x) } def baseHeap: BaseHeap[BSHeap[E, BaseHeap]] def create(h: BSHeap[E, BaseHeap]): This override def empty = create(Empty) override def isEmpty: Boolean = h == Empty // etc
Now the question is, is there a better way than this great type annotation?
[E, BaseHeap[X] <: Heap[X, BaseHeap[X]], This <: BootstrappedHeap[E, BaseHeap, This]]
X
seems unnecessary, although I have not found a way to get rid of it;This
link seems a bit off the beat;- finally,
BaseHeap
has nothing to do with the public interface: I want this to be an implementation detail, can I hide it?