为什么<$>和<*>以与>> =相反的顺序获取输入?

Ele*_*fee 20 parameters monads haskell functor applicative

我理解了<$>类型签名背后的原因,因为它只是一个中缀版本fmap,但是将它与>>=类型签名相比较,它对我来说没什么意义.

让我们首先确定我的意思.

(>>=) :: Monad m => m a -> (a -> m b) -> m b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
(<$>) :: Functor f => (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

查看类型签名,我们可以看到>>=左边是一个值,右边是一个函数,如果考虑它的链接属性,这很有意义:foo >>= bar >>= baz

这使我想知道,你为什么不<*><$>做到这一点?你不能写,foo <*> bar <*> baz因为它需要输出foo <*> bar是一个函数,而不是一个值.

我知道<**>=<<存在这两个参数的顺序,允许我做类似的事情:

Just 4 <**> pure (+3) <**> pure (*2) >>= (\x -> Just (x-3)) 
Run Code Online (Sandbox Code Playgroud)

这本可以精美地减少到:

Just 4 <$$> (+3) <$$> (*2) >>= (\x -> Just (x-3))
Run Code Online (Sandbox Code Playgroud)

如果<$$>已经存在,或者如果参数顺序<$>,并<*>发生了逆转.

让我想知道为什么存在差异的另一件事是,它让新手更难以习惯和/或记住它是否是功能,或者首先是价值,而不必查阅它.

那么,为什么在案件<*><$>它的fn op val,但与>>=它的val op fn

Don*_*art 22

不要让monad妨碍这里.考虑申请.

相比:

(<$>) :: Functor f => (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

($) :: (a -> b) -> a -> b
Run Code Online (Sandbox Code Playgroud)

您可以看到常规应用程序与仿函数下的应用程序之间存在连接.

琐事:有建议使用括号来重载空格(应用程序),以便我们可以写:

(| f a1 .. an |)
Run Code Online (Sandbox Code Playgroud)

代替

pure f <*> a1 <*> .. <*> an
Run Code Online (Sandbox Code Playgroud)

  • 我从来没有这样看过,我只是用`fmap`看了`<$>`,现在你已经把它作为'$`的变体呈现了它更有意义 (4认同)

Mat*_*hid 18

"为什么它按照这个顺序采取参数"的答案基本上是"因为".定义这些功能的人认为这是最好的方法.(在每种情况下,它可能不是同一个人.)但是,我将提供一些例子:

假设我们有某种解析monad.假设我们已经定义了

 data Foobar = Foobar X Y Z

 parseFoo :: Parser X
 parseBar :: Parser Y
 parseBaz :: Parser Z
Run Code Online (Sandbox Code Playgroud)

然后我们可以写

 parseFoobar :: Parser Foobar
 parseFoobar = do
   foo <- parseFoo
   bar <- parseBar
   baz <- parseBaz
   return (Foobar foo bar baz)
Run Code Online (Sandbox Code Playgroud)

或者,明确地,

parseFoobar =
  parseFoo >>= \ foo ->
  parseBar >>= \ bar ->
  parseBaz >>= \ baz ->
  return (Foobar foo bar baz)
Run Code Online (Sandbox Code Playgroud)

现在让我们写一下应用风格:

parseFoobar = return Foobar <*> parseFoo <*> parseBar <*> parseBaz
Run Code Online (Sandbox Code Playgroud)

或者,或者,

parseFoobar = Foobar <$> parseFoo <*> parseBar <*> parseBaz
Run Code Online (Sandbox Code Playgroud)

如果我们假设<**> = flip <*>存在(并且具有正确的关联性),那么我们就有了

parseFoobar = parseBaz <**> parseBar <**> parseFoo <**> return Foobar
Run Code Online (Sandbox Code Playgroud)

这看起来很奇怪.最后的函数和反向的参数?你为什么要这样写呢?(请注意,任何效果也是相反的顺序.)

在monadic版本中,效果从上到下发生.在应用版本中,效果从左到右发生.这似乎是"自然的".