Scala:涉及匿名子类、回调和类型参数的棘手案例

Scala:涉及匿名子类、回调和类型参数的棘手案例,scala,Scala,我甚至不知道如何描述我在做什么,除了举个例子: class Node abstract class App { def schema: Node } def bind(app: App, f: Node => Node) { f(app.schema) } val app = new App { val schema = new Node { val child = new Node } } bind(app, _.child) 这

我甚至不知道如何描述我在做什么,除了举个例子:

class Node

abstract class App {
    def schema: Node
}

def bind(app: App, f: Node => Node) {
    f(app.schema)
}

val app = new App {
    val schema = new Node {
        val child = new Node
    }
}

bind(app, _.child)
这是不可编译的。我从
bind
调用中获取:
错误:值子节点不是此节点的成员

我不知道如何解决这个问题,但我认为这可能涉及到参数化类型的使用。我需要
f
的参数类型是分配给
schema
的实际
节点
子类的参数类型


编辑:我不能明确命名我的
节点
子类型,因为在现实生活中,我有静态定义的
节点
的整棵树,命名它们是不切实际的。

节点
没有方法
子节点
,因此类应用程序必须保留封闭节点的参数:

abstract class App[N <: Node] {
  def schema: N
}
最后,您可以将
bind
编写为:

 def bind[N <: Node](app: App[N], f: N => N) = {
    f(app.schema)
 }

 val app = new App[ParentNode] {
    val schema = new ParentNode
 }
def绑定[N]{
f(应用程序架构)
}
val app=新应用程序[父节点]{
val schema=newparentnode
}

bind
具有签名
appx(Node=>Node)=>Node

\.child
在此上下文中表示
{n:Node=>n.child}
并且Node未定义child。这就是错误消息所告诉的

在您的特定情况下,您可以期望它能够工作,因为您知道bind的函数参数应用于app参数的schema节点。但是,您应该告诉编译器几乎相同的内容。这将迫使您公开一些实现细节

首先,您的函数可能没有节点参数,而是更精确的参数。您可以有一个泛型参数:

def bind[N <: Node](app: App, f: N => Node)
最后,您必须使应用程序的类型更加明确,至少是这样

class NodeOfApp{def child: Node}
val app = new App[NodeOfApp]{...}

你可以这样做:

def bind[T](app: App{val schema: T}, f: T => Node) { f(app.schema) }
bind[{val child: Node}](app, _.child)

我想这对于您试图实现的目标来说仍然过于冗长。

Thank you@paradigmatic。我应该澄清一下,我需要保持匿名节点子类型的使用。这是我正在开发的内部DSL的代表,节点树要易于实现,并且不需要显式命名子类。T谢谢。请参阅我对@paradigmatic的评论。我无法明确命名我的节点子类型,因为在现实生活中,我有整个静态定义节点树,命名它们并不实际。谢谢,但这需要在参数类型定义中重复整个模式。在现实生活中,模式是一个连接节点的大型图实例。
class NodeOfApp{def child: Node}
val app = new App[NodeOfApp]{...}
def bind[T](app: App{val schema: T}, f: T => Node) { f(app.schema) }
bind[{val child: Node}](app, _.child)