world as value

P.R. Serrarens pascalrs@cs.kun.nl
Mon, 19 Jul 1999 10:49:43 +0200


Erik Zuurbier wrote:

> Is it possible generally, to give the Clean-user a function to split off
> unique sub-environments or sub-structures from any unique object? It may
> not be easy, but I hope my examples will make it clear it will be needed in
> the end.

At the moment it is not possible to make multiple subenvironments which are in
fact pointers to the same datastructure (that is how I interpret your
suggestion). However, I have been playing with this idea a couple of weeks
back. I am in the same room as Thorsten (who implented CLAS, an linear algebra
package) and he implemented slices for Clean. I don't know whether he said
anything about it in public, but as you used the name slices in the example I
think he has. As he is on vacation at the moment, I will discuss it here and now.

The problem with his slices is that they are very specialised to the case of
numerical computations. They are based on matrices and are based on
often-occuring constructions in numerical computations. As few weeks back, I
thought: can't this be done in a more general way and came with the following
solution. (I won't discuss CLAS any further now, in the end my idea did not
prove to be very useful)

class Slice1D slice
where
    updateSubArray ::
        (Int, Int) *{# a}
        ((slice a) *(slice a) -> *(slice a))
         -> *{! a }
    
    updateSlice :: *(slice a) Int a -> *(slice a)
    selectSlice ::  (slice a) Int -> a
    uselectSlice :: *(slice a) Int -> (a, *(slice a))

:: Slice  a      // Slice  with   bounds-checking
:: Slice` a      // Slice without bounds-checking

instance Slice1D Slice
instance Slice1D Slice`

With the function <updateSubArray> one can update a range in an array in
combination with the possibility to access the elements outside that range in
a free (non-sequential) manner. The function takes a range and the array to be
updated, plus a function which gets the array twice: a unique, updatable
reference and a non-unqiue, not updatable reference. These references, which
we will call restricted arrays (the old name is slice, but that interfered
with Thorsten's work),  do not have a normal array type, and can therefore not
be used in combination with the normal array functions. But we do provide the
same set of functions (a restricted set is shown) for these restrictued
arrays. These function can test wether the operations are performed on the
right elements. For example, the update function can test wether the update
takes place within the region, while the select function can only be used
outside the range. The uselect function can only be used whithin the range.

We have two types of restricted arrays: with and without boundary checking.
With boundary checking you get safety at the price of performance, because
run-time checks have to be performed, while without boundary checking you get
the full performance. This is exactly the same as boundary checking for
arrays, but with the advantage that you can toggle boundary checking for each
array separately.

Note, however that this function is only legal for unboxed arrays! I will not
discuss this here and now, but the reason is for safety.

I did not go any further with this idea, because I have a thesis to write, but
one could extend this approach to other linear structures, like files.

I just got another idea. A few months back there was a suggestion about files
and pipes and communication channels, suggesting that I might want to provide
a channel interface to files, so that files can be used as a communication
channel. I implemented this in Concurrent Clean and it worked very well; I am
writing about this in my thesis right now. Back to the idea: maybe we also
want a array-like interface to files, so that files can be used as arrays,
with the difference that files are stored on disk instead of the heap.


> In the general case, it will be impossible to have the compiler find out if
> updates on one sub-structure interfere with others. Clean has two
> approaches to that. The first one is introducing run-time checks. That is
> what already happens with array boundaries. The other is putting the
> responsibility on the programmer. That is what happens with array
> boundaries when the user disables the run-time checks. Programmers are not
> generally tempted to abuse this latter possibility to create non-functional
> programs in Clean, as the behaviour of matrices peeking and poking outside
> their bounds is (almost) impossible to predict. Yet, it is a door open to
> non-functional programming in Clean.

Yup, I do not know what to do about this. However, note that we have the same
approach for the restricted arrays above.
 
> Another door is the use of ABC-code in a 'code {...}' construct that I can
> freely use anywhere in my Clean program. This also allows me to create
> non-functional behaviour in Clean. In other words, the creators of Clean
> already silently rely on programmer decency to back up their claim that
> Clean is purely functional.

This is how restricted arrays are implemented, of course.

> This being the case, they could perhaps create a general function to split
> off unique sub-environments and sub-structures and add a compiler-option to
> add or not add run-time checks on mutual interference.

See above.

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