From: ····@pobox.com
Subject: Monadic scheme of I/O
Date: 
Message-ID: <6fmf85$rj3$1@nnrp1.dejanews.com>
Haskell shows best and brightest the glamor of monads in performing
i/o, calling C functions and doing other _interactions_. Other
languages however are not barred from partaking in these riches. With
an appropriate _style_, one can closely emulate monadic i/o, as this
article tries to show on an example of Scheme. Scheme thus allows both
unbridled side-effecting interaction, and a "pure", monadic IO where
all worldly effects are performed only by a distinguished actor.

Let me borrow an example from a wonderful paper by Philip Wadler "How
to Declare an Imperative" (ACM Computing Surveys, 1997, v. 29, N3,
pp. 240-263). Let's start with two intentionally wrong examples:

(let ((x (display "ha")))
  (cout "We said " x "-" x "\n"))

As Wadler noted, the laugh is on us. If you run this code, you'll see
what he meant: only a single "ha" would be printed, as a side-effect
at the time variable x is bound. This obviously wasn't the _right_
time. The original "wrong" example in Wadler's paper was written in
SML, btw, and was to illustrate referential opaqueness of i/o in
SML. Scheme can be just as "transparent".

(let ((x (lambda () (display "ha"))))
  (cout "We said " (x) "-" (x) "\n"))

Now, two "ha" are printed, but again at the wrong moment: "hahaWe said
#<void>-#<void>".  The action - printing - occurs when the arguments
of cout are evaluated, rather than at the time their values are
actually "used". Fortunately, it's easy to fix:

(let ((x (lambda () (display "ha"))))
  (cout "We said " x "-" x "\n"))

This expression, when evaluated, prints exactly what is expected:
        "We said ha-ha"

As Wadler explained, x is an abstraction of an interaction (expressed
in Scheme, this makes a neat pun). Therefore, x is not an action
itself but merely a "promise" of it. The action is exacted only when
the monad is "applied".  Then the world shall change. Until that
moment however promises can be used as "pure" values: passed around,
returned from functions, bound to symbols, etc. It is when 'cout'
calls on the collected promises that the "delayed" actions are
performed, in the right sequence.

Here's the definition of cout, the distinguished actor and "debt
collector":

(define (cout . args)
  (for-each (lambda (x)
              (if (procedure? x) (x) (display x)))
            args))

This monadic i/o is not merely a trick: I use it rather frequently,
for example, in writing CGI scripts in Scheme. The output from a CGI
script is supposed to follow special conventions (that is, to begin
with HTTP headers). Monads make it easy to decouple "output
production" from "output arrangement". With due apologies, here are a
few snippets from some of CGI code of mine:

