Sage-Code Laboratory
index<--

Bee Types

Data types represent a domains of values. In other words, data type represent constraints that can be used to validate a particular value. Data"type" is an attribute of any data value.

Bee use several kind of data types described below. Use these links to jump to a particular data type. Use browser back-button to revisit a particular data type:

  1. Primitive types;
  2. Constant literals;
  3. Special types;
  4. Type declaration;
  5. Range type;
  6. Domain type;
  7. Constant declarations;
  8. Variable declarations;
  9. Modify values;
  10. Alphanumeric type;
  11. Type inference;
  12. Type checking;
  13. Boolean type;
  14. Rational numbers;

Usability:

Primitive Types

Primitive data types are defined using one capital letter. This may be unusual in Computer Science but standard in Mathematics. Therefore Bee uses this convention.

Alias Code Description + Default representation
Boolean B Boolean or 8 bit number, 0 = False, >= 1 True
Alpha A Alpha-numeric E-ASCII ('0'..'9') ('a'..'Z')
Unicode U Unsigned 32 bit, max: U-FFFFFFFF (UTF32)
Rational Q Fix point representation number: like 1/2. Notation: Q(14,17)
Natural N Unsigned large positive integer 64 bit [0..+]
Integer Z Signed large integer 64 bit [-..+] Z(64)
Real R Double precision float 64 bit (-..+) R(64)

Notes:

Constant Literals

These are symbolic representations for primitive data types:

Example Type Literal characters
'a' A (+-) & (0..9) & (a..z) & (A..Z)
'Ω' U (Δ Λ Φ Γ Ψ Ω Σ Π π ⊥ ǁ α β ɣ ε δ μ ω ...)
"str" S (∀ UTF8)
0b0,0b1 B (0,1) & B
1234567890 N (0,1,2,3,4,5,6,7,8,9)
+0 Z (-+) & (0,1,2,3,4,5,6,7,8,9)
'a','b' A ASCII (0x00..OxFF)
U+FFFF U (U+) & (0,1,2,3,4,5,6,7,8,9) & ABCDEF
U-FFFFFFFF U (U-) & (0,1,2,3,4,5,6,7,8,9) & ABCDEF
0.05 R (-.) & (0,1,2,3,4,5,6,7,8,9)
-1/2 Q (-/) & (0,1,2,3,4,5,6,7,8,9)
1E10 R (-1E)& (0,1,2,3,4,5,6,7,8,9)
1e10 R (-1e)& (0,1,2,3,4,5,6,7,8,9)

note

Special types

Special types have an alias starting with capital letter. These types are embeded in the language and contribute to language coherence. All these types are actually references to memory structures:

Alias Type Description
Complex C Double precision pair of double float numbers (9r+9j)
String S UTF8 encoded double quoted string "α β ɣ ε δ μ ω"
Date D "DD/MM/YYYY"
Time T "hh:mm,ms"
Lambda L Lambda expression or function.

Collection types

Bee define a collection literal using a special notation based on brackets. These types are going to be explained later in another page. We mention these types here because they represent types.

delimiter collection types
() List
[] Array / Matrix
{} Set / Map / Object / Ordinal

Notes:

Type declaration

User can define type alias using operators ":" and sub-types using operator "<:" (inheritance). Usr can specify type of variables explicit usin operator ∈

** declare new type alias
type Type_Identifier: type_descriptor <: super_type;

** declare variables using type alias
new var_name ∈ Type_Identifier;

** declare many variables using type alias
new var_name, var_name ... ∈ Type_Identifier;

Notes:

Range Type

A range is a notation that designate a sub-set of consecutive integer numbers between two limits: lower limit and upper limit included in round parenthesis and separated by two dots (..) or (!).

Syntax:

range ::= (min..max);
range ::= (min.!max); -- exclude upper limit
range ::= (min!.max); -- exclude lower limit

Notes:

Example:

