Haskell’s typeclasses are intentionally designed to let us create new instances of a typeclass whenever we see fit:
-- file: ch06/JSONClass.hs doubleToJValue :: (Double -> a) -> JValue -> Either JSONError a doubleToJValue f (JNumber v) = Right (f v) doubleToJValue _ _ = Left "not a JSON number" instance JSON Int where toJValue = JNumber . realToFrac fromJValue = doubleToJValue round instance JSON Integer where toJValue = JNumber . realToFrac fromJValue = doubleToJValue round instance JSON Double where toJValue = JNumber fromJValue = doubleToJValue id
We can add new instances anywhere; they are not confined to the module where we define a typeclass. This feature of the typeclass system is referred to as its open world assumption. If we had a way to express a notion of “the following are the only instances of this typeclass that can exist,” we would have a closed world.
We would like to be able to turn a list
into what JSON calls an array. We won’t worry about implementation
details just yet, so let’s use
undefined as the bodies of
the instance’s methods:
-- file: ch06/BrokenClass.hs instance (JSON a) => JSON [a] where toJValue = undefined fromJValue = undefined
It would also be convenient if we could turn a list of name/value pairs into a JSON object:
-- file: ch06/BrokenClass.hs instance (JSON a) => JSON [(String, a)] where toJValue = undefined fromJValue = undefined
If we put these definitions into a source file and ...