и различные сущности.

отаю над кодом, который взаимодействует со схемой базы данных, которая моделирует постоянный граф. Прежде чем перейти к деталям моего конкретного вопроса, я подумал, что это может помочь обеспечить некоторую мотивацию. Моя схема вокруг книг, людей и ролей авторов. Книга имеет много авторских ролей, где в каждой роли есть человек. Однако вместо того, чтобы разрешать прямые запросы UPDATE для объектов книги, вы должны создать новую книгу и внести изменения в новую версию.

Теперь вернемся к земле Хаскелла. В настоящее время я работаю с несколькими типами классов, но главное, что у меня естьHasRoles а такжеEntity:

class HasRoles a where
    -- Get all roles for a specific 'a'
    getRoles :: a -> IO [Role]

class Entity a where
    -- Update an entity with a new entity. Return the new entity.
    update :: a -> a -> IO a

Вот и моя проблема. Когда вы обновляете книгу, вам нужно создать новую версию книги, но вытакже нужно скопировать поверх предыдущих книг роли (иначе вы потеряете данные). Самый простой способ сделать это:

instance Entity Book where
    update orig newV = insertVersion V >>= copyBookRoles orig

Это хорошо, но есть кое-что, что меня беспокоит, и это отсутствие какой-либо гарантии инварианта, что если что-тоEntity а также HasRoles, затем вставка новой версии скопирует существующие роли. Я подумал о 2 вариантах:

Используйте больше типов

Одним из «решений» является введениеRequiresMoreWork a b, Исходя из вышесказанного,insertVersion теперь возвращаетHasRoles w => RequiresMoreWork w Book. update хочетBookчтобы выйти изRequiresMoreWork значение, мы могли бы назватьworkComplete :: RequiresMoreWork () Book -> Book .

Однако реальная проблема заключается в том, что наиболее важной частью головоломки является сигнатура типаinsertVersion, Если это не соответствует инвариантам (например, он не упомянул о необходимостиHasRoles) затем все снова разваливается, и мы снова находимся в нарушении инварианта.

Докажите это с помощью QuickCheck

Удаляет проблему из времени компиляции, но по крайней мере мы все еще утверждаем инвариант. В этом случае инвариант является чем-то вроде: для всех сущностей, которые также являются экземплярамиHasRolesвставка новой версии существующего значения должна иметь те же роли.

Я немного озадачен этим. В Лиспе я бы использовал модификаторы методов, в Perl я бы использовал роли, но есть ли что-нибудь, что я могу использовать в Haskell?

Ответы на вопрос(2)

Ваш ответ на вопрос