Haskell 函数组合 (.) 与函数应用 ($)

Haskell Function Composition (.) vs Function Application ($)

我正在学习 this source code

在第 81 行,我看到以下代码:

MaybeT . fmap Just $ locked .= False

我对function composition的使用很疑惑所以我把它加载到我的repl中并替换为function application

MaybeT $ fmap Just $ locked .= False

我很惊讶这两段代码给出了准确的结果。

Control.Monad.State.Class.MonadState Game m => MaybeT m ()

事实上,我可以理解函数应用程序 ($) 是如何产生这个结果的,但我对函数组合 (.) 如何产生这个结果感到困惑。这两个函数的签名不同,我认为如果一个函数替换另一个函数,它们应该会产生明显不同的结果。

:t (.) :: (b -> c) -> (a -> b) -> a -> c
:t ($) :: (a -> b) -> a -> b

谁能给我解释一下为什么 ($)(.) 在这种情况下可以互换。

. 的优先级高于 $:

> :info ($)
($) :: (a -> b) -> a -> b   -- Defined in ‘GHC.Base’
infixr 0 $
> :info (.)
(.) :: (b -> c) -> (a -> b) -> a -> c   -- Defined in ‘GHC.Base’
infixr 9 .

所以 a $ b $ c $ da $ (b $ (c $ d)),但是 a . b . c $ d(a . (b . c)) $ d

它们不可互换。

你拥有的是

MaybeT . fmap Just $ locked
MaybeT $ fmap Just $ locked        -- you had `dead` here

但由于运算符的优先级,它实际上被解析为

(MaybeT . fmap Just) locked  -- and
 MaybeT $ fmap Just  locked

.$ 在这里参与不同结构的表达式。可互换意味着您可以替换

(MaybeT . fmap Just) locked  -- with
(MaybeT $ fmap Just) locked

显然情况并非如此。

因此,在 same 表达式中将 . 替换为 $ 会产生不同的结果,正如您所期望的那样。同时两个 不同的 表达式恰好产生相同的结果。没什么奇怪的,表达式一直被简化为等价的不同表达式。