范畴论基本概念

如果你是第一次听说范畴论(category theory),看到这高大上的名字估计心里就会一咯噔,到底数学威力巨大,光是高等数学就能让很多人噩梦连连。和搞编程的一样,数学家喜欢将问题不断加以抽象从而将本质问题抽取出来加以论证解决,范畴论就是这样一门以抽象的方法来处理数学概念的学科,主要用于研究一些数学结构之间的关系及联系。

在范畴论里,一个范畴(category)指的是这样一个好东西,它由三部分组成:

  1. 一系列的对象(object).
  2. 一系列的态射(morphism).
  3. 一个组合(composition)操作符,用点(.)表示,用于将态射进行组合。

一个对象可以看成是一类东西,数学上的群,环,甚至简单的有理数,无理数等都可以归为一个对象,对应到编程语言里,可以理解为一个类型,比如说整型,布尔型,类型事实上可以看成是值的集合,例如整型就是由 0,1,2...等组成的,因此范畴论里的对象简单理解就可以看成是值(value)的集合。

一个态射指的是一种映射关系,简单理解,态射的作用就是把一个对象 A 里的值 va 映射为 另一个对象 B 里的值 vb,这和代数里的映射概念是很相近的,因此也有单射,满射等区分。态射的存在反映了对象内部的结构,这是范畴论用来研究对象的主要手法:对象内部的结构特性是通过与别的对象的关系反映出来的,动静是相对的,范畴论通过研究关系来达到探知对象的内部结构的目的。

组合操作符的作用是将两个态射进行组合,例如,假设存在态射 f: A -> B, g: B -> C, 则 g.f : A -> C.

看!好像没有想象中的复杂!一个结构要想成为一个范畴, 除了必须包含上述三样东西,它还要满足以下三个限制:

  1. 态射要满足结合律,即 f.(g.h) = (f.g).h。

  2. 态射在这个结构必须是封闭的,也就是,如果存在态射 f, g,则必然存在 h = f.g。

  3. 对结构中的每一个对象 A, 必须存在一个单位态射 Ia: A -> A, 对于单位态射,显然,对任意其它态射 f, f.I = f。

讲完了!范畴论就这么点东西!-- 当然是不可能的,但暂时来说,知道这些就已经很足够了。

Haskell 中的范畴

在 Haskell 中存在着这样一个唯一的范畴,名字称为 Hask, 这个 Hask 满足前面关于范畴的全部约定,因此是范畴论里一个纯正的“范畴":

  1. 对象就是 Haskell 里的所有类型,记得类型是一个集合。

  2. 态射就是编程语言里的一般函数(function),如: func :: Int -> Bool,将对象 int 映射为 对象 bool。

  3. 态射的组合就是函数的组合,在 Haskell 里,函数也是通过点号(.)进行组合的。

另外三个约束条件很容易证明也是满足,因此整个 Haskell 从数学的角度上看它就是一个范畴,这个角度的理解是很深刻的,这样一来传统意义上诸如语法,类型,函数等语言特性其实都只是这个内在本质的外在表现而已。

函子

前面对范畴的介绍反映了范畴内部各个对象之间的联系与相互作用,在范畴论里另外研究的重点是范畴与范畴之间的关系,就正如对象与对象之间有态射一样,范畴与范畴之间也存在某些映射,从而可以将一个范畴映射为另一个范畴,这种映射在范畴论中叫作函子(functor),具体来说,对于给定的两个范畴 A 和 B, 函子的作用有两个:

  1. 将范畴 A 中的对象映射到范畴 B 中的对象。

  2. 将范畴 A 中的态射映射到范畴 B 中的态射。

显然,函子反映了不同的范畴之间的内在联系,函子的定义是十分松散的,而不同范畴之间的关系有强有弱,一个随便定义的函子很多时候并不能太深刻反映范畴之间结构上的联系,因此数学上,对函子通常有几个限制,先假设 F 是范畴 A 与范畴 B 上一个函子,则:

  1. 对范畴 A 上的单位态射Ia, F 必须将其映射为范畴 B 上的单位态射 Ib, F(Ia) = Ib.

  2. 函子对态射的组合必须满足分配徤,即,假设 f, g 是范畴 A 上的态射,则 F(f.h) = F(f).F(g)。

