[Haskell-cafe] Mutable and persistent values (was: Top Level TWI's again)

Graham Klyne GK at ninebynine.org
Tue Nov 23 04:26:37 EST 2004


[I'm moving my response to the Haskell-cafe mailing list, as it seems more 
appropriate for this kind of discussion.]

Your question seems to touch on the old chestnut of how to reconcile pure 
functional programs with the inherently procedural aspects of I/O and state 
management.  Most of the richness to which you refer is, to my mind, a 
fairly esoteric corner of Haskell with which I've had little cause to 
engage.  I sense you may be coming from a perspective similar to mine of a 
couple of years ago, hence this response.  Maybe what follows is already 
well known to you (some of it is basic stuff), so please accept my 
apologies if I'm retreading well-worn paths for you.

The classical work (c. 1970's) on using functions to describe programs that 
update machine state models such programs as functions that take a state 
and return a new state, maybe returning some other values as well.  This 
could get complicated to handle, and along the way functional structures 
based on monads were invoked to tidy up the housekeeping.  (A paper by 
Simon Peyton-Jones and John Launchbury [1] about handling state in Haskell 
was useful for me.)  Note the central role of higher order functions in 
dealing with this:  a state-monad function represents a computation on some 
state, not the result of that state;  the result of the computation is 
available only when the function is applied to some initial state.  The 
do-notation is a syntactic sugar to make this easier to write, but (I 
think) it can sometimes obscure what is going on.  Philip Wadler's paper 
"The Essence of Functional Programming" [3] nicely illustrates how monads 
can take care of various housekeeping chores.

The IO monad can be viewed as a special case that allows a program to 
access and update state ("the real world") that exists outside the program.

So, turning to your specific questions/concerns:

>Also, ultimately, I want to be able to save  my work and restart
>the next day (say) picking up the tags where I left off.

Your top-level program must be "in the IO monad" (or: is an expression that 
describes an IO monad value, which is a computation that interacts with the 
real world).  Thus, it can access yesterdays work, and also your 
interactive inputs, and compute a new value that is today's work.  The IO 
monad allows you to sequence the various interactions with persistent state 
and user dialogue, in a purely functional way.

>I'm darned if I can see how to do this in a callback without a global
>variables (and references from other callbacks, by the way).

I would expect the callback function to accept an initial value of the 
"global" variable(s), and return its new value(s), leaving the calling site 
to ensure that the new value is used as required.  (This interaction may be 
"hidden" in a monad (e.g. a state monad), and if the "callback" itself 
involves interaction with a user must use the IO monad.)

>    I want to use the old value of a tag to compute the new value, in a
>    callback,
>
>    I want to access the tag from other callbacks, and
>
>    I want to the value to a mutable list from within the callback.

All of these are accommodated by adopting the 
accept-a-value-and-return-a-new-value perspective.  The calling program 
that invokes the callbacks deals with ensuring that the callbacks have 
access to the appropriate results from other callbacks.

It is my view that use a functional language effectively, it is necessary 
to think differently about its structure than one would for a conventional 
imperative program.  Global values become parameters and return 
values;  mutable values become input values and new (separate) return 
values.  If you're used to writing imperative programs that do not use 
global state, but rather use parameters to pass values, the difference 
isn't always quite as great as might be imagined.

For complex values, this sounds horribly inefficient, but because values 
are pure (not mutable), very high levels of sharing can (sometimes, with 
good design!) be extensively shared.  Thus, a return value may well consist 
mostly of a copy of the input value, with differences, rather than actually 
being a complete new copy.  (Chris Okasaki's book shows well how to design 
to obtain these benefits.)

Also, because Haskell is lazy, complex structures passed between functions 
don't necessarily ever exist in their entirety.  Sometimes, I think of a 
data structure as describing a computational traversal through some data, 
rathert than something that actually exists.  (This leads to very elegant 
expression of things like Prolog search-and-backtrack algorithms.)

So the main point of this posting is to say that I think that the 
"richness" of "implicit parameters, linear implicit parameters, 
unsafePerformIO, ..." to which you refer is a shoal of red herring, as far 
as your goals are concerned.

I hope this helps.  I've added below a couple of links to my web site to 
stuff that I accumulated while learning Haskell over the past couple of years.

#g
--

[1] Simon Peyton-Jones and John Launchbury, State in Haskell, linked from: 
http://research.microsoft.com/Users/simonpj/Papers/papers.html#monads, 
document at: 
http://research.microsoft.com/Users/simonpj/Papers/state-lasc.ps.gz, also 
at: http://www.cse.ogi.edu/~jl/Papers/stateThreads.ps. Introduces monads as 
a general technique for handling state, and then introduces a concept of 
"the world" as a state manipulated by IO. I found this to be one of the 
more illuminating introductions to Monads (which are central to Haskell I/O).

[2] Chris Okasaki, "Purely Functional Data Structures", Cambridge 
University Press, 1998

[3] Philip Wadler, "The essence of functional programming", linked from 
http://homepages.inf.ed.ac.uk/wadler/topics/monads.html, paper at 
http://homepages.inf.ed.ac.uk/wadler/papers/essence/essence.ps .

[4] http://www.ninebynine.org/Software/Learning-Haskell-Notes.html

[5] http://ninebynine.org/Links.html#Programming-Haskell


At 15:34 22/11/04 -0800, John Velman wrote:
>On Mon, Nov 22, 2004 at 07:27:44PM +0100, Lennart Augustsson wrote:
> >
>[snip]
> > I admit there are proper uses of global variables, but they are very
> > rare.  You have not convinced me you have one.
> >
> >       -- Lennart
>
>It's with some trepidation I bring a problem as a total newbie, but I've
>been obsessed with this and hung up on it ever since I decided a couple of
>weeks ago to learn Haskell by using it.
>
>Some brief background:
>
>A while back I decided I wanted a simple 'concept mapping' program that
>would work the way I work instead of the way someone else works.  I
>envisioned a GUI with a canvas and an entry box (TK/tcl).  I type a
>"concept name" into the entry box, and it shows up on the canvas (initially
>in a slightly randomized position), in a box, with a unique sequenced
>identifier.  The identifier is also used as a canvas tag for the item.
>Similar input for relations between concepts.   I think that's enough
>description for now.
>
>Initially, I started programming this with PerlTK, but that effort was
>interrupted for a few weeks.  When I got back to it, I decided to do it in
>Python instead. But that effort also got interrupted for a few weeks.
>Before I got back to it, I ran across some material on Haskell I've had in
>my files for a few years, and decided that I'd use this as a vehicle to
>actually learn Haskell.   (This all sounds a bit unfocused, and it is:  I'm
>retired, sometimes describe myself as an ex mathematician or an ex-PhD
>having spent years in the aerospace industry instead of academia.  Anyway,
>I have both the luxury and lack of focus of no deadlines, no pressure to
>publish.  I hope to use Haskell to further my main hobby of knowledge
>representation.)
>
>In perl, my labels/tags were very easy:
>
>In the initialization code:
>
>      my @taglist = ();
>      my $nextag = "a";
>
>and in the callback for the entry box:
>
>     push(@taglist,$nextag);
>     $nextag++;
>
>(With the starting tag of "a"  this results in "a",...."z","aa","ab",...)
>
>Also, ultimately, I want to be able to save  my work and restart
>the next day (say) picking up the tags where I left off.
>
>I'm darned if I can see how to do this in a callback without a global
>variables (and references from other callbacks, by the way).
>
>In looking for a method, I've discovered that Haskell is a lot richer than
>I thought (or learned when I tinkered with it back in the late '90s ).
>I've found out about (but don't know how to use properly) implicit
>parameters, linear implicit parameters, unsafePerformIO, "safe and sound
>implementation of polymorphic heap with references and updates (Oleg
>Kiselyov, (http://www.haskell.org/pipermail/haskell/2003-June/011939.html),
>implicit configurations, phantom types, ...
>
>I've also found warnings against many of these.  I'm inclined to try the
>unsafePerformIO route as being the simplest, and most commonly used, even
>though perhaps the least haskell-ish.  I like implicit configurations, but
>couldn't begin to say I understand them yet, and it's a bit heavy for a
>novice.
>
>In a nutshell:
>
>    I want to use the old value of a tag to compute the new value, in a
>    callback,
>
>    I want to access the tag from other callbacks, and
>
>    I want to the value to a mutable list from within the callback.
>
>I'd certainly be interested in doing without global variables, and would
>appreciate any advice.
>
>(By the way, I'm using Linux, and so far it looks like HTk is my choice for
>the GUI interface.)
>
>Best,
>
>John Velman
>_______________________________________________
>Haskell mailing list
>Haskell at haskell.org
>http://www.haskell.org/mailman/listinfo/haskell

------------
Graham Klyne
For email:
http://www.ninebynine.org/#Contact



More information about the Haskell-Cafe mailing list