Hacker News new | ask | show | jobs
by captaincrowbar 14 days ago
‘Non-IO functions can't call IO functions.’

How do you handle logging then? If f() calls g(), how can I add logging to g() without having to change or recompile f() (and everything in the call stack above it)? ‘You can’t’ is not an acceptable answer.

4 comments

Not sure why people are saying "you can't" when it seems to me the whole point of algebraic effects that you can. You can define g so that it has no ability to do "general IO", all it can do is yield log messages. Then f can call g in a way that turns the log messages into writes to stdout. For example, here's how you would do it in Bluefin:

    type Log = Yield String
    
    -- workWithLogging cannot do arbitrary IO!
    -- All it can do is yield log messages, which
    -- must be processed elsewhere.
    workWithLogging  ::
      (e1 :> es) =>
      Log e1 ->
      Int ->
      Int ->
      Eff es Int
    workWithLogging l x y = do
      yield l ("x was " <> show x)
      yield l ("y was " <> show y)
      let result = x + y
      yield l ("result was " <> show result)
      pure result
    
    -- ghci> example
    -- x was 5
    -- y was 7
    -- result was 12
    -- 12
    example :: IO Int
    example = runEff $ \io -> do
      -- forEach determines how each log message
      -- should be handled.
      forEach
        (\l-> workWithLogging l 5 7)
        (\logMsg -> effIO io (putStrLn logMsg))
"You can't" is simpler, because the inevitable reply is "but how do I do actual logging inside g"
"Actual logging" as in direct access to IO?
Yes
Don't declare it as non-logging.
If `left_pad()` calls `send_env_vars()`, how can you add exfiltration to `send_env_vars()` without having to change `left_pad()` to expose the use of the network?

"You can't" should be the ONLY acceptable answer.

You can’t is an acceptable answer. The entitle point of such a feature is to prevent people from doing that.