Haskell:了解应用函子的纯函数

时间:2019-07-19 02:00:28

标签: haskell functional-programming applicative

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

pure :: a -> f a 

我知道pure函数可以接受任何类型的值,并返回其中包含该值的适用值。因此,如果应用实例为Maybe,则pure 3将给出Just 3

但是,当您将纯值应用到应用值中已经包含的值时会发生什么?例如。如果您进行类似pure Just 3的操作会怎样?

2 个答案:

答案 0 :(得分:9)

  

当您将纯值应用于应用值中的值时会发生什么?

它只是包裹在一个附加层中。最终结果是一个嵌套在另一个应用程序值内的应用程序值。

  

例如如果您进行类似pure Just 3的操作会怎样?

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

  • pure (Just 3)只需将pure应用于值Just 3,正如我上面所讨论的,得出Just (Just 3),这是一个嵌套的应用值。
  • (pure Just) 3是一个有趣的情况。回忆一下pureJust的类型:

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

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

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

    …除了事实证明可以进行类型检查!因此,我们缺少了一些东西。在这种情况下,事实证明有一个函数的应用实例:

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

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

    (pure Just) 3

    因此,这里的想法是(pure Just) 3 = (\r -> Just) 3 = Just pure包装为一个应用值,在这种情况下,该值恰好是一个函数;然后,我们将此功能应用于Just,它会摆脱包装器以显示原始3

答案 1 :(得分:4)

首先,pure具有以下类型:

pure :: Applicative f => a -> f a

为简化起见,请考虑f的种类

:k f 
f :: * -> *

a的种类为*

然后,a的类型就是a,任何a,都是所有类型中最多态的(但要记住种类*)。因此,您实际上并不关心a的值,只是有一个限制,那就是typeclass适用性和f的种类(记住* -> *

在这种情况下:

gchi> pure 3 :: Maybe Int
ghci> Just 3

这里fMaybe,而a3

以同样的方式

gchi> pure $ Just 3 :: Maybe (Maybe Int)
gchi> Just (Just 3)

这里f再次为MaybeaJust 3

您可以进行一些操作,将类型更改为纯:

gchi> pure 3 :: [Double]
ghci> [3.0]

这里,f是[],a3

相同的方式

ghci> pure [3] :: [[Double]]
ghci> [[3.0]]

最后,f再次是[],而a是[3]