for i in 0 to arr.len() {
new_val = f(arr[i]);
log("Changing {arr[i]} to {new_val}.\n");
arr[i] = new_val;
}
I haven't used Haskell in a long time, but here's a kind of pure way you might do it in that language, which I got after tinkering in the GHCi REPL for a bit. In Haskell, since you want to separate IO from pure logic as much as possible, functions that would do logging return instead a tuple of the log to print at the end, and the pure value. But because that's annoying and would require rewriting a lot of code manipulating tuples, there's a monad called the Writer monad which does it for you, and you extract it at the end with the `runWriter` function, which gives you back the tuple after you're done doing the computation you want to log.You shouldn't use Text or String as the log type, because using the Writer involves appending a lot of strings, which is really inefficient. You should use a Text Builder, because it's efficient to append Builder types together, and because they become Text at the end, which is the string type you're supposed to use for Unicode text in Haskell.
So, this is it:
import qualified Data.Text.Lazy as T
import qualified Data.Text.Lazy.Builder as B
import qualified Data.Text.Lazy.IO as TIO
import Control.Monad.Writer
mapWithLog :: (Traversable t, Show a, Show b) => (a -> b) -> t a -> Writer B.Builder (t b)
mapWithLog f = mapM helper
where
helper x = do
let x' = f x
tell (make x <> B.fromString " becomes " <> make x' <> B.fromString ". ")
pure x'
make x = B.fromString (show x)
theActualIOFunction list = do
let (newList, logBuilder) = runWriter (mapWithLog negate list)
let log = B.toLazyText logBuilder
TIO.putStrLn log
-- do something with the new list...
So "theActualIOFunction [1,2,3]" would print: 1 becomes -1. 2 becomes -2. 3 becomes -3.
And then it does something with the new list, which has been negated now.