首页 > 解决方案 > 寻找一种更好的方法来编写一个将类型构造函数作为参数的函数

问题描述

我有一个 Haskell 仆人应用程序。我想从文件中读取并用文件的内容填充数据库。我有的是这个

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

现在我想要一个可以使用 User 或 Product 并产生与上面类似的结果的函数。就像是:

hydrateDB :: Handler [Entity a]
hydrateDB =
    \alist con createItem listItems -> do
    items <- liftIO alist
    let list = fmap con items
    traverse_ createItem list
    listItems

标签: haskellservant

解决方案


这可能是类型类的一个很好的用途。把从一个版本到另一个版本不同的东西放在一个类中。设计可能会有所改进,但这是第一步:

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

(我做了一些更改以使类型有意义,但你明白了)


推荐阅读