Haskell和OCaml中的functor有何相似之处?

47

我过去一年左右一直在玩Haskell,现在实际上开始“懂了”,直到单子、镜头、类型族等等。

我即将离开这个舒适区一点,我要作为日常工作移动到一个OCaml项目中。我稍微看了一下语法,我正在寻找类似的高级概念,例如functor。

我阅读了OCaml中functor的代码和结构,但我似乎不能确定它们是否是Haskell和OCaml中的相似概念。 简而言之,在Haskell中,functor对我来说主要是将函数提升到Haskell中的一种方式,我像那样使用它(并且喜欢它)。 在OCaml中,它让我感觉更接近于面向接口编程(例如创建set或list时,用到比较函数),我真的不知道如何将函数提升到functor上,等等。

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

Kasper

1个回答

51
从实际角度来看,你可以将OCaml和Haskell中的"函数子"视为不相关的。正如你所说,在Haskell中,任何允许你在其上映射函数的类型都是函数子。而在OCaml中,函数子是一个由另一个模块参数化的模块。 函数式编程中什么是函数子?很好地描述了两种语言中的函数子以及它们之间的差异。
但是,正如名称所示,这两个看似不相关的概念实际上存在联系!两种语言中的函数子都只是范畴论中的一个概念的实现。
范畴论研究的是范畴,它们只是具有“态射”(或称“箭头”)的任意对象集合。范畴的概念非常抽象,因此“对象”和“态射”可以是任何带有一些限制的东西-每个对象都必须有一个恒等态射,并且态射必须能够组合。
最明显的范畴示例是集合和函数的范畴:集合是对象,集合之间的函数是态射。显然,每个集合都有一个恒等函数,并且函数可以组合。通过查看像Haskell或OCaml这样的函数式编程语言,可以形成非常相似的范畴:具体类型(例如带有*种类的类型)是对象,而Haskell/OCaml函数是它们之间的态射。
在范畴论中,函子是范畴之间的变换。它就像范畴之间的函数。当我们查看Haskell类型的范畴时,函子基本上是一种类型级别的函数:它将类型映射到其他内容。我们关心的特定类型的函子将类型映射到其他类型。这方面的完美示例是MaybeMaybeInt映射到Maybe Int,将String映射到Maybe String等等。它为每个可能的Haskell类型提供了映射。
Functors有一个额外的要求 - 它们必须将范畴的态射以及对象映射。特别地,如果我们有一个态射A→B,并且我们的functor将A映射到A'和B映射到B',它必须将态射A→B映射到某个态射A'→B'。作为一个具体的例子,假设我们有类型Int和String。有很多Haskell函数Int→String。对于Maybe成为一个合适的functor,它必须有一个函数Maybe Int→Maybe String,其中包括每一个这样的函数。
令人高兴的是,这正是fmap函数所做的 - 它映射函数。对于Maybe,它具有类型(a→b)→Maybe a→Maybe b; 我们可以添加一些括号来得到:(a→b)→(Maybe a→Maybe b)。这个类型签名告诉我们,对于任何我们拥有的普通函数,我们也有相应的函数在Maybe上。
因此,一个函子是类型之间的映射,同时也保留它们之间的函数。函数fmap本质上只是对函子的第二个限制的证明。这使得很容易看出Haskell Functor类只是数学概念的一个特定版本。
那么OCaml呢?在OCaml中,functor不是一种类型-它是一个模块。特别地,它是一个参数化模块:一个接受另一个模块作为参数的模块。我们已经可以看到一些相似之处:在Haskell中,Functor就像类型级函数;在OCaml中,functor就像模块级函数。因此,它实际上是相同的数学思想;然而,它不是用于像Haskell中那样的类型,而是用于模块。

关于OCaml的functor与范畴论functor的更多细节,请参考CS网站上的内容:SML中functor与范畴论functor之间的关系是什么?。该问题讨论的是SML而非OCaml per se,但我的理解是,OCaml的模块系统与SML非常密切相关。

总之:Haskell和OCaml中的functor是两种根本不同的结构,它们都恰好是同一个非常抽象的数学概念的具体化。我认为这很棒 :).


8
坦白说,我不确定闲聊范畴论能否帮助大多数初学者理解Haskell函子,这可能应该保留给更高级的语言设计探究。(1) ML函子和范畴理论之间的关系几乎是胡扯。这是对一些东西的反向解释,它可能只是挑选了一个看起来像“函数”的名字,并且并不令人信服也不有助于处理ML函子。你可以只说“模块之间的函数”就可以让每个人都省去麻烦。(2) - gasche
13
(1)在我了解背后的范畴论之前,函子似乎很难理解,它们看起来非常任意。有一些很好的教程可以让所有东西变得清晰明了,但不幸的是我忘记了链接。我真希望早点找到那个教程。 (2)虽然我不太了解ML是如何设计的,但它似乎足够适合。重要的是要看到Haskell思想和ML思想之间的相似之处。 - Tikhon Jelvis
1
问题在于Haskell和ML的思想之间没有合理的相似之处,只有一个命名冲突。 - gasche
5
我发现这个答案非常有趣。 - MathematicalOrchid
2
我也是,认为范畴论确实不失为一种好方法。我还在思考模块到模块函子对于 'fmap' 的影响。看看是否会有新的问题产生;-) - Kasper
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接