使用类型参数的类型参数作为 Scala 中的字段类型 [英] Use type parameter's type argument as field type in Scala
问题描述
所以跟进 Scala 中的递归类型定义,我现在有了我的类型CatenableListFromQueue
的数据承载结构:
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]
}
现在参数 Q 的预期值自然是一个队列.我的 Queue
本身是一个类型类,即它只定义了一些通用数据承载结构的方法:
now the intended value for the parameter Q is, naturally, a queue. My Queue
itself is a type class, i.e. 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, e.g.
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
}
}
一切都很顺利,直到我需要创建一个 CatenableListFromQueue
,它保存了来自上一个问题的数据结构和 Queue
的数据承载结构,<代码>队列#Q:
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]
因此,在我的理想世界中,该类获得了一个 Queue
实例,即队列操作在某些结构上的实现(此处:Queue#Q
),并且在turn 创建并处理实际元素的 CatList
和包含更多 CatList
s 的 Queue#Q
s.
So in my ideal world the class gets an instance of Queue
, i.e. 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.
问题是,我似乎无法想出一种在 Scala 中编写代码的方法;在 Haskell 中,这似乎很简单:
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
但在 Scala 中,我无法想出任何编码方式,因为我的 Queue
需要该数据承载结构作为参数,并且数据承载自然包含它的元素,在这种情况下包含更多相同类型的数据承载结构.
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.
推荐答案
好吧,遵循 Haskell 的方法是正确的方法:
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.
所以我们保留 CatenableListFromQueue
一个 trait,稍后将它与 QBS
的特定类型一起使用:
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.
这篇关于使用类型参数的类型参数作为 Scala 中的字段类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!