图文解释 Swift 中的 Functor、Applicative 和 Monad

657 查看

这是一篇 Haskell 官网 文章 Functors, Applicatives, And Monads In Pictures 的 Swift 移植版本。

创作这篇文章的并不是我,我只是将它其中的代码翻译为 Swift ,这个过程很有趣。

如果你喜欢这篇文章,请感谢原作者 Aditya Bhargava,@_egonschiele

尽管关于 Swift 的宣传沸沸扬扬,但是它并不是一门真正的函数式语言。这意味着要实现一些 Haskell 内置的操作符功能,我们可能需要写一些额外的代码。

你可以在 GitHub 找到包含本文所有代码的 playground。

最后,如果你觉得这篇文章内容对于你来说很难理解不要担心,我也是在将原文读了许多遍之后才渐渐找到思路,而在翻译为 Swift 的过程中依然是一团糟。

这是一个简单的值(value):

我们也知道如何使用函数(function)来处理值:

这很容易懂,那么拓展一下,任意值都能在处于特定的上下文(context)中。你可以先想象上下文就像是一个盒子,你可以把值放进去。

现在当你使用函数处理这个值,根据上下文的不同会得到不同的结果。Functors, Applicatives, Monads,Arrows等概念都是基于此。Optional 类型定义了两种相关的上下文:

注意:图上的 Maybe(Just | None)来自 Haskell,类似于 Swift 的 Optional,.Some.None

紧接着我们将看到一个值的类型是 .Some(T) 或者是 .None 会怎样造成函数作用的不同。我们先来谈谈 Functors!

Functors

当一个值被封装到盒子里,一个普通的函数无法作用于它:

这个是就是 map 的由来(在 Haskell 是 fmap)。map 知道如何使用函数处理数据类型。例如,你想要使用一个函数,将 .Some(2) 加 3。使用 map:

或者用更简洁的语法,使用 Swift 的 autoclosure:

砰! map 的作用我们看到了,但是它是怎么做到的?

到底什么是 Functor?

任意定义了 map ( Haskell 中的 fmap)如何作用于自己的类型都是 Functor,map是这样作用的:

所以我们可以这么做

map 神奇地使函数起了作用,因为 Optional 是一个 Functor。它表明了 map 是如何应用 SomeNone

Optional.Some(2).map { $0 + 3 }:

这里是当我们写下 Optional.Some(2).map { $0 + 3 } 背后所发生的:

所以我们就像在说,map,请将 { $0 + 3 }作用与 .None 上?

就像黑客帝国中的 Morpheus,map 知道要做什么;开始时是 None,结束也是 Nonemap 是一种禅。现在你可以理解为什么 Optional 类型的存在。举个例子,对于没有 Optional 类型的语言,比如 Ruby,对于一条数据库记录是这么工作的:

但是用 Swift 使用 Optional 仿函数: