为什么所有Haskell类型类都有法则?

时间:2013-02-21 13:51:36

标签: haskell typeclass

Typeclassopedia中的所有类型类都有相关的定律,例如某些运算符的关联性或可交换性。 “法律”的定义似乎是一种无法在类型系统中表达的约束。我当然明白为什么你想拥有monad定律,但是有一个根本原因可以在类型系统中完全表达的类型类是没有意义的吗?

3 个答案:

答案 0 :(得分:18)

您会注意到法律几乎总是代数法。它们可以通过类型系统通过使用一些扩展来表达,但证明表达起来很麻烦。因此,您有未经检查的法律,可能的实施可能会破坏它们。为什么这样好?

原因在于Haskell中使用的设计模式是通过数学结构(通常来自抽象代数)来激励(并且在大多数情况下是镜像的)。虽然大多数其他语言都具有安全性,性能和语义等特定功能的直观概念,但我们Haskell程序员更喜欢建立形式概念。这样做的好处是:一旦您的类型和功能遵守安全法则,它们在基础代数结构的意义上是安全的。它们可证明安全。

以仿函数为例。 Haskell仿函数有以下两个定律:

fmap f . fmap g = fmap (f . g)
fmap id         = id

首先,这非常重要:Haskell中的函数是不透明的。你不能检查,比较或任何它们。虽然这在Haskell中听起来像是一件坏事但实际上这是一件非常好的事情。 fmap函数无法检查您传递的函数。特别是它无法检查您是否已通过身份功能或已通过作文。总之:它不能作弊!它遵守这两条法律的唯一方法实际上就是不引入自己的任何影响。这意味着,在适当的仿函数fmap中,永远不会做任何意外的事情。事实上,除了映射给定的函数之外,它无能为力。这是一个非常简单的例子,我没有解释为什么fmap不能作弊的所有细微之处,但它证明了这一点。

现在扩展这个语言,基础库和最明智的第三方库。这为您提供了一种语言可以像语言一样可预测的语言。当你编写代码时,你知道它将要做什么。这是Haskell代码经常开箱即用的主要原因之一。我经常在编译之前编写Haskell代码页面。一旦我的类型错误得到修复,我的程序通常会有效。

为什么这是可取的另一个原因是它允许更多组合风格的编程。这在团队合作时特别有用。首先,将应用程序映射到代数结构并建立必要的法则。例如:您表达了对有效Web服务器的意义。特别是,您建立了Web服务器组合的正式概念。如果组成两个有效Web服务器,则结果为有效Web服务器。你知道这是怎么回事吗?建立这些法律后,队友们去上班,他们孤立地工作。完成工作几乎不需要沟通。当他们再次见面时,每个人都会展示他们的有效Web服务器,他们只是将它们组合成最终产品,一个网站。由于各个组件都是有效Web服务器,因此最终结果必须是有效Web服务器。可证明。

答案 1 :(得分:7)

是和否。例如,Show类没有与之相关的任何法律,它肯定是有用的。

然而,类型类表达接口。接口需要满足的不仅仅是一堆函数 - 您希望这些函数满足规范。规范通常比Haskell的类型系统中表达的更复杂。例如,参加Eq课程。它只需要为我们提供一个函数,其类型必须是a -> a -> Bool。这是Haskell类型系统允许我们从Eq类型的实例中获取的最多。但是,我们通常会期望更多来自此函数 - 您可能希望它是等价关系(自反,对称和传递)。那么你就把这些要求说成是单独的“法律”。

答案 2 :(得分:1)

类型类不需要有规则,但如果有规则通常会更有用。许多类型类预计会以某种方式发挥作用,法律规定了用户的期望。这些法律允许用户对类型类的实例的工作方式做出假设。如果你违反了类型规则,你不会被Haskell警察逮捕,你最终会被困惑的用户。