ap fromMaybe 是如何组成的?
How does ap fromMaybe compose?
我当时写了一个函数,它接受一个值作为输入,在该输入上调用一个函数,如果结果是 Just x
,它应该 return x
;否则,它应该 return 原始输入。
换句话说,这个函数(我不知道该叫什么):
foo :: (a -> Maybe a) -> a -> a
foo f x = fromMaybe x (f x)
因为它看起来像一个通用函数,我想知道它是否已经定义,所以I asked on Twitter, and Chris Allen replied它是ap fromMaybe
。
这听起来很有希望,所以我启动了 GHCI 并开始试验:
Prelude Control.Monad Data.Maybe> :type ap
ap :: Monad m => m (a -> b) -> m a -> m b
Prelude Control.Monad Data.Maybe> :type fromMaybe
fromMaybe :: a -> Maybe a -> a
Prelude Control.Monad Data.Maybe> :type ap fromMaybe
ap fromMaybe :: (b -> Maybe b) -> b -> b
ap fromMaybe
的类型当然看起来是正确的,并且一些实验似乎表明它也具有所需的行为。
但是它是如何工作的?
fromMaybe
函数对我来说似乎很清楚,并且孤立地,我认为我理解 ap
的作用 - 至少在 Maybe
的上下文中。当 m
为 Maybe
时,它的类型为 Maybe (a -> b) -> Maybe a -> Maybe b
.
我不明白 ap fromMaybe
是如何编译的。对我来说,这个表达式看起来像是部分应用,但我可能理解错了。但是,如果是这种情况,我不明白这些类型是如何匹配的。
ap
的第一个参数是 m (a -> b)
,但是 fromMaybe
的类型是 a -> Maybe a -> a
。那怎么搭配呢?编译器推断 m
是哪个 Monad
实例? fromMaybe
接受两个(柯里化)参数,如何变成接受单个参数的函数?
有人可以帮我把这些点联系起来吗?
但是 ap
在 Maybe
的上下文中 而不是 。我们将它与函数 fromMaybe
一起使用,因此它在函数的上下文中,其中
ap f g x = f x (g x)
在各种 Monad
个实例中,我们有
instance Monad ((->) r)
原来如此
ap :: Monad m => m (a -> b) -> m a -> m b
fromMaybe :: r -> (Maybe r -> r)
ap :: (r -> (a -> b)) -> (r -> a) -> (r -> b)
ap f g x :: b
ap fromMaybe :: (r -> a) -> (r -> b) , a ~ Maybe r , b ~ r
因为 ->
在类型中关联到右边:a -> b -> c ~ a -> (b -> c)
。尝试将这些类型组合在一起,我们只能得到上面的定义。
还有(<*>) :: Applicative f => f (a -> b) -> f a -> f b
,我们可以写成(fromMaybe <*>)
,如果你喜欢这样的涂鸦:
#> :t (fromMaybe <*>)
(fromMaybe <*>) :: (r -> Maybe r) -> r -> r
正如在此处的另一个答案中正确指出的那样,当与函数一起使用时,<*>
就是你的好 ole' S combinator。我们不能很好地在 Haskell 中使用名为 S
的函数,因此 <*>
只是 point-free 编码风格的标准指令集的一部分。 Monadic bind(更是如此,翻转),=<<
,可能更加神秘,但 pointfree 编码器并不关心,并且会愉快地使用它来编码另一个类似的模式,
(f =<< g) x = f (g x) x
在 combinatory 函数调用中,神秘与否(想到 zipWith (-) =<< drop 1
)。
为清楚起见,我将重新标记类型参数。
ap :: Monad m => m (a -> b) -> m a -> m b
fromMaybe :: c -> Maybe c -> c
Which Monad instance does the compiler infer that m is?
((->) r)
是一个 Monad
。这是所有以类型 r
作为参数的函数,对于某些 specific r
.
所以在类型中:
ap :: Monad m => m (a -> b) -> m a -> m b
m
~ (c ->)
、a
~ Maybe c
和 b
~ c
。
return 类型 m a -> m b
扩展为 (c -> Maybe c) -> c -> c
- 这是 ap fromMaybe
的类型。
对于简洁和机械的回答表示歉意。我不喜欢 cherry-picking Applicative 或 Monad 之类的东西,但我不知道你在哪里。这是 not my usual approach to teaching Haskell.
首先,ap
实际上是 (<*>)
。
Prelude> import Control.Monad
Prelude> import Data.Maybe
Prelude> import Control.Applicative
Prelude> :t ap
ap :: Monad m => m (a -> b) -> m a -> m b
Prelude> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
这是什么意思?这意味着我们不需要像 Monad 这样的 "strong" 来描述我们正在做的事情。适用性就足够了。但是 Functor 没有。
Prelude> :info Applicative
class Functor f => Applicative (f :: * -> *) where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
Prelude> :info Functor
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
这里是 ap
/(<*>)
可能 Monad/Applicative:
Prelude> ap (Just (+1)) (Just 1)
Just 2
Prelude> (<*>) (Just (+1)) (Just 1)
Just 2
首先要弄清楚的是,我们在谈论 Applicative 类型类的哪个实例?
Prelude> :t fromMaybe
fromMaybe :: a -> Maybe a -> a
从 Maybe 的类型中稍微脱糖可以得到:
(->) a (Maybe a -> a)
所以我们在这里关注的类型构造函数是(->)
。关于 (->)
也称为函数类型,GHCi 告诉我们什么?
Prelude> :info (->)
data (->) a b -- Defined in ‘GHC.Prim’
instance Monad ((->) r) -- Defined in ‘GHC.Base’
instance Functor ((->) r) -- Defined in ‘GHC.Base’
instance Applicative ((->) a) -- Defined in ‘GHC.Base’
嗯。 Maybe 呢?
Prelude> :info Maybe
data Maybe a = Nothing | Just a -- Defined in ‘GHC.Base’
instance Monad Maybe -- Defined in ‘GHC.Base’
instance Functor Maybe -- Defined in ‘GHC.Base’
instance Applicative Maybe -- Defined in ‘GHC.Base’
对 Maybe 使用 (<*>)
发生的事情是这样的:
Prelude> (+1) 1
2
Prelude> (+1) `fmap` Just 1
Just 2
Prelude> Just (+1) <*> Just 1
Just 2
Prelude> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
Prelude> let mFmap = fmap :: (a -> b) -> Maybe a -> Maybe b
Prelude> (+1) `mFmap` Just 1
Just 2
Prelude> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Prelude> let mAp = (<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
Prelude> :t (+1)
(+1) :: Num a => a -> a
Prelude> :t Just (+1)
Just (+1) :: Num a => Maybe (a -> a)
Prelude> Just (+1) `mAp` Just 1
Just 2
好的,函数类型的 Functor 和 Applicative 呢?这里棘手的部分之一是 (->)
必须在类型 中部分应用 才能成为 Functor/Applicative/Monad。因此,您的 f
成为整体 (->) a b
的 (->) a
,其中 a
是参数类型,b
是结果。
Prelude> (fmap (+1) (+2)) 0
3
Prelude> (fmap (+1) (+2)) 0
3
Prelude> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
Prelude> let funcMap = fmap :: (a -> b) -> (c -> a) -> c -> b
Prelude> -- f ~ (->) c
Prelude> (funcMap (+1) (+2)) 0
3
Prelude> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Prelude> let funcAp = (<*>) :: (c -> a -> b) -> (c -> a) -> (c -> b)
Prelude> :t fromMaybe
fromMaybe :: a -> Maybe a -> a
Prelude> :t funcAp fromMaybe
funcAp fromMaybe :: (b -> Maybe b) -> b -> b
Prelude> :t const
const :: a -> b -> a
Prelude> :t funcAp const
funcAp const :: (b -> b1) -> b -> b
不保证有用。您可以仅从类型和了解参数化的工作原理来判断 funcAp const
并不有趣。
编辑:说到撰写,(->) a
的 Functor 就是 (.)
。适用的是,但有一个额外的论点。 Monad 是 Applicative,但参数翻转了。
更进一步:适用于(->) a
) 的<*>
是S,pure
是SKI 组合子演算的K。 (你可以从K和S推导出I。其实你可以从K和S推导出任何程序。)
Prelude> :t pure
pure :: Applicative f => a -> f a
Prelude> :t const
const :: a -> b -> a
Prelude> :t const
const :: a -> b -> a
Prelude> let k = pure :: a -> b -> a
Prelude> k 1 2
1
Prelude> const 1 2
1
如果您更喜欢中缀语法,您正在寻找的 monad 是 (->) r
或 r -> _
。
然后 ap
的签名扩展为:
m (a -> b) -> m a -> m b =
(r -> (a -> b)) -> (r -> a) -> r -> b = -- now we use the signature of fromMaybe
(b -> (Maybe b -> b)) -> (b -> Maybe b) -> b -> b
现在,如果您将 ap fromMaybe
视为部分应用函数,瞧,您将获得所需的结果。
我当时写了一个函数,它接受一个值作为输入,在该输入上调用一个函数,如果结果是 Just x
,它应该 return x
;否则,它应该 return 原始输入。
换句话说,这个函数(我不知道该叫什么):
foo :: (a -> Maybe a) -> a -> a
foo f x = fromMaybe x (f x)
因为它看起来像一个通用函数,我想知道它是否已经定义,所以I asked on Twitter, and Chris Allen replied它是ap fromMaybe
。
这听起来很有希望,所以我启动了 GHCI 并开始试验:
Prelude Control.Monad Data.Maybe> :type ap
ap :: Monad m => m (a -> b) -> m a -> m b
Prelude Control.Monad Data.Maybe> :type fromMaybe
fromMaybe :: a -> Maybe a -> a
Prelude Control.Monad Data.Maybe> :type ap fromMaybe
ap fromMaybe :: (b -> Maybe b) -> b -> b
ap fromMaybe
的类型当然看起来是正确的,并且一些实验似乎表明它也具有所需的行为。
但是它是如何工作的?
fromMaybe
函数对我来说似乎很清楚,并且孤立地,我认为我理解 ap
的作用 - 至少在 Maybe
的上下文中。当 m
为 Maybe
时,它的类型为 Maybe (a -> b) -> Maybe a -> Maybe b
.
我不明白 ap fromMaybe
是如何编译的。对我来说,这个表达式看起来像是部分应用,但我可能理解错了。但是,如果是这种情况,我不明白这些类型是如何匹配的。
ap
的第一个参数是 m (a -> b)
,但是 fromMaybe
的类型是 a -> Maybe a -> a
。那怎么搭配呢?编译器推断 m
是哪个 Monad
实例? fromMaybe
接受两个(柯里化)参数,如何变成接受单个参数的函数?
有人可以帮我把这些点联系起来吗?
但是 ap
在 Maybe
的上下文中 而不是 。我们将它与函数 fromMaybe
一起使用,因此它在函数的上下文中,其中
ap f g x = f x (g x)
在各种 Monad
个实例中,我们有
instance Monad ((->) r)
原来如此
ap :: Monad m => m (a -> b) -> m a -> m b
fromMaybe :: r -> (Maybe r -> r)
ap :: (r -> (a -> b)) -> (r -> a) -> (r -> b)
ap f g x :: b
ap fromMaybe :: (r -> a) -> (r -> b) , a ~ Maybe r , b ~ r
因为 ->
在类型中关联到右边:a -> b -> c ~ a -> (b -> c)
。尝试将这些类型组合在一起,我们只能得到上面的定义。
还有(<*>) :: Applicative f => f (a -> b) -> f a -> f b
,我们可以写成(fromMaybe <*>)
,如果你喜欢这样的涂鸦:
#> :t (fromMaybe <*>)
(fromMaybe <*>) :: (r -> Maybe r) -> r -> r
正如在此处的另一个答案中正确指出的那样,当与函数一起使用时,<*>
就是你的好 ole' S combinator。我们不能很好地在 Haskell 中使用名为 S
的函数,因此 <*>
只是 point-free 编码风格的标准指令集的一部分。 Monadic bind(更是如此,翻转),=<<
,可能更加神秘,但 pointfree 编码器并不关心,并且会愉快地使用它来编码另一个类似的模式,
(f =<< g) x = f (g x) x
在 combinatory 函数调用中,神秘与否(想到 zipWith (-) =<< drop 1
)。
为清楚起见,我将重新标记类型参数。
ap :: Monad m => m (a -> b) -> m a -> m b
fromMaybe :: c -> Maybe c -> c
Which Monad instance does the compiler infer that m is?
((->) r)
是一个 Monad
。这是所有以类型 r
作为参数的函数,对于某些 specific r
.
所以在类型中:
ap :: Monad m => m (a -> b) -> m a -> m b
m
~ (c ->)
、a
~ Maybe c
和 b
~ c
。
return 类型 m a -> m b
扩展为 (c -> Maybe c) -> c -> c
- 这是 ap fromMaybe
的类型。
对于简洁和机械的回答表示歉意。我不喜欢 cherry-picking Applicative 或 Monad 之类的东西,但我不知道你在哪里。这是 not my usual approach to teaching Haskell.
首先,ap
实际上是 (<*>)
。
Prelude> import Control.Monad
Prelude> import Data.Maybe
Prelude> import Control.Applicative
Prelude> :t ap
ap :: Monad m => m (a -> b) -> m a -> m b
Prelude> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
这是什么意思?这意味着我们不需要像 Monad 这样的 "strong" 来描述我们正在做的事情。适用性就足够了。但是 Functor 没有。
Prelude> :info Applicative
class Functor f => Applicative (f :: * -> *) where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
Prelude> :info Functor
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
这里是 ap
/(<*>)
可能 Monad/Applicative:
Prelude> ap (Just (+1)) (Just 1)
Just 2
Prelude> (<*>) (Just (+1)) (Just 1)
Just 2
首先要弄清楚的是,我们在谈论 Applicative 类型类的哪个实例?
Prelude> :t fromMaybe
fromMaybe :: a -> Maybe a -> a
从 Maybe 的类型中稍微脱糖可以得到:
(->) a (Maybe a -> a)
所以我们在这里关注的类型构造函数是(->)
。关于 (->)
也称为函数类型,GHCi 告诉我们什么?
Prelude> :info (->)
data (->) a b -- Defined in ‘GHC.Prim’
instance Monad ((->) r) -- Defined in ‘GHC.Base’
instance Functor ((->) r) -- Defined in ‘GHC.Base’
instance Applicative ((->) a) -- Defined in ‘GHC.Base’
嗯。 Maybe 呢?
Prelude> :info Maybe
data Maybe a = Nothing | Just a -- Defined in ‘GHC.Base’
instance Monad Maybe -- Defined in ‘GHC.Base’
instance Functor Maybe -- Defined in ‘GHC.Base’
instance Applicative Maybe -- Defined in ‘GHC.Base’
对 Maybe 使用 (<*>)
发生的事情是这样的:
Prelude> (+1) 1
2
Prelude> (+1) `fmap` Just 1
Just 2
Prelude> Just (+1) <*> Just 1
Just 2
Prelude> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
Prelude> let mFmap = fmap :: (a -> b) -> Maybe a -> Maybe b
Prelude> (+1) `mFmap` Just 1
Just 2
Prelude> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Prelude> let mAp = (<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
Prelude> :t (+1)
(+1) :: Num a => a -> a
Prelude> :t Just (+1)
Just (+1) :: Num a => Maybe (a -> a)
Prelude> Just (+1) `mAp` Just 1
Just 2
好的,函数类型的 Functor 和 Applicative 呢?这里棘手的部分之一是 (->)
必须在类型 中部分应用 才能成为 Functor/Applicative/Monad。因此,您的 f
成为整体 (->) a b
的 (->) a
,其中 a
是参数类型,b
是结果。
Prelude> (fmap (+1) (+2)) 0
3
Prelude> (fmap (+1) (+2)) 0
3
Prelude> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
Prelude> let funcMap = fmap :: (a -> b) -> (c -> a) -> c -> b
Prelude> -- f ~ (->) c
Prelude> (funcMap (+1) (+2)) 0
3
Prelude> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Prelude> let funcAp = (<*>) :: (c -> a -> b) -> (c -> a) -> (c -> b)
Prelude> :t fromMaybe
fromMaybe :: a -> Maybe a -> a
Prelude> :t funcAp fromMaybe
funcAp fromMaybe :: (b -> Maybe b) -> b -> b
Prelude> :t const
const :: a -> b -> a
Prelude> :t funcAp const
funcAp const :: (b -> b1) -> b -> b
不保证有用。您可以仅从类型和了解参数化的工作原理来判断 funcAp const
并不有趣。
编辑:说到撰写,(->) a
的 Functor 就是 (.)
。适用的是,但有一个额外的论点。 Monad 是 Applicative,但参数翻转了。
更进一步:适用于(->) a
) 的<*>
是S,pure
是SKI 组合子演算的K。 (你可以从K和S推导出I。其实你可以从K和S推导出任何程序。)
Prelude> :t pure
pure :: Applicative f => a -> f a
Prelude> :t const
const :: a -> b -> a
Prelude> :t const
const :: a -> b -> a
Prelude> let k = pure :: a -> b -> a
Prelude> k 1 2
1
Prelude> const 1 2
1
如果您更喜欢中缀语法,您正在寻找的 monad 是 (->) r
或 r -> _
。
然后 ap
的签名扩展为:
m (a -> b) -> m a -> m b =
(r -> (a -> b)) -> (r -> a) -> r -> b = -- now we use the signature of fromMaybe
(b -> (Maybe b -> b)) -> (b -> Maybe b) -> b -> b
现在,如果您将 ap fromMaybe
视为部分应用函数,瞧,您将获得所需的结果。