-
I've attempted for a while myself but haven't gotten anywhere. Something like..? type ExceptA m a = (Monad m) => ExceptT a m a
data EarlyReturn :: Effect where
DoReturnEarly :: ExceptA m a -> EarlyReturn m a
type instance DispatchOf EarlyReturn = Dynamic
earlyReturn
:: (HasCallStack, EarlyReturn :> es)
=> ExceptA m a
-> Eff es a
earlyReturn action = send (DoReturnEarly action)
runEarlyReturn :: Eff (EarlyReturn : es) a -> Eff es a
runEarlyReturn = interpret $ \_ -> \case
DoReturnEarly action -> do
x <- runExceptT action
case x of
Left y -> pure y
Right z -> pure z Any help would be greatly appreciated. Thank you! |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 2 replies
-
Early return is best implemented as an exception in effectful. We do early return by just doing: data EarlyReturn = EarlyReturn
earlyReturn :: Error EarlyReturn :> es => Eff es ()
earlyReturn = throwError EarlyReturn
runEarlyReturn :: Eff (EarlyReturn : es) () -> Eff es (Maybe a)
runEarlyReturn = fmap (either (const Nothing) Just) . runErrorNoCallStack @EarlyReturn I think effectful would benefit from packaging this up into |
Beta Was this translation helpful? Give feedback.
-
You should piggyback on the import Effectful
import Effectful.Dispatch.Dynamic
import Effectful.Error.Static
data EarlyReturn r :: Effect where
ReturnWith :: r -> EarlyReturn r m a
type instance DispatchOf (EarlyReturn r) = Dynamic
returnWith
:: (HasCallStack, EarlyReturn r :> es)
=> r
-> Eff es a
returnWith = send . ReturnWith
runEarlyReturn :: Show r => Eff (EarlyReturn r : es) a -> Eff es (Either (CallStack, r) a)
runEarlyReturn = reinterpret_ runError $ \case
ReturnWith r -> throwError r You can also do |
Beta Was this translation helpful? Give feedback.
-
Thank you for the quick replies! Will play around with it |
Beta Was this translation helpful? Give feedback.
-
Is this type runEarlyReturn :: Show r => Eff (EarlyReturn r : es) a -> Eff es (Either (CallStack, r) a) maybe problematic? Specifically the Regardless of that (which may not be a big issue, is there a simple way around it?), I think it would be preferable to have a type I've got a version which type checks now, but seems there is still an issue as the call site is giving me an error I don't well understand. The effect: import Control.Monad.Trans.Except (ExceptT (..), runExceptT, throwE)
data EarlyReturn :: Effect where
ReturnWith :: ExceptT a m a -> EarlyReturn m a
type instance DispatchOf EarlyReturn = Dynamic
returnWith
:: forall a es
. (HasCallStack, EarlyReturn :> es)
=> a
-> Eff es a
returnWith a = send (ReturnWith (throwE a))
runEarlyReturn :: Eff (EarlyReturn : es) a -> Eff es a
runEarlyReturn = interpret $ \env -> \case
ReturnWith action -> localSeqUnlift env $ \unlift -> do
fmap (either id id) (unlift (runExceptT action))
Attempt to use it: earlyReturnTest
:: forall es
. (HasCallStack, EarlyReturn :> es)
=> Int
-> Eff es Bool
earlyReturnTest n = do
when (n < 10) $
returnWith True
pure False Error:
|
Beta Was this translation helpful? Give feedback.
You should piggyback on the
Error
effect, sinceEarlyReturn
isError
withoutCatchError
:You can also do
runErrorNoCallStack
if you don't want a call stack in the result (orthrowError_
if you don't want to impose …