您的位置:首页 > 编程语言 > PHP开发

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

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

我们看看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之后他才是一个具体类型,其实就是一个可接受一个类型的东东,就好像一个函数,需要接受一个值才能返回一个实际的值,只不过类型构造子是接受类型返回类型(我在内心对于没有副作用的函数多了一点理解,它接受一个值,构造出另外一个值返回给我们,这不正是函数的定义吗?这里指的是没有副作用的函数,使用这个函数仅仅是为了得到return的值,而且相同的输入每次都返回相同的输出)在接受一个类型之后它也就是具体类型了,比如Maybe是一个类型构造子,我们把类型变量a替换为Int传入进去之后Maybe Int这一整个东西就是一个具体类型啦。

再来看实例化Functor 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: