首页 > 解决方案 > Haskell:理解 Applicative 函子的纯函数

问题描述

我正在学习 Applicative Functors 并且纯函数具有以下类型声明:

pure :: a -> f a 

我知道纯函数接受任何类型的值并返回一个应用值,其中包含该值。所以如果应用实例是Maybepure 3就会给出Just 3

但是,当您将 pure 应用于已经在应用值内的值时会发生什么?例如,如果你做类似的事情会发生什么pure Just 3

标签: haskellfunctional-programmingapplicative

解决方案


当您将 pure 应用于已经在应用值内的值时会发生什么?

它只是被包裹在一个额外的层中。最终结果是嵌套在另一个应用值中的应用值。

例如,如果你做类似的事情会发生什么pure Just 3

这是一个有趣的问题,尽管可能不是出于您的意思。这里的重点是区分pure (Just 3)——这可能是你的意思——和pure Just 3 = (pure Just) 3你写的。这给出了两种情况:

  • pure (Just 3)简单地应用于purevalue Just 3,正如我上面讨论的那样,它给出了Just (Just 3),这是一个嵌套的应用值。
  • (pure Just) 3是一个有趣的案例。回想 和 的pure类型Just

    pure :: Applicative f => a -> f a
    Just :: a -> Maybe a
    -- so:
    pure Just :: Applicative f => f (a -> Maybe a)
    

    换句话说,pure Just获取函数Just并将其包装在一个应用值中。

    接下来,我们要将其pure Just应用于 value 3。但我们不能这样做,因为f (a -> Maybe a)它是一个值,而不是一个函数!所以(pure Just) 3应该导致类型错误。

    ......但事实证明类型检查很好!所以我们错过了一些东西。在这种情况下,事实证明有一个函数的应用实例:

    instance Applicative ((->) r) where
      pure x = \r -> x
      (<*>) = _irrelevant_here
    

    语法有点滑稽,但它基本上意味着这r -> ...是一个应用程序。这个特定的实例被称为Reader monad,它的使用非常广泛。(有关此特定数据类型的更多信息,请参见此处此处。)这个想法是r -> a可以计算a给定的r输入;在这种情况下,pure x创建一个忽略其输入并x始终返回的函数,并将f <*> x输入r输入到两者fx,然后将两者结合起来。在这种情况下,我们只使用pure,因此很容易(pure Just) 3手动评估:

    (pure Just) 3
    = (\r -> Just) 3
    = Just
    

    所以这里的想法是pure包装Just一个应用值,在这种情况下它恰好是一个函数;然后,我们将此函数应用于3,它摆脱了包装器以显示原始Just


推荐阅读