Bounded Polymorphic Functions



The following examples show the use of polymorphic functions.

The polymorphic function QuickSort has a type parameter X, which is the type of the elements of the list to be sorted. The value parameters are the list to be sorted and the ordering relation for the element of the list. The function is then applied to a list of integers, to sort them in ascending order.

The second example shows a bounded polymorphic function, QuickSortOnK, which is defined through the use of QuickSort. It orders lists of records of type X, which have (at least) an attribute k, of a generic type Y. Note the use of the subtype relation in specifying the generic types. The function is then applied to a list of records, with the field k of type integer. After this, the function is called to sort a set of records with the field k of type string, with the second parameter a lexicographical order relation.

Finally, the last example shows the interaction between polymorphism and views. The function QuickSortOnK is applied to the views of the elements of a class, with the sorting attribute renamed in order to match the type declaration of the function. From the result of the sorting, the elements are extracted again with the original type (so that the expression returns a list of persons).



let rec QuickSort :=
    fun [ElementType] (s: seq ElementType,
                       less:(ElementType # ElementType) -> bool): seq ElementType is
		if emptyseq(s)
		then s
       else use
             p := first(s) and
             r := rest(s)
            in QuickSort[ElementType](
                   (select x from x In r where less(x, p)),
                    less)
               append {p}
               append QuickSort[ElementType](
                         (select x from x In r where Not less(x, p)),
                          less);

let LessThan := fun(x:int, y :int):bool is x < y;
QuickSort [int] ({2;4;3;1;9;5}, LessThan);

let rec QuickSortOnK :=
    fun [FieldType<:any; RecordType<:[k:FieldType]]
          (s: seq RecordType,
             less:(FieldType#FieldType) -> bool): seq RecordType is
        QuickSort[RecordType](s, fun(x:RecordType, y:RecordType):bool is less(x.k,y.k)) ;

QuickSortOnK [int; [k:int; v:string]]
                 ({[k := 4; v := "a"];
                   [k := 2; v := "b"];
                   [k := 3; v := "c"]}, LessThan);

let rec StrLessThan:= fun(x:string, y:string):bool is
   use rec lessThanAscii:= fun(x:seq int, y:seq int):bool is
           if emptyseq(x) then true
           else if emptyseq(y) then false
           else if first(x) = first(y)
                then lessThanAscii(rest(x), rest(y))
                else if first(x) < first(y)
                     then true
                     else false
   in lessThanAscii(explodeascii(x), explodeascii(y));

QuickSortOnK [string; [v:int; k:string]]
                 ({[v := 4; k := "a"];
                   [v := 2; k := "b"];
                   [v := 3; k := "c"]}, StrLessThan);

let Persone class
  Persona <-> [Nome:string; Eta:int] key(Nome);

select x As Persona
  from x In (QuickSortOnK[int; <Persona> view [k:int]]
              (Persone rename* (Eta => k), LessThan));