Skip to content
Go back

monad

Updated:

monad

在 Haskell 中,FunctorApplicativeMonad 是三种重要的类型类,它们各自提供了不同层次的抽象来操作容器类型。下面我们将介绍 FunctorApplicative 的局限性,解释为什么需要 Monad,并对 Monad 的类型类进行详细介绍。

1. Functor 的局限性

Functor 类型类定义了一个基本的映射(map)操作,使我们可以对容器中的每个元素应用一个函数。其核心方法是 fmap 或中缀形式 <$>

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

2. Applicative 的局限性

Applicative 类型类提升了 Functor 的功能,可以将多个容器内的值进行组合。其核心方法是 pure<*>

class Functor f => Applicative f where
    pure :: a -> f a
    (<*>) :: f (a -> b) -> f a -> f b

3. Monad 类型类:解决依赖关系的灵活组合

为了解决 FunctorApplicative 的局限性,Haskell 引入了 Monad 类型类,它允许我们在计算中根据上一步的结果动态决定下一步的计算方式。Monad 的核心方法是 >>=(称为 bind):

class Applicative m => Monad m where
    (>>=) :: m a -> (a -> m b) -> m b
    return :: a -> m a  -- 'return' 是 'pure' 的别名

Monad 的优势

Monad 允许我们对容器内的值逐步进行计算,每一步可以动态依赖上一步的结果。这种特性使得 Monad 可以解决 FunctorApplicative 无法处理的依赖关系问题。

4. 使用 Monad 进行非确定性计算

以列表 [] 为例,[]Monad 的一个实例。通过 Monad,我们可以实现基于上一步计算结果的非确定性计算:

-- 从两个列表中选择元素,并要求第一个选择的元素小于第二个
choose :: [Int] -> [Int] -> [(Int, Int)]
choose xs ys = do
    x <- xs
    y <- ys
    guard (x < y)  -- 依赖于上一步的结果
    return (x, y)

-- 示例调用
result = choose [1, 2, 3] [2, 3, 4]
-- 结果:[(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)]

在这里,choose 使用 do 表达式和 guard 进行条件筛选,每一步的计算依赖于前一步的结果,这是 Applicative 无法做到的。

monad

5. Monad 的一些常见应用场景

总结

通过 Monad,Haskell 提供了更灵活的容器操作方式,适合处理依赖关系复杂的计算场景。


Suggest Changes

Previous Post
deepkit学习
Next Post
do语法