I have a Haskell Servant Application. I want to read from a file and populate the database with the contents of the file. What I have is this
userList :: IO [User]
productList :: IO [Product]
data User = User { age :: Int, fname :: String, lname :: String }
data Product = Product { title :: String, description :: String }
data Item = UserI User | ProductI Product
listUsers :: Handler [Entity User]
listProducts :: Handler [Entity Product]
hydrateUserDB :: Handler [Entity User]
hydrateUserDB = do
items <- liftIO userList
let list = fmap User items
traverse_ createUser list
listUsers
hydrateProductDB :: Handler [Entity Product]
hydrateProductDB = do
items <- liftIO productList
let list = fmap Product items
traverse_ createProduct list
listProducts
Now I would like one function that can take either User or Product and yield the similar result as above. Something like:
hydrateDB :: Handler [Entity a]
hydrateDB =
\alist con createItem listItems -> do
items <- liftIO alist
let list = fmap con items
traverse_ createItem list
listItems
This is perhaps a good use for typeclasses. Put the things that vary from one version to the other in a class. The design could probably be improved, but this is the first step:
class DBItem a where
itemList :: IO [a]
createItem :: a -> Handler ()
listItems :: Handler [Entity a]
instance DBItems User where
itemList = userList
createItem = ...
listItems = listUsers
instance DBItems Product where
itemList = productList
...
hydrateDB :: (DBItem a) => Handler [Entity a]
hydrateDB = do
items <- liftIO itemList
traverse_ createItem items
listItems
(I made a few changes to make the types make sense, but you get the idea)