world as value

P.R. Serrarens pascalrs@cs.kun.nl
Thu, 22 Jul 1999 09:58:59 +0200


Hi Adrian,

You wrote:
> 
> On Mon 19 Jul, P.R. Serrarens wrote:
> > I don't quite see what you mean here: what is this artificial dependency and
> > when it is important? How do you (or the runtime system) decide this?
> 
> Examples of artificial dependency...
>  1- World as value (including Haskell IO monad), in my humble opinion
>  2- [] messages in Pict
>  3- Concurrent Haskell MVars (although since these may be used to pass
>     values, perhaps the dependancy often isn't artificial.)

And 4: strictness (like the `seq` combinator in GHC)

> I'm not sure which of the above I prefer or something entirely different,
> but I'm pretty sure example 1 would not be my prefered choice.

They all create dependencies by passing pieces of non-information and make the
system believe that this information is needed, before it can continue. To me,
they are all different syntactical constructs to achieve the same through the
same method.

> > So as to make this concrete: you have a collection of action, with type *env
> > -> *env (I am not specifying what the environment is, it is not important) and
> > put them into a list, for example:
> 
> I'm not sure I agree with you here. In my view an action is _not_ a function.

Hmmm. I though we liked a functional approach?

> It may return values, and its effects and results may well depend on the exact
> state of the environment(s) it manipulates, but to regard it as a function of
> some world or environment value is the the wrong way of thinking about it,
> because I don't think IO environments are proper values.

So the type of an action should be something like  (Action -> a). Yes, it is a
function, but it does not explicitly use environments.

> > Now you can execute these actions by using the function <doActions>:
> 
> Again no, the 'non-deterministic do' (doActions) would not be a function.
> It would be a syntactic construct which translated user friendly notation
> (yet to be specified) into something like Pict perhaps.

But this will not give you a functional system, but merely a kind of
coordination language which may use functional expressions.

(Note that the Monads and even better, do-syntax fall also in this class for me!)

> I'm not really sure how such a scheme would really work in practice or how
> it could be implemented without suffering a 'thread explosion'. I'm just
> thinking about it, and the unnecesary (in my opinion) linearity of
> environment as value IO.
> 
> I think you over estimate the dangers, a lot depends on how the environments
> which the actions manipulate are constructed (and how difficult/easy it
> is to introduce controls for sequencing if required). As far as I can
> see, given 'well constructed environments' the worst that's likely to
> happen is some actions get blocked, but only those actions which really
> need to be blocked.

I don't know whether you have experiences with systems which do not need this
environment-based threading, but I do. I got into troubles very quickly. For
example a Concurrent Object I/O program (which is implemented using threads)
at some point deadlocked. Then remember that such a program typically uses
many message passing channels, which all could be used in a independent way
and somewhere there was a dependence which I forgot about and the system
deadlocked. It took me a day to solve this problem. Because of such bugs, I
hardly use independent channels. So if _I_ cannot avoid these problems, why
should a less experienced programmer have less problems?

> Consider the independent environments approach to say.. a printer and a
> filing system. You might like to consider them independent, but in reality
> both the printer and the disc drive are sitting on a SCSI bus (for example).
> The SCSI host adapter is controlled by a process (environment). Both the
> printer driver process (environment) and the filing system process
> (environment) use the SCSI process (environment) to get anything done.
> So in what sense are they independent? Yet Clean (presumably) would consider
> them as independent and printer and file system operations could be performed
> concurrently. I think this is perfectly safe, but only because the
> environments concerned are 'well constructed', if you see what I mean.

Of course, devices are almost never independent. Deciding whether they are
really independent can only happen at run-time, as programs can run on
different systems, which may or may not have that specific dependency.

The main poimt here is that it is often convenient and natural to treat some
environments as being independent, although in reality they may not be
completely. This is not a uncommon approach. The same can be used for
non-determinism: it is often convenient to view a system as being
non-deterministic, altough it may not be in reality (some people argue that no
system is non-deterministic!). Only in exceptional cases the real dependencies
between systems may appear.

> It occurs to me that one solution to the sequencing problem (for things like
> files) would be to arrange that all file actions took a unique token and
> returned that token as part of the result. This is what Clean really does
> isn't it?.

Yes, you can say so for writable files. This may be either *File or another environment.

> That way the user would be forced to consider the order in which
> things were done. But for environments in which the order didn't matter,
> you could leave the token out.

This is what is done for read-only files.

> Of course the other effect of such a token
> (in lazy Clean) is to force file actions to occur by 'evaluating' the
> token in the file close function. For tokenless environments one could not
> rely on this effect, so the 'non-deterministic do' would have to be
> imperative rather than functional (another good reason for not regarding
> actions as functions I think).

That does not have to be, for reading from a read-only file is forces by
demanding the value that is read.

But remember we are working on functional languages: if the result of an
action is not represented in the result of the program, then this action
should not have happened, otherwise we loose referential transparency. (An
exception might be that the action cannot be detected by the program, but as
almost everything is depedent in reality, this might be hard to achieve)

If you are willing to give up this property, I will give up thinking about you idea.

-- 
Pascal Serrarens
Concurrent Clean developer
University of Nijmegen, NL