So following up on Recursive type definition in Scala , I now have my type for the data-bearing structure of CatenableListFromQueue
:
object CatenableListFromQueue {
sealed trait CatList[+Q, +E]
object Empty extends CatList[Nothing, Nothing]
case class C[Q[_], E](x: E, q: Q[CatList[Q, E]]) extends CatList[Q, E]
}
now the intended value for the parameter Q is, naturally, a queue. My Queue
itself is a type class, ie it only defines the methods for some generic data-bearing structure:
trait Queue[E, Q] {
def empty: Q
def isEmpty: Q => Boolean
def snoc: (Q, E) => Q
def head: Q => E
def tail: Q => Q
}
It seems to work just fine for me, eg
class BatchedQueue[E] extends Queue[E, (List[E], List[E])] {
override def empty: (List[E], List[E]) = (Nil, Nil)
override def isEmpty: ((List[E], List[E])) => Boolean = {
case (Nil, _) => true
case _ => false
}
val checkf: (List[E], List[E]) => (List[E], List[E]) = {
case (Nil, r) => (r.reverse, Nil)
case q => q
}
override def snoc: ((List[E], List[E]), E) => (List[E], List[E]) = {
case ((f, r), x) => checkf(f, x :: r)
}
override def tail: ((List[E], List[E])) => (List[E], List[E]) = {
case (Nil, _) => throw new IllegalStateException("tail called on an empty queue")
case ((_ :: f), r) => checkf(f, r)
}
override def head: ((List[E], List[E])) => E = {
case (Nil, _) => throw new IllegalStateException("head called on an empty queue")
case ((x :: _), _) => x
}
}
That all was going well until I needed to create a CatenableListFromQueue
, which holds a data structure from the previous question with the data-bearing structure of the Queue
, Queue#Q
:
class CatenableListFromQueue[E, CL, Q](queue: Queue[E, Q]) extends CatenableList[E] {
type CL = CatList[queue#Q, E]
So in my ideal world the class gets an instance of Queue
, ie the implementation of the queue operations over some structure (here: Queue#Q
), and in turn creates and handles a CatList
of the actual elements and the Queue#Q
s containing further CatList
s.
The problem is, I cannot seem to come up with a way to code that in Scala; in Haskell, it seems as trivial as:
data CatList q a = E | C a (q (CatList q a))
instance Queue q => CatenableList (CatList q) where
-- methods
But in Scala I cannot come up with any way to encode the same as my Queue
requires that data-bearing structure as a parameter, and the data-bearing naturally contains it elements which in this case contain further data-bearing structures of the same type.
Well, following Haskell's approach was the right way:
object CatenableListFromQueue {
sealed trait CatList[+Q[_], +E]
object Empty extends CatList[Nothing, Nothing]
case class C[Q[_], E](x: E, q: Q[Susp[CatList[Q, E]]]) extends CatList[Q, E]
}
trait CatenableListFromQueue[E, QBS[_]] extends CatenableList[E, CatList[QBS, E]] {
type Q = Queue[Susp[CatList[QBS, E]], QBS[Susp[CatList[QBS, E]]]]
def q: Q
type CL = CatList[QBS, E]
def just(e: E): CL = C(e, q.empty)
// etc.
So we keep the CatenableListFromQueue
a trait, and use it later with a specific type for QBS
:
new CatenableListFromQueue[Int, HoodMelvilleQueue.Repr] {
val q = new HoodMelvilleQueue[Susp[CL]]
}
This way, it all compiles just fine, and seems to work well.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.