[Haskell-cafe] Typeclasses question in "Real World Haskell" book
daniel.is.fischer at web.de
Mon Jul 26 10:03:50 EDT 2010
On Monday 26 July 2010 15:16:36, Angel de Vicente wrote:
> 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
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
> 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
> *Main> fromJValue (JBool False)
> 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
- 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
*Main> fromJValue (JBool False) :: Either JSONError JValue
Right (JBool False)
> Thanks a lot,
> Ángel de Vicente
More information about the Haskell-Cafe