Basics
Variables
Variables store values that can be reused throughout your BAML code. Use let
to declare variables:
// A global variable
let poem_subject = "Math";
// Another global variable
let default_poem = ClaudePoem(poem_subject);
Variables can store any value type and can reference function calls or other variables.
They can not be changed after they are defined.
Mutable Variables
Use let mut
to declare mutable variables:
// A global variable
let mut signups: string[] = [];
function AddBert() {
signups.push("Bert")
}
It works inside functions & blocks, too:
function GetSignups() -> string[] {
let mut signups: string[] = [];
signups.push("Bert");
signups
}
Use mut
to declare an argument as mutable:
function AddBert(mut signups: string[]) -> string[] {
signups.push("Bert")
signups
}
Comments
Comments explain your code and are ignored during execution:
// Single line comment
Data Types
Basic data types
BAML supports several fundamental data types:
let msg: string = "Hello world"; // String
let answer: int = 42; // Integer
let pi: float = 3.14; // Float (not shown in example but supported)
let exists: bool = true; // Boolean
Strings are enclosed in double quotes, integers are whole numbers, and booleans are true
or false
.
Arrays
Arrays store ordered collections of elements of the same type:
let numbers: int[] = [1, 2, 3, 4, 5];
let names: string[] = ["Alice", "Bob", "Charlie"];
let empty: float[] = [];
// Access elements by index
let first = numbers[0]; // 1
let second = names[1]; // "Bob"
Arrays use square brackets and are zero-indexed.
Maps
Maps store key-value pairs with string keys:
let scores: map<string, int> = {
"math": 95,
"science": 87,
"english": 92
};
// Access values by key
let mathScore = scores["math"]; // 95
Maps use curly braces with quoted string keys.
Optional types
Optional types represent values that may or may not be present:
let maybe_name: string? = "Alice";
let maybe_age: int? = null;
// Check if optional has a value
if (maybe_name != null) {
print("Name is: " + maybe_name);
}
Optional types are denoted with ?
after the type name and can hold either a value or null
.
Tuples
Tuples store fixed-size collections of values with different types:
let point: (int, int) = (10, 20);
let person: (string, int, bool) = ("Alice", 30, true);
// Access tuple elements
let x = point.0; // 10
let y = point.1; // 20
let name = person.0; // "Alice"
let age = person.1; // 30
Tuples use parentheses and access elements with dot notation and index numbers.
Nested structures
You can combine different compound types to create complex data structures:
let team: string[][] = [
["Alice", "Engineer"],
["Bob", "Designer"],
["Charlie", "Manager"]
];
let user_scores: map<string, int[]> = {
"alice": [95, 87, 92],
"bob": [88, 90, 85],
"charlie": [92, 94, 89]
};
// Mixed compound types
let complex: (string, int[], map<string, bool>) = (
"project",
[1, 2, 3],
{"active": true, "published": false}
);
Classes
Class definitions
Classes allow you to define your own structured data types with named fields:
class Todo {
id int
todo string
completed bool
userId int
}
class Comparison {
poem_1_score int @description("1-10 rating of the first poem's quality")
poem_2_score int @description("1-10 rating of the second poem's quality")
reasoning string @description("Reasons for the above scores, explicitly contrasting the poems.")
}
Classes can include:
- Field names and types
@description
annotations for documentation
Class usage
Use classes as parameter and return types in functions:
class Todo {
id int
todo string
completed bool
userId int
}
function Completed(
t: Todo
) -> Todo {
Todo {
completed: true,
..t
}
}
function TodoContents(t: Todo) -> String {
// Access fields of a class like this:
t.todo
}
Functions
Defining functions
Define a function with the function
keyword, a list of typed
parameters, a return type, and a function body.
function Ten() -> int {
10
}
function Pair(i: int) -> int[] {
[i, i]
}
Function calls
Call functions by name with arguments in parentheses:
function RunPoemFaceoff(
subject: string,
length: int
) -> Comparison {
let poem1 = ClaudePoem(subject, length);
let poem2 = OpenAIPoem(subject, length);
ComparePoems(subject, poem1, poem2)
}
Functions can call other functions and use variables within their scope.
Built-in functions
BAML provides built-in functions for common operations:
function GetTodo() -> Todo {
std::fetch_value<Todo>(std::Request {
base_url: "https://dummyjson.com/todos/1",
headers: {},
query_params: {},
})
}
The std::fetch_value
function makes HTTP requests to external APIs.
Flow Control
For loops
Iterator for loops
For loops iterate over a collection of values. Currently only arrays are supported:
let names = ["Pete", "Bob", "Sam"];
for name in names {
print(name)
}
Like while
loops, for
loops also support continue
and break
control flow modifiers:
let numbers = [5, 10, 2, 0, 3];
let mut sum = 0;
for num in numbers {
if num > 10 {
continue;
}
if num < 2 {
break;
}
sum += num;
}
print(sum)
C-like for loops
You can also use the traditional c-like for
loop, specially handy
when part of the loop must be run on continue
:
let names = ["Pete", "Bob", "Sam"];
for (let mut i = 0; i < names.len(); i += 1) {
print(name[i])
}
While loops
While loops continue executing as long as a condition is true:
let mut count = 0;
while count < 5 {
print(count);
count = count + 1;
}
continue
and break
statements are supported:
while true {
let input = getUserInput();
if input == "quit" {
break;
}
if input == "hello" {
sayHello();
continue;
}
}
While loops check the condition before each iteration.
Break & Continue
While loops support break
and continue
statements:
let mut x = 0;
while x < 10 {
x += 1;
if x == 9 {
continue;
}
x += 1;
let randomNumber = GetRandom(x);
if randomNumber % 10 == 0 {
break;
}
}
If statements
If statements execute code conditionally:
if (age >= 18) {
print("Adult");
}
if (score >= 90) {
print("A grade");
} else if (score >= 80) {
print("B grade");
} else if (score >= 70) {
print("C grade");
} else {
print("Below C");
}
Nested control flow
You can combine different control flow statements:
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
print("Even: " + i);
} else {
print("Odd: " + i);
}
}
let mut x = 0;
while (x < 100) {
if (x % 10 == 0) {
print("Milestone: " + x);
}
x = x + 1;
}
You can use continue
and break
inside your loops: