List
A list is a central datastructure in all functional languages. Albatross has a strong functional component and therefore has a list class defined in its base library.
List Type
The module core of the base library defines the class in the following
manner.
class
LIST[A]
create
[]
(^) (head:A, tail:LIST[A])
end
The operator [] is used to create an empty list. The expression a ^ l
adds the element a in front of the list l.
The operator ^ is right associative, i.e. a ^ b ^ l is parsed as a ^ (b ^
l).
The operator ^ is an arithmetic operator which has higher precedence than
the addition and the multiplication operators. In order to add 3+4 at
the front of a list of naturals parentheses have to be used (3+4) ^ natlist.
Because lists are used frequently there are some shorthands. [A] is a
shorthand for LIST[A] and [a,b,c] is a shorthand for a ^ b ^ c ^ [].
The module core does not contain more declarations for lists. More
interesting functions are declared in the module list. All the following
subchapters explain functions declared in the module list.
Browse the source code of the module list to see the complete user
interface.
List Functions
It is possible to extract the first element of a list and tail of a list
(i.e. the list without the first element) provided that the list is not
empty. The module list defines two partial functions to do this.
head (a:[A]): G
-- The first element of the list 'a'.
require
a as x ^ t
ensure
-> inspect
a
case h ^ _ then
h
end
tail (a:[A]): [A]
-- The list 'a' with the first element removed.
require
a as x ^ t
ensure
-> inspect
a
case _ ^ t then
t
end
Since LIST is a inductive type, recursive functions are easy to define. The
module list defines some basic list functions.
(in) (x:G, a:[A]): BOOLEAN
-- Is the element 'x' contained in the list 'a'?
-> inspect
a
case [] then
false
case h ^ t then
x = h or x in t
elements (a:[A]): {A}
-- The set of elements of the list 'a'.
-> {x: x in a}
(+) (a,b: [A]): [A]
-- The concatenation of the lists 'a' and 'b'.
-> inspect
a
case [] then
b
case h ^ t then
h ^ (t + b)
(-) (a:[A]): [A]
-- The reversed list 'a'.
-> inspect
a
case [] then
[]
case h ^ t then
- t + [h]
Lists and Higher Order Functions
Higher order functions are functions which receive functions as arguments or return functions as results.
We can define a function which receives a list and a function from the list element type to another type and which uses the function to map all elements of the list to generate a new list.
B: ANY
[] (f:A->B, a:[A]): [B]
-- The list 'a' where all elements are mapped by 'f'.
require
a.elements <= f.domain
ensure
-> inspect
a
case [] then
[]
case h ^ t then
f(h) + f[t]
end
It is very convenient to use the bracket operator [] to define this
function because then the expression f[a] maps the whole list a
elementwise by the function f and the notation is very intuitive.
Having this function we can map a list of naturals by the successor function.
successor[[0,1,2]] = [1,2,3]
Note that successor is a defined function and not a function object as
required by the signature of []. However the compiler converts the function
successor into the function object n -> n.successor automatically.
Another interesting higher order function is the function folded which folds
a folding function over a list.
A folding function for a list of type [A] is a binary function with the
signature [B,A]->B. I.e. it takes a value of type B and a list element of
type A and returns a value of type B. The folding needs a start value s
and then we get
f.folded(s, [a,b,c]) = f( f( f(s,a), b), c)
The function folded is defined as follows.
folded (f:(B,A)->B, s:B, l:[A]): B
-- The function 'f' folded with start value 's' over the list 'l'.
require
f.is_total
ensure
-> inspect
l
case [] then
s
case h ^ t then
f.folded(f(s,h), t)
end
If f is a binary left associative operator op, then we get
(op).folded(s, [a,b,c]) = s op a op b op c
i.e.
(+).folded(a, [b,c,d]) = a + b + c + d