- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
函数式语言中的 GADT 是否等同于传统的 OOP + 泛型,或者存在这样的情况:GADT 可以轻松实现正确性约束,但使用 Java 或 C# 很难或不可能实现?
例如,这个“类型良好的解释器”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
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 ... */
最佳答案
OOP 类是开放的,GADT 是封闭的(就像普通的 ADT)。
在这里,“开放”意味着您以后可以随时添加更多子类,因此编译器不能假定可以访问给定类的所有子类。 (有一些异常(exception)情况,例如 Java 的 final
阻止任何子类化,以及 Scala 的密封类)。相反,ADT 是“关闭的”,因为您以后无法添加更多构造函数,并且编译器知道这一点(并且可以利用它来检查例如穷举性)。有关详细信息,请参阅“expression problem”。
考虑以下代码:
data A a where
A1 :: Char -> A Char
A2 :: Int -> A Int
data B b where
B1 :: Char -> B Char
B2 :: String -> B String
foo :: A t -> B t -> Char
foo (A1 x) (B1 y) = max x y
Char
是唯一的类型
t
哪一个可以同时产生
A t
和
B t
.关闭的 GADT 可以确保这一点。如果我们尝试使用 OOP 类来模仿这一点,我们会失败:
class A1 extends A<Char> ...
class A2 extends A<Int> ...
class B1 extends B<Char> ...
class B2 extends B<String> ...
<T> Char foo(A<T> a, B<T> b) {
// ??
}
T
。)我们可能会考虑在
A
中添加一些通用方法。或
B
允许这样做,但这将迫使我们为
Int
实现所述方法和/或
String
也是。
Char foo(A<Char> a, B<Char> b) // ...
A
之间共享的类型和
B
可能是比单例更大的集合
Char
.更糟糕的是,类是开放的,所以一旦添加一个新的子类,集合就会变得更大。
A<Char>
的变量你仍然不知道那是不是
A1
与否,因此您无法访问
A1
的字段,但使用类型转换除外。这里的类型转换是安全的,因为程序员知道
A<Char>
没有其他子类。 .在一般情况下,这可能是错误的,例如
data A a where
A1 :: Char -> A Char
A2 :: t -> t -> A t
A<Char>
必须是
A1
的父类(super class)和
A2<Char>
.
data Teq a b where
Teq :: Teq t t
foo :: Teq a b -> a -> b
foo Teq x = x
trans :: Teq a b -> Teq b c -> Teq a c
trans Teq Teq = Teq
interface Teq<A,B> {
public B foo(A x);
public <C> Teq<A,C> trans(Teq<B,C> x);
}
class Teq1<A> implements Teq<A,A> {
public A foo(A x) { return x; }
public <C> Teq<A,C> trans(Teq<A,C> x) { return x; }
}
A,B
,然后仅在
A=B
的情况下实现(
implements Teq<A,A>
) 按类别
Teq1
.
foo
来自
A
至
B
,以及“传递性证明”
trans
, 其中给出
this
类型
Teq<A,B>
和
x
类型
Teq<B,C>
可以产生一个对象
Teq<A,C>
.这是与上面使用 GADT 的 Haskell 代码类似的 Java。
A/=B
时无法安全实现该类,据我所知:它需要返回空值或不终止作弊。
关于haskell - GADT 提供了什么是 OOP 和泛型无法做到的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29454528/
在 Haskell 中,类型声明使用双冒号,即 (::),如 not::Bool -> Bool。 但是在许多语法与 Haskell 类似的语言中,例如榆树、 Agda 、他们使用单个冒号(:)来声明
insertST :: StateDecoder -> SomeState -> Update SomeState SomeThing insertST stDecoder st = ... Stat
如果这个问题有点含糊,请提前道歉。这是一些周末白日梦的结果。 借助 Haskell 出色的类型系统,将数学(尤其是代数)结构表达为类型类是非常令人愉快的。我的意思是,看看 numeric-prelud
我有需要每 5 分钟执行一次的小程序。 目前,我有执行该任务的 shell 脚本,但我想通过 CLI 中的键为用户提供无需其他脚本即可运行它的能力。 实现这一目标的最佳方法是什么? 最佳答案 我想你会
RWH 面世已经有一段时间了(将近 3 年)。在在线跟踪这本书的渐进式写作之后,我渴望获得我的副本(我认为这是写书的最佳方式之一。)在所有相当学术性的论文中,作为一个 haskell 学生,读起来多么
一个经典的编程练习是用 Lisp/Scheme 编写一个 Lisp/Scheme 解释器。可以利用完整语言的力量来为该语言的子集生成解释器。 Haskell 有类似的练习吗?我想使用 Haskell
以下摘自' Learn You a Haskell ' 表示 f 在函数中用作“值的类型”。 这是什么意思?即“值的类型”是什么意思? Int 是“值的类型”,对吗?但是 Maybe 不是“值的类型”
现在我正在尝试创建一个基本函数,用于删除句子中的所有空格或逗号。 stringToIntList :: [Char] -> [Char] stringToIntList inpt = [ a | a
我是 Haskell 的新手,对模式匹配有疑问。这是代码的高度简化版本: data Value = MyBool Bool | MyInt Integer codeDuplicate1 :: Valu
如何解释这个表达式? :t (+) (+3) (*100) 自 和 具有相同的优先级并且是左结合的。我认为这与 ((+) (+3)) (*100) 相同.但是,我不知道它的作用。在 Learn
这怎么行 > (* 30) 4 120 但这不是 > * 30 40 error: parse error on input ‘*’ 最佳答案 (* 30) 是一个 section,它仍然将 * 视为
我想创建一个函数,删除满足第二个参数中给定谓词的第一个元素。像这样: removeFirst "abab" ( 'b') = "abab" removeFirst [1,2,3,4] even =
Context : def fib(n): if n aand returns a memoized version of the same function. The trick is t
我明白惰性求值是什么,它是如何工作的以及它有什么优势,但是你能解释一下 Haskell 中什么是严格求值吗?我似乎找不到太多关于它的信息,因为惰性评估是最著名的。 他们各自的优势是什么。什么时候真正使
digits :: Int -> [Int] digits n = reverse (x) where x | n digits 1234 = [3,1,2,4]
我在 F# 中有以下代码(来自一本书) open System.Collections.Generic type Table = abstract Item : 'T -> 'U with ge
我对 Haskell 比较陌生,过去几周一直在尝试学习它,但一直停留在过滤器和谓词上,我希望能得到帮助以帮助理解。 我遇到了一个问题,我有一个元组列表。每个元组包含一个 (songName, song
我是 haskell 的初学者,我试图为埃拉托色尼筛法定义一个简单的函数,但它说错误: • Couldn't match expected type ‘Bool -> Bool’
我是 Haskell 语言的新手,我在使用 read 函数时遇到了一些问题。准确地说,我的理解是: read "8.2" + 3.8 应该返回 12.0,因为我们希望返回与第二个成员相同的类型。我真正
当我尝试使用真实项目来驱动它来学习 Haskell 时,我遇到了以下定义。我不明白每个参数前面的感叹号是什么意思,我的书上好像也没有提到。 data MidiMessage = MidiMessage
我是一名优秀的程序员,十分优秀!