欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Functor 101

程序员文章站 2022-03-23 14:58:57
...

hi 多磨! 好久没有写东西了。。。。这学期总算是把mina应付过去了。。。。
Ok 之前写了这么多特别基础的东西,让我来点一般语言里没有的吧。Functor!, 如果中文直译的话应该叫函子, 不过我不太确定这样的翻译对不对。函子 本意是个范畴论里的概念, 说的是两个catergory 之间的映射关系。Haskell 不能说和范畴论完全没有关系,从语言设计思想的角度来说他提供的抽象概念很多借鉴了范畴论里的东西, 可以类比, haskell还是一门有很高强度和表达能力的语言, 不代表你需要去深入学习范畴论等数学工具。

为了在理解上方便这里暂时放下category theory不说(haskell 的wiki book非常好,日常看看还是很有启发的, 等将来有机会希望能组织小伙伴翻译一下)。

既然是Functor 101, 当然不会有什么很难的内容,看定义吧!

class Functor f where  
    fmap :: (a -> b) -> f a -> f b  

请千万不要觉得functor和他的定义一样简单,在haskell的世界里,约简单的代码很可能意味着越难理解和使用

还记得Maybe类型嘛, 是的,他们都是所谓的高阶类型,Functor这个是一个类型构造子, 他的Kind 很明显是* -> *. 他有一个数fmap,所以从定义上来说Functor, 代表着一簇可以被fmap所作用的函数。 相信大家都已经对map很熟悉了吧,高阶函数,作用一个函数到一个list, set之类的container里。fmap可以理解为是对传统的container的概念进行了一次扩展, 这里的容器可以指任意一个类型!

在haskell中所有的类型都可以看作一个盒子,盒子里面放的东西是, 如何制作一个盒子呢? 很简单,使用值构造子, 如何打开一个盒子呢,使用pattern match, 回忆一下之前我们对Maybe类型的操作,我们把一个可能包含空值语义的结果使用Maybe 这个盒子包装,同时我们也保存好了他的类型。

Prelude> ubox (Just a) = a
Prelude> ubox (Just 1)
1
Prelude> :t ubox
ubox :: Maybe a -> a

拆装箱的操作非常的繁琐,很多时候,比如空值语义的安全处理, 我们希望的是取出值,对值进行运算,再把结果封回原来的箱子, 因此我们需要对这种行为进行抽象

fmap :: Functor f => (a -> b) -> f a -> f b

fmap这个函数很好的完成了任务,所以对于需要这种抽象的场合,我们只需要去实现Functor这个高阶typeclass就可以啦。

但是这里和普通语言中定义的map有一个本质的区别, 拆装箱过程中我们的值很多时候是会发生变化的,比如一个Int的值在我们计算之后变成了Double,这中行为在一般的编程语言中由于不存在高阶类型(High Kinded Type)的概念, 非常难实现。Haskell强大的表达能力在这里就表现了出来!我们在这里定义的这种拆装箱的行为更加的宽泛,不需要拘泥与值的类型。重新装箱我们完全可以得到新的类型,通过闭包函数完成类型参数转换的工作

简单总结一下:

Functor是在一簇拥有相同类型构造子的类型空间中,实现从高阶类型的某一种特化到另一种特化的映射

嘛定义不重要,看看使用Funtor如何完成Maybe的拆装箱定义吧

instance Functor Maybe where  
    fmap f (Just x) = Just (f x)  
    fmap f Nothing = Nothing  

Easy? 但是还是希望大家动手实现一下,比如对于List和Set这样的容器类,也许也没有你想得那么简单呢hhhhh

上一篇: STL string类

下一篇: STL中的string类