0
votes

I'm going through this source code for learning.

On line 81 I see the following code:

MaybeT . fmap Just $ locked .= False

I was puzzled by the use of the function composition so I loaded it in my repl and replaced it with function application

MaybeT $ fmap Just $ locked .= False

I'm very surprised these two pieces of code give the exact result.

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

In fact, I can understand how function application ($) is producing this result but I'm floored as to how function composition (.) is producing this result. The signatures of these two functions are different and I think they should clearly produce different results if one replaces the other.

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

Can someone explain to me why the ($) and (.) are interchangeable in this case.

2
(a . b) $ c is the same thing as a $ (b $ c) - or without the explicit $, which only is syntactical sugar for grouping: (a . b) c = a (b c)Bergi
Why did I get down voted?mac10688
I'm not a downvoter, but ($) vs (.) is a topic we already discussed several times. Just to mention one question: stackoverflow.com/questions/3030675/…chi
I tried searching around a bit before posting but I didn't see it. Sorry I missed it. At first glance, I still think my question is still relevant because the line of code involves more complexity and noise. It's harder for me to boil down to the answer. Also, the topic is a bit different. The other post wasn't confused about how they were working, just which style was preferred. My question is specifically how it works that way. But thanks for the link, for sure. I'll be going through that too and looking for more resources.mac10688

2 Answers

3
votes

. has a higher precedence than $:

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

So a $ b $ c $ d is a $ (b $ (c $ d)), but a . b . c $ d is (a . (b . c)) $ d.

3
votes

They are not interchangeable.

What you have is

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

but because of operator precedence it is really parsed as

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

the . and $ participate in differently structured expressions here. To be interchangeable would mean you could replace

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

and clearly this is not the case.

So, swapping . for $ in the same expression produces different results, just as you expected. At the same time two different expressions happen to produce the same result. Nothing strange there at all, expressions get simplified into equivalent different expressions all the time.