我有两个简单的例子:
1)xt
功能(这是什么?)
Prelude> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
Prelude> :{
Prelude| f::Int->Int
Prelude| f x = x
Prelude| :}
Prelude> xt = fmap f // ?
Prelude> :t xt
xt :: Functor f => f Int -> f Int
Prelude> xt (+2) 1
3
2)xq
功能(通过作文)
Prelude> :{
Prelude| return x = [x]
Prelude| :}
Prelude> xq = return . f
Prelude> :t xq
xq :: Int -> [Int]
Prelude> :t return
return :: a -> [a]
xq
函数我通过撰写return(f(x))
。但这意味着什么:fmap f
和有什么区别?
答案 0 :(得分:5)
Functor
的{{1}}实例将(->) r
定义为函数组合:
fmap
因此,fmap f g = f . g
(因为xt (+2) == fmap f (+2) == f . (+2) == (+2)
是f
)的标识函数。应用于1,您将获得观察到的答案3。
Int
是由fmap
类型类定义的函数:
Functor
它将一个函数作为其参数,并将一个新函数“提升”到有问题的仿函数中。确切的定义由class Functor f where
fmap :: (a -> b) -> f a -> f b
实例提供。以上是函数函子的定义;这里有一些比较简单的列表和Functor
:
Maybe
由于您可以将仿函数视为包含一个或多个值的框,因此函数仿函数的直觉是函数是一个包含将函数应用于其参数的结果的框。也就是说,instance Functor [] where
fmap = map
instance Functor Maybe where
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)
> fmap (+1) [1,2,3]
[2,3,4]
> fmap (+1) Nothing
Nothing
> fmap (+1) (Just 3)
Just 4
是一个包含一些值加2的框。(F)在该框上映射函数提供了一个框,其中包含将(+2)
应用于原始函数结果的结果,即,生成一个函数,它是具有原始函数的f
的组合。
答案 1 :(得分:1)
xq = return . f
和xt = fmap f
都可以 eta-expanded :
xq x = (return . f) x = return (f x) = return x
现在可以 eta-contract :
xq = return
第二个是
xt y = fmap f y = fmap (\x -> x) y = fmap id y = id y = y
fmap
的类型为:: Functor f => (a -> b) -> f a -> f b
,因此fmap f
的类型为:: Functor f => f Int -> f Int
,因为f :: Int -> Int
。从其类型我们可以看出fmap f
是一个函数,期望Int
,并生成Int
。
根据f x = x
的{{1}}定义,它表示Int
为f = id
,其中Int
是以相同方式定义的预定义函数因为id
是(但一般来说,对于任何类型)。
然后通过 Functor法 (我们需要了解所有 “Functors” ), f
所以fmap id = id
,换句话说它也是xt y = y
- 但仅适用于id
s,
Int
当然,xt = id :: Int -> Int
。
附录:表示某事物是“Functor”意味着它可以代替<{p>}中的xt (+2) = id (+2) = (+2)
f
使得所涉及的表达式有意义(即形成良好,即具有类型),并且上述等式成立(它们实际上是两个“Functor定律”)。