码迷,mamicode.com
首页 > 其他好文 > 详细

浅谈haskell中functor typeclass和普通typeclasses的区别

时间:2014-09-17 20:33:52      阅读:198      评论:0      收藏:0      [点我收藏+]

标签:style   java   ar   数据   sp   on   c   line   size   

其实这个区别就好像普通函数和高阶函数的区别一样。这样是不是很好理解了呢,额,如果你说你还不知道啥是高阶函数,那么还是不要看这个文章了。下面来看看我是如何把他们类比起来的。

我们看看haskell中的Eq是如何定义的,这个我把它叫"普通typeclasses"(为了区分functor typeclasses,我就这么叫它了:P),这里定义了一个typeclasses并且在这个typeclasses里面定义了一个行为,普遍的说法就是你可以把这个typeclasses想象成java的interface,而typeclasses的行为想象成interface里面的抽象方法。这里面a是一个类型变量,也就是可以使任何的类型。

class Eq a where 
    (==) :: a -> a -> Bool 
    (/=) :: a -> a -> Bool 
    x == y = not (x /= y) 
    x /= y = not (x == y)

接着我们定义一个自己的数据类型

data TrafficLight = Red | Yellow | Green

既然我们把typeclasses想象成interface,那么它自然和interface一样可以实例化咯

instance Eq TrafficLight where 
    Red == Red = True 
    Green == Green = True 
    Yellow == Yellow = True 
    _ == _ = False

实例化的时候我们将typeclasses里面的a这个类型变量替换成了实际类型TrafficLight,记住这里是实际类型,因为这是我们要区分functor typeclasses的关键,这样就算是定义了一个普通typeclasses和实现了Eq的instance。


然后我们定义一个functor typeclasses,看看它是如何定义的。

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

定义数据类型,我们就拿下面这个说事

data Maybe a = Just a | Nothing

咦,这里在定义数据类型的时候多了个a,如何区别于前面定义的TrafficLig这个,正规官方的说法就是Maybe 是一个类型构造子,可接受一个类型作为参数,然后返回一个具体类型。我是这么理解的,TrafficLig就直接定义了具体类型给它,而Maybe,它需要接受一个类型变量a之后他才是一个具体类型,其实就是一个可接受一个类型的东东,在接受一个类型之后它也就是具体类型了,比如Maybe是一个类型构造子,我们把类型变量a替换为Int传入进去之后Maybe Int这一整个东西就是一个具体类型啦。

再来看实例化factor typeclasses。

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

果然和前面的普通typeclasses不一样,这里实例化的时候我们传入的是我们前面提到的类型构造子。漂亮,而前面那个普通的typeclasses接受的是什么?没错,是一个具体类型,我们发现了本质上的区别,我们再次来看下类型构造子和具体类型的区别。类型构造子是一个可接受一个类型作为参数,然后返回一个具体类型的东东。看看Maybe里面定义的函数fmap(fmap 接受一个函数,这个函数从一个类型映射到另一个类型,还接受一个 functor 装有原始的类型,然后会回传一个 functor 装有映射后的类型)

这就把他和map这个高阶函数联系在了一起。我们来看看map的定义

map :: (a -> b) -> [a] -> [b]

他接受一个函数,这函数把一个类型的东西映射成另一个。还有一串装有某个类型的 List 变成装有另一个类型的 List。哇,和fmap好像。那么我们来看看List是如何被定义为functor的instance的。

instance Functor [] where 
    fmap = map

哈哈哈,perfect,就是map函数。看清楚functor后面传入的是一个[]而不是[a],这里[]就是一个类型构造子,接受一个具体类型之后返回具体类型,而[a]是一个具体类型。

而普通的函数就和普通的typeclasses一样,接受一个具体类型返回一个具体类型。

比如:

fun :: Int -> Int

接受一个Int类型返回一个Int类型。

看了这个之后是不是对于functor这个typeclasses有了更深的理解呢:P


浅谈haskell中functor typeclass和普通typeclasses的区别

标签:style   java   ar   数据   sp   on   c   line   size   

原文地址:http://my.oschina.net/firebroo/blog/314899

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!