[Alice-users] Re: CTM Chapter 6

Andreas Rossberg rossberg at ps.uni-sb.de
Thu Jul 14 11:37:23 CEST 2005


Chris Rathman wrote:
>
> I had looked at Map at one time, thinking it might be what I was looking 
> for, but I guess I wasn't persistent enough in my investigation.  Is 
> there sample code available so that I could have a go-by?

No, but it is really simple. For example, to have an (imperative) 
dictionary over strings just define

   structure Dict = MkRedBlackImpMap String

or, if you want it based on hashing,

   structure Dict = MkHashImpMap String

Both produce a structure with the same signature, namely IMP_MAP 
(http://www.ps.uni-sb.de/alice/manual/library/imp-map.html), with 
String.t=string as their key type. I hope the documentation of the 
signature is sufficient to make use of such maps - if not, please let us 
know.

Usually a functional map type is preferable, in which case you do

   structure Dict = MkRedBlackMap String

and you get a module of signature MAP 
(http://www.ps.uni-sb.de/alice/manual/library/map.html).

Everything works analogous for sets.

> Also, while 
> I'm on the subject, am I correct in assuming that the data structure 
> libraries are written in Alice (i.e. not low-level)?  If they are in 
> Alice ML, where are they located?  Been wanting to see if they can teach 
> me a bit more about modules.

Well, they are in the Alice CVS, under lib/data. In the distribution 
they are only contained in compiled form. But I'd say that their use of 
modules isn't any more advanced than your examples are already - they 
just define simple functors of the form

   functor F (Key : ORDERED) ...
   functor F (Key : HASHABLE) ...

where ORDERED and HASHABLE are straightforward signatures containing a 
type, plus a respective ordering or hashing function (see 
http://www.ps.uni-sb.de/alice/manual/library/ordered.html and 
http://www.ps.uni-sb.de/alice/manual/library/hashable.html).

> Was kind of 
> wondering though why the same sort of record accessor wouldn't work in 
> the presence of the constructor.  Something like:
> 
>   val x = Person{ name="George", age=25 }
>   #age x

Well, this doesn't work for the same reason that, say,

   #age (13, {name="George", age=25})

doesn't: the argument to a selector function must be of record type, not 
something arbitrary just containing a record type. That is,

   #age  :  {age:'a, ...} -> 'a

How could one specify a more general type for it? And in any case, what 
should #age x possibly mean if I defined

   datatype person = Person of {name:string, age:int} | ImmortalAlmighty

?

This is different from Oz, where the moral equivalents of datatypes and 
records are mingled into one feature, and more importantly, where the 
issue of static type safety is simply ignored (i.e. if you do x.age in 
Oz you have no guarantee that it will succeed, you might encounter the 
"wrong case").

> Strictly concerned with encapsulation in chapter 6.  Inheritance and 
> subtyping are covered in the next chapter, but unless I get comfortable 
> with the encapsulation techniques, those aren't going to be within 
> reach.

Subtyping simply won't work - you have to use explicit coercions. 
Inheritance can be simulated to a certain extend, but will be ugly and 
requires some repetition:

   structure Point1D =
   struct
     type point = {getX : unit -> int, move : int -> unit}
     fun new x' =
     let
        val x = ref x'
     in
        {getX = fn () => !x, move = fn x' => x:=x'}
     end
   end

   structure ColoredPoint1D =
   struct
     type colored_point =
        {super : Point1D.point,
         getX : unit -> int,
         move : int -> unit,
         getColor : unit -> string,
         dye : string -> unit}
     fun new (x', c') =
     let
        val super = Point1D.new x'
        val c = ref c'
     in
        {super, getX = #getX super, move = #move super,
         getColor = fn () => !c, dye = fn c' => c:=c'}
     end
   end

   val p  = Point1D.new 5
   val cp = ColoredPoint1D.new (7, "red")
   val x1 = #getX p ()
   val x2 = #getX cp ()
   val xs = List.map (fn p => #getX p ()) [p, #super cp]

Some form of record extension syntax would make this nicer. You can 
avoid the repetition in the type and record definitions at the price of 
having to write something like

   val x2 = #getX (#super cp) ()

every time you need to access an inherited message (which is terrible 
with deeper inheritance).

Obviously, you won't have downcasts in either case...

> (And I'm assuming that 
> the habit of making them truly abstract is the habit you are goading me 
> to get into?)

Yes, absolutely :-)

Cheers,

   - Andreas

-- 
Andreas Rossberg, rossberg at ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB


More information about the alice-users mailing list