大致介绍了幺半群(monoid)后,我们重新回顾最初引用wadler(haskell委员会成员,把monad引入haskell的家伙)的那句话:

现在我们来解读这句话中包含的另一个概念:自函子(Endofunctor),不过我们先需要一些铺垫:

首先,什么是函子(Functor)?

乍一看名字,以为函子(functor)对函数(function)是一种封装,实际没有关系,尽管他们都是表示映射,但两者针对的目标不一样。

函数表达的映射关系在类型上体现在特定类型(proper type)之间的映射,举例来说:

而函子,则是体现在高阶类型(确切的说是范畴,可把范畴简单的看成高阶类型)之间的映射(关于高阶类型参考: scala类型系统:24) 理解 higher-kinded-type),听上去还是不够直观,函子这个术语是来自群论(范畴论)里的概念,表示的是范畴之间的映射,那范畴又与类型之间是什么关系?

把范畴看做一组类型的集合

假设这里有两个范畴:范畴C1 里面有类型String 和类型 Int;范畴C2 里面有 List[String] 和 List[Int]

函子表示范畴之间的映射

从上图例子来看,这两个范畴之间有映射关系,即在C1里的Int 对应在C2里的List[Int],C1里的String对应C2里的List[String],在C1里存在Int->String的关系态射(术语是morphism,我们可理解为函数),在C2里也存在List[Int]->List[String]的关系态射。

换句话说,如果一个范畴内部的所有元素可以映射为另一个范畴的元素,且元素间的关系也可以映射为另一个范畴元素间关系,则认为这两个范畴之间存在映射。所谓函子就是表示两个范畴的映射。

怎么用代码来描述函子?

从上图的例子,我们已经清楚了functor的含义,即它包含两个层面的映射:

要满足这两点,我们需要一个类型构造器

我们现在可以把这个定义再简化一些,类型的映射方法可以不用,并把它作为一个type class

现在我们自定义一个My[_]的类型构造器,测试一下这个type class:

不过大多数库中对functor的支持,都不是通过type class模式来做的,而是直接在类型构造器的定义中实现了map方法:

这样相当于显式的让My同时具备了对类型和函数的映射(A->My[A]A=>B -> My[A]=>My[B];在haskell里把这两个行为也叫提升(lift),相当于把类型和函数放到容器里),所以我们也可以说一个带有map方法的类型构造器,就是一个函子。

范畴与高阶类型

我们再来思考一下,如果忽略范畴中的关系(函数),范畴其实就是对特定类型的抽象,即高阶类型(first-order-type或higher-kinded-type,也就是类型构造器),那么对于上面例子中的”范畴C2″,它的所有类型都是List[T]的特定类型,这个范畴就可以抽象为List高阶类型。那对于”范畴C1″呢?它又怎么抽象?其实,”范畴C1″的抽象类型可以看做是一个Identity类型构造器,它与任何参数类型作用构造出的类型就是参数类型:

是不是很像单位元的概念?在shapeless里已经提起过

这么看的话,如果范畴也可以用类型(高阶)来表达,那岂不是只用普通函数就可以描述它们之间的映射了?别急,先试试,方法里是不支持类型构造器做参数的:

方法中只能使用特定类型(proper type)做参数。

http://hongjiang.info/understand-monad-4-what-is-functor/

最新文章

  1. iOS开发小技巧--利用运行时得到隐藏的成员变量
  2. 对get_baserel_parampathinfo函数的学习
  3. jsp中如何获得url路径和绝对路径
  4. 调用ShellExecute所须要头文件
  5. EventBus消息机制在Eclipse环境下的使用
  6. CoreAnimation 图层几何学
  7. 百度地图JavaScript API本地搜索的结果面板
  8. 自动化之路 Graphite监控上手指南
  9. 初始化nodejs+webpack+vuejs
  10. Django代码注意
  11. What can university bring to you?
  12. TinScrapy-简化的Scrapy原码-查看爬虫的执行流程
  13. 使用jieba库与wordcloud库第三方库进行词频统计
  14. LoadRunner服务水平协议SLA
  15. django之ORM补充
  16. 【JVM】-NO.111.JVM.1 -【JDK11 HashMap详解-1-hash()剖析】
  17. 十九、springcloud(五)配置中心本地示例和refresh
  18. [TJOI 2018]智力竞赛
  19. HDU 2075 A|B?
  20. ELK之使用kafka作为消息队列收集日志

热门文章

  1. Servlet3.0中使用getPart进行文件上传
  2. DataSource是一个java ee的标准接口和servlet一样,用于数据库连接池上
  3. [csdn markdown]使用摘记一源码高亮及图片上传和链接
  4. 《鸟哥的Linux私房菜-基础学习篇(第三版)》(五)
  5. 揭秘传智播客班级毕业薪资超7k的内幕系列之四----汽车工的华丽转身
  6. centos改动sshport
  7. zzulioj--1730--通信基站(全排列+dfs)(好题)
  8. bzoj3033 太鼓达人——欧拉图搜索
  9. bzoj1708[Usaco2007 Oct]Money奶牛的硬币(背包方案数dp)
  10. Django day13 form组件, 渲染错误信息, 全局钩子