Haskell:了解应用函子的纯函数
Haskell: Understanding the pure function for Applicative functors
我正在学习 Applicative Functors,纯函数具有以下类型声明:
pure :: a -> f a
我知道纯函数接受任何类型的值,returns 一个包含该值的应用值。因此,如果应用实例是 Maybe
,pure 3
将给出 Just 3
.
但是,当您将 pure 应用于已在应用值内的值时会发生什么?例如。如果您执行 pure Just 3
?
之类的操作会怎样
What happens when you apply pure to a value that's already inside an applicative value?
它只是被包裹在一个额外的层中。最终结果是一个应用值嵌套在另一个应用值中。
E.g. what happens if you do something like pure Just 3
?
这是一个有趣的问题,尽管可能不是出于您所指的原因。这里的重点是区分 pure (Just 3)
——这可能是你的意思——和 pure Just 3 = (pure Just) 3
,这是你写的。这给出了两种情况:
pure (Just 3)
只是将 pure
应用于值 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
并将其应用于值 3
。但是我们不能这样做,因为 f (a -> Maybe a)
是一个值,而不是一个函数!所以 (pure Just) 3
应该会导致类型错误。
…除了结果是类型检查就好了!所以我们错过了一些东西。在这种情况下,事实证明有一个适用于函数的实例:
instance Applicative ((->) r) where
pure x = \r -> x
(<*>) = _irrelevant_here
语法有点滑稽,但它基本上意味着 r -> ...
是一个应用程序。这个特殊的实例被称为 Reader monad,它的使用非常广泛。 (有关此特定数据类型的更多信息,请参阅 here or here。)这个想法是 r -> a
可以在给定 r
输入的情况下计算 a
;在这种情况下,pure x
创建一个忽略其输入的函数,并且 returns x
总是,并且 f <*> x
将 r
输入提供给两个 f
和 x
,然后将两者结合起来。在这种情况下,我们只使用 pure
,因此很容易手动计算 (pure Just) 3
:
(pure Just) 3
= (\r -> Just) 3
= Just
所以这里的想法是 pure
将 Just
包装在一个应用值中,在这种情况下恰好是一个函数;然后,我们将此函数应用于 3
,它摆脱了包装以显示原始 Just
.
首先,pure 具有以下类型:
pure :: Applicative f => a -> f a
为了简单起见,想想那种f
:k f
f :: * -> *
而a
的种类是*
那么 a
的类型就是 a
,任何 a
,是所有类型中最具多态性的(但记住种类 *
)。所以你并不关心a的值,你只是有一个限制,那就是typeclass
Applicative,还有f
的那种(记住* -> *
)
所以在这种情况下:
gchi> pure 3 :: Maybe Int
ghci> Just 3
这里 f
是 Maybe
而 a
是 3
同理
gchi> pure $ Just 3 :: Maybe (Maybe Int)
gchi> Just (Just 3)
这里 f
又是 Maybe
而 a
又是 Just 3
你可以玩一点把类型改成纯的:
gchi> pure 3 :: [Double]
ghci> [3.0]
这里,f
是[],a
是3
同理
ghci> pure [3] :: [[Double]]
ghci> [[3.0]]
终于到了,f
又是[]
,a
是[3]
我正在学习 Applicative Functors,纯函数具有以下类型声明:
pure :: a -> f a
我知道纯函数接受任何类型的值,returns 一个包含该值的应用值。因此,如果应用实例是 Maybe
,pure 3
将给出 Just 3
.
但是,当您将 pure 应用于已在应用值内的值时会发生什么?例如。如果您执行 pure Just 3
?
What happens when you apply pure to a value that's already inside an applicative value?
它只是被包裹在一个额外的层中。最终结果是一个应用值嵌套在另一个应用值中。
E.g. what happens if you do something like
pure Just 3
?
这是一个有趣的问题,尽管可能不是出于您所指的原因。这里的重点是区分 pure (Just 3)
——这可能是你的意思——和 pure Just 3 = (pure Just) 3
,这是你写的。这给出了两种情况:
pure (Just 3)
只是将pure
应用于值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
并将其应用于值3
。但是我们不能这样做,因为f (a -> Maybe a)
是一个值,而不是一个函数!所以(pure Just) 3
应该会导致类型错误。…除了结果是类型检查就好了!所以我们错过了一些东西。在这种情况下,事实证明有一个适用于函数的实例:
instance Applicative ((->) r) where pure x = \r -> x (<*>) = _irrelevant_here
语法有点滑稽,但它基本上意味着
r -> ...
是一个应用程序。这个特殊的实例被称为 Reader monad,它的使用非常广泛。 (有关此特定数据类型的更多信息,请参阅 here or here。)这个想法是r -> a
可以在给定r
输入的情况下计算a
;在这种情况下,pure x
创建一个忽略其输入的函数,并且 returnsx
总是,并且f <*> x
将r
输入提供给两个f
和x
,然后将两者结合起来。在这种情况下,我们只使用pure
,因此很容易手动计算(pure Just) 3
:(pure Just) 3 = (\r -> Just) 3 = Just
所以这里的想法是
pure
将Just
包装在一个应用值中,在这种情况下恰好是一个函数;然后,我们将此函数应用于3
,它摆脱了包装以显示原始Just
.
首先,pure 具有以下类型:
pure :: Applicative f => a -> f a
为了简单起见,想想那种f
:k f
f :: * -> *
而a
的种类是*
那么 a
的类型就是 a
,任何 a
,是所有类型中最具多态性的(但记住种类 *
)。所以你并不关心a的值,你只是有一个限制,那就是typeclass
Applicative,还有f
的那种(记住* -> *
)
所以在这种情况下:
gchi> pure 3 :: Maybe Int
ghci> Just 3
这里 f
是 Maybe
而 a
是 3
同理
gchi> pure $ Just 3 :: Maybe (Maybe Int)
gchi> Just (Just 3)
这里 f
又是 Maybe
而 a
又是 Just 3
你可以玩一点把类型改成纯的:
gchi> pure 3 :: [Double]
ghci> [3.0]
这里,f
是[],a
是3
同理
ghci> pure [3] :: [[Double]]
ghci> [[3.0]]
终于到了,f
又是[]
,a
是[3]