peter a g
peter a g

Reputation: 165

ghci unexpected behavior instance of class

I've been going through Bryan O'Sullivan's and co's "Real World Haskell," and came across what I would call unexpected 'laxness' on the part of GHCi, version 7.8.3, under Windows. I ":loaded" the following -

module JSONModule   where

data JValue = JNumber Double
           | JBool Bool
             deriving ( Show, Eq, Ord )


class JSON a where
  toJValue :: a -> JValue
  fromJValue :: JValue -> Either String  a


fromJBool (JBool b) = Right b
fromJBool _ = Left "not a JSON boolean"

instance JSON Double where
  toJValue = JNumber
  fromJValue = doubleToJValue id

instance JSON Bool where
  toJValue = JBool
  fromJValue = fromJBool

doubleToJValue :: (Double -> a) -> JValue -> Either String a
doubleToJValue f (JNumber v) = Right (f v)
doubleToJValue _ _ = Left "not a JSON number"

Then, in ghci :

*JSONModule> :r
[1 of 1] Compiling JSONModule       ( JSONModule.hs, interpreted )
Ok, modules loaded: JSONModule.
*JSONModule> toJValue False
JBool False
*JSONModule> fromJValue it
Left "not a JSON number"

While this is true, it is not what would have expected. I think ghci should have told me to fly a kite, as there were 2 instances for fromJValue. Indeed, if I specify

fromJValue it :: Either String Bool

I get Right False. The issue seems to be doubleToJValue. Eliminating the JSON Double instance, and adding a JChar Char constructor to JValue, and a corresponding instance of JSON Char, I get the expected 'ambiguous' response from ghci. So I think there is a bug. Comments? Thanks...

Upvotes: 2

Views: 79

Answers (2)

Ørjan Johansen
Ørjan Johansen

Reputation: 18199

This is not a bug, but a result of the ExtendedDefaultRules extension, which is enabled by default at the GHCi prompt, but not in files.

Approximately, when a type is otherwise ambiguous and has class constraints of the right form, GHC with this extension will try defaulting it to the first type which fits from (), Integer, Double.

Without the ExtendedDefaultRules extension, such as in module files by default, defaulting can still happen, but the requirements are stricter (at least one numeric class must be involved, and () isn't tried) and will only apply to a fixed set of classes, not any you define yourself.

Upvotes: 4

user2407038
user2407038

Reputation: 14623

To see what is really happening:

[1 of 1] Compiling JSONModule       ( test.hs, interpreted )
Ok, modules loaded: JSONModule.
>:set -Wall
>:t fromJValue (toJValue False)
fromJValue (toJValue False) :: JSON a => Either String a
> fromJValue (toJValue False)

<interactive>:6:2: Warning:
    Defaulting the following constraint(s) to type `Double'
      (JSON a0) arising from a use of `it' at <interactive>:6:2-28
      (Show a0) arising from a use of `print' at <interactive>:6:2-28
    In the first argument of `print', namely `it'
    In a stmt of an interactive GHCi command: print it
Left "not a JSON number"

As you can see, ghc defaults the ambiguous type variable to Double. The reason that it gives the ambiguous type error when there is no instance for Double is because the default behavior is to only default constraints to Integer or Double, because these are the cases that have been found to be most useful (or common). More info on defaulting.

Upvotes: 3

Related Questions