These bookmarks enable you to visit a particular collection type. If you are first time here, just scrol down and read the whole page at least one time. Next time you can use this small index to jump to a particular topic. Enjoy!
Bee uses composite types to declare ...
A new type is defined from a super-type using symbol "<:"
type new_type: descriptor <: super_type
Ordinal is an abstract data set. It is a group of identifiers. Each identifier represents an integer value starting from 0 to capacity-1. Associated values can start with a different integer number. Values can be specified using pair up operator ":". All values must be unsigned integer (i ≤ 0) in consecutive ascending order.
type type_name: { name1:0, name2, name3} <: Ordinal;
make a, b, c ∈ type_name; //a, b, c will have same type
rule main():
alter a := type_name.name1; //a=2
alter b := type_name.name2; //b=3
alter c := type_name.name3; //c=4
return;
Note: When element name start with "." no need to use qualifiers for the individual values. This is becouse values starting with "." are public by default and known in the scope where ordinal is defined (or loaded).
** using public elements in enumeration
type type_names: {.name0, .name1} <: Ordinal;
make a, b ∈ type_name;
rule main()
alter a := name0; //a = 0
alter b := name1; //b = 1
return;
A list is a dynamic collection of elements connected by two references:
A list has two very important elements:
Chained List
list type
You can define a list type using empty list: ()
type Type_name: (element_type) <: List;
variable declaration You can use one of three forms of declarations:
make name ∈ (element_type); //explicit declaration
make name := (constant,...); //implicit declaration
make name := (constant,...) ∈ Type_name; //full declaration
properties
** define a diverse lists
make two:() ∈ (Z); //empty list of integers = ()
make one:(0,); //initialize list with single element
make two:(1,2); //initialize list with two elements
** define a list type of unsigned short integer
type Lon:(N) <: List;
** define a list variable of defined type Lou
make myList:(0, 1, 2, 3, 4, 5) ∈ Lon;
** list traversal
rule main():
given x <- myList do
write x;
write "," if (x ≠ myList.head);
cycle;
print; //0,1,2,3,4,5
rule;
Bee define Arrays using notation: [type](c), where [type] is the data type of elements and (c) is the capacity (total number of elements). Arrays are automatically initialized. However, if the array contains composite types all elements are null until initialized.
** diverse array variables
make array_name ∈ [element_type] ; //single element array
make array_name ∈ [element_type](); //undefined capacity array
make array_name ∈ [element_type](c); //capacity c
make array_name ∈ [element_type](n,m); //capacity c = n·m
** define new kind of array
type Array_Type: [element_type](c) <: Array;
** use previous defined type
make array_name ∈ Array_Type;
In next example we declare an array and use index "i" to access each element of the array by position. Later we will learn smarter ways to initialize an arrays and access its elements by using a visitor pattern.
Array Index
Lets implement previous array: numbers[] and print it nicely using a cycle.
# define public array
make .numbers[Z](10) := [0,1,2,3,4,5,6,7,8,9];
** access .numbers elements one by one
rule main():
write "numbers = [";
given i <- (1..10) do
write numbers[i];
write ',' if i < 10;
cycle;
write "]";
print; // flush the buffer
return;
numbers = [0,1,2,3,4,5,6,7,8,9]
initialize elements
Initial value for elements can be set during declaration or later:
** you can use a single value to initialize all vector elements
make zum:0 ∈ [Z](10); //explicit initialization using single value
rule main():
** modify one element by index
alter zum[1] := 1;
alter zum[-1] := 10;
print zum; //expect [1,0,0,0,0,0,0,0,0,10]
** modify all elements
alter zum[*] := 0;
print zum; //expect [0,0,0,0,0,0,0,0,0,0]
return;
Deferred initialization: We can define an empty array and initialize its elements later. Epty arrays do not have establish a capacity until array is initialized
** array without capacity (partial type inference)
make vec ∈ [A]();
make nec ∈ [N]();
rule main():
** arrays are empty
print vec = []; //True
print nec = []; //True
** smart initializer with operator "×"
alter vec := 'x' × 10; //10;
print vec; //expect ['x','x','x','x','x','x','x','x','x','x']
** smart initializer with 0 values
alter nec := 0 × 10;
print nec; //expect [0,0,0,0,0,0,0,0,0,0];
return;
A matrix is an array with 2 or more dimensions. In next diagram we have a matrix with 4 rows and 4 columns. Total 16 elements. Observe, matrix index start from [1,1] as in Mathematics.
Matrix Index
In next example we demonstrate a curious notation for matrix. You have maybe not seen this before in any other language becouse is ridiculous to parse. But from aestetic point of view we think this is the way a matrix literal should look like:
# define a subtype of Matrix
type Mat: [R](4,4) <: Matrix;
make mat ∈ Mat //define matrix variable
rule main()
** modify matrix using ":=" operator
alter mat := [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
print mat[1,1]; //1 = first element
print mat[4,4]; //16 = last element
** support for 2D matrix literals
pass if mat = ⎡ 1, 2 , 3, 4 ⎤
⎢ 5, 6 , 7, 8 ⎥
⎢ 9, 10 ,11, 12 ⎥
⎣13, 14 ,15, 16 ⎦;
** nice optput using array print method
apply mat.print;
return;
⎡ 1, 2 , 3, 4 ⎤ ⎢ 5, 6 , 7, 8 ⎥ ⎢ 9, 10 ,11, 12 ⎥ ⎣13, 14 ,15, 16 ⎦
Memory is linear, so we fake a matrix. In reality elements are organized in row-major order. That means first row, then second row...last row. We can access the entire matrix like it would be a longer array. So next program can initialize a matrix in a normal cycle, not nested!
** initialize matrix elements
make i := 1;
make mat := [Z](3,3);
make x := mat.length;
rule main():
while (i < x) do
mat[i] := i+1;
i += 1;
cycle;
apply mat.print; //nice output
return;
⎡ 1 2 3 ⎤ ⎢ 4 5 6 ⎥ ⎣ 7 8 9 ⎦
A data set is a sorted collection of unique values. Elements of a data set can be accessed sequential. There is no index associated with elements like we have in Arrays so the access to an element is slow.
** user defined set
type NS: {N} <: Set; //define a set of natural numbers
make uds ∈ NS; //define a shared variable of type set
** define shared sets s1, s2 of 3 elements each
make s1 := {1,2,3} ∈ {N};
make s2 := {2,3,4} ∈ {N};
** specific operations
make u := s1 ∪ s2; //{1,2,3,4,5}:union
make i := s1 ∩ s2; //{2,3} :intersection
make d1 := s1 - s2; //{1} :difference 1
make d2 := s2 - s1; //{4} :difference 2
make d := s2 ⊖ s1; //{1,4} :symmetric difference
rule main():
** verify expectation
pass if d = d1 ∪ d2; //equivalent (else fail)
** belonging check
print s1 ⊂ s; //True
print s ⊃ s2; //True
** declare a new set
make a := {1,2,3};
** using operator +/- to mutate set a
alter a += 4; // {1,2,3,4}
alter a -= 3; // {1,2,4}
return;
A hash map is a set of (key:value) pairs sorted by key.
** define a hash map type
type type_name: {(key_type: value_type)} <: Hash;
** declare a new empty hash map
make new_map := {} ∈ type_name;
Hash-Map Anatomy
** initial value of map
make map := {('key1':"value1"), ('key2':"value2")};
rule main():
** create new element
alter map['key3'] := "value3";
** finding elements by key
print map['key1']; //"value1"
print map['key2']; //"value2"
print map['key3']; //"value3"
** remove an element by key
scrap map['key1']; //remove "first" element
apply map.print; //expected: {('key2':"value2"), ('key3':"value3")};
return;
We can check if an element is included in a collection using "∈".
type Tmap: {(A:U)} <: Hash;
make map := {('a':"first"), ('b':"second")} ∈ Tmap;
rule main():
when ('a' ∈ map) do
print("a is found");
else
print("not found");
done;
return;
Bee has 4 kind of string literals:
quote | used for |
---|---|
`_` |
Back quotes, ASCII single symbol |
'_' | UTF32 Unicode single symbol |
"_" | Double quoted UTF8 Unicode string or string template |
For large text literals (X) we can use a markup language:
make query :=
<sql>
select name, age
from persons
where age < 24;
</sql>;
Single quoted or back quoted literals can contain a single symbol.
** fixed capacity array or ASCII symbols
type A128: [A](128) <: Array;
rule main()
** populate array using spreading operator (*)
make str ∈ A128;
alter *str := "test"; //spreading a ASCII literal
print str; // [`t`,`e`,`s`,`t`]
** fixed capacity array of symbols UTF32
make uco ∈ [U](128);
alter *uco := "∈≡≤≥÷≠"; //spreading a Unicode literal
print uco; // ['∈','≡','≤','≥','÷','≠'];
return;
Double quoted string literals are Unicode UTF8 strings.
rule main():
** fixed capacity string UTF8
make uco ∈ S; //Unicode string unknown capacity
alter uco := "∈ ≡ ≤ ≥ ÷ ≠ · × ¬ ↑ ↓ ∧ ∨";
** strings are printed with quotes
print uco; //"∈ ≡ ≤ ≥ ÷ ≠ · × ¬ ↑ ↓ ∧ ∨"
return;
Escape You can use this literal with escape sequence: \n to break a line
print("this represents \n new line in string");
output:
this represents
new line in string
like this
;Below operators will concatenate two strings.
symbol | description |
---|---|
* | Concatenate a string with itself multiple times |
+ | Concatenate two strings as they are no trim is performed |
- | Concatenate two strings and reduce white spaces to one |
. | Concatenate path using using '/' or '\' depending on OS type |
/ | URL/Path concatenation: trim and use single separator: "/" |
\ | Windows path concatenation: trim and use single separator: "\" |
examples
make m: ('-' * 10) ∈ S; //m = "----------"
make (u, c, s) ∈ S; //default length is 128 octets = 1024 bit
rule main():
** string concatenation
alter c := "This is " + "a large string";
** automatic conversion to string
alter s := "40" + 5; // "405"
** URL/path concatenation
make test_file := $pro.'src'.'test.bee';
** when $platform = "Windows"
** Let's say $pro = "c:\work\project\"
print test_file; // "c:\work\project\src\test.bee"
** when $platform = "Linux"
** Let's say $pro = "/work/project/"
print test_file; // "/work/project/src/test.bee"
return;
Conversion of a string into number is done using parse rule:
make x,y ∈ R;
rule main():
** rule parse return; a Real number
alter x := parse("123.512",2); //convert to real 123.5
alter y := parse("10,000.3333",2); //convert to real 10000.33
return;
Object type is a data structure with elements enclosed in curly brackets { , , ,} and separated by comma. Each attribute of an object has a name and a data type. This is a heterogenous collection of values.
** declare a category of objects
type Type_name: {attribute ∈ type_name, ...} <: Object;
rule main():
** create an object instance using default constructor
make item_name := {
attribute : constant,
...
} ∈ Type_name;
** modify one object attribute
alter object_name.attribute := new_value;
return;
Object structure can be ...
type size:
Type size is a constant that can be calculated using: size(type).
type Person: {name ∈ S, age ∈ N} <: Object;
** array of 10 persons
make catalog ∈ [Person](10);
** initialize value using literals
make catalog[0] := {name:"Cleopatra", age:15};
make catalog[1] := {name:"Martin", age:17};
rule main():
** using one element with dot operators
print caralog[0].name; //will print Cleopatra
print caralog[1].name; //will print Martin
** member type can be check using _type()_ built in
print type(Person.name); //will print U
print type(Person.age); //will print W
** print size of structure
print size(Person);
return;
We can limit how deep a call stack become using a directive. $recursion:1000
** example of single recursive node
type Node: {
data ∈ Z, /* integer data */
previous ∈ Node /* reference to previous node */
} <: Object;
This kind of structure can be used to create a data chain.
** example of double recursive node
type Node <: {
data ∈ Z, /* integer data */
prior ∈ Node, /* reference to previous node */
next ∈ Node /* reference to next node */
} <: Object;
An exception is a recoverable error. It can be declared by the user or by the system. Exception is also known as "error". Bee has predefined type: Error that can be used to declare your own errors.
Parts of Bee compiler will be created using Bee language. Here is the definition of global variable @error, that is available for introspection after you call a rule.
** global exception type
type Error: {code ∈ Z, message ∈ S, line ∈ Z} <: Object;
** global system error
make @error ∈ Error;
You can define exceptions with code > 200 and raise exceptions with 3 statements:
make my_error := {200,"message"} ∈ Error;
fail my_error if condition;
pass if condition;
String interpolation "?" can be used to customize the error messages:
rule main():
make flag ∈ L;
read (flag, "enter flag (0/1):");
make my_error := {201,"error:#(s)"} ∈ Error;
fail (my_error ? "test") if flag;
return;
error:"test"
Next we create unrecoverable exception:
abort -1; //end program and error code = -1
abort -2; //end program and error code = -2
See also:
Read next: Data Processing