Являются ли GADT в функциональных языках эквивалентными традиционным OOP + generics, или существует сценарий, в котором существуют ограничения корректности, которые легко выполняются GADT, но трудно или невозможно достичь с помощью Java или С#?
Например, этот "хорошо типизированный интерпретатор" программы Haskell:
data Expr a where
N :: Int -> Expr Int
Suc :: Expr Int -> Expr Int
IsZero :: Expr Int -> Expr Bool
Or :: Expr Bool -> Expr Bool -> Expr Bool
eval :: Expr a -> a
eval (N n) = n
eval (Suc e) = 1 + eval e
eval (IsZero e) = 0 == eval e
eval (Or a b) = eval a || eval b
можно записать эквивалентно в Java с использованием дженериков и соответствующей реализации каждого подкласса, хотя гораздо более подробный:
interface Expr<T> {
public <T> T eval();
}
class N extends Expr<Integer> {
private Integer n;
public N(Integer m) {
n = m;
}
@Override public Integer eval() {
return n;
}
}
class Suc extends Expr<Integer> {
private Expr<Integer> prev;
public Suc(Expr<Integer> aprev) {
prev = aprev;
}
@Override public Integer eval() {
return 1 + prev.eval()
}
}
/** And so on ... */