"interact" behaves oddly if used interactively

b.i.mills at massey.ac.nz b.i.mills at massey.ac.nz
Thu Oct 2 10:20:11 EDT 2003

On the pedagogic part of this issue, I personally feel that using interact 
causes concentration on the temporal logic aspects of the code. That is, 
on understanding the interaction between the computer and the user as a 
whole. Although the monad approach has this in it, I feel it to be more 
hidden, and I like my students to have some experience with interact 
before going any significant distance into monadic IO. Similarly, I like
them to look at other monads before IO monads, and IO monads before trying
the do constructs. I've found that without the background of monads, the
students get into tangles with the seemingly strange logic of the construct,
and the error messages don't help them at all.

However, on the down side of interact, I do have a grumble.

I like to use the exercise of writing a generic command line
processor, with line editing capacity as the basic task. The
answer I'm looking for is just something like ...

parse = lines

execute s = if s==endCode then "" else "{" ++ s ++ "}"

endCode = "stop"

fini a = (take (length endCode) a) == endCode

del ('\27':'\91':'\51':'\126':t) = True
del _ = False

edit s = aux 0 s [] where
         aux n [] b = '\n' : (blat (reverse b))
         aux 0 b c | del b = aux 0 (drop 4 b) c
         aux n b (x:c) | del b = '\b' : ' ' : '\b' : (aux (n-1) (drop 4 b) c)
         aux n (a:b) c = a : (aux (n+1) b (a : c))

join (a:b) = a ++ "\n" ++ (if (fini a) then [] else "cmd: " ++ (join b))

blat s = execute (head (parse s))

myCmd = interact (\s -> "cmd: " ++ (join (map edit (lines s))))

In this code ... look at join, we could write this more along
the lines of ...

join ("stop\n":b) = "stop\n"
join (a:b) = a ++ "\ncmd: " ++ (join b)

But this basic approach has the problem (at least under Hugs) that 
when we enter the word "stop" at the command prompt, the word will 
not be echoed until we have got past the p in stop. But, it does 
not matter which line code we take, the initial characters of the 
string are the same. 

Although it is a tall order to work this out in general, it does
seem to be fairly obvious in this case. That is, if I feed in something
of the form ('s':b), then I can see that under each clause I must 
irrevocably get something of the form ('s':t) back, and further more
if the first clause does not in the end match, then the second one
will anyway (since we already know we have a list of at least one
character). So, it is apparent at this stage that the output will
not be an error (the only way that join has started processing this
is that it was successfully returned by edit as a complete string), 
and will start with an 's'.

Would such a characteristic make it easier or harder to work 
with interact?

Just a thought,


Institute for Information and Mathematical Sciences
Massey University at Albany, New Zealand.

More information about the Haskell mailing list