I’m trying to parse a YAML chunk and create a Request instance from it.
So basically I have the following (implementations of FromJSON URI, FromJSON RequestMethod and FromJSON Header are omitted for brevity):
...
instance FromJSON (Request r) where
parseJSON (Object v) = Request <$>
v .: "uri" <*>
v .: "method" <*>
v .: "headers" <*>
v .: "body"
Trying to compile (using GHC) this code produces:
No instance for (FromJSON r)
arising from a use of `.:'
In the second argument of `(<*>)', namely `v .: "body"'
In the expression:
Request <$> v .: "uri" <*> v .: "method" <*> v .: "headers"
<*> v .: "body"
In an equation for `parseJSON':
parseJSON (Object v)
= Request <$> v .: "uri" <*> v .: "method" <*> v .: "headers"
<*> v .: "body"
I feel it’s a newbie question (and that’s who I am), but apparently GHC cannot infer the type for the request body (which appears to be polymorphic) and I’m lacking the skills for handling this. Although I managed to “pacify” the compiler by replacing the instance declaration with:
instance FromJSON (Request Text) where
...
and adding {-# LANGUAGE FlexibleInstances #-} option, but I’m somehow sure it’s wrong.
So, how do I properly parse this (and similar cases)?
Thank you!
Thanks to @hammar, the answer boils down to the 2 following points:
1) To be able to join the computation, “r” (which refers to the request body) in the instance declaration has to be restricted to “FromJSON” class.
2) and, when the parser is used, it must be explicitly notified of the body type it is to handle:
I’m not sure how obvious that was, but GHC could’ve inferred the class restriction on its own, I guess. Not yet, perhaps.