Skip to content

How to return a conduit from an effect? #108

@endgame

Description

@endgame

I have been trying to write an effect for the functions in ftp-client-conduit:

data Ftp :: Effect where
  -- Among others
  Retr :: String -> Ftp m (ConduitT Void ByteString m ())

$(makeEffect ''Ftp)

runFtpIO ::
  ( IOE :> es,
    Reader Ftp.Handle :> es,
    Resource :> es
  ) =>
  Eff (Ftp ': es) a ->
  Eff es a
runFtpIO = interpret $ \_ -> \case
  Retr s -> do
    h <- ask
    pure $ Ftp.retr h s

This fails with the following error:

 error:
    • Could not deduce (IOE :> localEs)
        arising from a use of ‘Ftp.retr’
      from the context: (IOE :> es, Reader Ftp.Handle :> es,
                         Resource :> es)
        bound by the type signature for:
                   runFtpIO :: forall (es :: [Effect]) a.
                               (IOE :> es, Reader Ftp.Handle :> es, Resource :> es) =>
                               Eff (Ftp : es) a -> Eff es a
        at <location>
      or from: (HasCallStack, Ftp :> localEs)
        bound by a type expected by the context:
                   EffectHandler Ftp es
        at <location>
      or from: a1 ~ ConduitT Void ByteString (Eff localEs) ()
        bound by a pattern with constructor:
                   Retr :: forall (m :: * -> *).
                           String -> Ftp m (ConduitT Void ByteString m ()),
                 in a case alternative
        at <location>
    • In the second argument of ‘($)’, namely ‘Ftp.retr h ss’
      In a stmt of a 'do' block: pure $ Ftp.retr h ss
      In the expression:
        do h <- ask
           pure $ Ftp.retr h ss
   |
xx |     pure $ Ftp.retr h ss
   |            ^^^^^^^^

It looks to me like we cannot know what's going inside the monad that the ConduitT is applied to, and since @isovector has hit the same problem I think it looks pretty fundamental to the way these effect libraries work.

In effectful's case, it seems like I can get it to compile by being specific about the monad inside the conduit:

data Ftp :: Effect where
   -- I think I like this the best, as we can lift into whatever we need
  Retr :: String -> Ftp m (ConduitT Void ByteString ResIO ())

  -- Constrain the monad
  Retr' :: (MonadIO n, MonadResource n) => String -> Ftp m (ConduitT Void ByteString n ())

  -- Constrain the monad to be an Eff
  Retr'' :: (IOE :> es, Resource :> es) => String -> Ftp m (ConduitT Void ByteString (Eff es) ())

Do you have any alternate suggestions?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions