java - 在 Java 中模拟 ADT

标签 java haskell algebraic-data-types

应用程序可以在两种模式下运行 - “实时”模式(它查看世界状态的每次更新)或“采样”模式(它仅每 T 毫秒查看一次世界状态)。

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

data Mode = RealTime | Sampled Int

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

case mode of
    RealTime         -> -- do realtime stuff
    Sampled interval -> -- do sample stuff with 'interval'

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

如何以类型安全的方式在 Java 中对同一事物建模?也就是我要

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

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

最佳答案

在像 Java 这样只以类型安全的方式提供开放类(可以随时继承)的语言中模拟封闭代数数据类型的传统方法是 Visitor pattern :

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();
    }
}

正如@user3237465 所指出的,数据类型的几种编码是可能的,当数据类型不是递归时,它们碰巧重合:Church 编码是一种折叠:它允许您累积一个值通过对 Church 编码数据类型的递归。 Scott 编码对应于实际的模式匹配。无论如何,访问者都可以用来实现所有这些编码。感谢@user3237465 的鼓励!

关于java - 在 Java 中模拟 ADT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31428870/

相关文章:

java - 如果数据库中没有值,Android Firebase 查询监听器不会监听

haskell - 如何在没有 Cabal 或 Cabal-Install 的情况下安装包/库?

haskell - 为什么我不能在不同的数据类型之间重用相同的值构造函数?

在 Jar 文件中找不到 JavaFx 图像

java - Tomcat启动后调用构造函数

java - 如何更新 SQLite 数据库中的值?

haskell - 你能做些什么对 Haskell 类型类有用?

haskell - (模拟)Haskell 中的宏?

c++ - 代数数据类型的惯用现代 C++ 是什么?

list - 从列表初始化代数数据类型