gpt4 book ai didi

Java 标记的 union/sum 类型

转载 作者:IT老高 更新时间:2023-10-28 20:46:29 24 4
gpt4 key购买 nike

有没有办法在 Java 中定义 sum 类型? Java 似乎天生就直接支持乘积类型,我认为枚举可能允许它支持 sum 类型,而继承看起来也许可以做到,但至少有一种情况我无法解决。详细地说,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一个没有字段且只有一个构造函数(私有(private)、无参数、空)的抽象类,并将您的“数据构造函数”(leftright 静态工厂方法)嵌套在类中,以便他们可以看到私有(private)构造函数,但没有别的可以,有效地密封类型。

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

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<A, B>() {
@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<A, B>() {
@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());
}
}

愉快又安全!没办法搞砸。因为类型是有效密封的,所以您可以放心,只有两种情况,并且每个操作最终都必须根据 either 定义。方法,它强制调用者处理这两种情况。

关于您尝试解决的问题 class Left<L> extends Either<L,?> ,考虑签名<A, B> Either<A, B> left(A value) .类型参数B不会出现在参数列表中。因此,给定某个类型的值 A ,您可以获得Either<A, B>对于任何类型B .

关于Java 标记的 union/sum 类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48143268/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com