[clean-list] unique record fields.

Martijn Vervoort martijnv@cs.kun.nl
Wed, 6 Jun 2001 08:57:34 +0200


Hello,

> Hello,
>
> > Hello,
> >
> >   This is probably a very basic question (for which I apologize).
>
> Unfortunately, it is not such a basic question.
>
> >   I am trying
> >   to write hashtables in Clean.  The way I want to go about it is to
> define
> >   a Map type (parameterized by key and value types) corresponding to a
> record
> >   containing a (unique) array (and some other useful state):
> >
> > :: *Map *a b =
> > { state :: {[(a, b)]}
> > , size  :: Int
> > , put   :: (Map a b) -> a -> b -> (Map a b)
> > ... etc.
> > }
> >
> >   Then the function to construct an object of this type would look like:
> >
> > Map hash equal size =
> > { state = createArray size []   // <- error 2
> > , put = put
> > ... etc.
> > }
> > where
> > put :: (*Map *a b) *a b -> (*Map *a b)    // <- error 1
> > put map key val =
> > ...
> > map
> >
> >   However when I try to compile this program I get the following type
> errors:
> >
> > Type error [Map.icl,34,put]: "map" attribute at the indicated position
> cannot be coerced: Map ^ a b | == b
> > Type error [Map.icl,22,Map]: "createArray ({})" cannot create a
non-unique
> variant of this type at the indicated position: ^ [(a,b)]
> >
>
> Error 2:  You are in effect constructing an array of unique elements (due
to
>           the '*' in front of a in the type definition of Map).
>           But if you take a look at the type of createArray you'll see:
>
>               createArray :: !Int e -> .(a e)
>
>           Because there is no '.' or '*' in front of e, createArray can
only
> be used
>           to create arrays of *non-unique* elements.
>
>           Solution: I always use array-comprehensions to construct such
> arrays:
>
>               state = {[] \\ i <- [1..size]}
>
>           This will do the trick.
>
> Error 1:  There are actually two errors here. The first I won't even try
to
> explain.
>           (because I can't) You have to replace the type of 'put' in your

If the put-function is partially applied, it becomes necessarily unique
which
means that the partially applied put-function *itself* becomes unique to
prevent sharing of its second and third argument unique object.

The language report version 1.3, page 62/63 under Higher Order Uniqueness
Typing describes it also.

> record by:
>
>               put :: (Map a b) -> *(a -> *(b -> (Map a b)))
>
>           It still is obscure to me why this is needed.
>           Secondly, you have to change the type of the local function
'put'.
>           This one is easier: the '*' annotation always has to be written
> *outside*
>           the brackets, not inside. So:
>
>               put :: *(Map *a b) *a b -> *Map *a b
>
>           (The * inside the brackets will be ignored by the parser and can
> be omitted)
>
> As you can see, there are quite some things going on here.
>
> >   I am doing nothing in the program except defining the constructor, I
am
> not
> >   even calling it.  Does anyone have any insight into this?
> >   If this list is not the right place for these sorts of questions I
would
> be
> >   happy to direct them to the right place.
> >
> >   Thanks in advance,
> >
> >   Ilya
> >
>
> Maarten de Mol

Martijn Vervoort
>
> PS: Note that fields in a unique record will not automatically be unique
> themselves.
>     If you want the state field to be unique, you have to write
>
>          state :: *{[(a,b)]}