5

I have a complex nested json, which i'm trying to parse with Aeson and Attoparsec, into my custom types. Based on info from questions: Haskell, Aeson & JSON parsing into custom type, Aeson: How to convert Value into custom type? and some info from Internet.

When I'm using following code I'm getting "Nothing" Value from overlapped FromJSON instance, but code goes through each instance for sure, I've tested this by disabling some other insances. So the main question : how to test code in instances and see how data changes over execution in GHCi?

P.S: Tried to set breakpoints and "trace", but they are worked only in main & parseCfg functions.

{-# LANGUAGE OverloadedStrings, FlexibleInstances #-}

-- high level data
data Cfg = Cfg { nm  :: CProperty,
             author :: CProperty,
             langs :: CValue,
             grops :: CListArr,
             projs :: CPropArr
           } deriving (Show)

...

instance FromJSON CProperty where
parseJSON _          = mzero
parseJSON (Object o) = CProperty <$> toCProperty o
  where
    toCProperty :: (HM.HashMap T.Text Value) -> J.Parser (T.Text, T.Text)
    toCProperty _  = error "unexpected property"
    toCProperty o' = do
      l <- return $ HM.toList o'
      k <- return $ fst $ head l
      v <- return $ snd $ head l
      v' <- parseJSON v
      return $ (k, v')

... lot's of different instances

-- |this instance is specific for different files
-- based on common functions to work with most of nested json code
instance FromJSON Cfg where
  parseJSON _          = mzero
  parseJSON (Object o) = do
    nm     <- (parseJSON :: Value -> J.Parser CProperty) =<< (o .: T.pack "Name")
    autor  <- (parseJSON :: Value -> J.Parser CValue)    =<< (o .: T.pack "Author")
    langs  <- (parseJSON :: Value -> J.Parser CProperty) =<< (o .: T.pack "Languages")
    groups <- (parseJSON :: Value -> J.Parser CListArr)  =<< (o .: T.pack "Groups")
    projs  <- (parseJSON :: Value -> J.Parser CPropArr)  =<< (o .: T.pack "Projects")
    return $ Cfg nm author langs groups projs
------------------------------------------------------------------------------------

main :: IO ()
main = do:
  s <- L.readFile "/home/config.json"
  -- print $ show s
  let cfg =  parseCfg s
  print $ show $ cfg

parseCfg :: L.ByteString -> Maybe Cfg
parseCfg s = decode s
Community
  • 1
  • 1
sigrlami
  • 1,822
  • 1
  • 17
  • 35

1 Answers1

3

The obvious problem is that in

instance FromJSON CProperty where
    parseJSON _          = mzero
    parseJSON (Object o) = ...

the first clause matches all input, so your instance returns mzero whatever the argument is. You should change the order of the clauses.

When compiling with warnings, GHC would tell you of the overlapping patterns.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
  • Yes, that helps, working with breakpoints now. Follow up question: is there any way to handle errors and useless values in a first place? (that's, actually, why I wrote such code) – sigrlami Sep 13 '12 at 14:26
  • There are ways to handle useless values (and errors, but that possibly only in IO, depends on what "errors" means), but to get meaningful advice, you should be more specific. What are errors/useless values, how are they indicated/detected, and where do you want to handle them. That's probably a new question. – Daniel Fischer Sep 13 '12 at 14:34
  • 1
    Ok, thank you anyway. I'll create new one, when I have more specific question. – sigrlami Sep 13 '12 at 14:37