; Given a string 'str' make a promise to write this string in an XML
; nice way, that is, paying attention to quote #\< and other characters
; that needed to be "escaped"
(define (promise-nice-xml-string str)
  (lambda ()
    (do ((i 0 (++ i))) ((>= i (string-length str)))
      (let ((c (string-ref str i)))
        (case c
          ((#\<) (display "&lt;"))
          ((#\>) (display "&gt;"))
          ((#\&) (display "&amp;"))
          ((#\') (display "&apos;"))
          ((#\") (display "&quot;"))
          (else (write-char c)))))))

; export one Channel "type"
; given one row of the TypesOfThings
    (define (export-a-type type_id mime_type descr)
      (cout "<Channel>\n<Abstract>" (promise-nice-xml-string descr)
             "\n</Abstract>\n<Title VALUE='" type_id "'/>\n"
             (lambda () (export-category-instances type_id mime_type))
             "</Channel>\n"))


and
 (cout "Content-type: text/html\n\n" "[snipped]"
         "<P><SELECT NAME=type_id><OPTION VALUE=\"\">Select Category"
        (lambda ()
          (query->OPTIONS
             check-them: (cgi#type_id :as-list)
            "SELECT type_id, descr FROM TypesOfThings;"
            ))
        "</SELECT>\n<P><BR>\n"
        "<P>You need to enter a description for the created channel\n"
        "[more snipped]")

In the following example, a lot of promises are being made and passed
from one function to another...

; Make a Channel activation record, a multi-part message,
; given part-promises, thunks that output specific parts
; of the message
(define (pack-car part-promise . other-promises)
  (let ((boundary "boundary-MCCM yradnuob"))
    (cout "Content-Type: text/x-car\n\n"
          "Content-Type: multipart/mixed; boundary=\""
          boundary "\"\n")
    (for-each
      (lambda (part-writer)
        (cout nl "--" boundary nl part-writer))
      (cons part-promise other-promises))
    (cout nl "--" boundary "--" nl)))
   .....
  (pack-car (make-send-file-promise "sub.html" write-html-bookmark)
        (make-send-file-promise "things.mbl"
          (lambda ()
            (cout (list sub-id (list "products"  (cons "DiscreteThings"
cids))))))
        (lambda ()
          (cout "Content-type: text/x-mc-activate; sub-id=\"" sub-id
            "\"\n\n")))
Needless to say that write-html-bookmark is a promise too.

I have tried to say that like OO, monadic programming is more a matter
of style rather than that of a language.

Thank you,
        Oleg
        http://pobox.com/~oleg/ftp/Scheme/

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/   Now offering spam-free web-based newsreading

From: Fergus Henderson
Subject: Re: Monadic scheme of I/O
Date: 
Message-ID: <6fo674$7lc$1@mulga.cs.mu.OZ.AU>
····@pobox.com writes:

>Haskell shows best and brightest the glamor of monads in performing
>i/o, calling C functions and doing other _interactions_. Other
>languages however are not barred from partaking in these riches. With
>an appropriate _style_, one can closely emulate monadic i/o, as this
>article tries to show on an example of Scheme.

Yes, you can emulate monadic i/o in Scheme, but the trouble with Scheme
or even ML is that the type system won't help you to distinguish between
procedures with side effects and those without.

--
Fergus Henderson              | Designing grand concepts is fun;
···@cs.mu.oz.au               | finding nitty little bugs is just work.
http://www.cs.mu.oz.au/~fjh   | -- Brooks, in "The Mythical Man-Month".
PGP key fingerprint: 00 D7 A2 27 65 09 B6 AC  8B 3E 0F 01 E7 5D C4 3F
From: Daniel Wang
Subject: Re: Monadic scheme of I/O
Date: 
Message-ID: <r8tra3kduln.fsf@vista.CS.Princeton.EDU>
···@cs.mu.OZ.AU (Fergus Henderson) writes:

> Yes, you can emulate monadic i/o in Scheme, but the trouble with Scheme
> or even ML is that the type system won't help you to distinguish between
> procedures with side effects and those without.

So in Haskell can I write a splay-tree library that uses a single imperative
update for performance reasons, but semantically behaves completely
functionally? Can I do this without cluttering my abstract functional
interface with an implementation detail?

Being able to distinguish between side-effecting and pure functions has it
advantages, but I think it also has the potential to force you to leak
implementation detail in your interface.
From: Fergus Henderson
Subject: Re: Monadic scheme of I/O
Date: 
Message-ID: <6fq0ib$6qm$1@mulga.cs.mu.OZ.AU>
Daniel Wang <·······@vista.CS.Princeton.EDU> writes:


>···@cs.mu.OZ.AU (Fergus Henderson) writes:
>
>> Yes, you can emulate monadic i/o in Scheme, but the trouble with Scheme
>> or even ML is that the type system won't help you to distinguish between
>> procedures with side effects and those without.
>
>So in Haskell can I write a splay-tree library that uses a single imperative
>update for performance reasons, but semantically behaves completely
>functionally? Can I do this without cluttering my abstract functional
>interface with an implementation detail?

Yes, you can.  You just need to use `unsafePerformIO'
(and `MutVar' or something like that for the actual destructive update).

Of course, if you use `unsafePerformIO' willy-nilly, then Haskell's
type system won't help you either -- hence the name "unsafe".
But a disciplined use of `unsafePerformIO' in those relatively rare
situations such as the one described above will give you the best of
both worlds.

Haskell is not quite ideal in this area, IMHO; I think the approach
we've taken in the latest version of Mercury, where the language has
explicit support for `impure' procedures, is a little bit nicer.

Mercury is a pure language, like Haskell; the vast majority of Mercury
procedures are pure, and only a tiny minority are impure.
Since impure procedures make it much harder to reason about programs,
then if they do occur, we want this to be very clear.  Thus
Mercury's impurity system requires that every impure procedure
must be declared with the `impure' keyword, and every call to an
impure procedure must be preceded with the `impure' keyword.
Furthermore, for any procedure that calls an impure procedure,
either the caller must also be impure, or there must be a
`pragma promise_pure' declaration for the caller.

In Mercury, `unsafe_perform_io' is impure, and thus any procedure
which calls it must be declared impure or must have a `pragma promise_pure'
declaration.  I think this is slightly nicer than the Haskell approach,
because in order to abuse unsafe_perform_io you not only have to call
it, you also have to explicitly lie to the compiler (with an untruthful
`pragma promise_pure' declaration).

(However, in Haskell simply using `unsafePerformIO' may be good enough
that the [small] increase in complexity of Mercury's impurity system is
no warranted.)

--
Fergus Henderson              | Designing grand concepts is fun;
···@cs.mu.oz.au               | finding nitty little bugs is just work.
http://www.cs.mu.oz.au/~fjh   | -- Brooks, in "The Mythical Man-Month".
PGP key fingerprint: 00 D7 A2 27 65 09 B6 AC  8B 3E 0F 01 E7 5D C4 3F
From: Thomas Lindgren
Subject: Re: Monadic scheme of I/O
Date: 
Message-ID: <3mn2e7853b.fsf@harpo.csd.uu.se>
Daniel Wang <·······@vista.CS.Princeton.EDU> writes:
> ···@cs.mu.OZ.AU (Fergus Henderson) writes:
> 
> > Yes, you can emulate monadic i/o in Scheme, but the trouble with Scheme
> > or even ML is that the type system won't help you to distinguish between
> > procedures with side effects and those without.
> 
> So in Haskell can I write a splay-tree library that uses a single imperative
> update for performance reasons, but semantically behaves completely
> functionally? Can I do this without cluttering my abstract functional
> interface with an implementation detail?

As far as I understand, the splay-tree would have to be
single-threaded BUT the type system would enforce single-threadedness
at compile-time. The programs where the imperative splay-tree isn't
ST won't type check. (Well, that's my understanding, at least.)

			Thomas
-- 
Thomas Lindgren, Uppsala University		
e-mail: ·······@csd.uu.se			
http://www.csd.uu.se/~thomasl/