

Ask HN: How would you do this in Haskell? - AnimalMuppet

Say I have a complicated calculation, but it&#x27;s pure functional all the way.  Now somewhere in the middle of it, I want to log something if some condition is met.  In a procedural language, that&#x27;s easy - I just add an &quot;if&quot; and a log statement.  But how would you do that in Haskell?<p>The best answer I&#x27;ve come up with so far is, from that function, to return a tuple containing two values: the value the function returned before, and a Maybe.  The Maybe contains Just String if the logging happened, and Nothing otherwise.<p>But then all functions from there to the end of the calculation have to be changed to return a tuple instead of just the results of the calculation.  That doesn&#x27;t sound like composablility.<p>Or, I could jam IO into the function where the data was to decide whether to do the logging, but that just feels wrong.<p>What&#x27;s the idiomatic way to do something like this?
======
paulrpotts
Mr. Muppet, I am not a Haskell expert, but I had a similar coding issue that I
blogged about a while back. I was threading a score value through some code
that calculates an updated gameboard. The solution (well, one solution) was a
writer monad. That got me over the hump a little further towards understanding
monads, and the conventional wisdom nowadays seems to be that teaching
beginning Haskell developers how to _use_ them is more effective than pointing
them at endless monad tutorials or articles on category theory.

If that sounds helpful, see:
[http://praisecurseandrecurse.blogspot.com/2013/07/the-
polar-...](http://praisecurseandrecurse.blogspot.com/2013/07/the-polar-game-
in-haskell-day-5-12.html) and see also the next post in the blog. Then maybe
go from there!

~~~
AnimalMuppet
That's actually rather helpful, especially the "important stuff, but not the
point" line. That's a bigger deal than my question.

~~~
paulrpotts
Glad to hear it. I think once you've used one of the monads the whole concept
starts to make a lot more practical sense.

------
Tyr42
This is exactly where you might like to use the writer monad. Check out LYAH
[http://learnyouahaskell.com/for-a-few-monads-
more](http://learnyouahaskell.com/for-a-few-monads-more)

It's just a fancy name for composing functions of the form `a -> (b, String)`,
via

    
    
        (>>=) :: (a, String) -> (a -> (b, String)) -> (b, String)
        (a, log1) >>= f = let (b, log2) = f a in
                          (b, log1 ++ log2).

------
spimta
Echoing stonemetal, I would recommend seeing if you can refactor so that you
can keep your pure function as-is, and then lift it into some monad that takes
care of the logging. The Writer monad can be a good way to do this elegantly.

~~~
AnimalMuppet
Yeah, I kind of suspected that this was going to involve a monad :-) And the
Writer monad looks like the right one for the job.

But doesn't using that involve making the rest of the code (at least from the
function that needs to log out to the top level) return monads, rather than
returning whatever they were returning before?

~~~
Tyr42
So, it'd require making any code that calls the function doing the logging do
one of two things:

1\. Explicitly end the scope of implicitly logging things by calling
runWriter, and getting a pair of (result, log) out.

2\. Continue working in the implicit log monad, which would mostly involve
extracting the result of the log function with `do x <\- theLoggingThing`, but
you can still mix in pure statments with `do let y = 5` or other function
calls, and then end the do block with `return val`, where val was what you
were going to return before.

------
stonemetal
There is a problem with your premise. Why do you need to log in the middle of
that function? In a procedural language you need to log right then to make
sure state hasn't changed on you. In Haskell you could do it before or after
the function and not be able to tell the difference because state can't change
on you.

~~~
AnimalMuppet
No, it's not a matter of the state changing. The premise is that, at each step
of the calculation, a function does some computation and returns a result. At
the point where the logging decision is being made, the decision is based on
data _available within_ the function, but not being _returned by_ the function
- only a derived value is returned.

Now, perhaps you could argue that the _right_ way to do the problem (without
the logging) in Haskell is to not have functions like that - to break up that
function so that the data that, in my version, is only available within the
function is instead explicitly returned by some smaller function.

But if you don't argue that, then you're left with the stated problem: What's
the right way of getting logging out of the middle of a function in Haskell?

------
cptndarling
Debug.Trace --
[https://hackage.haskell.org/package/base-4.8.0.0/docs/Debug-...](https://hackage.haskell.org/package/base-4.8.0.0/docs/Debug-
Trace.html)

