[Haskell-cafe] Newbie:Debugging and Overgeneralization
Robert Dockins
robdockins at fastmail.fm
Mon May 15 12:11:34 EDT 2006
On May 15, 2006, at 11:14 AM, Aditya Siram wrote:
> I have been working with a Haskell text for the past couple of
> months or so and I have some general problem solving questions.
>
> 1. Is there a way to output intermediate values of a calculation?
> As an imperative programmer I have become used to using
> "System.out"'s or 'cout's to check that my function works as
> intended. I can see no easy way to do that in Haskell. The only
> solution I could come up with was to avoid using nested functions
> except for the most trivial expressions and test all expressions in
> the interpreter. This approach seems to make my code ugly and less
> readable.
Two responses here:
1) Check out Debug.Trace in the standard libs. (http://
www.haskell.org/ghc/docs/latest/html/libraries/base/Debug-
Trace.html) It lets you insert debugging messages into pure code.
Be warned, its a little tricky to use; your message will only be
printed _when_and_if_ the thing you "attach" the message to is
evaluated.
2) I'm not sure exactly what you mean by "nested functions", but
writing small functions and composing them together to do larger
tasks is a pretty Haskellish way to approach things. As you noted,
this lets you easily test subparts of your computation, and it's
generally considered good style. Appropriate use of the composition
operator (.) or of monads can make function composition more readable.
Creating intermediate representations and writing functions that
transform data between these representations is a good way to
structure programs that allows this compositional style. See: http://
www.haskell.org/hawiki/IntermediateRepresentation
> 2. Haskell is great because it makes abstracting from problem very
> easy. For example, if the problem asks for the area of a square,
> why not write a function to compute the area of all polygons? find
> myself falling into the trap of generalizing to the point that a
> simple problem becomes quite a bit harder . From a general design
> perspective should I concentrate on abstracting away just enough to
> solve the problem or solve the harder problem in the hoping of
> reusing that code to make life easier in the future?
I'd say, unless you are developing a general-purpose library, solve
the problem in the simplest (correct!) way first. One of the nice
things about Haskell is that its easy to replace code under the hood
at a later time (pure functional programming is your friend).
For example if you write:
> areaOfSquare :: Square -> Double
> areaOfSquare = <special purpose code>
And later you discover you also need:
> areaOfNPolygon :: NPolygon -> Double
> areaOfNPolygon = <n-polygon code>
You can replace areaOfSquare with:
> areaOfSquare = areaOfNPolygon . squareToNPolygon
to reduce duplication, or you can keep the special-purpose code in
the interests of efficiency. If you keep the special-purpose code,
you can use quick check to make sure it gives the same answer as the
n-polygon routine, which is a nice benefit.
Rob Dockins
Speak softly and drive a Sherman tank.
Laugh hard; it's a long way to the bank.
-- TMBG
More information about the Haskell-Cafe
mailing list