You seem to be moving the goalposts to "why is FP better than X". I was simply pointing out that printf debugging is easy in FP. In fact, it's probably
easier in FP, since everything is an expression, whereas imperative languages have a weird expression/statement distinction. For example, if I have code like:
buggyCode x y = if foo x
then bar x y
else baz y
I can wrap
anything on the right-hand-side in a printf (except the keywords if/then/else). At the extreme end I could do:
buggyCode x y = trace "hit buggy code" (if trace "applying foo to x" ((trace "hit foo" foo) (trace "hit foo's x" x)
then trace "applying bar x to y" ((trace "applying bar to x" ((trace "hit bar" bar) (trace "hit bar's x" x))) (trace "hit bar's y" y))
else trace "applying baz to y" ((trace "hit baz" baz) (trace "hit baz's y" y))
I could even move the x and y arguments across to the right-hand-side using anonymous function notation, then I can trace partial applications too:
buggyCode = trace "hit buggyCode" (\x -> trace "gave x to buggyCode" (\y -> trace "gave y to buggyCode" ))
Note that we the built-in if/then/else is mostly a legacy crutch to aid familiarity. We can just use a function instead, and printf all the things:
ifThenElse True x y = x
ifThenElse False x y = y
buggyCode = \x -> (\y -> (ifThenElse (foo x)
(bar x y)
(baz y)))
(Of course, defining our own if/then/else isn't much use; we're usually better off writing more meaningful, domain-specific alternatives)