Ищите лучший способ написать функцию, которая принимает конструктор типа в качестве аргумента - PullRequest
1 голос
/ 15 марта 2019

У меня есть заявка на слугу 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

Теперь я хотел бы одну функцию, которая может принимать либо пользователя, либо продукта и давать результат, аналогичный приведенному выше.Что-то вроде:

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

1 Ответ

4 голосов
/ 15 марта 2019

Возможно, это хорошее применение для классов типов.Поместите вещи, которые варьируются от одной версии к другой в классе.Дизайн, возможно, можно улучшить, но это первый шаг:

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

(я сделал несколько изменений, чтобы типы имели смысл, но вы поняли)

...