Laziness appears to have a wierd interaction with IO.
According to the docs, you should add two numbers from the user like this:
> main = do
>          hSetBuffering stdout NoBuffering            
>          putStr   "Enter an integer: "        
>          x1 <- readNum 
>          putStr   "Enter another integer: "          
>          x2 <- readNum                          
>          putStr  ("Their sum is " ++ show (x1+x2) ++ "\n")
>       where readNum :: IO Integer
>             readNum =  do { line <- getLine; readIO line }

The tutorial describes a simulation of a client/server system using
recursively defined lists. i.e.

> client init (resp:resps) = init : client (next resp) resps
> server      (req:reqs)   = process req : server reqs

The latter approach appears to be more within the spirit of functional
programming, but the IO documentation seems to avoid using the latter
method in talking to the world.  Based on the servers example, addTwo
might be written something like:

> main = do  input <- getContents
>            putStr $ addTwo $ makeLines input

> addTwo lines = ask1++(ask2 (Strict x)) ++ (result (Strict y))
>       where   x:y:xs = map read lines
>               ask1   = "Enter an Integer: "
>               ask2 _ = "Enter another Integer: "
>               result _ = "Theis sum is "++show (x+y)++"\n"

> data (Eval a) => Strict a = Strict !a
> makeLines text = 
>  (takeWhile ('\n'/=) text): (makeLines $ tail (dropWhile ('\n'/=) text))

But this code doesn't work.  It prints all the text and then waits for
input.  Shouldn't laziness guarantee that addTwo doesn't print "Enter
another integer" until the user enters the first integer?  (that is what
the file copy example in the tutorial implies) 

The nice thing about actually doing IO using lists like this (if it
is possible), is that it makes it very straightforward to port a
client/server simulation into a real deployment. 
For example I am writing an application that handles HTTP transactions 
and uses a database backend.
Ideally, I would like to write cgifunctions of type:

myCGIFunction:: [HTTPRequest]->[DatabaseVersion]->
                        ([HTTPResponse],[DatabaseChanges])

HTTPRequests come from _middleware_ that recieves http requests from the
httpd and append them to a list. Attempts to get the next item in the
HTTPRequest list block until requests come in to fill the list.

DatabaseVersions come from a driver that appends a new txnBegin object
to a list.

The program would look something like:
main = do 
        (dbSource,dbSink) <- dbConnect "ODBC: someodbcurl"
        (httpSource,httpSink) <- apacheConnect "urlToListenOn"
        (httpResponses,dbUpdates) <- return $ myCGIFunction httpSource dbSource
        dbSink dbUpdates
        httpSink httpResponses

Which leads to the next question: how do I write Sources and Sinks?

-Alex-


___________________________________________________________________
S. Alexander Jacobson                   i2x Media  
1-212-697-0184 voice                    1-212-697-1427 fax








Reply via email to