silkapp/rest

rest-example - example of handling nested ReaderT

ronslow opened this issue · 2 comments

I am following rest-examples, simplifying, and building a service to return a single Booking, identified by BookingId, from an (AcidState Diary)

newtype DiaryApi a = DiaryApi { unDiaryApi :: ReaderT (AcidState Diary) IO a }
  deriving ( Applicative
           , Functor
           , Monad
          , MonadIO
          , MonadReader (AcidState Diary)

       )

type WithBookingId = ReaderT BookingId DiaryApi

resource ::  Resource DiaryApi WithBookingId BookingId Void Void
resource = mkResourceReader { R.name = "booking"

                        , R.get = Just getBooking
                        }

getBooking ::  Handler WithBookingId
getBooking = mkIdHandler jsonO handler where
 handler :: () -> BookingId -> ExceptT (Reason Void) WithBookingId  Booking
 handler _ bid = do
   diary <- lift $ DiaryApi $ lift $ ask -- this is the problem line
   return $ liftIO $ query diary (GetBooking bid) -- this line is looking up the booking in the       AcidState Diary, works within IO, and is known to be correct

The problem line of course lifts the diary into a ExceptT (Reason Void) BookingApi Booking monad, whereas I need it to be inside an ExceptT (Reason Void) WithBookingId Booking monad

Am I going about this in the right way? Is it correct to nest ReaderT in this way for subresources?

Robert

getBooking = mkIdHandler jsonO handler where
  handler :: () -> BookingId -> ExceptT (Reason Void) WithBookingId  (Maybe Booking)
  handler _ bid = lift handler'
  handler' :: WithBookingId (Maybe Booking)
  handler' = do
    bid <- ask
    lift $ handler'' bid
  handler'' :: BookingId -> DiaryApi (Maybe Booking)
  handler'' bid = do
      diary <- DiaryApi ask
      liftIO $ query diary (AS.GetBooking bid)

The moral of the story was of course to subdivide the problem into typechecked definitions and then use the typechecker to guide to the solution

Sorry for not responding sooner to this, good to see you found the solution (lift ask).