45

在过去一年左右的时间里,我一直在玩 Haskell,实际上我开始“理解”它,直到 Monads、Lenses、Type Families ……很多。

我即将离开这个舒适区一点,我将转向 OCaml 项目作为日常工作。稍微浏览一下语法,我一直在寻找类似的更高级别的概念,例如仿函数。

我阅读了 OCaml 中的代码和仿函数的结构,但我似乎无法了解它们现在是否是 Haskell 和 OCaml 中的相似概念。简而言之,Haskell 中的函子对我来说主要是一种在 Haskell 中提升函数的方法,我就这样使用它(并且喜欢它)。在 OCaml 中,它让我感觉它更接近于对接口进行编程(例如,当使用该比较函数制作集合或列表时)并且我真的不知道如何将函数提升到函子左右。

有人可以解释一下这两个概念是否相似,如果是的话,我错过了什么或没有看到什么?我用谷歌搜索了一下,似乎没有找到明确的答案。

卡斯帕

4

1 回答 1

48

从实际的角度来看,您可以认为 OCaml 和 Haskell 中的“函子”是不相关的。正如您所说,在 Haskell 中,仿函数是允许您在其上映射函数的任何类型。在 OCaml 中,函子是由另一个模块参数化的模块。

在函数式编程中,什么是函子?很好地描述了两种语言中的函子是什么以及它们之间的区别

然而,顾名思义,这两个看似完全不同的概念,其实是有联系的!两种语言的函子都只是范畴论中一个概念的实现。

范畴论是对范畴的研究,范畴只是对象之间具有“态射”的任意集合。范畴的概念是非常抽象的,所以“对象”和“态射”实际上可以是任何有一些限制的东西——每个对象都必须有一个恒等态射,而且态射必须组合。

范畴最明显的例子是集合和函数的范畴:集合是对象,集合之间的函数是态射。显然,每个集合都有一个恒等函数,并且函数可以组合。通过查看像 Haskell 或 OCaml 这样的函数式编程语言可以形成一个非常相似的类别:具体类型(例如,具有 kind的类型*)是对象,而 Haskell/OCaml 函数是它们之间的态射。

在范畴论中,函子是范畴之间的转换。它就像类别之间的函数。当我们查看 Haskell 类型的类别时,函子本质上是一个类型级别的函数:它将类型映射到其他东西。我们关心的特定类型的函子将类型映射到其他类型。一个完美的例子是MaybeMaybe映射IntMaybe IntStringMaybe String等等。它为每种可能的 Haskell 类型提供了映射。

函子还有一个额外的要求——它们必须映射类别的态射以及对象。特别是,如果我们有一个态射A → B并且我们的函子映射AA'BB',它必须将态射映射A → B到某个态射A' → B'。作为一个具体的例子,假设我们有类型IntString。有一大堆 Haskell 函数Int → String。为了Maybe成为一个合适的函子,它必须对其中Maybe Int → Maybe String的每一个都有一个函数。

令人高兴的是,这正是fmap函数所做的——它映射函数。因为Maybe,它有类型(a → b) → Maybe a → Maybe b;我们可以添加一些括号来获得:(a → b) → (Maybe a → Maybe b)。这个类型签名告诉我们的是,对于我们拥有的任何普通函数,我们在Maybes 上也有一个对应的函数。

所以函子是类型之间的映射,它也保留了它们之间的函数。该fmap函数本质上只是对函子的第二个限制的证明。这使得很容易看出 HaskellFunctor类只是数学概念的一个特定版本。

那么OCaml呢?在 OCaml 中,仿函数不是类型——它是一个模块。特别是,它是一个参数化模块:一个将另一个模块作为参数的模块。我们已经可以看到一些相似之处:在 Haskell 中,aFunctor就像一个类型级函数;在 OCaml 中,仿函数就像一个模块级函数。所以真的,这是同一个数学概念。但是,它不像在 Haskell中那样用于类型,而是用于模块

在 CS 网站上有更多关于 OCaml 函子如何与类别理论函子相关的详细信息:SML 中的函子与类别理论之间的关系是什么?. 问题是关于 SML 而不是 OCaml本身,但我的理解是 OCaml 的模块系统与 SML 的模块系统非常密切相关。

总之:Haskell 和 OCaml 中的函子是两种根本不同的结构,它们恰好都是同一个非常抽象的数学思想的具体化。我认为这很整洁:)。

于 2013-05-03T07:23:57.677 回答