Haskell:对Functor的分析
这篇文章里面介绍Functor class
。Functor class
的定义如下:
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
{-# MINIMAL fmap #-}
-- Defined in ‘GHC.Base’
instance Functor (Either a) -- Defined in ‘Data.Either’
instance Functor [] -- Defined in ‘GHC.Base’
instance Functor Maybe -- Defined in ‘GHC.Base’
instance Functor IO -- Defined in ‘GHC.Base’
instance Functor ((->) r) -- Defined in ‘GHC.Base’
instance Functor ((,) a) -- Defined in ‘GHC.Base’
注意到它的核心就是定义了fmap函数类型:
fmap :: (a -> b) -> f a -> f b
这个fmap类型的定义很清楚,它接受两个参数:
(a -> b)
f a
对上面的定义说明如下:
- 第一个参数是个函数,这个函数接受类型为
a
的参数,返回值类型为b
。其中a
和b
是类型参数,它们代表的类型都是f
,f
对应Functor class
。 - 第二个参数是个
a
类型的参数,a
代表f
类型,f
代表Functor class
。 - 返回值类型是
b
,b
也代表f
类型,f
也代表Functor class
。
是不是有点晕?其实是非常清晰明了的一个定义,没关系,接下来看,就很清楚了。
我们接着看看Functor class
下面的instance
:
instance Functor [] -- Defined in ‘GHC.Base’
从上面这个instance
,我们知道了,原来列表(就是[]
类型的数据)也是Functor
的instance
,说明列表实现了fmap
。
那么列表数据是怎样实现fmap
的?
答案是:map
就是fmap
的实现。
我们看下map的定义:
Prelude> :t map
map :: (a -> b) -> [a] -> [b]
Prelude>
实际上map
把fmap
给实现了,fmap
里面的f a
和f b
被具体到了[]
列表类型。
最后我们看下为什么说map
就是fmap
的实现。
首先我们下载haskell的源代码:
然后我们确定一下map
的位置:
Prelude> :info map
map :: (a -> b) -> [a] -> [b] -- Defined in ‘GHC.Base’
从上面的info我们看到map is defined in “GHC.Base”
于是我们验证一下map
实现了fmap
,首先根据上面的信息,找到正确的分析位置:
$ grep -rl 'fmap =' * | grep -v test | grep GHC
grep: inplace/test spaces: No such file or directory
ghc/GHCi/UI/Monad.hs
libraries/base/GHC/Arr.hs
libraries/base/GHC/Base.hs
然后我们打开Base.hs
,看到了证据:
以下是map
的具体定义:
----------------------------------------------
-- map
----------------------------------------------
-- | 'map' @f xs@ is the list obtained by applying @f@ to each element
-- of @xs@, i.e.,
--
-- > map f [x1, x2, ..., xn] == [f x1, f x2, ..., f xn]
-- > map f [x1, x2, ...] == [f x1, f x2, ...]
map :: (a -> b) -> [a] -> [b]
{-# NOINLINE [0] map #-}
-- We want the RULEs "map" and "map/coerce" to fire first.
-- map is recursive, so won't inline anyway,
-- but saying so is more explicit, and silences warnings
map _ [] = []
map f (x:xs) = f x : map f xs
可以看到map
的定义是递归式的。
*小结*
在这篇文章中,给大家介绍了Functor class
,明白了这个class的核心是为了定义fmap
这个行为。
- 上一篇 玩转WebSocket(下)
- 下一篇 OpenLDAP的安装与基本使用方法(八)