Давайте использовать стейт правильно
Говно
#!/usr/bin/env runhaskell
{-# LANGUAGE NamedFieldPuns #-}
module Logger (
Severity(Fatal, Error, Warn, Info, Debug)
, Logger(FileLogger)
, log
, runLogger
, main -- example
) where
import Prelude hiding (log)
import Control.Monad
import Control.Monad.Trans.Class
import qualified Control.Monad.Trans.State as State -- from mtl-2.2.1
import qualified System.IO as IO
data Severity = Fatal | Error | Warn | Info | Debug deriving (Eq, Ord)
data Logger = FileLogger {
device :: IO.Handle
, severity :: Severity
, progname :: String
}
log :: Severity -> String -> State.StateT Logger IO ()
log severity' text = do
FileLogger{severity, device} <- State.get
when (severity >= severity') $
lift $ IO.hPutStr device $ text ++ "\n"
runLogger :: Logger -> State.StateT Logger IO () -> IO ()
runLogger = flip State.evalStateT
--- example
main :: IO ()
main = runLogger logger $ do
log Debug "debug disabled"
State.state $ \ logger -> ((), logger{severity = Debug})
log Debug "debug enabled"
where
logger = FileLogger { device=IO.stdout, severity=Info, progname="update"}
Охуенно
#!/usr/bin/env runhaskell
{-# LANGUAGE NamedFieldPuns #-}
module Logger (
Severity(Fatal, Error, Warn, Info, Debug)
, Logger(FileLogger)
, log
, runLogger
, main -- example
) where
import Prelude hiding (log)
import Control.Monad
import Control.Monad.Trans.Class
import qualified Control.Monad.Trans.Reader as Reader -- from mtl-2.2.1
import qualified System.IO as IO
data Severity = Fatal | Error | Warn | Info | Debug deriving (Eq, Ord)
data Logger = FileLogger {
device :: IO.Handle
, severity :: Severity
}
log :: Severity -> String -> Reader.ReaderT Logger IO ()
log severity' text = do
FileLogger{severity, device} <- Reader.ask
when (severity >= severity') $
lift $ IO.hPutStr device $ text ++ "\n"
runLogger :: Logger -> Reader.ReaderT Logger IO () -> IO ()
runLogger = flip Reader.runReaderT
--- example
main :: IO ()
main = runLogger logger $ do
log Debug "debug disabled"
Reader.withReaderT (\logger -> logger{severity = Debug}) $
log Debug "debug enabled"
where
logger = FileLogger { device=IO.stdout, severity=Info}
Это на самом деле не пост про хаскель,
Просто на нем все выглядит понятно и доходчиво. А теперь представьте себе, что у вас есть язык с сайд-эффектами. Так какого хрена вы пишете
I18n.locale = :ru
, а не
I18n.with_locale(:ru) do
?????
На самом деле я пригорел даже не с руби,
что само по себе редкий случай, а с flow, написанного, на минуточку, на ocaml. Который типа функциональный и все такое. Почему там стейт ебаного логгера управляется так?
И эти люди еще хотят,
чтобы компилятор сам решал когда можно пустить в несколько потоков, а когда нет. Пиздец
Да, этот пост про
haskell, ocaml, ruby и js одновременно. Привыкайте, епт
Мини-анонс
Скоро (возможно даже в этом году) будет пост про динамические переменные. Рекомендую не пропустить, там будет про охуеннейшую штуку, которую почему то не завезли в “мейнстримные” скриптовые языки. В хаскеле, понятное дело, оно имеет не больше смысла, чем в эрланге, но все равно стоит почитать. Да, это что то типа withReaderT
PS
да, поцоны, я пишу логгер без монады Writer. Почему? Идите нахуй, вот почему