#integer domain
rule main:
  print (0..5); -- 0,1,2,3,4,5
  print (0.!5); -- 0,1,2,3,4
  print (0!.5); -- 1,2,3,4,5

  pass if  32667 ∈ (0..+); -- expect to pass
  pass if -32668 ∈ (-..0); -- expect to pass
return;

Ranges can use symbols that are ASCII or Unicode. In this case the symbols must be included in single quotes: 'X' or use U+ notation:

Example:

** sub-type declarations
type  .Digit:    ('0'..'9')       <: Z;
type  .Capital:  ('A'..'Z')       <: A;
type  .Lowercase:('a'..'z')       <: A;
type  .Latin:    (U+0041..U+FB02) <: U;

rule main:
  ** following statements should pass
  pass if '0' ∈ Digit;
  fail if 'x' ∈ Capital;
  pass if 'X' ∈ Capital;
  pass if 'e' ∈ Latin;
return;

Domain Type

Domain is very similar to range except a domain has a ratio. This is the difference, the numbers are not integers, can be fractional or Q umber.


type Domain: (min..max:ratio)  <: Super_Type;

Examples:

** generate rational numbers
print (0..1:1&\4); -- 0&\4, 1&\4, 2&\4, 3&\4, 1

** generate float numbers
print (0..1:0.25); -- 0.00, 0.25, 0.50, 0.75, 1.00

Constant declarations

Constants literals bound to identifiers using keyword "set".

** using explicit type
set constant_name: constant_literal ∈ type_name;

** using implicit type
set constant_name := constant_literal;

Notes:

Example:

#define symbol constants
set forall1: U+2200     ∈ A; -- Symbol: ∀
set forall2: U-00002200 ∈ U; -- Symbol: ∀

Note:

Variable declarations

Variables are defined using type inference and these operators:

operator purpose
declare variable/element type
: define | block start | pair up operator
: set initial value (require type in declarations)
:= type inference | share a reference | assign operator
:: deep copy | duplicate object | cloning operator

Notes:

** primitive variable declarations with type
new var_name ∈  type_name; -- declaration only type without initial value
new var_name: value ∈  type_name; -- declaration with initial value and type

** Variable declaration using type inference
new var_name := expression; -- expression ":=" do not require type hint ("∈").

** Multiple variables can be define in one single line using comma separator:
new var1, var2 ... ∈  TypeName;   -- default initial values
new var1, var2 ... := Expression; -- use type inference for all initial values

** Initialize multiple variables, of the same type (type is required)
new var1:con1, var2:con2 ... ∈ TypeName;

Modify values

One can modify variables using alter statement.

Example:

#fragment of code

new a:10, b:0 ∈ Z; -- initialize two variables
let b := a + 1;   -- modify b using binding operator :=
let b += 1;       -- modify b using modifier +=
expect b = 12;    -- check if b has proper value

Notes:

Examples:

** declare a public constant
set .PI: 3.14 ∈ R;

rule main:
  ** declare a single variable
  new a   ∈ Z; -- Integer

  ** declare multiple variables
  new (x,y):0 ∈ R; -- Double
  new (q,p):0 ∈ L; -- Logic

  ** using modifiers
  let a := 10; -- modify value of: a == 10
  let a += 1;  -- increment value of: a == 11
  let a -= 1;  -- decrement value of: a == 10

  ** modify two variables using one single constant
  let x, y := 10.5;

  ** modify two variables using two constants
  let q, p := True, False;

  ** swapping two variables
  let p, q := q, p;
return;

Type conversion

When data type mismatch you must perform explicit conversion.

Example:

** data conversion
rule main:
   new a:0, b:20 ∈ Z;
   new v:10.5, x:0.0 ∈ R;
** explicit conversion
   let a:=v :> N;
   print a; -- truncated to 10
** explicit conversion
   let x := b :> R;
   print x; -- expect 20.00
return;

Notes:

Alphanumeric type

Bee define A as single UTF-8 code point with representation: U+HH


