
Hi Emmanuel. It's somewhat confusing that in Haskell, data constructors and datatypes can have the same name. They're nevertheless different beasts. A data constructor is a way to construct values of a datatype, or to destruct them via pattern matching. Such constructors themselves are *not* types. The definition of JSValue looks as follows:
data JSValue = JSNull | JSBool !Bool | JSRational Bool{-as Float?-} !Rational | JSString JSString | JSArray [JSValue] | JSObject (JSObject JSValue) deriving (Show, Read, Eq, Ord, Typeable)
So there are six different ways to construct a JSValue, the last one is the JSObject constructor. It contains one item which is of *type* JSObject JSValue. This time, JSObject refers to a datatype, also defined in the library:
newtype JSObject e = JSONObject { fromJSObject :: [(String, e)] } deriving (Eq, Ord, Show, Read, Typeable )
Now to your functions: if you write
getObject :: JSValue -> JSObject JSValue getObject x@(JSObject _) = x
or
getObject :: JSValue -> JSObject JSValue getObject (JSObject x) = JSObject x
you are writing essentially the identity function, but trying to assign a more specific type to the value. This doesn't quite work in Haskell. There's no subtyping between different datatypes. Instead, what you should do is perform the pattern match once and extract its contents:
getObject :: JSValue -> JSObject JSValue getObject (JSObject x) = x
Now you have the stuff that was "inside" the constructor, and isolated the point of failure. Cheers, Andres -- Andres Löh, Haskell Consultant Well-Typed LLP, http://www.well-typed.com