Version française
Home     About     Download     Resources     Contact us    

This site is updated infrequently. For up-to-date information, please visit the new OCaml website at

Browse thread
environment idiom
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: 2004-12-13 (10:20)
From: Thomas Fischbacher <Thomas.Fischbacher@P...>
Subject: Re: [Caml-list] environment idiom

On Mon, 13 Dec 2004, Jacques Garrigue wrote:

> > Of course, it's possible to just forget about all that and fall back to 
> > transliterating imperative code to IO monad code, but it is just as well 
> > possible to find the sum of all the numbers from 1 to 1000 using the 
> > following piece of Maple code:
> You make me curious. Most of the code I've seen using the IO monad (or
> the state transformer monad) was just transliterating imperative to
> monadic code. Of course using closures, but not that much, and you can
> certainly do that in an impure functional language also.

First, I should perhaps mention that in my point of view, John does have a 
valid point in what he says. It's only that he expressed it in a way I 
just *cannot* agree with.

> So what is so incredible about the IO monad?

There is nothing "in-credible" about it. It is just plainly nothing else 
as working with values that describe "plans" to do IO. We do have a magic 
place that can bring such plans to life, causing them to be executed, but 
from the pure Haskell point of view this is not relevant. All we do is to 
construct plans how to do IO.

> By the way, if you want an example of non referentially code, this
> looks easy:
>    do
>      x <- readInt
>      y <- readInt
>      return (x-y)

> (The syntax and functions may be wrong but you get the idea.)

Okay. Let's see. Well, readInt is

Prelude> :type readInt
readInt :: Integral a => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a

so this is indeed not monadic. Let's instead talk about, say

>    do
>      x <- getLine
>      y <- getLine
>      return (y++x)

Which, I suppose, conveys the very same idea you had in mind.

> Of course according to your definition this contains nothing that is
> not referentially transparent once you've taken the syntactic sugar.

Precisely. To go a bit more into detail:

Referential transparency is about the substitution of definitions. 
Evidently, x <- ... is _not_ a definition. But according to e.g. the 
haskell98 tutorial, this do-syntax actually is nothing more but an 
abbreviation. Let me cite:

   The do syntax provides a simple shorthand for chains of monadic 
   operations. The essential translation of do is captured in the
   following two rules:
     do e1 ; e2      =        e1 >> e2
     do p <- e1; e2  =        e1 >>= \p -> e2

So the "official" notation of what is written in shorthand above is:

main =
    getLine >>= (\x -> (getLine >>= \y -> putStr (">> "++y++x)))


The notion of "substitution" of course only makes sense for this 
"official" form. It's not quite clear what one might want to substitute 
here, but everything that one could imagine just works. For example:

main =
    let plan_to_read = getLine
      plan_to_read >>= (\x -> (plan_to_read >>= \y -> putStr (">> "++y++x)))

In a certain sense, this "do" notation - which is NOT a special extension 
of the powers of pure, functional haskell but only a short-hand notation 
for things that can be spelled out explicitly - is "poison" that allows 
one to "just hack one's imperative thoughts into haskell without 
even having know about the abstract point of view". This is a bit like 
FORTRAN programmers asked to adjust themselves to C showing the attitude 
that "at least, they can forget all that for/while/etc. mumbo-jumbo and 
do everything with goto, as they are used to".

> But looking at the code, it looks like readInt is executed twice
> returning different results, i.e. this function does not always return
> 0.

Well, as I said, if one looks at the code in such a way, one just grossly 
misreads what actually is written down. The code is about combining 
plans, not about "executing something twice".

> So I suppose this is just an instance of what you see is _not_ what
> you get, but wasn't referencial transparency about avoiding that?

So, yes, "do" notation is a tool that exists in order to help you to 
misread code, or let your code be misread. In an ideal world, it would 
certainly not be here to stay. But considering the large mass of
present and future C programmers that yet has to make this transition to 
a much more abstract point of view, this is bound to (1) stay for 
quite a while, and (2) give many people (especially those depending on 
functional code written by that fraction of imperative programmers that 
have problems adjusting to abstract ideas, I fear) a major headache 
during the next thirty years.

Coming back to the original question, which was whether one may "just 
stick in some monadic stuff to get a notion of an `environment'", I'm 
inclined to say that from the purely functional point of view, this 
perhaps is not a good idea, as this is not just "a minor change to the 
code" but changes pretty much anything of its original properties.

regards,                   (o_
 Thomas Fischbacher -  //\
(lambda (n) ((lambda (p q r) (p p q r)) (lambda (g x y)           V_/_
(if (= x 0) y (g g (- x 1) (* x y)))) n 1))                  (Debian GNU)