Reputation: 34944
Given this:
data Base = Base {
key1 :: Text,
key2 :: Text,
key3 :: Text
} deriving (Show)
instance FromJSON Base where
parseJSON (Object v) = Base <$>
((v .: "base123") >>= (.: "key1")) <*> -- 1
((v .: "base123") >>= (.: "key2")) <*> -- 2
((v .: "base123") >>= (.: "key3")) -- 3
parseJSON _ = mzero
What's the order of in which the infix operators <$>
, <*>
and <*>
are applied? In other words, if I rewrite it in prefix form:
instance FromJSON Base where
parseJSON (Object v) = Base <$> ((<*>) ((v .: "base123") >>= (.: "key1")) $ (<*>) ((v .: "base123") >>= (.: "key2")) ((v .: "base123") >>= (.: "key3")))
parseJSON _ = mzero
(notice $
operator), will the right part of the second <*>
be evaluated first because only in this case it makes sense because the first <*>
requires 2 arguments? And since it requires 2 arguments, we have to use $
also.
I might've asked my question so that it was difficult to understand what I meant but I hope you did understand.
Upvotes: 1
Views: 105
Reputation: 48766
Actually your prefix form is not quite correct, it should be like this:
parseJSON (Object v) = ((<*>)
((<*>)
((<$>) Base ((v .: "base123") >>= (.: "key1")))
(((v .: "base123") >>= (.: "key2"))))
(((v .: "base123") >>= (.: "key3"))))
The above definition is still not in complete prefix form. You have to take >>=
and .:
to the left to make them completely prefix. That being said, to find the exact order of evaluation of multiple operators in infix form I would suggest you to play up in ghci to get more insights into types. As an initial step, check the associativity and the precedence order for all the operators:
λ> :i (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
infixl 4 <$>
λ> :i (<*>)
(<*>) :: f (a -> b) -> f a -> f b
infixl 4 <*>
So, they both are left associative and have the same precedence. The infix form of the definition is quite clear on how the evaluation will take place: they start from left and initially <$>
is applied over Base
and then followed by application of two <*>
functions. The type Base
is initially applied to <$>
:
λ> :t Base
Base :: Text -> Text -> Text -> Base
λ> :t (Base <$>)
(Base <$>) :: Functor f => f Text -> f (Text -> Text -> Base)
Now, ((v .: "base123") >>= (.: "key1"))
is applied to the resultant of the above type:
λ> let (Object v) = undefined :: Value
λ> :t (Base <$> ((v .: "base123") >>= (.: "key1")))
(Base <$> ((v .: "base123") >>= (.: "key1"))) :: Parser (Text -> Text -> Base)
You can see that it returns a function wrapped in Parser
type. And to extract the underlying function out of the Parser
type, you have to use <*>
:
λ> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
λ> :t (Base <$> ((v .: "base123") >>= (.: "key1")) <*>)
(Base <$> ((v .: "base123") >>= (.: "key1")) <*>) :: Parser Text -> Parser (Text -> Base)
You can follow the similar steps to see how it is applied to the other parts of the function definition. At the end, you will get a type of Parser Base
.
Upvotes: 2