rule main:
  new a, b ∈ A; -- ASCII
  new x, y ∈ B; -- Binary integer
  let a :='0';     -- ASCII symbol '0'
  let x := a :> B; -- convert to binary 30
  let y := 30;     -- decimal code for '0'
  let b := y :> A; -- convert to ASCII symbol '0'
return;

Type inference

You can use symbol ":=" to initialize variables using type inference.

** declare constants
set i := 4;   -- integer constant
set r := 2.5; -- real constant
set q := 1&\8; -- rational constant
** declare variables
new x := 0;   -- integer number
new y := 0.0; -- real number
new z := 0\1; -- rational number

Type checking

We can use variable type to validate expression type.

** using type inference
rule main:
  new a := 0;   -- integer variable
  new b := 0.0; -- real variable

  let a:= 10.5; -- error: explicit conversion is required
return;

You can use operator "∈" to verify data type:


rule main:
  new a := 0 ∈ Z;

  ** expected: Integer
  expect a ∈ Z;
return;

Boolean type

Boolean type is Bee is native numeric of type B. However we also implement native two constants True, False that are publicly available in core library


** overwrite the default values
set False = 0; 
set True  = 1; 

Printing native Boolean values is going to print numbers. Type B can support a number between 0b0 and 0b00000001. Therefore printing this type is done using notation 0b0 and 0b1.


** printing Boolean values
rule main:
  print False; -- 0b0
  print True;  -- 0b1
return;

You can convert B to a number, safely. You can convert a number to B explicit using cast operator: number :> B. The number will loose all it's significance and become 0b1 or 0b0.

Logic operations

Bee uses several familiar logic operators from mathematics:

Precedence: { ¬, ∧, ∨ }. Symbol ¬ will apply first, symbol ∨ will apply last.

bitwise

In Bee we define special operators to perform bitwise operations. One opperator is overwrite: ⊕. This operator (xor) can operate on both, logical values or expressions and also on integer numbers.

# bitwise operations
print 4 | 3; -- out:7 is because 100 | 011 = 111 = 7;
print ~4;    -- out:3 is because: 100 ~  100 = 011 = 3;
print 4 & 7; -- out:4 is because: 100 & 111 = 100 = 4;
print 4 ⊕ 4;  -- out:0 is because: 100 ⊕ 100 = 000 = 0;
print 1 << 2;  -- out:2 is because: 001 << 2   = 100 = 4;
print 6 >> 2;  -- out:1 is because: 110 >> 2   = 001 = 1;

Other operators

Comparison operators will create a Boolean response: 1 = True or 0 = False. Also, the equivalent and belonging operators will create a Boolean response. You can combine them to create Boolean expressions.

Example:


rule main:
  new (x, y):4 ∈  Z; -- primitive integer
  ** value comparison
  print x = 4;  -- 1 (equal)
  print x ≡ 4;  -- 1 (identical)
  print x = y;  -- 1 (equal)
  print x ≡ y;  -- 1
  print x ≠ 5;  -- 1 (different)
  print x!≡ 5;  -- 1 (not identical)

  ** reference ordering
  print x ≥ y;  -- 1: x and a are actually equal
  print x ≥ 4;  -- 1: greater or equivalent to 4
  print x ≤ 4;  -- 1: less than or equivalent to 4
  print x > 4;  -- 0: not greater than 4
  print x < 4;  -- 0: not less than 4


  ** arithmetic expressions have primitive results
  print x - 4 = 0; -- 1
  print x - 4 ≡ 0; -- 1
return;

singleton

Primitive types are unique. That means they are equivalent. A literal or constant is equivalent to another literal having the same value.

** primitive values are singleton
print  1  ≡  1;  -- 1
print "s" ≡ "s"; -- 1

** alternative operator have the same significance
print  1  == 1;  -- 1
print "s" == "s"; -- 1

Precedence:

Logic operators have greater precedence than comparison operators.

Logical expression

Logical expression have value { 0 = False, 1 = True }


** define constants based on Boolean values
set f: False;
set t: True;

