Haskell中的模块签名是什么?

时间:2019-03-09 14:00:56

标签: haskell haskell-backpack

我最近发现了Haskell的称为“模块签名”的功能。如我所知,它们被放入.hsig文件中,并以signature关键字而不是module开头。 这样的文件的示例语法可能看起来像

signature Str where

data Str
empty :: Str
append :: Str -> Str -> Str

但是,我无法想象人们将如何以及为什么使用它们。您能解释一下它们解决了哪些问题以及如何正确利用它们吗?

他们强烈提醒我可以在OCaml(link)中看到的模块系统,该系统也具有模块签名和单独的实现,但是我无法确定这两个概念有多接近。有什么关系吗?

2 个答案:

答案 0 :(得分:4)

它们与OCaml模块系统有关,但有一些重要区别:

  • 签名是在语言中定义的(在 .hsig 文件中),但与OCaml不同,它们不是在语言中实例化的。相反,包管理器控制实例化(当前,仅Cabal提供实例化)。模块从不知道它们是要导入抽象签名还是实际模块。

  • 实现模块对签名一无所知,并且不直接引用它们。如果定义恰好兼容,则任何现有模块都可以实现签名。

  • 实例化是由某个编译单元(可执行文件,库,测试套件...)中的依赖项中模块名称和签名名称的重合触发的。当名称重合时,将发生一个称为“签名匹配”的过程验证类型和定义是否兼容。

“幸福的道路”是,在您的程序中,您依赖于具有签名“漏洞”的某个库,并且还依赖于另一个提供具有相同名称的实现模块的库。然后签名匹配自动发生。如果名称不匹配,或者我们需要使用签名的库的多个实例,则必须在Cabal文件的mixins部分中重命名签名和/或模块。


关于为什么模块签名可能有用的原因,请考虑bytestring,这是迄今为止在Haskell中处理二进制数据最流行的库。但是还有其他类型,例如stdio类型为Bytes

假设您正在编写自己的使用二进制数据的库,并且不想强迫用户进入stdio或bytestring。您有什么选择?

  • 一种方法是创建一个类似Bytelike的类,并使用它对所有函数进行参数化。您还需要向每个包含字节的每个数据类型添加一个类型参数。
  • 另一种方法是创建一个签名,该签名定义抽象的二进制数据类型以及该类型所需的所有操作。您的库将使用签名,并保持“不确定”状态,直到用户在创建自己的库时都依赖于您的库和适当的实现。

从用户的角度来看,typeclass解决方案并不令人满意。用户知道他想使用ByteStringBytes之一。该决定将不依赖于某些运行时标志,并且将在 his 程序范围内保持不变。然而,他必须处理更复杂的API,这使他不时回想起已经确定的问题。

最好是先做出决定,然后将其写入.cabal文件,然后再处理一个更简单的API。

答案 1 :(得分:1)

here所述,它们与OCaml模块签名密切相关。它们使您可以创建缺少某些模块的软件包,并说包含这些类型和值的模块应由软件包的用户交付。我还没有亲自测试过,但我想像这样的软件包非常类似于OCaml函子。