我在那里,写一个函数,它接受一个值作为输入,调用该输入的函数,如果结果是Just x
,它应该返回x
; 否则,它应该返回原始输入.
换句话说,这个功能(我不知道该叫什么):
foo :: (a -> Maybe a) -> a -> a foo f x = fromMaybe x (f x)
由于它看起来像是一个通用功能,我想知道它是否已经定义,所以我在推特上问过,克里斯艾伦回复说它是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
.那怎么样?Monad
编译器推断出哪个实例m
?如何fromMaybe
将两个(curried)参数变成一个只需要一个参数的函数?
有人可以帮我连接点吗?
但是,使用的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
正如在这里另一个答案是理所当然指出,与功能使用时,<*>
就是你的好极了" 小号组合子.我们不能很好地具有S
在Haskell中命名的函数,因此<*>
它只是无点编码风格的标准库的一部分.Monadic bind(更多的是,翻转),=<<
可能更加神秘,但是一个无点的编码器只是不关心并且乐意用它来编码另一个相似的模式,
(f =<< g) x = f (g x) x
在组合函数调用,神秘或没有神秘(zipWith (-) =<< drop 1
想到).
为简洁和机械的答案道歉.我不喜欢樱桃挑选像Applicative或Monad这样的东西,但我不知道你在哪里.这不是我教授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那样强大的东西来描述我们正在做的事情.适用就足够了.尽管如此,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
/ (<*>)
与Maybe Monad/Applicative:
Prelude> ap (Just (+1)) (Just 1) Just 2 Prelude> (<*>) (Just (+1)) (Just 1) Just 2
要弄清楚的第一件事是,我们谈论的类型类适用的哪个实例?
Prelude> :t fromMaybe fromMaybe :: a -> Maybe a -> a
从Maye的类型中汲取一点点给我们:
(->) 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’
人力资源管理.可能呢?
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
的整体(->) a b
在哪里,结果.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
从类型中了解并不知道参数化是如何工作的.
编辑:谈到撰写,Functor for (->) a
just (.)
.适用的是,但有一个额外的论点.Monad是应用程序,但有争议翻转.
进一步的whuttery:适用<*>
于(->) a
)是S并且pure
是SKI组合子演算的K. (您可以从K和S派生出来.实际上,您可以从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
为清楚起见,我将重新标记类型参数.
ap :: Monad m => m (a -> b) -> m a -> m b fromMaybe :: c -> Maybe c -> c
哪个Monad实例编译器推断m是?
((->) r)
是一个Monad
.r
对于某些特定的 ,这是所有以类型作为参数的函数r
.
所以在类型中:
ap :: Monad m => m (a -> b) -> m a -> m b
m
〜(c ->)
,a
〜Maybe c
和b
〜c
.
返回类型,m a -> m b
扩展为(c -> Maybe c) -> c -> c
- 这是类型ap fromMaybe
.
您正在寻找的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
视为部分应用函数,那么您将获得所需的结果.