Imperative Notation

John van Groningen johnvg@cs.kun.nl
Wed, 10 Feb 1999 11:44:32 +0100


Nick Kallen writes
>I've done very little programming with the Object IO library although I've
>done (enough) with the 0.8 library. The points I bring up in this message
>are undoubtedly ones the Clean team have considered in the past, but I stil=
l
>think they're worth a more careful examination, especially in light of the
>recent development with Arrows in the Haskell world.
>
>> Start world
>>     # (_,mbListener,world)              =3D openTCP_Listener 1888 world
>>       (mbTCPDuplexChan, listener, world)=3D receive (fromJust
>> mbListener) world
>>       (_,{sChan,rChan})                 =3D fromJust mbTCPDuplexChan
>>       world                             =3D closeChan listener world
>>       (receivedData, rChan, world)      =3D receive rChan world
>>       (sChan, world)                    =3D send sChan receivedData world
>>       world                             =3D closeChan sChan world
>>       world                             =3D closeChan rChan world
>>     =3D world
>
>I can't be the only person whom this strikes as horrible. Dare I bring up
>the topic of a "do" notation?

You can hide some state passing using infix macros or functions. I often use=
:

(>:) infixl;
(>:) f g:=3D=3Dg f;

to hide state passing of functions that return just a new state.
Then you can write:

Start world
  # (_,mbListener,world)             =3D openTCP_Listener 1888 world
    (mbTCPDuplexChan,listener,world) =3D receive (fromJust mbListener) world
    (_,{sChan,rChan})                =3D fromJust mbTCPDuplexChan
    (receivedData,rChan,world)       =3D world >: closeChan listener
                                             >: receive rChan
    (sChan, world)                   =3D send sChan receivedData world
  =3D world                            >: closeChan sChan
                                     >: closeChan rChan

>Now, I know the Clean argument against Monads. Multiple environments
>preclude this in principle. Why does Clean have multiple environments? For
>concurrency purposes of course. Where is *Concurrent* Clean? Anybody's gues=
s
>;)

Using multiple environment makes it easier to reason about your program. A=
 function that reads from a file gets just a File and a function that=
 updates a window just a Picture. Without multiple environments, both=
 functions would get the whole World, and you have to look at the=
 implementation of those functions to see that they just do file io or draw =
something.
Multiple environments are also necessary for some unique datastructures,=
 like arrays.

>Regardless. It is a pain to read and write even the most trivial functions
>with this explicit CPS. It makes me cringe. Am I the only Clean programmer
>who has surrendered and said: "Give me do!?"
>
>Simple stuff like the above map to "do" trivially. But, how do we handle
>multiple environments? Well, has anybody looked into whether Arrows would
>suffice?

I don't know what Arrows is.

>I'm sure some nice syntactic solution to the implicit multiple environment
>passing problem could be created. Has anyone in the Clean team tried? I'm
>under the impression that you guys have said: "We have uniqueness typing,
>it's better than monads; therefore, we don't need a do notation."

We added #, instead of do, this solved many problems with state passing.

>I don't have a proposal but I think this is a worthy topic to bring out in
>the open between Clean users and the Clean people.

The best proposal I have though of so far, is to write the name of the state=
 just once, only before =3D, not after =3D, and use a special character to=
 indicate that the name of the state should be added after =3D as well (at=
 the end). For example, using & to mark the states:


Start world
     # (_,mbListener,&world)             =3D openTCP_Listener 1888      =20
        (mbTCPDuplexChan,listener,&world)=3D receive (fromJust mbListener)
       (_,{sChan,rChan})                 =3D fromJust mbTCPDuplexChan
       &world                            =3D closeChan listener
       (receivedData,rChan,&world)       =3D receive rChan
       (sChan,&world)                    =3D send sChan receivedData
       &world                            =3D closeChan sChan
       &world                            =3D closeChan rChan
     =3D world

John van Groningen
University of Nijmegen