编程语言
首页 > 编程语言> > Java标记了union / sum类型

Java标记了union / sum类型

作者:互联网

有没有办法在Java中定义sum类型? Java似乎自然地直接支持产品类型,我认为枚举可能允许它支持和类型,并且继承看起来可能它可以做到,但至少有一个我无法解决的情况.
详细说明,sum类型是一种类型,它可以具有一组不同类型中的一种,如C中的标记并集.
就我而言,我正在尝试用Java实现haskell的Either类型:

data Either a b = Left a | Right b

但是在基础级别我不得不将其作为产品类型实现,而忽略其中一个字段:

public class Either<L,R>
{
    private L left = null;
    private R right = null;

    public static <L,R> Either<L,R> right(R right)
    {
        return new Either<>(null, right);
    }

    public static <L,R> Either<L,R> left(L left)
    {
        return new Either<>(left, null);
    }

    private Either(L left, R right) throws IllegalArgumentException
    {
        this.left = left;
        this.right = right;
        if (left != null && right != null)
        {
            throw new IllegalArgumentException("An Either cannot be created with two values");
        }
        if (left == right)
        {
            throw new IllegalArgumentException("An Either cannot be created without a value");
        }
    }

    .
    .
    .
}

我尝试使用继承来实现它,但是我必须使用Java泛型不允许的通配符类型参数或等效参数:

public class Left<L> extends Either<L,?>

我没有太多使用Java的Enums,但是虽然它们似乎是次佳的候选者,但我并不抱有希望.
在这一点上,我认为这可能只能通过类型转换Object值来实现,我希望完全避免它,除非有一种方法可以安全地执行它,并且能够将它用于所有和类型.

解决方法:

使用一个私有构造函数创建一个抽象类,并在类中嵌套“数据构造函数”(左侧和右侧静态工厂方法),以便它们可以看到私有构造函数,但没有其他任何东西可以有效地密封类型.

使用抽象方法either来模拟详尽的模式匹配,在静态工厂方法返回的具体类型中适当地覆盖.实现便利方法(如fromLeft,fromRight,bimap,first,second).

import java.util.Optional;
import java.util.function.Function;

public abstract class Either<A, B> {
    private Either() {}

    public abstract <C> C either(Function<? super A, ? extends C> left,
                                 Function<? super B, ? extends C> right);

    public static <A, B> Either<A, B> left(A value) {
        return new Either<>() {
            @Override
            public <C> C either(Function<? super A, ? extends C> left,
                                Function<? super B, ? extends C> right) {
                return left.apply(value);
            }
        };
    }

    public static <A, B> Either<A, B> right(B value) {
        return new Either<>() {
            @Override
            public <C> C either(Function<? super A, ? extends C> left,
                                Function<? super B, ? extends C> right) {
                return right.apply(value);
            }
        };
    }

    public Optional<A> fromLeft() {
        return this.either(Optional::of, value -> Optional.empty());
    }

    // other convenience methods
}

愉快又安全!没办法搞砸了.

关于您尝试上课的问题Left< L>扩展要么< L,?>,考虑签名< A,B> < A,B>左(一个值).类型参数B未出现在参数列表中.因此,给定某种类型A的值,您可以获得Either< A,B>适用于任何类型B.

标签:algebraic-data-types,java,haskell
来源: https://codeday.me/bug/20191003/1851335.html