Hello, Friedrich.

On Tue, Jun 01, 1999 at 04:04:42PM +0200, Friedrich Dominicus wrote:
> [...]

> > longerThan :: String {- filename -} -> Int {- length limit -} -> IO ()
> > longerThan fn lenlim = do
> >     content <- readFile fn
> >     let li = lines content
> >         fl = filter (\l -> length l > lenlim) li
> >     putStr (unlines fl)

> I want to try if I got it right. You're using lazy evaluation here with
> readFile, is that correct?

In that example, lazy evaluation is not essential. But with strict
evaluation, that function needs memory proportional to the size
of the input file, while with lazy evaluation, it needs only memory
proportional to the length of the longest line in the file.
So to understand the basic working of that code, lazy vs strict
evaluation is irrelevant.

So, the statements are:

- read file fn into one large string named content
- split the lines of content into a list of strings named li
- choose from li those lines l where (\l -> ...) l is true,
  i.e. whose length is > lenlim, bind fl to the result of that filtering
- fl is a list of strings (meaning lines), and unlines fl joins those
  lines into one string, which is output with putStr.

> So after I read in a chunk form that file
> into one large String, lines splits that line on a '\n' position. The
> lines li are filtered and l is one line a String-List which is added to
> fl all the filterd lines are then put back into on large String. Uff. Is
> that nearly correct?

Yes, filter applies the function parameter (in that case the lambda)
to each element of the list parameter (2nd) to yield booleans, and
returns a list of those elements of the original list, where the
function yielded true.

> Sometimes I've got the feeling that Haskell drives me nuts. I really
> have a hard time to learn that, but somtimes I feel that this is the way
> to go. But everytime I try to do I/O I've got the feeling as I had never
> programmed before.

What is difficult is that by using some predefined function, one can
express very much in very small code. I believe Haskell is even more
expressive than most OO languages with comparable libraries
(perhaps except Smalltalk, as that has also a very compact syntax).

Another difficulty is monadic I/O. Perhaps you should exercise
programming with standard higher-order functions without I/O
a bit more, so that you master that difficulty and don't have
to *simultaneously* understand both the HOF things and I/O.

> This solution is quite nice. I now have one extra question (maybe two
> ;-) How can I combine the output with a line-number can I put that into
> the filter? Or do I have to found another solution?

Either look at the solutions with the "pipe" (.|) operator that
have been posted. (I like them, btw :-) ). Or pre/postprocess the
li/fl variables, depending on if you need the original line numbers
or numbers for the generated lines.

In the latter case, you can do this:
  let numbered_lines = zipWith (\lineno linecont ->
                                  show lineno ++ "\t" ++ linecont)
                               [1..]
                               fl
  putStr (unlines numbered_lines)
instead of the original putStr "statement".

In the first case, you must attach line numbers to the original file
contents. li is the list of lines.
  let li' = zip [1..] li
creates a list of pairs (line number, line content).

You must then adapt the filter function from \l -> ... to
\(_linenumber, l) -> ..., to extract the line content from the
(line number, content) pair.

For the final output, you must convert the remaining (number,content)
pairs from fl to single strings containing the line number in textual
form, i.e.
  let fl' = map (\(number, content) -> show number ++ "\t" ++ content) fl
  putStr (unlines fl')

> Regards
> Friedrich

Regards, Hannah.


Reply via email to