寻找一种更好的方法来编写将类型构造函数作为参数的函数
Looking for a better way to write a function that takes a type constructor as argument
我有一个 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
这也许是 typeclasses 的一个很好的用途。将一个版本与另一个版本不同的东西放在 class 中。设计或许可以改进,但这是第一步:
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
(我做了一些更改以使类型有意义,但你明白了)
我有一个 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
这也许是 typeclasses 的一个很好的用途。将一个版本与另一个版本不同的东西放在 class 中。设计或许可以改进,但这是第一步:
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
(我做了一些更改以使类型有意义,但你明白了)