用Java模拟ADT

Chr*_*lor 9 java haskell algebraic-data-types

应用程序可以以两种模式运行 - "实时",它查看对世界状态的每次更新,或"采样",其中它仅每T毫秒查看世界状态.

如果我正在编写Haskell(或任何使用ADT的语言),我会将其建模为

data Mode = RealTime | Sampled Int
Run Code Online (Sandbox Code Playgroud)

可以以类型安全的方式使用如下

case mode of
    RealTime         -> -- do realtime stuff
    Sampled interval -> -- do sample stuff with 'interval'
Run Code Online (Sandbox Code Playgroud)

我说它是"类型安全的",因为如果您在实时模式下运行,则无法尝试访问该interval字段(如果您在采样模式下操作,则会在您需要时提供该字段).

如何以类型安全的方式在Java中对相同的东西进行建模?那就是我想要的

  • 定义区分两种模式的类(或枚举),和
  • interval在实时模式下禁止访问该字段,以及
  • 让所有这些都由编译器检查.

这在Java中可行吗?如果没有,实现这种类型安全的惯用方法是什么?

pyo*_*yon 9

在类似Java的语言中模拟封闭代数数据类型的传统方法是访问者模式:只能以类型安全的方式提供开放类(可以随时继承).

abstract class Mode {
    public abstract <T> T accept(ModeVisitor<T> visitor);
}

final class RealTime extends Mode {
    public RealTime() {}

    public <T> T accept(ModeVisitor<T> visitor) {
        return visitor.visit(this);
    }
}

final class Sampled extends Mode {
    private final int interval;

    public Sampled(int interval) {
        this.interval = interval;
    }

    public int getInterval() {
        return this.interval;
    }

    public <T> T accept(ModeVisitor<T> visitor) {
        return visitor.visit(this);
    }
}

// The recursion principle itself
abstract class ModeVisitor<T> {
    public abstract T visit(RealTime mode);
    public abstract T visit(Sampled mode);
}

// Concrete uses of the recursion principle
final class ModeShow extends ModeVisitor<String> {
    private ModeShow() {}

    public static String show(Mode mode) {
        return mode.accept(new ModeShow());
    }

    public String visit(RealTime mode) {
        return "RealTime";
    }

    public String visit(Sampled mode) {
        return "Sampled " + mode.getInterval();
    }
}
Run Code Online (Sandbox Code Playgroud)

正如@ user3237465所说,数据类型的几种编码是可能的,当数据类型不是递归时恰好是一致的:Church编码是一个折叠:它允许你通过Church编码的数据类型的递归来累积值.Scott编码对应于实际模式匹配.无论如何,访问者可以用来实现所有这些编码.感谢你的推动,@ user3237465!