【发布时间】:2011-08-23 07:55:51
【问题描述】:
我想为树结构实现一个通用层次结构,以后可以以独立于实现的方式使用它来描述树上的通用算法。
我从这个层次结构开始:
interface BinaryTree<Node> {
Node left(Node);
bool hasLeft(Node);
Node right(Node);
bool hasRight(Node);
}
interface BinaryTreeWithRoot<Node> : BinaryTree<Node> {
Node root();
}
interface BinaryTreeWithParent<Node> : BinaryTree<Node> {
Node parent(Node);
bool hasParent(Node);
}
现在,基本上我希望能够以一种通用的方式实现子树的概念: 对于每个类 T : BinaryTree,我想要一个“类” Subtree(T),它提供与 T 相同的功能(因此它必须从它派生),并且还重写了 root() 功能。
类似这样的:
class Subtree<T, Node> : T, BinaryTreeWithRoot<Node>
where T : BinaryTree<Node>
{
T reference;
Node root;
void setRoot(Node root) {
this.root = root;
}
override Node BinaryTreeWithRoot<Node>::root() {
return this.root;
}
// Now, inherit all the functionality of T, so an instance of this class can be used anywhere where T can.
forall method(arguments) return reference.method(arguments);
}
现在有了这段代码,我不确定如何创建子树类型的对象,因为树对象应该以某种方式被注入。
一种方法是为我创建的每个树类创建一个子树类,但这意味着代码重复,而且毕竟是同一件事。
因此,一种方法是 mixins,它允许泛型类从其模板参数派生。
我也对如何在 Haskell 中实现这样的层次结构感兴趣,因为 Haskell 有一个很棒的类型系统,我认为注入这样的功能会更容易。
例如在 Haskell 中可能是这样的:
class BinaryTree tree node where
left :: tree -> node -> node
right :: tree -> node -> node
class BinaryTreeWithRoot node where
left :: tree -> node -> node
right :: tree -> node -> node -- but this is a duplication of the code of BinaryTree
root :: tree -> node
instance BinaryTree (BinaryTreeWithRoot node) where
left = left
right = right
data (BinaryTree tree node) => Subtree tree node =
...
instance BinaryTreeWithRoot (Subtree tree node) where ...
我很感兴趣是否以及如何在 oop 语言(c++、c#、d、java)中完成此操作,因为 c++ 和 d 提供开箱即用的 mixins(我不确定 d),出于对 Haskell 类型系统的好奇。
【问题讨论】:
-
在 C# 中,您不能从泛型类型参数继承。您可以实现
BinaryTreeWithRoot<Node>接口并将BinaryTree<Node>调用链接到传递的reference或T -
但这意味着对于每个可能的 BinaryTreeXXX 功能,我应该专门化通用子树并链接所有功能: class Subtree
where T : BinaryTree1 ... { all the methods BinaryTree1 } class Subtree where T : BinaryTree2 ... { BinaryTree2 的所有方法 } 等等... -
true,所以
SubTree应该实现BinaryTreeWithRoot<T>而不是BinaryTreeWithRoot<Node> -
我不太明白如何做到这一点。如果您建议使 BinaryTreeXXX 接口更通用,例如:pastebin.com/jSdcYYuS,那么我看不到特定的子树将如何映射到 BinaryTree 接口的特定实现。那是因为子树现在有方法,这些方法将树作为参数。此外,由于 C# 没有 typedef,我们应该显式传递所有模板类型参数以正确描述它们的条件,这对于(间接)依赖于许多模板参数的类来说将变得非常不方便。