I think the answer to your question revolves around the Alternative instance for Parser. Does the following code help?

Var <$> ((Left <$> parseJSON) <|> (Right <$> parseJSON))

What this is saying is "try to parse a MyList, and then wrap it with a Left. If that fails, try to parse an Item and wrap it with a Right. Whatever the result is from there, wrap it in a Var."

On Sat, May 2, 2015 at 3:56 PM Johannes Strecha <j.strecha@gmail.com> wrote:
Dear Cafe,

I need help parsing YAML files with varying structure. The minimal example is: a yaml file that has one key, which can hold either one key-value pair or two key value pairs.  I have data types for the one key, and the two possible sub-keys:

>data Var = Var {
>  v' :: Either MyList Item
>  } deriving Show
>
>data MyList = MyList {
>  a' :: Int,
>  b' :: Int
>  } deriving Show
>
>data Item = Item {
>  content' :: String
>  } deriving Show

To read MyList and Item from the file I wrote FromJSON instances

>instance FromJSON MyList where
>  parseJSON (Object m) = MyList <$> m .: (pack "a") <*> m .: (pack "b")
>  parseJSON  x = fail ("not an object: " ++ show x)
>
>instance FromJSON Item where
>  parseJSON (Object m) = Item <$> m .: (pack "c")
>  parseJSON x = fail ("not an object: " ++ show x)

I also have read functions for MyList and Item:

>readItem :: IO Item
>readItem = either (error.show) id <$> decodeFileEither "test.yaml"
>
>readMyList :: IO MyList
>readMyList = either (error.show) id <$> decodeFileEither "test.yaml"

The file test.yaml looks like

>v:
>  a: 4
>  b: 5

or, alternatively

>v:
>  c: "test"

The question is how I can decode test.yaml to get Var. Trying to code readVar like readItem (having FromJSON Var like FromJSON Item) failed. For convenience I attached the relevant source files.

Regards,
Johannes.
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe