Skip to content
Go back

functor

Updated:

functor

Functor 类型类只需要一个定义: fmap

AstroPaper v3

fmap 提供了一个适配器,如图 所示。请注意,我们使用的是 <$>,它是 fmap 的同义词(除了它是二元运算符而不是函数)。

AstroPaper v3

学习 Functor 是理解函数式编程中的一个重要概念,尤其是在像 Haskell 这样的语言中。Functor 提供了一种抽象的方式来操作包含在上下文中的数据。它可以类比为一种容器或包装器,允许你对容器内的数据应用函数,而不必关心数据的具体结构。

Functor 的定义

Functor 是一个类型类,定义了一个 fmap 函数,它接受一个函数并将其应用到 Functor 内部的值上。

在 Haskell 中,Functor 的类型类定义如下:

class Functor f where
    fmap :: (a -> b) -> f a -> f b

直观理解

可以把 Functor 想象成一种包装器。fmap 是一种工具,它帮助你打开包装,对里面的内容应用函数,然后再重新封装起来。

例如,在列表 [] 上,fmap 就是把函数应用到列表的每一个元素上:

fmap (*2) [1, 2, 3]
-- 结果是 [2, 4, 6]

Maybe 上,fmap 允许你对一个可能包含值的结构进行操作:

fmap (*2) (Just 5)
-- 结果是 Just 10

fmap (*2) Nothing
-- 结果是 Nothing

Functor 的意义

Functor 抽象的核心思想是 在不改变结构的情况下操作其中的值。具体来说,fmap 会保留容器(或上下文)的结构,而只改变其中的内容。

具体例子

  1. 列表 []

    列表是一个最简单的 Functorfmap 就是把函数作用到列表的每个元素:

    fmap (+1) [1, 2, 3]
    -- [2, 3, 4]
    
  2. Maybe

    Maybe 是一个包含 JustNothing 的类型,fmap 会对 Just 中的值应用函数,而 Nothing 则保持不变:

    fmap (*2) (Just 5)
    -- Just 10
    
    fmap (*2) Nothing
    -- Nothing
    
  3. Either

    Either 类型可以用来表示错误或成功的结果。EitherFunctor 实现只对 Right 中的值应用函数,Left 中的值表示错误,保持不变:

    fmap (+1) (Right 10)
    -- Right 11
    
    fmap (+1) (Left "Error")
    -- Left "Error"
    

Functor 定律

为了使 fmap 在不同类型中行为一致,Functor 必须遵循两个定律:

  1. 同一性定律(Identity Law)

    对任意的 xfmap id x == x。即应用 id(恒等函数)不会改变 Functor 的内容。

    fmap id [1, 2, 3] == [1, 2, 3]
    
  2. 组合性定律(Composition Law)

    对任意函数 fgfmap (f . g) == fmap f . fmap g。即将组合后的函数应用在 Functor 上,等价于先分别应用每个函数再组合结果。

    fmap ((+1) . (*2)) [1, 2, 3] == fmap (+1) (fmap (*2) [1, 2, 3])
    -- 结果都为 [3, 5, 7]
    

为什么 Functor 很重要?

总结

通过学习 Functor,你可以在 Haskell 中更自然地理解和使用函数式编程中的抽象和组合理念。

Functor 类型类允许您将普通函数应用于容器(例如 List )或上下文(例如 IO 或 Maybe )内的值。如果您有一个函数 Int -> Double 和一个值 Maybe Int ,则可以使用 Functor 的 fmap (或 <$> 运算符)将 Int -> Double 函数应用于 Maybe Int 值,从而产生 Maybe Double 值。函子非常有用,因为它们允许您将单个函数与属于函子类型类的任何类型重用。 [Int]、 Maybe Int 和 IO Int 都可以使用相同的核心函数。


Suggest Changes

Previous Post
do语法
Next Post
bind fmap join