显然这两个限制是很强的,如果两个范畴之间存在这样一个函子,则反映了他们之间在结构上有着很强的相似性,从看似风牛马不相及的东西里找出他们内在的相似性,数学家最爱干的事情了。

和态射一样函子也可以是自映射的,即函子允许将范畴映射到其自身,这样做有什么好处呢?不同范畴之间的映射反映了范畴间的相似性,范畴到范畴自身的映射则显然是反映了范畴内部的自相似性 --- 到底认识自己也不是一件容易的事啊。。。自相似性是大自然里美妙的存在,想想六角形的雪花,想想分形... 在范畴论里,这种将范畴映射到自身的函子被称为自函子(endofunctor).

Haskell 中的函子

知道为什么要讲自函子了吗,Haskell 中只有一个范畴! 那么这个唯一的范畴 Hask 中,存不存在自函子呢?有的!终于讲到重点了,为什么 Haskell 有这么些奇怪的概念? Haskell 的老鸟会告诉你,这些奇怪的东西都是宝贝,它们都是有本而来的。

那么 Haskell 中的自函子是怎么体现出来的呢? 根据前面的定义,一个函子其实就是一个映射,它把对象映射为对象,把态射映射为态射,我们知道在 Haskell 中对象就是一个类型,如整型,布尔型等,将一个类型映射为另一个类型,没错,就是 type constructor 在干的事情,c++ 的程序员可以用模板类来想象一下,如,vector<int> 其实就是将 int 映射为 vector<int>, 这是两种不同的类型了,实例化模板的过程实际上就是把一个类型变成另一个类型的过程。

注意不要把对象的映射与对象内部的态射混淆了,态射是将对象内部的值进行映射,而对象的映射(函子)是把对象这个整体映射为另一个对象,函子根本不关心一个对象内部会有什么值。

类型到类型的映射事实上并不是普遍存在的,自函子反映的是范畴内部的结构关系,这些关系并不是因为函子的存在而存在,函子只是揭示了这些内在的关系。具体在 Haskell 中,类型间的关系并不是普遍存在的,比如说, Int -> Bool 就没有直接对应的映射关系,而存在映射关系的类型,它们都有一些共同的特点,比如可以看成是简单类型与复杂类型之间的相互转换。

type constructor 就是自函子的一部分!

好了,现在类型到类型的映射在 Haskell 中找到了,那态射到态射之间的映射呢?必竟这也是函子的必要组成部分。

在 Haskell 中,态射就是一般的函数,把一个函数映射为另一个函数,听起来不就是高阶函数在干的事情嘛。具体来说,映射函数这件事可以认为来自 Functor 这个 typeclass,连名字都一模一样,目的昭然若揭。Haskell 中的 Functor 是一个 typeclass,它的定义如下:

fmap 干嘛的?显然就是用来把态射 (a -> b) 映射为态射 (f a -> f b)的,它把范畴里的态射映射到另一个态射,且遵守了函子在映射态射时所需要遵守的两个原则。

讲到这里,我们一步一步不知不觉就已经向着 monad 靠近了,好激动,先打住了,回头再整理整理。

【参考】

http://en.wikibooks.org/wiki/Haskell/Category_theory

http://bartoszmilewski.com/2011/01/09/monads-for-the-curious-programmer-part-1/

http://www.cnblogs.com/catch/p/3973104.html

