A common case is when you need to add logging to a function.
There are 2 ways:
1. You cheat and use unsafePerformIO. This is discouraged and I won't go into the details.
2. You convert your inner function from being a "pure" function to being a monadic function over some abstract MonadLogger m. Then you can still call your function in a "pure" context by using a Writer monad for your MonadLogger, but you can also call it from the IO monad and get "better" logging (with real-time output and timing info).
Note that you still do need to convert your entire call chain from being pure to use "MonadLogger".
But I would argue that even in non-Haskell languages you should also do this (meaning you should thread a "Logger" object through all functions). Why? Let's say you don't, and now you want to do logging from some inner function. How do you configure the logging? To which file do you save it? What verbosity level? You will need to use a global/Singleton Logger object. But what if you want to call your function from two different places in your code and use a different verbosity setting for each? You can't. So I argue you are always just better off doing the refactor in all languages. The fact that Haskell forces this means that developers don't have the choice and are forced to do the right thing.
There are 2 ways:
1. You cheat and use unsafePerformIO. This is discouraged and I won't go into the details.
2. You convert your inner function from being a "pure" function to being a monadic function over some abstract MonadLogger m. Then you can still call your function in a "pure" context by using a Writer monad for your MonadLogger, but you can also call it from the IO monad and get "better" logging (with real-time output and timing info).
Note that you still do need to convert your entire call chain from being pure to use "MonadLogger".
But I would argue that even in non-Haskell languages you should also do this (meaning you should thread a "Logger" object through all functions). Why? Let's say you don't, and now you want to do logging from some inner function. How do you configure the logging? To which file do you save it? What verbosity level? You will need to use a global/Singleton Logger object. But what if you want to call your function from two different places in your code and use a different verbosity setting for each? You can't. So I argue you are always just better off doing the refactor in all languages. The fact that Haskell forces this means that developers don't have the choice and are forced to do the right thing.