rule main:
  ** expressions with single operant
  print f; -- 0
  print ¬ t; -- 0

  ** expressions with two operands
  print (f = t); -- 0
  print (f ≡ t); -- 0
  print (f ≠ t); -- 1
  print (f < t); -- 1
  print (f > t); -- 0
  print (f ∧ t); -- 0
  print (f ∨  t); -- 1
  print (f ⊕ t); -- 1
return;

Notes:

coercion Any numeric expression can be converted to a logic value using coercion operator ":>" (easy to memorize if you think is like an arrow).


set (a: 0.0, b: 1.5) ∈ R;
rule main:
  new (x, y) ∈ B;

  let x := a :> B; -- 0
  let y := b :> B; -- 1
return;

Notes:

design

** logical values are numeric
print True  ≡ 1;  -- 1
print False ≡ 0;  -- 1

** logical values do not compute
print False - True; -- Error
print True  + True; -- Error

** Null value is not True
print Null  ≡ True   -- 0
** Null value is not False
print Null  ≡ False  -- 0

Type inference

Type inference is a logical deduction of data type from constant literals.

Page bookmarks:

Default types

Each literal has associated a default type, induced by operators {":=", "::"}.

** string expressions
new c := 'a'     ;  -- type = A
new s := '∈'    ;  -- type = U
new s := "str"   ;  -- type = S
** numeric expressions
new i := 0;    -- type = Z
new j := 0.50; -- type = R
** define synonyms for logic constants
set f := False; -- type B
set t := True;  -- type B
** multiple variables get same value
new (x, y, z) := 5; -- type = Z for all
** multiple variables get multiple values
new int, rea := -4, 4.44;
print type(int); -- Z
print type(rea); -- R

Composite Types

Composite structures are using () [] and {} to create different data types. Next you can study some examples. We wil explain later all these types: List, Map, Array, Object. All of these are also called Bee collections.

** boxed integer (type = Z)
new i := [10]; -- array of one value = 10!
** array with capacity of 4 integers: Z
new d := [1,2,3,4];
** array with capacity of 10 real numbers: R = 0.00
new e := [0.00](10);
** list of one value (Z)
new a := (1);
** list of integers (Z)
new b := (1,2);
** list of symbols (type = A)
new l := ('a','b');
** list of Unicode symbol (type = U)
new u := ("Δ", "Λ", "Γ");
** 2d matrix with capacity of 10x10 real numbers: R
new m := [0.00](10,10);
** 3d matrix with capacity of 10x10x10 reals: R = 0.00
new m := [0.00](10,10,10);
** data set of 4 integers: Z
new s := {1,2,3,4};
** hash map of (Integer: String)
new c := {1:"storage",2:"string"};
** object with two attributes: name ∈ S, age ∈ Z
new b := {name:"Goliath", age:30};

Parameter types

When we define parameters we can use type inference only for optional parameters. Mandatory parameters must have type declaration using ∈ symbol. If default value is not specified the parameter will have defailt zero initial value.

Optional Parameters:

** in rule foo, parameters a, b are optional.
rule foo(a: 0 ∈ Z, b: 0 ∈ Z) => (r ∈ Z):
  let r := a + b;
rule;

rule main:
  print foo();    -- 0
  print foo(1);   -- 1
  print foo(1,2); -- 3
return;

Multiple parameters:

** parameters: a, b are mandatory, c is optional.
rule foo(a, b, c:0 ∈ Z) => (r ∈ Z):
  let r := a + b + c;
return;

rule main:
  print foo(1,2);   -- 3
  print foo(1,2,3); -- 6
  print foo(1);     -- Error: expected 2 arguments
return;

Pass arguments by name:

We can use parameter name and pair-up symbol ":" for argument value.

** rule with optional parameter (c)
rule bar(a, b, c:0 ∈ Z) => (result ∈ Z):
  let result := a+b+c;
return;
** observe we use pair-up ":" to give value for each argument
rule main:
  print bar( 1, 1 );    -- print 2 because c = 0
  print bar( a:1, b:1, c:1 ); -- print 3 because c = 1
return;  

