[Haskell-cafe] Haskell-Cafe Digest, Vol 93, Issue 58

Alexander Solla alex.solla at gmail.com
Thu Jun 9 06:39:36 CEST 2011

On Wed, Jun 8, 2011 at 8:17 PM, Gregory Guthrie <guthrie at mum.edu> wrote:

> An earlier note on students reactions to the imperative style forced on
> them by some Haskell libraries ("do ...") is interesting, and seems similar
> to an observation in a project I was developing for students; making a
> version of a simple lab from previous SML assignment.
> It uses a dictionary to do some statistics for a text analysis, but since
> the dictionary is read at a leaf node of the analysis algorithm, that
> function must be IO(), and thus the analysis using it also, ... etc. all the
> way up to the top.
> So the implication of the rules:
>  1) all IO must start from the top level, and there is only one IO
>  2) you cannot extract anything from an IO
> Seems to be that the whole program structure becomes a series of do...
> blocks, which is basically a sequential imperative looking style.
> The general advice of "Strive to keep as much of the program pure as
> possible" thus seems difficult.
You're right, in some ways.  But it is not difficult to stay out of IO.
 Just don't use the  (IO a) type if you don't need to do input and output. I
strongly suspect that "you" are starting your program writing process by
writing IO actions, which "naturally" leads to writing a tree of IO actions.
 Start by writing data types and transformation functions instead. "Every"
program does three things:  take some kind of input, apply a transformation,
and yield some kind of output.

Strive to define datatypes that capture the program's logic.  For example,
enumerate your cases in an abstract data type.  In this way, you can move
the program logic into the pure fragment of the language, as opposed to
using explicit if-then-else's in the IO monad.

> An option I suppose would be to read the dictionary at the top level, and
> then pass it all the way down to the analysis routine that uses it, but that
> exposes the details of how the analysis is done, and couples the top and
> bottom levels of the previously modular functions.
> While this is all logical and understandable, it is quite different than
> how I did this in SML; where I could encapsulate the IO in the analysis
> function. It was a local secret of the analysis what data it needed, and
> where it came from. Note that (of course...) if the dictionary was static
> and an internal data structure, then this would all go away. It is
> interesting to me (and curious at first) that one could not somehow treat a
> "constant" data definition file resource in a more encapsulated manner, and
> not have it ripple all the way up through the program because it was
> "impure" once converted to an external definition (=IO). My first impulse
> was to read the dictionary in a do... and then try to extract it and go
> merrily on, but that won't work - by design of course!

I don't know how ML handles IO, but Haskell is a lazy language.  In order
for a value to be computed, some other value has to "request" it.  And
programs usually have a single entry point -- main :: IO a.  So it is going
to be the thing that requests computations to be done.  On the other hand,
it can request a series of IO actions to determine program flow/logic, or it
can request pure computations to do the same.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20110608/e64d1db0/attachment.htm>

More information about the Haskell-Cafe mailing list