"interact" behaves oddly if used interactively

Colin Runciman colin at cs.york.ac.uk
Wed Oct 1 13:45:07 EDT 2003

Christian Maeder wrote:

> Malcolm Wallace wrote:
> [...]
>> Surely the name suggests that "interactive" behaviour is required, i.e.
>> exactly some interleaving of input and output.  The chunk-size of the
>> interleaving should depend only on the strictness of the argument to
>> "interact". 
> I'm not happy that interleaving depends on the strictness. Lazy or 
> strict evaluation should only change the behaviour of overall 
> termination (lazy evaluation should terminate more often). I'ld rather 
> implement interleaving (or "interactive" behaviour) explicitely by:
> interact f = do
>   s <- getLine
>   putStrLn (f s)
>   interact f
> (assuming line buffering) (Terminating with "ctrl-c")
> Surely also something is needed for endless character resources as
> Tom pointed out.
> Christian

In a lazy language, evaluation of arguments and results is interleaved.
This coroutine-like behaviour is an important and pleasing
characteristic, not a mistake to be avoided.

Lazy evaluation of String -> String functions with the argument attached
to an input device  (eg. keyboard) and the result attached to an output
device (eg. screen) is therefore a conceptually lean and natural way
to express sinple interactive programs in a lazy functional language.  

Historically, the wish to preserve the option of looking at interaction
this way, if only for pedagogical reasons, was the reason for keeping
the interact function in Haskell even after the monadic revolution.

If line-buffering is needed, it is easily programmed in Haskell as
a (lazily evaluated!) function lineBuffered :: String -> String.
If f :: String -> String is the core function of the program one can
define main = interact (f . lineBuffered) and the fact that the
program relies on line-buffered input is clearly expressed in the
program itself.

Conversely, if line-buffering is built-in as part of interact, there
is no way to program it out when defining interact's argument.

Let not the eager imperative tail wag the lazy functional dog!

Colin R

More information about the Haskell mailing list