函子与单子--从范畴论到编程
作为一名计算机工作者,理解范畴论中的函子与单子的目的,还是为了更好的理解函数式编程中的函子与单子,对于我来说,没有比理清两者之间的对应关系,能更好的帮助理解了。
先看一个范畴论中的函子F:
1. 给定一个范畴C,其元素为{X,Y,Z},态射为{f:X->Y, g:Y->Z};
2. 假设F是一个从C到D的函子,记作F:C->D
3. 那么范畴D的元素为{F(X), F(Y), F(Z)}, 态射为{F(f), F(g)}
这个函子F的能力概括为两点:
1. 能把C中的每一个元素,映射到D上,例如Fx:X->F(X)
2. 能把每一态射从C到映射到D上
简单的替换一下名称:
1. 给定一个范畴Types,其元素为{String,Enum, Int},态射为{f:String->Enum, g:Enum->Int};
2. 假设Fun是一个从Types到FunTypes的函子,记作Fun:Types->FunTypes
3. 那么范畴FunTypes的元素为{Fun(String), Fun(Enum), Fun(Int}, 态射为{Fun(f), Fun(g)}
对应起来
以Scala为例,如果把Fun(String)写为Fun[String], 那么这个Fun:Types->FunTypes很接近Scala中的一个Functor了,区别是Scala没有Fun(F)这样的形式,而以Fun.map(f)的形式代替,Fun.map(f: String->Enum): Fun[String] -> Fun[Enum].
在Scala中,一个函子F,天然具有把一个类型X映射到另外一个类型F[X]的能力,而map方法提供了映射态射(在编程语言中,就是函数)的能力,满足了函子的的两个能力。
单子呢?
与函子有一些区别,但根据函子的定义,也不难对应,我总结了一个对应表,总结他们的映射关系,如下表,其中A:C表示A是范畴C的一个元素,F[A]:D表示F[A]是D的一个元素;
小刚的图