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