
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.

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
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

Thanks for the hint. I wasn't aware of <|>. However, I couldn't get it to
work yet (due to missing background knowledge -- have to read up).
JS.
On Sun, May 3, 2015 at 9:26 AM, Michael Snoyman
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
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
participants (2)
-
Johannes Strecha
-
Michael Snoyman