dimanche 27 mai 2018

How to have type reflection in Haskell

I've written a simple Yesod Rest Server that persists entities in JSON files. Entities are stored on disk in files named data/..json. For instance retrieveCustomer "1234" should load data from file data/Customer.1234.json.

I'm using a polymorphic function retrieveEntity that can retrieve instances of any data type that instantiate the FromJSON typeclass. At the moment I fill in the type name hardcoded in type-specific functions like retrieveCustomer.

How do I manage to compute the type name dynamically in the generic retrieveEntity? I think I'm basically looking for a Haskell type reflection mechanism which I did not come across so far?

-- | retrieve a Customer by id
retrieveCustomer :: Text -> IO Customer
retrieveCustomer id = do
    retrieveEntity "Customer" id :: IO Customer


-- | load a persistent entity of type t and identified by id from the backend
retrieveEntity :: (FromJSON a) => String -> Text -> IO a
retrieveEntity t id = do
    let jsonFileName = getPath t id ".json"
    parseFromJsonFile jsonFileName :: FromJSON a => IO a

-- | compute path of data file
getPath :: String -> Text -> String -> String
getPath t id ex = "data/" ++ t ++ "." ++ unpack id ++ ex

-- | read from file fileName and then parse the contents as a FromJSON instance.
parseFromJsonFile :: FromJSON a => FilePath -> IO a
parseFromJsonFile fileName = do
    contentBytes <- B.readFile fileName
    case eitherDecode contentBytes of
        Left msg -> fail msg
        Right x  -> return x





Aucun commentaire:

Enregistrer un commentaire