
On Monday 26 July 2010 15:16:36, Angel de Vicente wrote:
Hi,
I'm stuck at page 151 of Real World Haskell and hoping that perhaps some of you can give me a hand here...
The code that is giving me trouble is below.
data JValue = JString String
| JNumber Double | JBool Bool | JNull | JObject [(String, JValue)] | JArray [JValue]
deriving (Eq, Ord, Show)
type JSONError = String
class JSON a where toJValue :: a -> JValue fromJValue :: JValue -> Either JSONError a
instance JSON JValue where toJValue = id fromJValue = Right
instance JSON Bool where toJValue = JBool fromJValue (JBool b) = Right b fromJValue _ = Left "not a JSON boolean"
I don't understand how the JSON typeclass is defined, in particular the fromJValue definition.
Given a JValue and a type (like Bool, JValue, String, Maybe [(Integer, ())]), fromJValue returns either Left errormessage or Right (value of desired type)
For instance, when defining the instance for Bool types, then I understand that both functions (toJValue and fromJValue) will be called upon when we supply a Bool type, but then the (JBool b) type in function fromJValue doesn't match....
fromJValue always takes a JValue as argument. That JValue can be a wrapped String, a wrapped Bool, a wrapped number (Double), ... Depending on the result type (Either JSONError a), it returns a wrapped value of type a [Right a] or a wrapped error message [Left JSONError]
toJValue is no problem, but I cannot understand how fromJValue is supposed to work, and the comments in the online book (http://book.realworldhaskell.org/read/using-typeclasses.html) don't help with this either.
*Main> :load ch6 [1 of 1] Compiling Main ( ch6.hs, interpreted ) Ok, modules loaded: Main. *Main> toJValue False JBool False *Main> :type it it :: JValue *Main> fromJValue False
<interactive>:1:11: Couldn't match expected type `JValue' against inferred type `Bool' In the first argument of `fromJValue', namely `False' In the expression: fromJValue False In the definition of `it': it = fromJValue False
That one should be pretty clear, fromJValue expects a JValue as argument and gets a Bool, it's like calling fromInteger True
*Main> fromJValue (JBool False)
<interactive>:1:0: Ambiguous type variable `a' in the constraint: `JSON a' arising from a use of `fromJValue' at <interactive>:1:0-23 Probable fix: add a type signature that fixes these type variable(s) *Main>
That's less easy. The compiler/interpreter doesn't know which result type to use. fromJValue :: JSON a => JValue -> Either JSONError a with which type should a be instantiated, should it use - JValue, in which case the result would be Right (JBool False) - Bool, in which case the result would be Right False - String, in which case the result woulde be something like No instance for (JValue [Char]) arising from a use of `fromJValue' at ... (unless you have such an instance in scope, then it would be something like Left "not a JSON string") - Int, in which case you'd get analogous behaviour - ...
Any pointers?
In an actual programme, there is usually enough context to fix the type variable a, then the compiler/interpreter knows what to do. At the prompt or when there isn't enough context otherwise, you need to explicitly tell the compiler/interpreter which type to use, *Main> fromJValue (JBool False) :: Either JSONError Bool Right False *Main> fromJValue (JBool False) :: Either JSONError JValue Right (JBool False)
Thanks a lot, Ángel de Vicente