Newsgroups: comp.lang.scheme,comp.lang.functional
Path: cantaloupe.srv.cs.cmu.edu!nntp.club.cc.cmu.edu!godot.cc.duq.edu!news.duke.edu!news-feed-1.peachnet.edu!gatech!swrinde!ihnp4.ucsd.edu!munnari.oz.au!cs.mu.OZ.AU!munta.cs.mu.OZ.AU!fjh
From: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Subject: Re: when to use state?
Message-ID: <9436516.26620@mulga.cs.mu.OZ.AU>
Sender: news@cs.mu.OZ.AU
Organization: Computer Science, University of Melbourne, Australia
References: <3dfv8i$ifp@nkosi.well.com> <JDONHAM.94Dec27174139@hadron.us.oracle.com> 	<ROCKWELL.94Dec28104921@nova.umd.edu> <JDONHAM.94Dec28135842@hadron.us.oracle.com>
Date: Sat, 31 Dec 1994 05:32:43 GMT
Lines: 75
Xref: glinda.oz.cs.cmu.edu comp.lang.scheme:11670 comp.lang.functional:5461

jdonham@us.oracle.com (Jake Donham) writes:

>"Raul" == Raul Deluth Miller <rockwell@nova.umd.edu> opines:
>
>    Raul> This can be considered in several ways:
>
>    Raul> (1) underlying semantics.  If the abstraction for f(x,
>    Raul> state) really depends on state then you're not going to be
>    Raul> able to eliminate the second use of f.
>
>If procedures are pure functions, then the fact that two calls to the
>same function have the same arguments (a purely syntactic attribute)
>can be used as a (conservative) indicator that the functions return
>the same value, and a call can be eliminated.
>
>If you write your program in "state-passing style" (passing and
>returning a state variable with each function call) you can't do
>common-subexpression elimination unless you analyze functions to see
>if they "modify" the state, since no two function calls will ever have
>the same arguments.

One possible way of avoiding this problem in imperative-syntax languages
is to have a language construct to specify that a particular
function is "pure", i.e. free of side-effects.  Then

	(1) The compiler can warn if the programmer fails to declare
	    a side-effect free function as "pure".

	(2) The compiler can complain if the programmer calls a non-pure
	    function from a pure one.

	(3) The compiler can optimize calls to "pure" functions.

GNU C has such a declaration ("__attribute((const))__").
Unfortunately it's not as useful as it could be, for several reasons.
One reason is that gcc only uses it for (3), not for (1) or (2).
The other reason is that it doesn't fit very well with C, because
C uses pointers for virtually everything useful, but pointers
implicitly depend on global state and hence can't be used in pure functions.

>    Raul> (2) syntactic expression.  If f(x, state) really modifies
>    Raul> state then you need some sort of syntax to express this
>    Raul> result.  There are a variety of ways of encapsulating this
>    Raul> sort of mechanism, one of which is: a=f(x); b=f(x);
>
>But this syntax makes no mention of the state which is modified, so it
>could be argued that it isn't as clear as the explicit-state syntax
>you gave above.

You could also argue the converse: that it is clearer, and the reason 
that it is clearer is precisely because the state passing is implicit
in the left-to-right ordering.  It's easier to see the rest of the
code, because it doesn't get lost amoungst all the state passing.

Of course, using an imperative syntax does make it less clear which
parts of the computation depend on the global state and which don't.
You could argue that an ideal syntax would allow you to use the
code ordering to implicitly specify state manipulation, but would
also allow you to clearly separate calls to "pure" functions.

One notation which can satisfy these demands is Prolog's DCG notation,
although it's actually a relational syntax rather than a functional
one.  Predicates which do not implicitly depend on state are written
using Prolog's usual `:-'.  Procedures which manipulate implicit state
are written with `-->' rather than `:-'.  In the body of these
procedures, calls to "pure" predicates must be enclosed in curly
braces.  This syntax then gives you the best of both worlds - you
can use ordering to represent implicit state manipulation yet still
keep it clear which parts of the computation depend on the global
state and which parts don't.  (That's why we use DCGs in Mercury, 
a new logic programming language which I and a couple of others
at Melbourne Uni are designing and implementing.)

-- 
Fergus Henderson - fjh@munta.cs.mu.oz.au
