函子到单子:形状的故事

主要观点:用“寻找守恒量”的直觉来理解 Haskell 中的 Functor 及相关抽象,如 fmap 保持的“形状”及改变的“结果”,并由此延伸到 Traversable、Applicative、Alternative、Monad 等类型类及自由结构(free structures)。
关键信息:

  • Functorfmap保持“形状”,不同 Functor 保持的“形状”不同,如列表的长度、可选类型的存在性等,且每个合法的 Functor 实例都诱导出一个守恒量,可称为“形状”。
  • TraversableTraversable让我们能映射“有效果的”函数并保持形状,如 Map k 的遍历实例能在不改变键的情况下映射函数。
  • ApplicativeApplicative给我们一种组合形状的方式,不考虑结果,其定律与 Functor 诱导的“形状”相关,很多库利用了其“知道形状而不知结果”的特性。
  • AlternativeAlternative<|><*> 类似,但组合形状的幺半群不同,引入了结果的基本数据依赖,形状合并与结果相关。
  • MonadMonad允许最终动作的形状依赖于第一个动作的结果,如 IO 中动作的形状依赖于执行结果,Monad使得 guard 等操作有用,且某些类型没有 Monad 实例。
  • Free Structures:通过指定形状并使用 Ap(用于自由 Applicative)或 Free(用于自由 Monad)创建相应的 Applicative 或 Monad,理解形状有助于选择合适的自由结构。

重要细节:

  • 以各种类型为例说明 Functor 保持的“形状”,如列表的长度、Map 的键等。
  • 详细解释 Applicative 中不同实例的组合形状方式,如 Writermappend、列表的乘法等。
  • 对比 ApplicativeAlternative 在形状和结果依赖上的差异。
  • 举例说明 Monad 中动作形状依赖结果的情况,如 IO 操作和解析器组合。
  • 通过自定义的 OptionSingle 类型展示自由结构的创建和使用。
阅读 12
0 条评论