date sorting II
Claus Reinke
claus.reinke@talk21.com
Sun, 10 Mar 2002 16:19:22 -0000
> So Here's the code... It is my first Haskell program so please forgive me if
> I broke any rules. I have been trying to debug it but keep running into
> walls, any and all help will be appreciated.
This is probably not quite what you expected, but I'd like to try a little
experiment: instead of completely rewriting your code by thinking about
what it should do, I've made it runnable through a series of small changes,
trying to stick closely to the code you've given. And instead of giving you
the resulting code, I'll just give you my change log, so that you can try to
reproduce the steps.
If this is absolutely no help, I can send my version of your code, but as
this kind of problem comes up again and again, I'd first like to see whether
this style of approach can be of more help than just posting a solution.
Claus
---------change log follows
1. - eliminated globals myList, myDates, myfile
- they don't seem to serve any purpose at the moment, and
while your imperative programming style suggests that you
want to use them, they shouldn't be necessary
2. - trying to load into Hugs - type error in use of while (in
getInput): loop body returns something other than ().
- you definitely want to keep the lines, so we have to change
the definition of while, not its use (looking at getInput
, which uses IO in the definition, but doesn't mention IO in
its type, we'll have to change getInput as well, but first
things first)
3. - according to the way getInput is used in start, I interpret
your comments as saying getInput should return a list of
Strings, one for each line of input.
- getInput is defined in terms of while, so we need to make
while return a list of Strings as well.
- the action you pass to while is essentially hGetLine, so it
seems easiest to adapt while to deal with an action that
returns a String (instead of an action that returns
nothing):
while :: IO Bool -> IO a -> IO [a]
4. - this means we have to modify the use of while in getInput
slightly: the body of the loop now only has to return a
single line, and while takes care of collecting the lines
into a list of Strings
- however, all that still involves IO, so the type should be:
getInput :: Handle -> IO [String]
5. - next stop (it helps to reload the partially correct program
into Hugs every now and then, as a kind of minimum test
suite, a program should load without problems): stripSpaces
is a plain function
stripSpaces :: [String] -> [[String]]
As such, it cannot be used directly as an IO action.
- either turn stripSpaces into an IO action, or (prefered) use
it as the function it is to compute the parameter to qsort
without IO (one way to do that: replace the monadic binding
"myDates <- ..;" by a let binding "let {myDates = ..};"
6. - now we've got the same problem with qsort
qSort :: [[String]] -> [[String]]
It's a function, not an IO action
- same remedy as before: use let to bind the sorted myDates
7. - next in line: formatOutput
formatOutput:: [[String]] -> [String]
no IO in sight, none needed.
- you've heard this before:) use let to bind the result of
formatOutput
8. - major breakthrough: the program loads for the first time!
- we've not said anything about correctness yet, but you might
want to clean up the code a bit before proceeding:
- the let bindings in start can be merged, if you rename the
variables a bit - e.g., call the result of qsort
sortedDates instead of myDates (you could also inline the
definitions, but names for intermediate values are a useful
documentation aid)
- in getInput, no do is needed for the body of the loop -
just (hGetLine myfile) should do
- it is always worth browsing the Haskell Prelude and
Standard Libraries for things that do what you need: e.g., right
next to hGetLine in module IO there is hGetContents, which
combines nicely with lines from module PreludeList
- its is good practice to close files you've opened after
use; and as that is so easy to forget, module IO provides
the bracket and bracket_ combinators (openFile and hClose
are similar to opening and closing brackets around the
part of the program that uses the filehandle)
- does getOutput really give you the output you want?
Having thus made your program runnable, you can now experiment
(in fact, usually one would build up such programs by developing
runnable, working fragments and composing them into bigger
fragments). Having simplified the code, you can then think about
correctness and efficiency.