哈斯克尔函数组合和fmap f.



我有两个简单的例子:

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,区别是什么?

(->) rFunctor实例将fmap定义为函数组合:

fmap f g = f . g

因此,xt (+2) == fmap f (+2) == f . (+2) == (+2)(因为fInt的恒等函数)。应用于 1,你会得到观察到的答案 3。


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)是一个包含某个值加 2 的框。(F)在该框上映射函数提供了一个框,其中包含将f应用于原始函数的结果,即生成一个函数,该函数是f与原始函数的组合。

xq = return . fxt = fmap f都可以进行 eta 扩展

xq x = (return . f) x = return (f x) = return x

现在它可以是eta签约的:

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 = xInts,这意味着f = idInts,其中id是一个预定义的函数,其定义方式与f相同(但通常,对于任何类型)。

然后通过函子定律(这就是我们需要了解关于"函子">的全部信息)fmap id = id等等xt y = y,换句话说,它也id- 但仅适用于Ints,

xt = id :: Int -> Int

自然,xt (+2) = id (+2) = (+2).


附录:对于某物,成为"Functor"意味着它可以代替f

fmap id (x :: f a) = x
(fmap g . fmap h)  = fmap (g . h)

因此所涉及的表达式有意义(即格式良好,即具有类型),并且上述方程成立(它们实际上是两个"函子定律")。

最新更新