函数式编程与范畴论

引言

如果要领会函数式编程的思想,不可避免的会接触到一个概念 Monad(单子),单子概念的理解对函数式编程的领会有着至关重要的作用,函数式编程大 神Phillip Wadler 说过一句话,"A monad is just a monoid in the category of endofunctors”, 翻译过来就是 “一个单子不就是自函子范畴上的幺半群么”。简单的一句话扯出了这篇系列文章的主题,范畴。

范畴论

范畴论在维基百科中的解释为,范畴论是数学的一门学科,以抽象的方法来处理数学概念,将这些概念形式化成一组组的“物件”及“态射”。这里提到了两个词“物件”即对象(Object)和态射(morphism)。对于非数学科班来理解这些概念可能有些枯躁,我尽快把这些概念带入我们熟悉的编程领域去解读。简单来讲,范畴论就是研究对象以及对象之间的态射。

什么是范畴

范畴就是一系列之间存在关系的对象所组成的一个“集合”。这里对象之间的关系就是态射。范畴由以下部分组成:

  • 一系列的对象(object).

  • 一系列的态射(morphism).

  • 一个组合(composition)操作符,用点(.)表示,用于将态射进行组合。

    可以用下图来表示

这里写图片描述

上图中表示了一个范畴,里面有 A, B, C, D 四个对象,我用箭头代码了每个对象之间的变换,即态射,其中对象 A 标示出了一个特殊的,称为单位态射的态射 id(A),其它对象也都有单位态射。这个范畴描述了,对象 A 可以通过态射 f 变换为 B,B 通过态射 g 可以变换为 C,B 还可以通过其它态射变换为 D,也就是 A 通过一系列态射变换为 C。这一系统变换与 h 等价,也就是 h = g.f 。记住顺序,从右向左。这就是组合操作,也就是范畴的本质是组合,很重要。
推理得到,任何一个态射与目标对象的单位态射组合,都是这个态射本身。

编程领域的一个范畴

我们通过范畴论来举一个编程领域的通用例子,直接与编程中一些概念联系起来。假设我们有个==类型==的范畴,它里面的对象都是编程中的一些类型,如 int, string, bool 等,如下

这里写图片描述

string 类型可以通过一个态射变换为 int, int 可以通过一个态射变换为 bool, 这两个态射可以是函数,如下:

int f(string s) {
    return s.ToInt();
}

bool g(int i) {
    return i == 0 ? false : true;
}

std::function h = [](string s) -> bool {
    return g(f(s));
}

那么态射 h 在这个类型范畴中是以一个函数对象的形式存在,因为兼顾 C/C++ 程序员的熟悉领域,这些代码主要以伪 C/C++ 的形式给出,由于 C/C++ 没有提供一些函数式编程的语法支持,所以有时会比较别扭。g.f 的组合就体现在 h 的定义中,我们直接调用 h(“7”),就相当于从 string->bool了。

柯里化

大家不难看出这个函数都是输入一个对象,输出一个对象,这是理想情况,但大多数情况都会有多个参数,这个时间就需要用柯里化(Currying) 来处理。
这里依然拿 C++ 中 std::function 来举例,在 std::function 中如果有一个函数需要两个参数,如

bool h1(string, string);

我们总是可以传入一个参数后,然后产生一个新的函数对象,这得益于 C++ 模板的一些偏特化特性。比如:

std::function<bool (string)> h = std::bind(&h1, "Oops", _1);
h("7");

当然也可以像下面这种做法

std::function<bool (string)> h(string) {
    return [](string s) -> bool {
        return g(f(s));
    };
}

h("Oops")("7");

所以说多输入总是能够通过柯里化,转换为单输入单输出,这样就可以转换为范畴里面,对象之间的转换了。

结束语

很多种思想其实都能在编程领域找到实践的影子,编程其实就是对现实世界的抽象,这也是编程的难点所在。这篇文章里引出了范畴论的概念,大家对范畴有了一个基本的认识,基于这些基本的认识,我们慢慢引出一些重要的概念和思想。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值