博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅谈haskell中Functor typeclass和普通typeclasses的区别
阅读量:5938 次
发布时间:2019-06-19

本文共 2197 字,大约阅读时间需要 7 分钟。

hot3.png

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

我们看看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

转载于:https://my.oschina.net/firebroo/blog/314899

你可能感兴趣的文章
如何解压缩后缀名为zip.001,zip.002等的文件
查看>>
OSGI企业应用开发(十二)OSGI Web应用开发(一)
查看>>
Python 以指定概率获取元素
查看>>
微信公众平台图文教程(二) 群发功能和素材管理
查看>>
关于System.Collections空间
查看>>
MPP(大规模并行处理)
查看>>
Centos下基于Hadoop安装Spark(分布式)
查看>>
Java 位运算
查看>>
好用的CSS模块化打包工具CSS-COMBO
查看>>
python 中的字符和字符串
查看>>
C#Winform限制Textbox只能输入数字
查看>>
EL表达式经典用法
查看>>
java.lang.NoClassDefFoundError: javax/mail/Authenticator
查看>>
联想集团涨超7% 杨元庆持股比例升至8.12%
查看>>
各省光伏十三五规划汇总:总规模将超130GW
查看>>
Apache Storm 官方文档 —— 常用模式
查看>>
聊聊JVM的年轻代
查看>>
lvm逻辑卷管理
查看>>
VS2010不能断点/下断的问题
查看>>
[Android]权限处理
查看>>