Decorator-style handler #298
Unanswered
emlautarom1
asked this question in
Q&A
Replies: 4 comments 3 replies
|
In a more generic fashion, the runLoggerAbove severity impl1 impl2 = interpret $ \_ -> \case
Log severity message -> do
if severity > minSeverity then do
-- use `impl1` as handler
else do
-- use `impl2` as handler |
0 replies
|
Ok, after some debugging I realized that runLoggerAbove :: (Logger :> es) => Severity -> Eff (Logger : es) a -> Eff es a
runLoggerAbove minSeverity = interpret $ \_ -> \case
Log severity message -> do
when (severity > minSeverity) $ do
log severity message |
0 replies
|
This leaves the question open as to how to deal with the "generic" approach that supports passing handlers as arguments, and decides which one to use based on the |
0 replies
Have a look at |
3 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
I'm trying to get the following code to compile:
{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} module Main where import Control.Monad import Effectful import Effectful.Dispatch.Dynamic import System.IO import Prelude hiding (log) data Severity = Info | Error | Fatal deriving (Show, Eq, Ord, Bounded) data Logger e :: Effect where Log :: Severity -> String -> (Logger e) m () type instance DispatchOf (Logger e) = Dynamic log :: (Logger e :> es) => Severity -> String -> Eff es () log severity message = send $ Log severity message runNoLogger :: Eff (Logger e : es) a -> Eff es a runNoLogger = interpret $ \_ -> \case Log _ _ -> return () runLoggerAbove :: (Logger e :> es) => Severity -> Eff (Logger e : es) a -> Eff es a runLoggerAbove minSeverity = interpret $ \_ -> \case Log severity message -> do when (severity > minSeverity) $ do log severity message runHandleLogger :: (IOE :> es) => Handle -> Eff (Logger e : es) a -> Eff es a runHandleLogger handle = interpret $ \_ -> \case Log severity message -> do liftIO $ hPutStrLn handle (prefix severity ++ " " ++ message) prefix :: Severity -> String prefix = \case Info -> "[INFO]" Error -> "[ERROR]" Fatal -> "[FATAL]" program :: (Logger e :> es) => Eff es () program = do log Info "Hello, world!" log Error "Something went wrong!" log Fatal "Everything is on fire!" main :: IO () main = do withFile "example.log" WriteMode $ \h -> runEff $ runHandleLogger h $ runLoggerAbove Info $ do programThe idea is that we have a single effect
Loggerwhich accepts multiple interpretations, for example, we might have a logger that does not log anything (runNoLogger) or a logger which writes to a file (runHandleLogger).Now, I would like to have a "handler" that works like a Decorator, that is, the "handler" requires another "handler" that actually does the work, but before (or after) this "inner" handle takes control the Decorator performs some kind of (pre/post)processing. In this case, I would like to have a decorator
runLoggerAbovethat when theseverityis some value it delegates the work to "inner", otherwise it does nothing (return ()).The code above does not compile with the following error:
My
.cabalfile looks like this:My environment:
All reactions