我在那里,写一个函数,它接受一个值作为输入,调用该输入的函数,如果结果是Just x,它应该返回x; 否则,它应该返回原始输入.
换句话说,这个功能(我不知道该叫什么):
foo :: (a -> Maybe a) -> a -> a
foo f x = fromMaybe x (f x)
Run Code Online (Sandbox Code Playgroud)
由于它看起来像是一个通用功能,我想知道它是否已经定义,所以我在推特上问过,克里斯艾伦回复说它是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
Run Code Online (Sandbox Code Playgroud)
这种类型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)参数变成一个只需要一个参数的函数?
有人可以帮我连接点吗?
Wil*_*ess 21
但是,使用的ap是不是在的情况下Maybe.我们将它与函数一起使用fromMaybe,因此它位于函数的上下文中
ap f g x = f x (g x)
Run Code Online (Sandbox Code Playgroud)
在Monad我们的各种情况中
instance Monad ((->) r)
Run Code Online (Sandbox Code Playgroud)
所以它是
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
Run Code Online (Sandbox Code Playgroud)
因为->类型与右边相关:a -> b -> c ~ a -> (b -> c).试图将类型插入到一起,我们最终只能得到上面的定义.
并用(<*>) :: Applicative f => f (a -> b) -> f a -> f b,我们可以把它写成(fromMaybe <*>),如果你喜欢这种涂鸦:
#> :t (fromMaybe <*>)
(fromMaybe <*>) :: (r -> Maybe r) -> r -> r
Run Code Online (Sandbox Code Playgroud)
正如在这里另一个答案是理所当然指出,与功能使用时,<*>就是你的好极了" 小号组合子.我们不能很好地具有S在Haskell中命名的函数,因此<*>它只是无点编码风格的标准库的一部分.Monadic bind(更多的是,翻转),=<<可能更加神秘,但是一个无点的编码器只是不关心并且乐意用它来编码另一个相似的模式,
(f =<< g) x = f (g x) x
Run Code Online (Sandbox Code Playgroud)
在组合函数调用,神秘或没有神秘(zipWith (-) =<< drop 1想到).
bit*_*app 16
为简洁和机械的答案道歉.我不喜欢樱桃挑选像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
Run Code Online (Sandbox Code Playgroud)
这是什么意思?这意味着我们不需要像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
Run Code Online (Sandbox Code Playgroud)
这是ap/ (<*>)与Maybe Monad/Applicative:
Prelude> ap (Just (+1)) (Just 1)
Just 2
Prelude> (<*>) (Just (+1)) (Just 1)
Just 2
Run Code Online (Sandbox Code Playgroud)
要弄清楚的第一件事是,我们谈论的类型类适用的哪个实例?
Prelude> :t fromMaybe
fromMaybe :: a -> Maybe a -> a
Run Code Online (Sandbox Code Playgroud)
从Maye的类型中汲取一点点给我们:
(->) a (Maybe a -> a)
Run Code Online (Sandbox Code Playgroud)
所以我们在这里关注的类型构造函数是(->).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’
Run Code Online (Sandbox Code Playgroud)
人力资源管理.可能呢?
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’
Run Code Online (Sandbox Code Playgroud)
使用(<*>)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
Run Code Online (Sandbox Code Playgroud)
好的,函数类型的Functor和Applicative怎么样?这里的一个棘手的部分是(->)要在类型中部分应用为Functor/Applicative/Monad.所以你f成为一个参数类型(->) a的整体(->) a b在哪里,结果.ab
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
Run Code Online (Sandbox Code Playgroud)
不保证有用.你可以funcAp const从类型中了解并不知道参数化是如何工作的.
编辑:谈到撰写,Functor for (->) ajust (.).适用的是,但有一个额外的论点.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
Run Code Online (Sandbox Code Playgroud)
为清楚起见,我将重新标记类型参数.
ap :: Monad m => m (a -> b) -> m a -> m b
fromMaybe :: c -> Maybe c -> c
Run Code Online (Sandbox Code Playgroud)
哪个Monad实例编译器推断m是?
((->) r)是一个Monad.r对于某些特定的 ,这是所有以类型作为参数的函数r.
所以在类型中:
ap :: Monad m => m (a -> b) -> m a -> m b
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
现在,如果您将其ap fromMaybe视为部分应用函数,那么您将获得所需的结果.