Rational numbers

In mathematics rational number is any number that can be expressed as the fraction p/q of two integer numbers: numerator "p" of type integer and a non-zero denominator "q" of type natural> 0.
Since "q" may be equal to 1, every binary integer is also a rational number.

Note: Q numbers are approximated numbers.

Other precision constants:

Literal Notation: p\q

It can be used with type inference to create Q numbers:

Example:


new x: 0     ∈ Q; -- 0
new a: 1\2   ∈ Q; -- 0.5
new b: 1\4   ∈ Q; -- 0.25
new c: 1\8   ∈ Q; -- 0.125
new d: 1\16  ∈ Q; -- 0.062
new e: 1\32  ∈ Q; -- 0.031

Note:

See also: wikipedia

Q Notation

Evaluation or rational number has a magnitude and precision defined by the user. Q numbers are defined using "fixed point arithmetic" This is a way of computing fractional numbers and control the precision.

For example: Number format "Q5.2" can store in range (-32.00..31.75) on 8 bits.


new v ∈ Q5.2;
let v := -32;   -- minim value
let v := 31.75; -- maxim value

See also: wikipedia

Typical Q numbers

Next I have predefined some numbers for orientation.

rezolution -> 1\4 ≈ 1\8 ≈ 1\16 ≈ 1\32 ≈ 1\64 ≈
↓ memory space ±0.25 ±0.125 ±0.062 ±0.031 ±0.015
8 bytes Q(5.2 ) Q(4.3 ) Q(3.4 ) Q(2.5 ) Q(1.6 )
16 bytes Q(13.2 ) Q(12.3 ) Q(11.4 ) Q(10.5 ) Q(9.6 )
32 bytes Q(29.2 ) Q(28.3 ) Q(27.4 ) Q(26.5 ) Q(25.6 )
64 bytes Q(61.2 ) Q(60.3 ) Q(59.4 ) Q(58.5 ) Q(56.6 )
128 bytes Q(125.2) Q(124.3) Q(123.4) Q(122.5) Q(121.6)

Note: r ≈ is the approximate resolution.

Examples:

A very large number with high resolution on 64 bit:

Q(50.12)

A number on 32 bit with resolution = 0.0005:

Q(20.11)

Default Q number

Q(14.17)

Bee is using default Q type for type inference, when precision is not specified. Default Q number has precision 10⁻⁵ = 2⁻¹⁷ ≈ 0.00001 and occupy 32 bit. It's a relative small number. For larger numbers you must specify the resolution and capacity.

Range:

Fraction:

Approximate comparison

Rational numbers and other numbers can be compared using "≈" instead of "=". Bee can be used to make aproximative computations and logic expressions based on precision.

Example:

In next example b = 0.33(3), delta = (b - a) = 0.083

** override default precision
set $precision := 0.01;

rule main:
    new a := 0.25; -- real
    new b := 1\3;  -- rational O.33(3)
    ** using specified precision 0.01
    print (a ≈ b); -- 0B0: (False, 0.033 - 0.25 = 0.08 )

    ** using specified precision:
    print (a ≈ b ± 0.01);  -- 0b0 (False)     
    print (a ≈ b ±  0.05); -- 0b0 (False)    
    print (a ≈ b ±  0.10); -- 0b1 (True)
return

Notes:

Conversion

Rational numbers are similar to complex numbers. The calculation of rational number is postponed until is necesary in expressions and it can produce different results depending on the precision.

** execute conversion
rule main:
    new a := 0.25; -- real
    new b := 1\4;  -- rational

    ** explicit conversion R :> Q
    expect a ≠ b; -- not equal, type mismatch
    expect a ≈ b; -- values match, aproximation
    expect a ≡ b; -- implicit conversion, match

    ** explicit conversion R :> Q
    new c := a :> Q; 
    expect c = b; -- type & value match
    expect c ≡ b; -- type & value match

    ** implicit conversion Q :> R
    new r := c ∈ R;
    expect c = 0.25;
return

Read next: Control