Haskell 与范畴论-函子、态射、函数的更多相关文章

  1. Haskell 与范畴论

    说到 Haskell,这真是一门逼格极高的编程语言,一般初学者如果没有相关函数式编程的经验,入门直接接触那些稀奇古怪的概念,简直要跪下.现在回想起来,隐隐觉得初学者所拥有的命令式编程语言(impera ...

  2. Haskell 笔记(四)函数系统

    函数系统 函数式编程当然少不了函数系统啦,在教程最初的时候就有一个最简单的函数,函数系统贯穿在Haskell全部,Haskell的函数有几个重要的性质. 首先声明一下函数的参数和返回值类型 然后有一个 ...

  3. Haskell高阶函数

    Haskell functions can take functions as parameters and return functions as return values. A function ...

  4. haskell 常用 函数

    在学习haskell 记录以下常用的函数 随时更新! span  span :: (a -> Bool) -> [a] -> ([a], [a]) span, applied to ...

  5. Haskell学习-函数式编程初探

    原文地址:Haskell学习-函数式编程初探   为什么要学习函数式编程?为什么要学习Haskell?   .net到前端,C#和JavaScript对我来说如果谈不上精通,最起码也算是到了非常熟悉的 ...

  6. 《Haskell趣学指南》

    <Haskell趣学指南> 基本信息 原书名:Learn You a Haskell for Great Good!: A Beginner's Guide 原出版社: No Starch ...

  7. C++学习笔记35:函数模板

    函数模板 函数模板的目的 设计通用的函数,以适应广泛的数据型式 函数模板的定义格式 template<模板型式参数列表>返回值型式 函数名称(参数列表): 原型:template<c ...

  8. haskell Types 和 Typeclasses

    Algebraic Data Types 入门 在前面的章节中,我们谈了一些 Haskell 内置的类型和 Typeclass.而在本章中,我们将学习构造类型和 Typeclass 的方法. 我们已经 ...

  9. haskell模块(modules)

    装载模块 Haskell 中的模块是含有一组相关的函数,类型和类型类的组合.而 Haskell 进程的本质便是从主模块中引用其它模块并调用其中的函数来执行操作.这样可以把代码分成多块,只要一个模块足够 ...

随机推荐

  1. PIE SDK图层树右键菜单与命令绑定

    1.   功能简介 上一节已经介绍过图层树如何和地图和制图关联,图层树右键菜单主要是基于TocControl控件进行对菜单节点进行控制,TocControl主要作用是显示当前加载的图层有哪些.采用什么 ...

  2. java中的线程(4):常用同步类 CountDownLatch、CyclicBarrier和Semaphore

    转自: http://www.cnblogs.com/dolphin0520/p/3920397.html 1.简介 CountDownLatch和CyclicBarrier都能够实现线程之间的等待, ...

  3. myEclipse注册码地址2019年最新

    myEclipse注册码地址2019年最新 https://www.sojson.com/myeclipse8.5/

  4. Java基础26-对象初始化过程

    /* 1.因为new Test1()用到了Test1类,所以会把它从硬盘上加载进入内存 2.如果有static静态代码块就会随着类的加载而执行,还有静态成员和普通方法也会随着类的加载而被加载 3.在堆 ...

  5. Yii框架 多表查询实例

    Yii框架多表查询实例:总共分为两个步骤(以下的代码我全部都写在model中):1.先在主表model中声明关联表中所需要查询的字段. public $surveyls_description; // ...

  6. 一、hadoop安装与配置

    准备环境: 系统:centos6.5 64位 192.168.211.129   master 192.168.211.131   slave1   在两台服务器上都要配置ssh免密码登录 在192. ...

  7. [转]v$parameter, v$parameter2, v$system_parameter, v$system_parameter2, v$spparameter区别

    本文转自:http://blog.csdn.net/huang_xw/article/details/617389 1 v$parameter v$parameter显示的是session级的参数. ...

  8. ASP .NET SVN && emmet 插件

    学习  ASP .NET 时间的第三周: 来讲讲如何在 visual studio 2013...上搭载 SVN吧: 废话不多说: One Step: 电脑上已安装 visual studio 201 ...

  9. tornado基本使用【服务】

    1.安装 2.请求处理程序和请求参数 1.安装 pip install tornado 2.请求处理程序和请求参数 Tornado 的 Web 程序会将 URL 或者 URL 范式映射到 tornad ...

  10. ADO.NET教程(2)实现增删查改

    声明一个类,在类中实现增删查改的方法 public class AdoNet { //声明连接字符串 public string Sqlstr = "data source={0};data ...