[Haskell-cafe] Typeclasses question in "Real World Haskell" book
Daniel Fischer
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:
> 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
More information about the Haskell-Cafe
mailing list