当前位置: 首页 > 知识库问答 >
问题:

Haskell中的存在类型与普遍量化类型

奚飞星
2023-03-14

这些到底有什么区别呢?我想我理解存在类型是如何工作的,它们就像OO中的基类没有向下强制转换的方法一样。通用类型有何不同?

共有1个答案

祁博涛
2023-03-14

这里的术语“普遍的”和“存在的”来自谓词逻辑中命名相似的量词。

通用量化通常被写成“have”,你可以读成“for all”,大致意思是它听起来像什么:在一个类似于“have x...”的逻辑语句中,无论“...”的位置是什么对于所有可能的“x”都是真的,你可以从任何被量化的东西中选择。

存在量化通常被写成“存在”,您可以将其读作“存在”,这意味着在类似于“存在x...”的逻辑语句中,无论“...”的位置是什么对于从被量化的事物集合中提取的一些未指定的“x”来说是正确的。

id :: forall a. a -> a
id x = x

由于a是普遍量化的,我们对它一无所知,因此无法以任何方式检查参数。因此id是该类型(1)唯一可能的函数。

在Haskell中,通用量化是“默认的”--签名中的任何类型变量都隐式地通用量化,这就是为什么ID的类型通常只写为a->a。这也被称为参数多态性,在Haskell中通常被称为“多态性”,在其他一些语言(例如C#)中被称为“泛型”。

这样的存在量化类型存在。a->a意味着,对于某些特定类型“a”,我们可以实现一个类型为a->a的函数。任何函数都可以,所以我挑一个:

func :: exists a. a -> a
func True = False
func False = True

最后一点让我们回到了通用量词,而Haskell(2)没有直接具有存在类型的原因(我的exists完全是虚构的,唉):因为具有存在量化类型的东西只能与具有通用量化类型的操作一起使用,所以我们可以编写exists类型。将用作所有R的。(对于所有a.a->r)->r--换句话说,对于所有结果类型r,给定一个函数,对于所有类型a接受a类型的参数并返回r类型的值,我们可以得到r类型的结果。

如果您不清楚为什么它们几乎等价,请注意,对于A,整体类型并不是普遍量化的--相反,它接受了一个参数,该参数本身对于A是普遍量化的,然后它可以将该参数用于它选择的任何特定类型。

顺便说一句,虽然Haskell实际上没有通常意义上的子类型概念,但我们可以将量词视为表示子类型的一种形式,其层次结构从普遍到具体再到存在。类型为的东西。可以转换为任何其他类型,因此可以将其视为所有内容的子类型;另一方面,任何类型都可以转换为存在的类型。,使其成为所有内容的父类型。当然,前者是不可能的(除了错误之外,所有a.a都没有类型的值),后者也是无用的(您不能使用exists a.a类型做任何事情),但这种类比至少在纸面上是有效的。:]

请注意,存在类型和普遍量化的参数之间的等价性与函数输入的方差翻转的原因相同。

因此,基本的思想大致是,普遍量化的类型描述了对任何类型都一样工作的事物,而存在类型描述了对特定但未知的类型工作的事物。

1:嗯,不完全是--只有当我们忽略导致错误的函数时,比如notid x=undefined,包括从不终止的函数,比如loopForever x=loopForever x

2:嗯,GHC。没有扩展,Haskell只有隐式的通用量词,根本没有谈论存在类型的真正方式。

 类似资料:
  • 问题内容: 我是C ++ / Java程序员,在日常编程中碰巧使用的主要范例是OOP。在某个线程中,我读到一条评论,即Type类本质上比OOP更直观。有人可以用简单的词来解释类型类的概念,以便像我这样的OOP家伙可以理解吗? 问题答案: 首先,我总是非常怀疑这种程序结构更直观。编程是违反直觉的,并且总是会因为人们自然而然地根据特定情况而不是一般规则来思考。要更改此设置,需要培训和实践,也称为“编程

  • 或者我只是混淆了概念,存在类型和泛型意味着完全不同的东西。请帮我弄明白。

  • Haskell是一种函数语言,它是严格类型化的,Haskell编译器在编译时知道整个应用程序中使用的数据类型。 1. 内置类型类 在Haskell中,每个语句都被视为数学表达式,并且此表达式的类别称为类型()。可以说是在编译时使用的表达式的数据类型。 要了解有关类型的更多信息,可以使用命令。以通用的方式可以将类型视为值,而可以将类型类视为一组相似类型的类型。在本章中,我们将学习不同的内置类型。 2

  • 存在类型似乎对它们包含的类型不感兴趣,但与它们匹配的模式表示存在某种类型,除非我们使用Typeable或Data,否则我们不知道它是什么类型。 当我们想要隐藏类型时(例如:对于异构列表),或者在编译时我们并不真正知道类型是什么时,我们会使用它们。 通过提供隐式为使用存在类型的代码提供了清晰、更好的语法 我的疑虑 在上面PDF的第20页中,下面的代码提到,函数不可能需要特定的缓冲区。为什么会这样?当

  • 一开始,我有一个简单的解析器类型: 我在左侧使用其中一个表示错误消息,在右侧使用解析表达式和其余标记。 此函数“解包”解析器函数。 我的目标是使解析器更加通用,使其不仅将令牌作为输入。所以我使用了pragma并将其更改为: 我想知道的是:“parse”函数现在有什么类型? 我无法弄清楚,也无法推断。GHCi给出了这个错误: 谢谢你的帮助。 编辑:非常感谢您的回答。 我之所以希望该类型看起来像“Pa

  • 我在Java中读到了关于将超类变量类型化为子类的知识,反之亦然。请告诉我哪些是有效的? 动物是超级类,有猫和狗子类。