我将简要地为我的问题提供一些背景信息,然后问题本身就会出现。
在Martin Odersky先前的出版物中以及最近在Scala的一些演讲中,他强调了Scala的类型系统与ML之间的以下关系:
在博客文章中已经开始更具体地尝试这些想法,例如:
特别是,在第二个链接中提供了函数定义的概念,以实现类型归属。
trait Set[A] {
type T
def empty: T
}
abstract class SetMod[A](Ord: Ordered[A]) extends Set[A] {
// Not the real implementaton, obviously.
type T = List[A]
override def empty = ???
def implementationHelper(x: Double): Int = ???
}
object MkSet {
def apply[A](implicit O: Ordered[A]): Set[A] =
new SetMod[A](O) {}
}
我们现在可以说像
lazy val IntSet = MkSet[Int]
其中implementationHelper
对IntSet
不可见,但如果我们愿意,我们仍然可以在REPL中以交互方式使用实现,因为没有private
。
让我们考虑一个更复杂的例子,这是一个非常通用的图形模块:
我们从界面开始,保持表示抽象:
trait Graph[A] {
type T <: GraphSig
type NodeLabel
type EdgeLabel
type Weight
case class Node(labe: NodeLabel, value: A)
case class Edge(start: Node, end: Node, weight: Weight, label: EdgeLabel)
def empty: T
trait GraphSig {
def nodes: Stream[Node]
def edges: Stream[Edge]
}
}
然后为简单情况添加接口的特化:
trait SimpleGraph[A] extends Graph[A] {
type Weight = Unit
type EdgeLabel = Unit
def edge(start: Node, end: Node): Edge =
Edge(start, end, (), ())
}
接下来,模块的实际实现:
abstract class GraphMod[A] extends Graph[A] {
override def empty = ???
class T extends GraphSig {
override def nodes = ???
override def edges = ???
}
def someHelper(x: Double): Int = ???
}
最后帮助我们创建新的图形模块的好帮手:
object Graph {
trait StringLabels {
type NodeLabel = String
}
}
我们现在可以按如下方式构建此模块的新特化(在Modules
对象内):
lazy val IntGraph: SimpleGraph[Int] with Graph.StringLabels =
new GraphMod[Int] with SimpleGraph[Int] with Graph.StringLabels {}
好的,现在是实际问题。
我想构建一个依赖于特定图形模块的新模块。一个算子。
特别是,我想要一个模块来帮助我将图形导出为不同的格式(如DOT格式)。
如果正在编写单个函数,那么这可以按预期工作:
object GraphFormat {
def asDot[A](G: Graph[A])(graph: G.T): String =
"okay"
}
例如,
scala> GraphFormat.asDot(IntGraph)(IntGraph.empty)
scala.NotImplementedError: an implementation is missing
at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225)
at GraphMod.empty(Graph.scala:39)
at GraphMod.empty(Graph.scala:38)
... 43 elided
(这不是编译错误,但预期正文为???
)。
但我真正想要的是这样的事情:
class GraphFormat[A](val Graph: Graph[A]) {
def asDot(graph: Graph.T): String =
"better"
// Other stuff that depends on `Graph`...
}
这不起作用,因为没有办法(我能想到)在定义之外“公开”Graph.T
的类型。
scala> val F = new GraphFormat(IntGraph)
F: GraphFormat[Int] = GraphFormat@27da03d5
scala> F.asDot(IntGraph.empty)
<console>:13: error: type mismatch;
found : Modules.IntGraph.T
required: F.Graph.T
F.asDot(IntGraph.empty)
请参阅?
有没有合理的方法来解决这个问题?
在这种特殊情况下,我可以在Format
特征中嵌入一个Graph
对象,但我认为这个例子总体上代表了在尝试以时尚方式使用仿函数时出现的问题。因此问题。 : - )
答案 0 :(得分:0)
感谢#scalaz
IRC频道上的人们,我找到了基于this blog post的解决方案。
即,让我们用帮助器Graph
来扩充Aux
对象,&#34;暴露&#34; type参数的值:
object Graph {
trait StringLabels {
type NodeLabel = String
}
type Aux[T0, A0] = Graph[A0] { type T = T0 }
}
并将GraphFormat
类重新定义为:
class GraphFormat[GraphInstance, A](val G: Graph.Aux[GraphInstance, A]) {
def asDot(graph: GraphInstance): String =
"better"
// Other stuff that depends on `Graph`...
}
这看起来很吓人,但使用它按预期工作:
scala> import Modules._
scala> val F = new GraphFormat(IntGraph)
F: GraphFormat[Modules.IntGraph.T,Int] = GraphFormat@305bb85a
scala> F.asDot(IntGraph.empty)
scala.NotImplementedError: an implementation is missing
at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225)
at GraphMod.empty(Graph.scala:41)
at GraphMod.empty(Graph.scala:40)
... 43 elided
scala> :t F.asDot _
Modules.IntGraph.T => String
哇噢! : - )