4

Assuming this YAML (saved in a file called users.yml):

- id: 1
  name: Unknown user
  reputation: 0

- id: 2
  name: Foo bar
  reputation: 4

and this Haskell data type:

data MyUser = MyUser {id :: Int,
                      name :: String,
                      reputation :: Int}
                      deriving (Show)

I want to use the yaml library to read the YAML into a [MyUser]. How can I do that?

Uli Köhler
  • 13,012
  • 16
  • 70
  • 120

1 Answers1

11

You need to create a FromJSON instance (note that this is called FromJSON as yaml is derived from the Aeson library) as described in the Data.Yaml documentation.

A similar issue with Aeson was previously discussed here whereas the choice of a Haskell YAML library was discussed here

Here's a minimal working example that converts the YAML file into a [MyUser]:

{-# LANGUAGE OverloadedStrings #-}
import Data.Yaml
import Control.Applicative -- <$>, <*>
import Data.Maybe (fromJust)

import qualified Data.ByteString.Char8 as BS

data MyUser = MyUser {id :: Int,
                      name :: String,
                      reputation :: Int}
                      deriving (Show)

instance FromJSON MyUser where
    parseJSON (Object v) = MyUser <$>
                           v .: "id" <*>
                           v .: "name" <*>
                           v .: "reputation"
    -- A non-Object value is of the wrong type, so fail.
    parseJSON _ = error "Can't parse MyUser from YAML/JSON"

main = do
         ymlData <- BS.readFile "users.yml"
         let users = Data.Yaml.decode ymlData :: Maybe [MyUser]
         -- Print it, just for show
         print $ fromJust users
Community
  • 1
  • 1
Uli Köhler
  • 13,012
  • 16
  • 70
  • 120
  • I can't get this to work: `/app/Main.hs:21:5: error: • Couldn't match type ‘Yaml.Value’ with ‘[Char]’ Expected type: unordered-containers-0.2.8.0:Data.HashMap.Base.HashMap text-1.2.2.1:Data.Text.Internal.Text String Actual type: Yaml.Object • In the second argument of ‘(<$>)’, namely ‘v’ In the first argument of ‘(.:)’, namely ‘Transaction <$> v’ In the first argument of ‘(.:)’, namely ‘(.:) Transaction <$> v "entryDate" <*> v’` – adius Jul 18 '17 at 07:36
  • @adius I can't reproduce. `cabal sandbox init ; cabal install yaml ; cabal exec runghc index.hs` where `index.hs` is the code listed in the answer correctly produces `[MyUser {id = 1, name = "Unknown user", reputation = 0},MyUser {id = 2, name = "Foo bar", reputation = 4}]` for me. Maybe you can try `cabal update` and changing the package versions? – Uli Köhler Jul 18 '17 at 22:29
  • The problem was that I didn't import `.:` from `Data.Yaml`. I thought it was a function that was exported by `Control.Applicative`. Unfortunately the compiler error was not really helpful in that regard – adius Jul 20 '17 at 09:31