| Objects, Classes and Slots Updates |
categories Lists, Sets and Instructions Lists, Sets and Tuples |
Blocks |
CLAIRE provides two easy means of manipulating collections of objects: sets and lists. Lists are ordered, possibly heterogeneous, collections. To create a list, one must use the list(...) instruction : it admits any number of arguments and returns the list of its arguments. Each argument to the list(...) constructor is evaluated.
| list(a, b, c, d) list(1, 2 + 3), list() |
| set(a,b,c) set(1,2 + 3) |
| list<thing>(a,b,c,d) list<integer>(1,2 + 3) list<float>() set<thing>(a,b,c) set<integer>(1, 2 + 3) |
Since typing is mandatory in order to assume type-safe updates onto a list or a set, if no type is provided, CLAIRE will forbid any future update: the list or the set is then a "read-only" structure. This is the major novelty in CLAIRE 3.2: there is a difference between:
| list(a,b,c,d) set(1,2 + 3) list{i | i in (1 .. 2)} |
| list<thing>(a, b) set<integer>(1, 2 + 3) list<integer>{i | i in (1 .. 2)} |
List or set types can be arbitrarily complex, to represent complex list types such as list of lists of integers. However, it is recommended to use a global constant to represent a complex type that is used as a list type, as follows :
| MyList :: list<integer> set<MyList>(list<integer>(1), list<integer>(2, 3)) |
| {a,b,c,d} {3, 8} |
A set can also be formed by selection. The result can either be a set with {x in a | P(x)}, or a list with list{x in a | P(x)}, when one wants to preserve the order of a and keep the duplicates if a was a list. Similarly, one may decide to create a typed or an un-typed list or set, by adding the additional type information between angular brackets. For instance, here are two samples with and without typing :
| {x in class | (thing % x.ancestors)} list{x in (0 .. 14) | x mod 2 = 0} set<class>{x in class | (thing % x.ancestors)} list<integer>{x in (0 .. 14) | x mod 2 = 0} |
Also, the imageof a set via a function can be formed. Here again, the result can either be a set with {f(x)|x in a} or a list with list{f(x) | x in a}, when one wants to preserve the order of a and the duplicates :
| {(x ^ 2) | x in (0 .. 10)} list<integer>{size(x.slots) | x in class} |
| average_salary(s:set[man]) : float -> (sum(list{m.sal | m in s}) / size(s)) |
| exists(x in (1 .. 10) | x > 2) // returns true some(x in (1 .. 10) | x > 2) // returns 3 in most implementations exists(x in class | length(x.ancestors) > 10) |
| when x := some(x in man | rich?(x)) in (borrow_from(x,1000), ...) else printf("There is no one from whom to borrow!") |
| forall(x in (1 .. 10) | x > 2) forall(x in (1 .. n) | exists(y in (1 .. x) | y * y > x)) |
Definition : A list is an ordered collection of objects that is organized into an extensible array, with an indexed access to its members. A list may contain duplicates, which are multiple occurrence of the same object. A set is a collection of objects without duplicates and without any user-defined order. The existence of a system-dependent order is language-dependent and should not be abused. The concept of bag in CLAIRE is the unifier between lists and sets : a collection of objects with possible duplicates and without order. |
A read-only (untyped) list can also be thought as tuples of values. For upward compatibility reasons, the expression tuple(a1,...,an) is equivalent to list(a1,...,an) :
| tuple(1,2,3), tuple(1,2.0,"this is heterogeneous") |
| tuple(1,2,3) % tuple(integer,integer,integer) tuple(1,2,3) % tuple(0 .. 1, 0 .. 10, 0 .. 100) tuple(1,2.0,"this is heterogeneous") % tuple(any,any,any) |
| categories | Lists, Sets and Tuples | normal dispatch | operation | Kernel method |
x /+ y returns a new list that is the concatenation of the two bag contents.
| categories | Lists, Sets and Tuples | normal dispatch | operation | Kernel method |
l1 /+ l2 returns a new list that is the concatenation of the two lists.
| categories | Lists, Sets and Tuples | normal dispatch | operation | Kernel method |
(l << n) left-shifts the list l by n units, which means that the n first members of the list are removed. This is a method with a side-effect since the returned value is the original list, which has been modified.
| categories | Lists, Sets and Tuples | normal dispatch | operation | Kernel method |
(s1 ^ s2) returns the intersection of the two sets s1 and s2 that is the set of entities that belong to both s1 and s2. Other internal restrictions of the property ^ exist, where ^ denotes the intersection (it is used for the type lattice).
| categories | Lists, Sets and Tuples | normal dispatch | operation | Kernel method |
(l ^ y) skips the y first members of the list l. If the integer y is bigger than the length of the list l, the result is the empty list, otherwise it is the sublist starting at the y + 1 position in l (up to the end).
| categories | Lists, Sets and Tuples | normal dispatch | operation | Kernel method |
add(s,x) adds x to the list l. The returned value is the list obtained by appending (x) to l.
| categories | Lists, Sets and Tuples | normal dispatch | operation | Kernel method |
add(s,x) adds x to the set s. The returned value is the set s U {x}. This method may modify the set s but not necessarily.
| categories | Lists, Sets and Tuples | normal dispatch | operation | Kernel method |
add*(l1,l2) returns the concatenated list l1 . l2, but it is destructive: it uses l1 as the data structure on which to perform the concatenation. Hence, the original l1 is no longer available after the method add* has been called
| categories | Lists, Sets and Tuples | normal dispatch | Core method |
Classical LISP methods that return the head of the list (e.g. l[1]).
| car(list(1,2,3)) -> 1 car(list(3,2,1)) -> 3 |
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
cast!(s, t) sets the member type of bag s to t. This method should be used carefully since their is no verification made to assert that all elements from the list actually belongs to the supplied type.
| cast!(list(1,2,3), integer) -> list<integer>(1,2,3) |
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
Classical LISP methods that return the tail of the list (e.g. the list l starting at its second element ).
| cdr(list(1,2,3)) -> (2, 3) cdr(list(3,2,1)) -> (2, 1) |
| categories | Lists, Sets and Tuples | normal dispatch | operation | Kernel method |
This traditional method appends x at the beginning of l and returns the constructed list.
| cons(1, list(2,3)) -> (1,2,3) |
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
The copy of a bag (a set or a list) returns a fresh set or list with the same elements
| categories | Lists, Sets and Tuples | normal dispatch | operation | Kernel method |
delete(p, x, y) is equivalent to p(x) :delete y. This is a destructive method in the sense that it modifies its input argument unless the result is nil (There is only one empty list). The proper way to use delete, therefore, is either destructive (l :delete x) or non-destructive (delete(copy(l), x)).
| categories | Lists, Sets and Tuples | normal dispatch | Core method |
difference(s, t) returns the difference set s - t, that is the set of all elements of s which are not elements of t.
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
get(l, x) returns the lowest i such that l[i] = x (if no such i exists, 0 is returned).
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
hash(l, x) returns an integer between 1 and length(l) that is obtained through generic hashing. To obtain the best dispersion, one may use a list of size 2i-3. This function can be used to implement hash tables in CLAIRE; it is the basis of the table implementation.
| categories | Lists, Sets and Tuples | normal dispatch | Core method |
last(l) returns l[length(l)]
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
returns the length of a list. The length of a list is not its size !
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
list!(s) transforms s into a list. The order of the elements in the list can be anything.
| categories | Lists, Sets and Tuples | normal dispatch | [XL] Kernel method |
returns an empty list with type member t. n gives the size of the allocated content (i.e. adding n element won't cause further allocation).
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
returns a list of length n filled with x (e.g., make_list(3, 0) = list(0, 0, 0)).
| categories | Lists, Sets and Tuples | normal dispatch | operation | Core method |
max(f,self) return the element of self that has the greatest value according to the ordering method f. For instance :
| max(< @ integer, list(1,2,3,2,1)) -> 3 |
| categories | Lists, Sets and Tuples | normal dispatch | operation | Core method |
min(f,self) return the element of self that has the lowest value according to the ordering method f. For instance :
| min(< @ integer, list(1,2,3,2,1)) -> 1 |
| categories | Lists, Sets and Tuples | Core constant |
nil is the empty list instance.
| categories | Lists, Sets and Tuples | normal dispatch | Kernel interface |
nth can be redefined on user class domain meant to have indexed access. The reader converts the x[y] notation into a call to nth(x,y) that at evaluation will call the redefined restriction :
| hash_table <: ephemeral_object(data:list[any]) nth(x:hash_table, x:any) : any -> x.data[hash_value(x) and \xFFF] |
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
nth(l,i) return the ithelement of the bag l. nth(l,i) is equivalent to l[i].
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
nth+(l,i,x) inserts element x at the ithposition in the bag l. By extension, i may be length(l) + 1, in which case x is inserted at the end of l.
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
nth-(l,i) removes the ithelement of the bag l. By extension, i may be length(l) + 1, in which case x is inserted at the end of l.
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
nth=(l,i,x) replace the ithelement of the bag l by x. nth(l,i,x) is equivalent to l[i] := x.
| categories | Lists, Sets and Tuples | normal dispatch | Kernel interface |
nth= can be redefined on user class domain meant to have indexed access. The reader converts the x[y] := z notation into a call to nth(x,y,z) that at evaluation will call the redefined restriction :
| hash_table <: ephemeral_object(data:list[any]) nth=(x:hash_table, x:any, y:any) : void -> x.data[hash_value(x) and \xFFF] := y |
| categories | Lists, Sets and Tuples | normal dispatch | Core method |
removes the last element of the list self.
| categories | Lists, Sets and Tuples | normal dispatch | Kernel method |
The method shrink truncates the list l so that its length becomes n. This is a true side-effect and the value returned is always the same as the input. As a consequence, shrink(l, 0) returns an empty list that is different from the canonical empty list nil.
| let l := list<integer>(1,2,3) in (shrink(l, 2), assert(length(l) = 2)) |
| categories | Lists, Sets and Tuples | normal dispatch | Core method |
this method sorts the list self according to the ordering method f
| categories | Lists, Sets and Tuples | normal dispatch | Core method |