I'm playing with free monads in Haskell and I got stuck with defining the functions that lift the functor constructors in the Free monad.
I have the AppF functor as a sum of several functors, each representing an effect. One of these functors is DbTrF, representing db transactions effects.
So my AppF is defined like this:
data AppF a =
DbTr (DbTrF a)
| ... functors for the other types of effects
deriving (Functor)
my DbTrF is defined like this:
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)
then I would like to have a transact function
transact :: Table i r t-> Op i r -> AppM (Maybe r)
...which I would like to use like this:
transactExample = transact UserTb (Get someUserId)
For that I want to introduce the type Table as the function which takes an operation and returns a DbTrF value:
newtype Table i r a = Table {tbId :: Op i r -> (Maybe r -> a) -> DbTrF a}
My attempt would be something like this:
transact (Table tb) op = liftF (DbTr (tb op ???))
but I'm not sure what to put instead of the question marks.
Is this a good direction to follow or am I doing it wrong?
Thanks!
Let's try to instantiate the body of the function progressively, keeping track of the expected type in the remaining hole:
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))
But we also have, from the type of Table tb
, tb :: Op i r -> (Maybe r -> a) -> DbTrF a
. Therefore a ~ Maybe r
, and we can just solve the hole above using id
, with a small change on the type of transact
.
transact :: Table i r (Maybe r) -> Op i r -> AppM (Maybe r)
transact (Table tb) op = liftF (DbTr (tb op id))