Functor #

一、Functor概念 #

1.1 什么是Functor #

Functor是可以被映射的类型构造器:

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

1.2 类型签名 #

haskell
-- fmap将函数应用于"容器"内的值
fmap :: (a -> b) -> f a -> f b

-- 类比
-- map :: (a -> b) -> [a] -> [b]
-- fmap是map的泛化版本

1.3 简单示例 #

haskell
-- Maybe是Functor
instance Functor Maybe where
    fmap _ Nothing  = Nothing
    fmap f (Just x) = Just (f x)

-- 使用
fmap (*2) (Just 5)  -- Just 10
fmap (*2) Nothing   -- Nothing

二、常见Functor实例 #

2.1 Maybe #

haskell
-- Maybe实例
instance Functor Maybe where
    fmap _ Nothing  = Nothing
    fmap f (Just x) = Just (f x)

-- 使用
fmap show (Just 42)  -- Just "42"
fmap length (Just "hello")  -- Just 5
fmap (+1) Nothing  -- Nothing

2.2 列表 #

haskell
-- 列表实例
instance Functor [] where
    fmap = map

-- 使用
fmap (*2) [1, 2, 3]  -- [2, 4, 6]
fmap show [1, 2, 3]  -- ["1", "2", "3"]

2.3 Either #

haskell
-- Either实例
instance Functor (Either e) where
    fmap _ (Left x)  = Left x
    fmap f (Right y) = Right (f y)

-- 使用
fmap (*2) (Right 5 :: Either String Int)  -- Right 10
fmap (*2) (Left "error" :: Either String Int)  -- Left "error"

2.4 IO #

haskell
-- IO实例
instance Functor IO where
    fmap f action = do
        x <- action
        return (f x)

-- 使用
main :: IO ()
main = do
    line <- fmap (map toUpper) getLine
    putStrLn line

2.5 元组 #

haskell
-- 二元组实例(只映射第二个元素)
instance Functor ((,) a) where
    fmap f (x, y) = (x, f y)

-- 使用
fmap (*2) (1, 5)  -- (1, 10)
fmap show (True, 42)  -- (True, "42")

三、Functor定律 #

3.1 恒等律 #

haskell
-- 恒等律
-- fmap id == id

-- 验证
fmap id (Just 5)  -- Just 5
id (Just 5)       -- Just 5

fmap id [1, 2, 3]  -- [1, 2, 3]
id [1, 2, 3]       -- [1, 2, 3]

3.2 组合律 #

haskell
-- 组合律
-- fmap (f . g) == fmap f . fmap g

-- 验证
fmap (show . (*2)) (Just 5)  -- Just "10"
(fmap show . fmap (*2)) (Just 5)  -- Just "10"

3.3 定律的重要性 #

haskell
-- 符合定律的实现行为可预测
-- 不符合定律的实现可能导致意外行为

-- 错误示例(违反定律)
-- instance Functor Maybe where
--     fmap _ _ = Nothing  -- 违反恒等律

四、<$>运算符 #

4.1 运算符形式 #

haskell
-- <$> 是fmap的中缀形式
(<$>) :: Functor f => (a -> b) -> f a -> f b

-- 使用
(*2) <$> Just 5  -- Just 10
show <$> [1, 2, 3]  -- ["1", "2", "3"]

4.2 与$对比 #

haskell
-- $ 用于普通函数应用
(*2) $ 5  -- 10

-- <$> 用于Functor映射
(*2) <$> Just 5  -- Just 10

4.3 链式操作 #

haskell
-- 链式fmap
show . (*2) <$> Just 5  -- Just "10"

-- 多个Functor操作
addMaybe :: Maybe Int -> Maybe Int -> Maybe Int
addMaybe x y = (+) <$> x <*> y
-- 需要Applicative

五、<$运算符 #

5.1 替换值 #

haskell
-- <$ 用值替换Functor内容
(<$) :: Functor f => a -> f b -> f a

-- 使用
1 <$ Just 5  -- Just 1
1 <$ Nothing  -- Nothing
'a' <$ [1, 2, 3]  -- ['a', 'a', 'a']

5.2 实现原理 #

haskell
-- <$ 实现
x <$ fa = const x <$> fa

-- 示例
1 <$ Just 5
= const 1 <$> Just 5
= Just (const 1 5)
= Just 1

六、函数作为Functor #

6.1 实例定义 #

haskell
-- 函数是Functor(reader functor)
instance Functor ((->) r) where
    fmap = (.)

-- 类型签名
-- fmap :: (a -> b) -> ((->) r a) -> ((->) r b)
-- 等价于
-- fmap :: (a -> b) -> (r -> a) -> (r -> b)
-- 即函数组合

6.2 使用 #

haskell
-- 函数作为Functor
fmap (*2) (+1) 5  -- 12
-- 等价于
(*2) . (+1) $ 5  -- 12

-- 链式
fmap show (+1) 5  -- "6"
show . (+1) $ 5   -- "6"

七、实践示例 #

7.1 处理Maybe值 #

haskell
-- 安全操作链
safeDiv :: Int -> Int -> Maybe Int
safeDiv _ 0 = Nothing
safeDiv x y = Just (x `div` y)

-- 使用fmap
process :: Int -> Int -> Maybe String
process x y = show <$> safeDiv x y

-- 使用
process 10 2  -- Just "5"
process 10 0  -- Nothing

7.2 处理列表 #

haskell
-- 数据转换管道
processData :: [Int] -> [String]
processData = fmap show . fmap (*2) . filter even

-- 等价于
processData' = map show . map (*2) . filter even

-- 使用
processData [1..10]  -- ["4", "8", "12", "16", "20"]

7.3 处理Either #

haskell
-- 错误处理链
validate :: Int -> Either String Int
validate x
    | x < 0     = Left "Negative"
    | x > 100   = Left "Too large"
    | otherwise = Right x

-- 使用fmap
process :: Int -> Either String String
process x = show <$> validate x

-- 使用
process 50   -- Right "50"
process (-1) -- Left "Negative"

7.4 处理IO #

haskell
-- IO操作链
readAndProcess :: IO String
readAndProcess = processLine <$> getLine
  where
    processLine = reverse . map toUpper

main :: IO ()
main = do
    result <- readAndProcess
    putStrLn result

八、Functor组合 #

8.1 嵌套Functor #

haskell
-- 嵌套Functor
nested :: Maybe [Int]
nested = Just [1, 2, 3]

-- 两层fmap
fmap (fmap (*2)) nested  -- Just [2, 4, 6]

-- 使用<$>
(*2) <$> (*2) <$> nested  -- Just [4, 8, 12]

8.2 Compose类型 #

haskell
-- Compose包装器
newtype Compose f g a = Compose { getCompose :: f (g a) }

instance (Functor f, Functor g) => Functor (Compose f g) where
    fmap f (Compose x) = Compose (fmap (fmap f) x)

-- 使用
-- fmap (*2) (Compose (Just [1, 2, 3]))
-- Compose (Just [2, 4, 6])

九、总结 #

Functor要点:

  1. 定义fmap :: (a -> b) -> f a -> f b
  2. 常见实例:Maybe、[]、Either、IO、元组
  3. 定律:恒等律、组合律
  4. 运算符<$>(fmap)、<$(替换)
  5. 函数Functorfmap = (.)
  6. 嵌套:可以多层fmap

掌握Functor后,让我们继续学习Applicative。

最后更新:2026-03-27