Bee Functions

Bee is a functional programming language. Bee enable functional programming using lambda expressions. These are arithmetic expressions that can make a computation and return a result.

Lambda expressions

A lambda expressions can have parameters and results. Lambda expressions can be used to create functions. Lambda expressions do not have a local scope.

Syntax:

-- declaration of Lambda expressions
new name := λ(p1 ∈ Type,...) => (expression) ∈ ResultType;

Example:

-- define lambda expression
new exp := λ(x,y ∈ Z) => x^y ∈ Z;

-- use introspection
print type(exp); -- L;

-- use the lambda expression
new z := 2 * exp(2,3);

-- verify the result
expect z = 16; -- will pass
print z; 

Properties:

Lambda Expressions...

  • are similar to mathematical functions;
  • can be used in other expressions;
  • can be used as arguments for call-back;
  • can be created from a rule as a result;
  • can be assigned to variables of type: L;

result:

  • lambda expressions can produce one single result;
  • result type must be specified but not the result name;
  • result is temporary and can be used in other expressions;

Purity invariants

To guarantee mathematical referential transparency, compiler SIMD vectorization, and thread safety, lambda expressions operate under four strict invariants:

  1. Statelessness: Lambdas CANNOT declare local state variables (new, let, alter) or maintain persistent static memory.
  2. Referential transparency: Given the same arguments, a lambda MUST return the exact same output without relying on global mutable state or system clocks.
  3. Side-effect isolation: Lambdas CANNOT perform I/O operations (print, write, file access) or mutate outer variables.
  4. Rule isolation: A rule CAN call a lambda; a lambda CANNOT call a rule. This prevents side-effects from creeping into mathematical expressions.

Lambda type

Lambda expressions have a special type: "L", that is a reference. This type can be used to define variables, collection elements or parameters that require a lambda expression;

Demo use-case

In next example we create a dictionary of expressions then we call every expression in the dictionary by string ID. This is a trick useful to parse a specific formula that comes as a string. You can use this trick for example to implement custom domain specific expressions.


-- instantiate 3 Lambda expressions
new gt := λ(x, y ∈ Z) => (x > y) ∈ B;
new lt := λ(x, y ∈ Z) => (x < y) ∈ B;
new eq := λ(x, y ∈ Z) => (x = y) ∈ B;

-- define a sub-type, dictionary of rules
type Dic: {[A]: L;} <: Map;

-- define a hash map of expressions
new dic := {'gt':gt,'lt':lt,'eq':eq} ∈ Dic;
-- call 3 rules in very unusual way
print dic['gt'](3,1); -- 1
print dic['lt'](1,2); -- 1
print dic['eq'](2,2); -- 1

Call-back functions

Lambda expressions become call-back functions when used as arguments for specific rules that require lambda expressions. The function is executed later in the rule. Lambda function signature is required to define the parameter.

Example


rule foo(a1, a2 ∈ N, xp: λ(x,y ∈ N) => R) => (r ∈ R):
   -- prepare the result
   let r := xp(a1,a2);
return;

rule main:
   -- call foo using anonymous expression
   print foo(2,3,(x,y)=> x^y); -- 8.0
   print foo(2,3,(x,y)=> x*y); -- 6.0
   print foo(2,3,(x,y)=> x/y); -- 1.5 
return

Note: A lambda function can't call a rule. Just a rule can call a lambda function. This prevent a lambda function to modify states and it remain pure.

Partial application

A lambda call may place the single-character ? placeholder in any argument position. The result is a partial application: the provided arguments are captured, and the open positions are filled when the partial is later invoked, left to right.

Example

-- x captured as 5, y left open
new add := &lambda;(x, y &isin; Z) => (x + y) &isin; Z;
new add5 := add(5, ?);
expect add5(3) = 8;  -- 3 fills y, so 5 + 3 = 8

A partial application is a first-class value (type L) and can be stored and reused like any lambda.

Immediately-invoked lambda expressions (IIFE)

A lambda expression may be defined and invoked in the same statement: write the lambda literal inline and follow it immediately with a call list. This is useful for a one-off pure transformation that does not need a name.

Syntax:

-- define an anonymous lambda and call it right away
new result := λ((x,y) => x + y)(10,20); -- 30
expect result = 30; -- pass

Example:

rule main:
  -- one-off pure transformation, no binding needed
  new total := λ((a,b) => a * b)(6,7);
  expect total = 42; -- will pass
return;

Properties:

  • the full λ form is required before the parameter list;
  • an IIFE results in a value, not a lambda reference — it is not stored as type L;
  • the purity invariants apply unchanged: the body stays stateless, side-effect free, and cannot call a rule.

SIMD & GPU auto-vectorization

Because lambdas are guaranteed pure and side-effect free, the Bee compiler automatically parallelizes collection map operations over vector domains:

  • SIMD auto-vectorization: Single Instruction Multiple Data instructions (e.g. AVX-512) process array items in parallel chunks.
  • GPU kernel offloading: High-throughput lambda operations applied over large collection domains are automatically lowered into native OpenCL / GPU compute pipelines.

Method-call dispatch (technical debt)

x.type() is the canonical way to query a value's runtime type. Its grammar is identical to a function call, but the receiver is namespaced by . and the method lookup table is derived from the type's declared method descriptors (see spec/06-objects.md §5). This entry remains in technical debt until the MethodCallExpression AST node is implemented (test reference test/debt/T0126-method-call.bee).

Diagnostic error codes

Diagnostic codes raised by the Functions module (spec/07 §7):

CodeConditionDescription
E0701RuleCallInLambdaLambda expression attempts to invoke a stateful rule.
E0702SideEffectInLambdaLambda contains I/O statement or variable mutation.
E0703LambdaTypeMismatchPassed lambda signature does not match expected parameter L.
E0704UnboundLambdaVariableLambda references outer variable that is not in scope.
E0705StateDeclarationInLambdaAttempt to use new, let, or alter inside a lambda.