Настройка
У меня есть несколько коллекций различных структур данных, которые представляют состояние моделируемых объектов в виртуальной системе. У меня также есть ряд функций, которые преобразуют (то есть создают новую копию объекта на основе оригинала и 0 или более параметров) этих объектов.
Цель состоит в том, чтобы позволить пользователю выбрать некоторый объект для применения преобразований (в рамках правил моделирования), применить эти функции к этим объектам и обновить коллекции, заменив старые объекты новыми.
Я хотел бы иметь возможность создать функцию такого типа, комбинируя меньшие преобразования в большие. Затем оцените эту комбинированную функцию.
Вопросы
Как мне структурировать мою программу, чтобы сделать это возможным?
Какой комбинатор я использую для создания транзакции, подобной этой?
Идеи
- Соберите все коллекции в одну огромную структуру и обведите эту структуру.
- Используйте государственную монаду, чтобы выполнить в основном то же самое
- Используйте IORef (или одного из его более могущественных кузенов, таких как MVar) и создайте действие IO
- Использование функционально-реактивного каркаса программирования
1 и 2 выглядят так, как будто они несут много багажа, особенно если я предполагаю в конечном итоге перенести некоторые коллекции в базу данных. (Darn IO Monad)
3, кажется, работает хорошо, но начинает выглядеть как воссоздание ООП. Я также не уверен, на каком уровне использовать IORef. (например, IORef (Collection Obj)
или Collection (IORef Obj)
или data Obj {field::IORef(Type)}
)
4 кажется наиболее функциональным по стилю, но, похоже, он также создает большую сложность кода без большой отдачи с точки зрения выразительности.
* 1 042 *
Пример
У меня есть фронт интернет-магазина. Я поддерживаю коллекции продуктов с (среди прочего) количеством на складе и ценой. У меня также есть коллекция пользователей, которые имеют кредит в магазине.
Пользователь приходит и выбирает 3 продукта для покупки, а затем проверяет их, используя кредит магазина. Мне нужно создать новую коллекцию продуктов с уменьшенным количеством на складе для 3 продуктов, создать новую коллекцию пользователей с дебетованной учетной записью.
Это означает, что я получаю следующее:
checkout :: Cart -> ProductsCol -> UserCol -> (ProductsCol, UserCol)
Но тогда жизнь усложняется, и мне нужно иметь дело с налогами:
checkout :: Cart -> ProductsCol -> UserCol -> TaxCol
-> (ProductsCol, UserCol, TaxCol)
И тогда мне нужно обязательно добавить заказ в очередь доставки:
checkout :: Cart
-> ProductsCol
-> UserCol
-> TaxCol
-> ShipList
-> (ProductsCol, UserCol, TaxCol, ShipList)
И так далее ...
Я хотел бы написать что-то вроде
checkout = updateStockAmount <*> applyUserCredit <*> payTaxes <*> shipProducts
applyUserCredit = debitUser <*> creditBalanceSheet
но проверка типов могла бы привести меня в замешательство. Как мне структурировать хранилище таким образом, чтобы функции checkout
или applyUserCredit
оставались модульными и абстрактными? Я не могу быть единственным, у кого есть эта проблема, верно?