0
votes

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!

1
I think it should be transactExample = transact (Table UserTb) (Get someUserId)Michael
You are right. I didn't actually get to compile that partvidi

1 Answers

2
votes

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))