-
Notifications
You must be signed in to change notification settings - Fork 0
Composite types
Composite types represent aggregated or organized data. They broadly encompass collections, associations, and tagged values.
A collection is a series of values while an association pairs keys with values. Below is an overview:
Collections
Name Syntax Ordered Indexable Deconstruct Countable Recursive Unique Lazy eval
----------- ---------- ------- --------- ----------- --------- --------- ------ ---------
Tuple T*U Yes No Yes Yes No No No
List [T] Yes Yes No Yes No No No
Linked list T<> Yes No No No Yes No No
Set set{T} No No No Yes No Yes No
Enumerator T-enum No No No No No No Yes
Associations
Name Syntax Ordered Indexable Deconstruct Countable Recursive Unique Lazy eval
---------- ------------ ------- --------- ----------- --------- --------- ------ ---------
Dictionary dict{T->U} No Yes No Yes No Yes No
Record {|a U, b V|} No No Yes No No Yes Property
Note: in records, keys are identifiers with potential varied types. Record values can be accessed by member name, not by index.
A tuple aggregates a fixed number of values without naming them, in a certain order:
-
(12, 47)
has typeint * int
. -
("hello", 12.23)
has typestr * float
.
You can deconstruct tuples:
-
let (x, y) = (3, 4)
would assign the value3
tox
.
A list is a series of values of the same type, that has variable length and is ordered. It can be accessed by index:
-
let a = [1, 2, 3]
defines a constant list of type[int]
. -
a[1] = 2
is true.
A linked list is similar to a list except it is built by joining the items with ::
operator and ending with the empty linked list <>
:
-
12::34::67::<>
is a linked list of typeint<>
with 3 elements. -
12::others
is linked list with tailothers
, another linked list for elements after the head12
.
A set is a collection of unique values of the same type. It is not ordered and elements can be added or deleted:
-
{1, 3, 2}
is the same as{1, 2, 3}
and is of typeset{int}
. -
{1, 2} {+} {2, 3}
will result to{1, 2, 3}
.
An enumerator is a lazy evaluated list. It can only be traversed once. It is represented by two generics types T-enum
and T-asyncEnum
where T is the type for enumerated items.
Ranges are provided as a way of producing usual enumerators, like 0..<10
for the range from 0 to 10 excluded.
An enumerator can also be expressed with the enum
keyword like a function that yields the values. For example:
enum n int "getNumbersSeq": int do // indicate the element type: int
var i int = 0
while i < n {
yield i // provide a value
i += 1
}
end
The actual result type of this function is an enumerator int-enum
. It is a record with a fetch
function that return the next value. Here is how it would be implemented explicitly:
fun n int "getNumbersSeq": int-enum => {|
_i int = 0
state fun () "fetch" =>
_i < n ? {
let yieldValue = _i
_i += 1
return #ok yieldValue
} else
#done
|}
All collections are compatible with the enum
/asyncEnum
type because they can be enumerated.
A dictionary pairs unique keys with corresponding values.
-
var d = dict{5 -> "five", 7 -> "seven"}
defines a variable dictionary of typedict{int -> str}
. -
d[5] := "cinco"
changes the value associated with the key5
. -
mut d del 5
removes the key5
.
A record represents a collection of named values. While they bear similarities to objects in object-oriented programming with attributes such as properties and constructors, records in Append have their distinctive characteristics. Records can either be anonymous or have a designated type name.
Basic Usage: Create a point with an anonymous type.
-
let p1 = {| x: 4, y: 6 |}
defines a point that assumes the type{| x int, y int |}
, which can also be written as{| x/y int |}
.
Named Records: Naming a record gives it a unique identity.
-
var r = new Rectangle {| x: 0, y: 0, width: 100, height: 100 |}
defines a variable rectangle of the named typeRectangle
. This name differentiates it from a similar anonymous record. The record type must be defined using therecord
keyword.
Deconstruction: Records also support deconstruction.
-
let {| x |} = {| x: 4; y: 6 |}
extracts the specific valuex
from the record into a local constantx
. -
let {| x: horizontal |} = {| x: 4; y: 6 |}
will renaming during deconstruction storing the value in a local constanthorizontal
.
Tagging a value clarifies its intent, especially useful for conveying success or errors:
-
#ok 42
is of type#ok int
and expresses the success of a function, returning the value 42. -
#done()
or#done
expresses the success of a function, but without return value.
These results can be handled with pattern matching.
You can nest tags for a more nuanced expression:
-
#ok #found 42
is equivalent to#ok (#found 42)
where #ok is the enveloping tag.