Как написать DSL на основе свободной монады?

Я играю со свободными монадами в Haskell, и я застрял с определением функций, которые поднимают конструкторы функторов в монаде Free.

У меня есть функтор AppF как сумма нескольких функторов, каждый из которых представляет эффект. Одним из таких функторов является DbTrF, представляющий эффекты транзакций db.

Итак, мой AppF определяется следующим образом:

data AppF a = 
  DbTr (DbTrF a)
  | ... functors for the other types of effects
  deriving (Functor)

мой DbTrF определяется следующим образом:

data Op i r =
  Get i
  | Insert i r
  | Delete i
  | Update i (r -> r)

data DbTrF a =
  UserTb (Op UserId UserData) (Maybe UserData -> a)
  | SessionTb (Op SessionId SessionData) (Maybe SessionData -> a)
  | ... here is the code for other tables
  deriving(Functor)

тогда я хотел бы иметь функцию transact

transact :: Table i r t-> Op i r -> AppM (Maybe r)

... который я хотел бы использовать следующим образом:

transactExample = transact UserTb (Get someUserId)

Для этого я хочу представить тип Table как функцию, которая выполняет операцию и возвращает значение DbTrF:

newtype Table i r a = Table {tbId :: Op i r -> (Maybe r -> a) -> DbTrF a}

Моя попытка будет примерно такой:

transact (Table tb) op = liftF (DbTr (tb op ???))

но я не уверен, что поставить вместо вопросительных знаков.

Это хорошее направление для подражания или я делаю это неправильно?

Спасибо!


person vidi    schedule 30.03.2017    source источник
comment
Я думаю, что это должно быть transactExample = transact (Table UserTb) (Get someUserId)   -  person Michael    schedule 31.03.2017
comment
Ты прав. Я на самом деле не смог скомпилировать эту часть   -  person vidi    schedule 31.03.2017


Ответы (1)


Давайте попробуем создать экземпляр тела функции постепенно, отслеживая ожидаемый тип в оставшейся дыре:

transact :: Table i r a -> Op i r -> AppM (Maybe r)
transact (Table tb) op
  = ??? :: AppM (Maybe r)
  = liftF (??? :: AppF (Maybe r))
  = liftF (DbTr (??? :: DbTrF (Maybe r)))
  = liftF (DbTr (tb op (??? :: Maybe r -> Maybe r))

Но у нас тоже есть, из типа Table tb, tb :: Op i r -> (Maybe r -> a) -> DbTrF a. Следовательно, a ~ Maybe r, и мы можем просто решить дыру выше, используя id, с небольшим изменением типа transact.

transact :: Table i r (Maybe r) -> Op i r -> AppM (Maybe r)
transact (Table tb) op = liftF (DbTr (tb op id))
person Li-yao Xia    schedule 30.03.2017
comment
Я пробовал это раньше, так как все примеры, которые я видел, использовали id, но это не работает. Ошибка: Не удалось сопоставить тип «t» с «Может быть r». «t» — это переменная жесткого типа, связанная сигнатурой типа для: transact :: forall i r t. Таблица i r t -> Op i r -> AppM (Maybe r) в src/App/AppMonad.hs:56:13 Ожидаемый тип: Maybe r -> t Фактический тип: t -> t • Во втором аргументе 'tb' а именно "id"... - person vidi; 31.03.2017
comment
Я изменил тип transact. Иного пути нет. - person Li-yao Xia; 31.03.2017
comment
Я этого не видел. Действительно, с измененным типом компилируется - person vidi; 31.03.2017