Java中的类ADT多态性(不改变类) [英] ADT-like polymorphism in Java (without altering class)

查看:142
本文介绍了Java中的类ADT多态性(不改变类)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Haskell 中,我可以定义以下数据类型:

 数据树=空
| Leaf Int
|节点树树

然后编写像这样的多态函数:

  depth :: Tree  - >深度(深度1)(深度r)



在Java中我可以用接口模拟代数数据类型:

 接口树{} 
类空实现树{}
类叶实现树{int n; }
类节点实现树{Tree l;树r; }

但是,如果我尝试使用类似于Haskell的多态性,则会出现错误:

  int depth(空节点){
return 0;
}
int深度(叶节点){
return 1;
}
int depth(节点节点){
return 1 + Math.max(depth(node.l),depth(node.r)); //错误:无法解析方法'深度(Tree)'
}

正确的方式克服这一点就是为每个课程放置方法 depth() 。但是如果我不希望将它放在那里呢?例如,方法 depth()可能与 Tree 没有直接关系,将它添加到类会破坏业务逻辑。或者,更糟糕的是, Tree 可能会写入我无权访问的第三方库中。在这种情况下,实现 ADT-like polymorpism 最简单的方法是什么?



以防万一,我现在使用的是以下语法,显然不太合适:

<$ (树叶)深度((叶)树)
if(tree instanceof Leaf)depth((Leaf)tree) );
if(tree instanceof Node)depth((Node)tree);
else抛出新的RuntimeException(不知道如何查找深度+ tree.getClass());
}


解决方案

尝试类似这样的操作。 / p>

对不起,我的Java非常生疏。如果和我不一样,你可以记住语法,你可以使用Java泛型来完善 Object Integer 或者任何类您正在编写的方法需要。但是你不能(你能吗?)返回原始类型,对不起。

 接口TreeFolder {
Object onEmpty );
Object onLeaf(int n);
Object onNode(Tree l,Tree r);
}

接口树{
Object fold(TreeFolder f);


类空实现树{
Object fold(TreeFolder f){
return f.onEmpty();
}
}

类Leaf实现树{
private int n;
Object fold(TreeFolder f){
return f.onLeaf(n);
}
}

类节点实现树{
private Tree l,r;
Object fold(TreeFolder f){
return f.onNode(l,r);
}
}

//同时,在远离另一个包的类中...
对象深度(Tree tree){
return tree.fold(new TreeFolder(){
Object onEmpty(){return new Integer(0);}
Object onLeaf(int n){return new Integer(n);}
Object onNode(Tree l,Tree r){
Integer ll =(Integer)l.fold(this);
Integer rr =(Integer)r.fold(this);
返回新的Integer (ll.intValue()+ rr.intValue());
}
});

$ / code>

请注意,在 depth()我必须在 Tree 参数上手动递归(调用 fold())。您可以选择在 Node.fold()(并相应地更改 TreeFolder >)中预先缓存它们,但随后你有递归 - 你不能只选择递归到左子树,如果你想。 (在Haskell中,我们不必因懒惰而做出折衷。)


In Haskell I can define following data type:

data Tree = Empty
      | Leaf Int
      | Node Tree Tree

and then write polymorphic function like this:

depth :: Tree -> Int
depth Empty = 0
depth (Leaf n) = 1
depth (Node l r) = 1 + max (depth l) (depth r)

In Java I can emulate algebraic data types with interfaces:

interface Tree {}
class Empty implements Tree {}
class Leaf implements Tree { int n; }
class Node implements Tree { Tree l; Tree r; }

But if I try to use Haskell-like polymorphism, I get an error:

int depth(Empty node) {
    return 0;
}
int depth(Leaf node) {
    return 1;
}
int depth(Node node) {
    return 1 + Math.max(depth(node.l), depth(node.r));   // ERROR: Cannot resolve method 'depth(Tree)'
}

Correct way to overcome this is to put method depth() to each class. But what if I don't want to put it there? For example, method depth() may be not directly related to Tree and adding it to class would break business logic. Or, even worse, Tree may be written in 3rd party library that I don't have access to. In this case, what is the simplest way to implement ADT-like polymorpism?

Just in case, for the moment I'm using following syntax, which is obviously ill-favored:

int depth(Tree tree) {
    if (tree instanceof Empty) depth((Empty)tree)
    if (tree instanceof Leaf) depth((Leaf)tree);
    if (tree instanceof Node) depth((Node)tree); 
    else throw new RuntimeException("Don't know how to find depth of " + tree.getClass());
}

解决方案

Try something like this.

Sorry, my Java is very rusty. If, unlike me, you can remember the syntax, you could use Java generics to refine Object to Integer or whatever class the method you're writing needs. But you can't (can you?) return primitive types, sorry.

interface TreeFolder {
    Object onEmpty();
    Object onLeaf (int n);
    Object onNode (Tree l, Tree r);
}

interface Tree {
    Object fold (TreeFolder f);
}

class Empty implements Tree {
    Object fold (TreeFolder f) {
        return f.onEmpty();
    }
}

class Leaf implements Tree {
    private int n;
    Object fold (TreeFolder f) {
        return f.onLeaf (n);
    }
}

class Node implements Tree {
    private Tree l, r;
    Object fold (TreeFolder f) {
        return f.onNode (l, r);
    }
}

// meanwhile, in a class in another package far far away...
Object depth (Tree tree) {
    return tree.fold (new TreeFolder() {
        Object onEmpty() { return new Integer(0); }
        Object onLeaf (int n) { return new Integer(n); }
        Object onNode (Tree l, Tree r) {
            Integer ll = (Integer) l.fold (this);
            Integer rr = (Integer) r.fold (this);
            return new Integer (ll.intValue() + rr.intValue());
        }
    });
}

Note that in depth() I have to manually recurse (call fold()) on the Tree parameters. You could instead choose to recurse on them upfront in Node.fold() (and change TreeFolder accordingly), but then you have to recurse --- you can't choose to recurse only into the left subtree, should you wish to. (In Haskell we don't have to make that trade-off thanks to laziness.)

这篇关于Java中的类ADT多态性(不改变类)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