4

This problem is related to this question.

Here is the data type I wish to make from the JSON:

data ProdObject = MKSpair (Text, Text)
                | MKSLpair (Text, [Text])
                | MKSOpair (Text, ProdObject)
                | MKObject ProdObject
                | End
                deriving Show

Here is a sample of the data I am working with, plus a generalization of the whole.

Here's my instance definition, which is causing an error. I've used this as a reference. I'm not sure if the error is telling me to fix my type, or that I'm way off. If the error really is straight-forward, I'd like some advice on how to fix my type,plus any advice on what else I may be doing wrong but haven't noticed yet.

instance FromJSON ProdObject where
  parseJSON (Object o) = MKObject <$> parseJSON o
  parseJSON (String s, String t)  = MKSpair (s, t)
  parseJSON (String s, Object o)  = MKSOpair (s, MKObject <$> parseJSON o)
  parseJSON (String s, Array a) = MKSLpair (s, V.toList a)
  parseJSON (Done d) = End
  parseJSON _        = mzero

Here's the error I have right now:

ghcifoo> :load test
[1 of 1] Compiling Main             ( test.hs, interpreted )

test.hs:23:52:
    Couldn't match expected type `Value'
                with actual type `Data.Map.Map Text Value'
    Expected type: Value
      Actual type: Object
    In the first argument of `parseJSON', namely `o'
    In the second argument of `(<$>)', namely `parseJSON o'
Failed, modules loaded: none.

Update: I've redone my data type, if I'm right I've got a phantom type. If I'm wrong, back to the drawing board

data ProdObject = MKSpair (Text, Text)
                | MKSLpair (Text, [Text])
                | MKSOpair (Text, ProdObject)
                | MKObject ProdObject (k,v)
                | End

Also I have reflected this change in my instance, though in an incomplete manner. I mention this just to ask if I am on the right track or not.

parseJSON (Object (k,v)) = MKObject ...

If I'm on the right track, I think I can either figure out the rest, or at least ask a specific question. Feedback anyone?

Community
  • 1
  • 1

1 Answers1

0

In this equation:

parseJSON (Object o) = MKObject <$> parseJSON o

o has type Map Text Value, but parseJSON has type Value -> Parser a, so you obviously can't apply parseJSON to o.

Also, you have a type error here:

parseJSON (String s, String t)  = MKSpair (s, t)

The type of parseJSON is Value -> Parser a, but you are trying to match against (Value, Value).

The same applies to this line:

parseJSON (Done d) = End

Done is not a constructor of type Value.


I couldn't understand why you need the ProdObject type to be recursive; here's how I would solve this problem:

data Outer = Outer {
  oName :: Text,
  oProducts :: M.Map Text Inner
} deriving Show

data Inner = Inner {
  iQA :: Text,
  iVM :: Text,
  iAvailable :: V.Vector Text
} deriving Show

instance FromJSON Outer where
    parseJSON (Object o) = Outer <$> o .: "name" <*> o .: "products"
    parseJSON _ = mzero

instance FromJSON Inner where
  parseJSON (Object o) = Inner <$> o .: "qa" <*> o .: "vm" <*> o .: "available"
  parseJSON _ = mzero

Full code listing can be found on Github.

Mikhail Glushenkov
  • 14,928
  • 3
  • 52
  • 65
  • I think what I have is the wrong concept of what a JSON object looks like. –  Oct 17 '11 at 22:55
  • I thought it needed to be recursive, because the data I was handed looked recursive to me. Thanks for the solution! –  Oct 17 '11 at 23:29