A Comprehensive Guide for Beginners and Developers
Version 7.1.0 - Production Ready
- Introduction
- Getting Started
- Your First Zixir Program
- Understanding Variables and Types
- Working with Data
- Operators and Expressions
- Control Flow
- Functions
- Pattern Matching
- Engine Operations (Zig NIFs)
- Python Integration
- Real-World Project 1: Data Processing Pipeline
- Real-World Project 2: AI Text Analysis
- Real-World Project 3: LLM Integration
- Real-World Project 4: Workflow Automation
- Best Practices
- Debugging Guide
- Complete Grammar Reference
- Quick Reference Card
- Appendix: Common Patterns
Zixir is a modern, expression-oriented programming language designed specifically for AI automation and development workflows. Unlike traditional languages that require you to write dozens of lines of boilerplate code, Zixir lets you express complex operations in just a few lines.
Zixir is unique because it combines three powerful technologies:
- Elixir - The orchestrator that manages everything
- Zig - The high-performance engine for math and data operations (10-100x faster)
- Python - Access to the world's largest library ecosystem
Think of it like a supercar: Elixir is the driver, Zig is the engine, and Python is the toolkit in the trunk.
Before Zixir:
# Python only - verbose and slow for math
import numpy as np
import json
data = [1.0, 2.0, 3.0, 4.0, 5.0]
mean = np.mean(data)
std = np.std(data)
result = json.dumps({"mean": mean, "std": std})With Zixir:
let data = [1.0, 2.0, 3.0, 4.0, 5.0]
{"mean": engine.list_mean(data), "std": engine.list_std(data)}
- Complete beginners: No programming experience required
- Python/JavaScript developers: Learn Zixir's unique features
- AI/ML engineers: Build automation workflows faster
By the end of this guide, you'll be able to:
- Write complete Zixir programs
- Process data using high-performance engine operations
- Call Python libraries seamlessly
- Build real AI automation workflows
- Debug and optimize your code
Before we begin, it's important to understand Zixir's current capabilities:
What Works Great:
- ✅ All primitive types (Int, Float, Bool, String)
- ✅ Arrays and array operations (indexing,
length,head,tail,push,reverse,range) - ✅ Maps and map indexing (
user["name"],keys(),values()) - ✅ All operators and expressions (including modulo
%) - ✅ 25+ built-in functions (
length,print,to_string,type_of,split,join,upper,lower,trim,abs,min,max,parse_int,parse_float,contains,reverse,range,head,tail,push,keys,values) - ✅ Functions (simple, recursive, closures, lambdas)
- ✅ Pattern matching
- ✅ If/else expressions
- ✅ Pipe operator (
|>) for chaining function calls - ✅ Engine operations (22 high-performance Zig NIF operations)
- ✅ Python FFI (module-level functions)
Current Limitations:
⚠️ Loops: While/for loops work but don't support variable accumulation across iterations (by design — Zixir is immutable). Use recursion or engine operations instead.⚠️ Python Methods: Only module-level functions work (e.g.,math.sqrt), not object methods (e.g.,str.lower)
Recommended Approach:
- Use pipe operator (
|>) to chain transformations cleanly - Use built-in functions for common operations (
length,to_string,print,split,join, etc.) - Use map indexing for key-value access (
user["name"]) - Use engine operations for bulk data processing (fastest)
- Use Python FFI for complex operations and external libraries
- Use recursion or engine operations instead of imperative loops with accumulation
macOS:
brew install elixirUbuntu/Debian:
wget https://packages.erlang-solutions.com/erlang-solutions_2.0_all.deb
sudo dpkg -i erlang-solutions_2.0_all.deb
sudo apt-get update
sudo apt-get install esl-erlang elixirWindows: Download and run the installer from: https://elixir-lang.org/install.html
Verify installation:
elixir --versionExpected output (version numbers may vary):
Erlang/OTP 25 [erts-13.0] [source] [64-bit] [smp:8:8]
Elixir 1.14.0 (compiled with Erlang/OTP 25)
Zixir can call Python libraries, but Python is optional if you only use engine operations.
macOS:
brew install pythonUbuntu/Debian:
sudo apt-get install python3 python3-pipWindows: Download from https://www.python.org/downloads/
Verify:
python3 --version# Clone the repository
git clone https://github.com/Zixir-lang/Zixir.git
cd Zixir
# Install dependencies
mix deps.get
# Compile the project
mix compile
# Run tests (optional, takes a few minutes)
mix test# Start the REPL
mix zixir.replYou should see:
Welcome to Zixir REPL v7.1.0
Type :help for help, :quit to exit
zixir>
The REPL (Read-Eval-Print Loop) is your interactive playground. Let's explore:
zixir> 42
42
zixir> "Hello, Zixir!"
"Hello, Zixir!"
zixir> :help
REPL Commands:
:help - Show this help message
:quit, :q - Exit the REPL
:clear - Clear the screen
:vars - Show defined variables
:engine - List available engine operations
:reset - Clear all variables
zixir> :quit
Goodbye!
Type this in the REPL:
zixir> "Hello, World!"
"Hello, World!"
What just happened?
- You typed a string literal
- Zixir evaluated it
- It returned the string (which is also the value)
- The REPL printed the result
Add explanations to your code:
# This is a comment - Zixir ignores it
let greeting = "Hello" # Comments can be at the end of lines too
zixir> 10 + 20
30
zixir> 100 / 4
25.0
zixir> 5 * 5
25
Type these in the REPL and observe the results:
1. 15 + 27
2. 100 - 33
3. 7 * 8
4. 81 / 9
5. "Hello" (just a string)
Questions to think about:
- What type of number do you get from division? (Hint: It has a decimal)
- What happens when you just type a string?
Variables are like labeled boxes that store values. In Zixir, we use let to create a variable:
let age = 25 # A box labeled "age" containing 25
let name = "Alice" # A box labeled "name" containing "Alice"
let pi = 3.14159 # A box labeled "pi" containing 3.14159
Important: Once you put a value in the box with let, you can't change it. This is called immutability.
Immutability makes your code safer and easier to understand:
# Without immutability (other languages)
let x = 5
x = 10 # Wait, what was x before? Did something else change it?
# With Zixir
let x = 5
# x will ALWAYS be 5 in this scope
# If you need a new value, create a new variable
let new_x = 10
Zixir has several built-in types:
Whole numbers without decimals:
let age = 25
let year = 2024
let negative = -10
let big_number = 1000000
Numbers with decimal points:
let pi = 3.14159
let price = 19.99
let temperature = -5.5
let scientific = 1.5e10 # 1.5 × 10^10 = 15000000000
Text enclosed in double quotes:
let greeting = "Hello, World!"
let name = "Alice"
let empty = ""
let with_numbers = "Room 101"
String operations:
let first = "Hello"
let second = "World"
let combined = first ++ " " ++ second # "Hello World"
True or false values:
let is_valid = true
let is_complete = false
Used for conditions and logic.
Ordered collections of values:
let numbers = [1, 2, 3, 4, 5]
let names = ["Alice", "Bob", "Charlie"]
let mixed = [1, "two", 3.0, true] # Can mix types
let empty = []
Accessing array elements:
let fruits = ["apple", "banana", "cherry"]
let first = fruits[0] # "apple" (arrays start at 0)
let second = fruits[1] # "banana"
let last = fruits[2] # "cherry"
Key-value pairs (like dictionaries):
let person = {
"name": "Alice",
"age": 30,
"city": "New York"
}
# Access map values with bracket indexing
let name = person["name"] # "Alice"
let age = person["age"] # 30
let city = person["city"] # "New York"
Map operations using built-in functions:
let user = {"name": "Alice", "role": "admin"}
let all_keys = keys(user) # ["name", "role"]
let all_values = values(user) # ["Alice", "admin"]
While Zixir figures out types automatically, you can add annotations for clarity:
let age: Int = 25
let name: String = "Alice"
let price: Float = 19.99
let items: [Int] = [1, 2, 3, 4, 5]
When to use annotations:
- Function parameters and return types (recommended)
- Complex data structures
- When you want to be explicit about types
For values that never change (like mathematical constants):
const PI = 3.14159
const MAX_USERS = 100
const APP_NAME = "MyApp"
Constants are evaluated at compile time for better performance.
# 1. Create variables for:
# - Your name (String)
# - Your age (Int)
# - Your height in meters (Float)
# - Whether you like programming (Bool)
# 2. Create an array of your favorite foods
# 3. Create a map representing a book with title, author, and year
# 4. Try to change a variable (it should fail!)
# let x = 5
# let x = 10 # Error!
Mistake 1: Using single quotes
let wrong = 'hello' # Error! Use double quotes
let right = "hello" # Correct
Mistake 2: Forgetting quotes around strings
let wrong = hello # Error! Zixir thinks hello is a variable
let right = "hello" # Correct
Mistake 3: Array index out of bounds
let arr = [1, 2, 3]
let x = arr[10] # Error! Index 10 doesn't exist (only 0, 1, 2)
Arrays are ordered lists that can grow or shrink.
Creating arrays:
let numbers = [10, 20, 30, 40, 50]
let empty = []
let nested = [[1, 2], [3, 4], [5, 6]] # Array of arrays
Getting the length:
let items = ["a", "b", "c"]
let count = length(items) # 3
Common array patterns:
# Get first and last
let arr = [10, 20, 30, 40, 50]
let first = arr[0]
let last = arr[length(arr) - 1] # 50 (dynamic last element)
# Slice (subset of array)
let middle = [arr[1], arr[2], arr[3]] # [20, 30, 40]
Maps store data as key-value pairs.
Creating maps:
let user = {
"id": 1,
"username": "alice",
"email": "alice@example.com",
"active": true
}
Accessing values:
let username = user["username"] # "alice"
let email = user["email"] # "alice@example.com"
Nested maps:
let company = {
"name": "TechCorp",
"address": {
"street": "123 Main St",
"city": "New York",
"zip": "10001"
},
"employees": 50
}
let city = company["address"]["city"] # "New York"
Working with Maps:
let user = {
"name": "Alice Johnson",
"age": 28,
"email": "alice@example.com"
}
# Access values with bracket indexing
let name = user["name"] # "Alice Johnson"
let age = user["age"] # 28
let email = user["email"] # "alice@example.com"
# Get all keys and values
let all_keys = keys(user) # ["name", "age", "email"]
let all_values = values(user) # ["Alice Johnson", 28, "alice@example.com"]
let size = length(user) # 3
Zixir uses bracket notation for both array and map access:
| Target | Syntax | Index/key | Result |
|---|---|---|---|
| Array | arr[i] |
Integer, zero-based | Element at position i; error if out of bounds |
| Map | map["key"] |
Any value (often string) | Value for key, or nil if key missing |
Array indexing: Zero-based and bounds-checked. Use a variable (or expression) on the left: let arr = [1, 2, 3] then arr[0]. Last element: arr[length(arr) - 1].
Map indexing: user["name"] returns the value or nil if the key is missing. Nested: company["address"]["city"].
let arr = [10, 20, 30]
arr[0] # 10
let m = {"a": 1, "b": 2}
m["a"] # 1
m["missing"] # nil
Zixir provides built-in functions for type conversion:
# Number to string
let num = 42
let num_str = to_string(num) # "42"
let pi_str = to_string(3.14) # "3.14"
let bool_str = to_string(true) # "true"
# String to number
let parsed_int = parse_int("42") # 42
let parsed_float = parse_float("3.14") # 3.14
# Check types at runtime
let t = type_of(42) # "Int"
let t2 = type_of("hello") # "String"
let t3 = type_of([1, 2, 3]) # "Array"
Maps make it easy to work with structured data:
# Store user profiles as maps
let user = {
"name": "Alice",
"age": 28,
"email": "alice@example.com"
}
# Access fields with bracket indexing
let name = user["name"] # "Alice"
let age = user["age"] # 28
# Build a summary string
let summary = "User " ++ name ++ " is " ++ to_string(age) ++ " years old"
print(summary) # "User Alice is 28 years old"
# Result: "User Alice is 28 years old"
Alternative: Use a map and access via Python:
let user = {"name": "Alice", "age": 28}
let name = python "operator" "getitem" (user, "name")
let age = python "operator" "getitem" (user, "age")
# 1. Create an array of temperatures for a week: [72, 75, 68, 70, 74, 76, 73]
# Calculate the average temperature
# 2. Create parallel arrays for a product:
# - product_names (Array of Strings)
# - product_prices (Array of Floats)
# - product_stock (Array of Bools)
# Calculate the average price of in-stock products
# 3. Create arrays for a library system:
# - book_titles (Array of Strings)
# - book_authors (Array of Strings)
# - book_years (Array of Ints)
# Find the oldest book year using engine.list_min
| Operator | Description | Example | Result |
|---|---|---|---|
+ |
Addition | 5 + 3 |
8 |
- |
Subtraction | 10 - 4 |
6 |
* |
Multiplication | 6 * 7 |
42 |
/ |
Division | 15 / 3 |
5.0 |
% |
Modulo (remainder) | 10 % 3 |
1 |
- |
Negation | -5 |
-5 |
Important: Division always returns a Float, even if the result is a whole number. Modulo returns an integer when both operands are integers.
10 / 2 # 5.0 (Float)
10 / 3 # 3.3333333333 (Float)
10 % 3 # 1 (remainder)
17 % 5 # 2
| Operator | Description | Example | Result |
|---|---|---|---|
== |
Equal to | 5 == 5 |
true |
!= |
Not equal to | 5 != 3 |
true |
< |
Less than | 3 < 5 |
true |
> |
Greater than | 7 > 4 |
true |
<= |
Less than or equal | 5 <= 5 |
true |
>= |
Greater than or equal | 6 >= 5 |
true |
let age = 25
let is_adult = age >= 18 # true
let is_senior = age >= 65 # false
let is_exactly_25 = age == 25 # true
| Operator | Description | Example | Result |
|---|---|---|---|
&& |
And | true && false |
false |
| ` | ` | Or | |
! |
Not | !true |
false |
let is_weekend = true
let is_sunny = true
let can_go_park = is_weekend && is_sunny # true
let has_coffee = true
let has_tea = false
let has_drink = has_coffee || has_tea # true
let is_raining = true
let not_raining = !is_raining # false
Truth table:
A B A && B A || B !A
--------------------------------------
true true true true false
true false false true false
false true false true true
false false false false true
let first = "Hello"
let second = "World"
let combined = first ++ " " ++ second # "Hello World"
let name = "Alice"
let greeting = "Hello, " ++ name ++ "!" # "Hello, Alice!"
Just like in math, some operations happen before others:
1. Parentheses: ( )
2. Unary: -, !
3. Multiplication/Division/Modulo: *, /, %
4. Addition/Subtraction: +, -
5. Comparison: <, >, <=, >=
6. Equality: ==, !=
7. Logical AND: &&
8. Logical OR: ||
9. Pipe: |> (lowest precedence)
# Without parentheses
5 + 3 * 2 # 11 (not 16) - multiplication first
# With parentheses
(5 + 3) * 2 # 16 - addition first
# Complex expression
10 + 5 * 2 > 15 && 4 < 8
# Step 1: 5 * 2 = 10
# Step 2: 10 + 10 = 20
# Step 3: 20 > 15 = true
# Step 4: 4 < 8 = true
# Step 5: true && true = true
# Calculate final price with tax
let price = 100.0
let tax_rate = 0.08
let discount = 10.0
let subtotal = price - discount
let tax = subtotal * tax_rate
let total = subtotal + tax
# Calculate average
let scores = [85, 92, 78, 96, 88]
let sum = scores[0] + scores[1] + scores[2] + scores[3] + scores[4]
let average = sum / 5
# Check if a number is in range
let x = 50
let min = 10
let max = 100
let in_range = x >= min && x <= max # true
# 1. Calculate the area of a rectangle (length * width)
# length = 10, width = 5
# 2. Check if a temperature is comfortable (between 68 and 72)
# temp = 70
# 3. Create a boolean expression for:
# "User can access if they are admin OR (logged_in AND has_permission)"
# is_admin = false
# is_logged_in = true
# has_permission = true
# 4. String concatenation:
# Create the sentence "The temperature is 72 degrees"
# from "The temperature is ", 72, and " degrees"
Zixir provides a set of built-in functions for common operations. These are always available without imports.
| Function | Description | Example | Result |
|---|---|---|---|
print(args...) |
Print values to output | print("Hello", 42) |
"Hello 42" |
print("Hello, World!")
print("Value:", 42)
print("Sum:", 2 + 3)
| Function | Description | Example | Result |
|---|---|---|---|
to_string(val) |
Convert any value to string | to_string(42) |
"42" |
parse_int(str) |
Parse string to integer | parse_int("42") |
42 |
parse_float(str) |
Parse string to float | parse_float("3.14") |
3.14 |
type_of(val) |
Get the type name as string | type_of(42) |
"Int" |
let n = 42
let s = to_string(n) # "42"
let greeting = "Number: " ++ s # "Number: 42"
let parsed = parse_int("100") # 100
let t = type_of(parsed) # "Int"
| Function | Description | Example | Result |
|---|---|---|---|
length(val) |
Get length of array, string, or map | length([1,2,3]) |
3 |
head(list) |
Get first element | head([1,2,3]) |
1 |
tail(list) |
Get all elements except first | tail([1,2,3]) |
[2,3] |
push(list, val) |
Append element to array | push([1,2], 3) |
[1,2,3] |
reverse(val) |
Reverse array or string | reverse([1,2,3]) |
[3,2,1] |
contains(col, val) |
Check if collection contains value | contains([1,2,3], 2) |
true |
range(a, b) |
Generate array from a to b | range(1, 5) |
[1,2,3,4,5] |
keys(map) |
Get all keys from a map | keys({"a": 1}) |
["a"] |
values(map) |
Get all values from a map | values({"a": 1}) |
[1] |
let arr = [10, 20, 30, 40, 50]
let len = length(arr) # 5
let first = head(arr) # 10
let rest = tail(arr) # [20, 30, 40, 50]
let extended = push(arr, 60) # [10, 20, 30, 40, 50, 60]
let nums = range(1, 10) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let has_five = contains(nums, 5) # true
| Function | Description | Example | Result |
|---|---|---|---|
upper(str) |
Convert to uppercase | upper("hello") |
"HELLO" |
lower(str) |
Convert to lowercase | lower("HELLO") |
"hello" |
trim(str) |
Remove leading/trailing whitespace | trim(" hi ") |
"hi" |
split(str, sep) |
Split string by separator | split("a-b-c", "-") |
["a","b","c"] |
join(list, sep) |
Join array into string | join(["a","b"], "-") |
"a-b" |
reverse(str) |
Reverse a string | reverse("abc") |
"cba" |
contains(str, sub) |
Check if string contains substring | contains("hello", "ell") |
true |
length(str) |
Get string length | length("hello") |
5 |
let text = " Hello, World! "
let cleaned = trim(text) # "Hello, World!"
let shouted = upper(cleaned) # "HELLO, WORLD!"
let words = split(cleaned, " ") # ["Hello,", "World!"]
let joined = join(words, "-") # "Hello,-World!"
| Function | Description | Example | Result |
|---|---|---|---|
abs(n) |
Absolute value | abs(-5) |
5 |
min(a, b) |
Minimum of two numbers | min(3, 7) |
3 |
max(a, b) |
Maximum of two numbers | max(3, 7) |
7 |
let diff = abs(-10) # 10
let smaller = min(5, 3) # 3
let bigger = max(5, 3) # 5
The pipe operator |> passes the result of the left expression as the first argument to the function on the right. This lets you chain transformations in a readable, top-to-bottom style instead of nesting function calls.
# Without pipe (nested, reads inside-out)
upper(trim(" hello "))
# With pipe (reads left-to-right)
" hello " |> trim() |> upper() # "HELLO"
When the right-side function takes additional arguments, the piped value becomes the first argument:
fn add(a, b): a + b
10 |> add(5) # 15 (same as add(10, 5))
"hello world" |> contains("world") # true
# Clean and transform a string
" Hello World " |> trim() |> lower() |> length() # 11
# Convert and format
-42 |> abs() |> to_string() # "42"
All 25+ built-in functions work with pipes:
[3, 1, 2] |> reverse() # [2, 1, 3]
[1, 2, 3] |> length() # 3
42 |> type_of() # "Int"
"abc" |> upper() # "ABC"
Tip: The pipe operator has the lowest precedence, so
3 + 4 |> to_string()evaluates3 + 4first, then pipes7intoto_string().
Control flow lets your program make decisions and repeat actions.
The simplest form of decision-making:
if condition: result_if_true else: result_if_false
Basic example:
let age = 20
let status = if age >= 18: "adult" else: "minor"
# Result: "adult"
Without else:
let x = 10
let message = if x > 5: "big"
# Result: "big"
let y = 3
let message2 = if y > 5: "big"
# Result: null (nothing returned when condition is false and no else)
Multiple conditions with nesting:
let score = 85
let grade = if score >= 90: "A"
else: if score >= 80: "B"
else: if score >= 70: "C"
else: if score >= 60: "D"
else: "F"
# Result: "B"
Using logical operators:
let temp = 75
let is_sunny = true
let activity = if temp > 70 && is_sunny: "go to beach"
else: if temp > 70: "go for walk"
else: "stay inside"
Repeat while a condition is true:
while condition: {
# code to repeat
}
Simple while loop:
# While loops work with expressions that don't require assignment
let x = 5
while x > 0: x - 1
x # Returns: 5 (note: x is immutable, so this doesn't change x)
# For actual iteration, use recursion or engine operations
Important Note About Loops: Zixir is expression-oriented. While loops exist but work best with pure expressions. For iteration with state changes, use recursion or high-level engine operations.
Processing with engine operations (recommended):
let data = [10.0, 20.0, 30.0, 40.0, 50.0]
let sum = engine.list_sum(data) # 150.0
Iterate over each element in a collection:
for item in collection: expression
Important: For loops in Zixir evaluate expressions for side effects. They don't support variable assignment within the loop body for accumulation.
Basic iteration:
let fruits = ["apple", "banana", "cherry"]
# For loop evaluates expression for each item
for fruit in fruits: fruit # Returns last item: "cherry"
For calculations, use engine operations:
let numbers = [10.0, 20.0, 30.0, 40.0, 50.0]
let total = engine.list_sum(numbers) # 150.0
For transformations, use engine operations:
let numbers = [1.0, 2.0, 3.0, 4.0, 5.0]
let doubled = engine.map_mul(numbers, 2.0) # [2.0, 4.0, 6.0, 8.0, 10.0]
# Calculate average temperature for the week
let temperatures = [72.0, 75.0, 68.0, 70.0, 74.0, 76.0, 73.0]
# Use engine operations for calculations (fastest approach)
let sum = engine.list_sum(temperatures)
let count = 7 # Hardcoded: array has 7 elements
let average = sum / count # 72.571428...
# Find temperatures above average using engine.filter_gt
let hot_threshold = average + 0.001 # Slightly above average
let hot_temps = engine.filter_gt(temperatures, hot_threshold)
# Note: To count filtered results, use Python or hardcode based on data
let hot_days = 3 # 3 days were above average (calculated from data)
# Create a summary report
{
"temperatures": temperatures,
"average": average,
"hot_days_count": hot_days,
"hot_temperatures": hot_temps
}
Key Points:
- Use
engine.list_sum()for summing arrays - Use
engine.filter_gt()for filtering - Array length must be hardcoded or known beforehand
- Engine operations are 10-100x faster than loops
# 1. Temperature categorization
# Write a program that categorizes temperatures:
# - If temp >= 90, print "Hot"
# - If temp >= 70, print "Warm"
# - If temp >= 50, print "Mild"
# - Otherwise, print "Cold"
# Test with: [95, 82, 65, 45, 30]
# 2. Calculate factorial of 5 using a recursive function
# Hint: fn factorial(n): if n <= 1: 1 else: n * factorial(n - 1)
# 3. Find the maximum value in an array [45, 12, 78, 23, 67, 89, 34]
# Use engine.list_max
# 4. Use engine.filter_gt to find all temperatures above 75 degrees
# temps = [72.0, 78.0, 65.0, 80.0, 74.0, 76.0]
Functions are reusable blocks of code that perform specific tasks.
Without functions (repetitive):
# Calculate area of three rectangles
let area1 = 10 * 5
let area2 = 8 * 4
let area3 = 12 * 6
With functions (clean and reusable):
fn rectangle_area(width, height): width * height
let area1 = rectangle_area(10, 5)
let area2 = rectangle_area(8, 4)
let area3 = rectangle_area(12, 6)
Basic syntax:
fn function_name(param1, param2, ...): expression
Example:
fn greet(name): "Hello, " ++ name ++ "!"
# Call it
let message = greet("Alice") # "Hello, Alice!"
With type annotations (recommended):
fn add(a: Int, b: Int) -> Int: a + b
fn greet(name: String) -> String: "Hello, " ++ name
fn is_adult(age: Int) -> Bool: age >= 18
With block body (multiple statements):
fn calculate_bmi(weight: Float, height: Float) -> Float: {
let height_squared = height * height
weight / height_squared
}
fn add(a: Int, b: Int) -> Int: a + b
fn multiply(a: Int, b: Int) -> Int: a * b
# Call them
let sum = add(5, 3) # 8
let product = multiply(4, 7) # 28
# Chain function calls
let result = add(multiply(2, 3), 4) # 10
# Step 1: multiply(2, 3) = 6
# Step 2: add(6, 4) = 10
Variables inside a function are separate from outside:
let x = 10 # Outside variable
fn double(n: Int) -> Int: {
let x = n * 2 # This is a DIFFERENT x
x
}
let result = double(5) # 10
# x outside is still 10
- Parameters: Variables in function definition
- Arguments: Actual values passed when calling
fn greet(name: String, greeting: String) -> String: {
# name and greeting are PARAMETERS
greeting ++ ", " ++ name ++ "!"
}
# "Alice" and "Hello" are ARGUMENTS
let msg = greet("Alice", "Hello")
Functions without names, useful for quick operations:
let double = fn(x: Int) -> Int: x * 2
let triple = fn(x: Int) -> Int: x * 3
double(5) # 10
triple(5) # 15
Functions that call themselves:
fn factorial(n: Int) -> Int: {
if n <= 1: 1
else: n * factorial(n - 1)
}
factorial(5) # 120
# 5 * 4 * 3 * 2 * 1 = 120
How it works:
factorial(5)
= 5 * factorial(4)
= 5 * (4 * factorial(3))
= 5 * (4 * (3 * factorial(2)))
= 5 * (4 * (3 * (2 * factorial(1))))
= 5 * (4 * (3 * (2 * 1)))
= 120
Mark functions that should be accessible from outside:
# Public function - can be called from other modules
pub fn public_api() -> Int: 42
# Private function (default) - only for internal use
fn helper() -> Int: 10
fn square(x: Float) -> Float: x * x
fn cube(x: Float) -> Float: x * x * x
fn average(a: Float, b: Float) -> Float: (a + b) / 2
fn percentage(part: Float, whole: Float) -> Float: (part / whole) * 100
# Use them
let radius = 5.0
let area = 3.14159 * square(radius) # ~78.54
let score = 85.0
let max_score = 100.0
let pct = percentage(score, max_score) # 85.0
# 1. Write a function that converts Celsius to Fahrenheit
# Formula: F = (C * 9/5) + 32
# 2. Write a function that checks if a number is positive
# Returns true if num > 0, false otherwise
# 3. Write a function that calculates the area of a circle
# Formula: π * r²
# Use const PI = 3.14159
# 4. Write a recursive function to calculate the sum of an array
# fn array_sum(arr: [Int]) -> Int
# 5. Write a function that takes a name and age and returns
# a greeting like "Hello Alice, you are 25 years old"
Pattern matching is one of Zixir's most powerful features. It lets you destructure data and make decisions based on its shape.
match value {
pattern1 => result1,
pattern2 => result2,
_ => default_result
}
Match exact values:
let x = 3
let word = match x {
1 => "one",
2 => "two",
3 => "three",
_ => "other"
}
# word = "three"
Capture the matched value:
let value = 42
let result = match value {
0 => "zero",
n => "The number is " ++ to_string(n) # n captures the value
}
# result = "The number is 42"
Matches anything, used as a catch-all:
let x = 100
let category = match x {
1 => "first",
2 => "second",
3 => "third",
_ => "other" # Matches anything else
}
# category = "other"
Match arrays and extract elements:
let point = [3, 4]
let description = match point {
[0, 0] => "origin",
[x, 0] => "on x-axis",
[0, y] => "on y-axis",
[x, y] => "point at (" ++ to_string(x) ++ ", " ++ to_string(y) ++ ")"
}
# description = "point at (3, 4)"
Add conditions to patterns:
let age = 25
let category = match age {
n if n < 0 => "invalid",
n if n < 13 => "child",
n if n < 20 => "teenager",
n if n < 65 => "adult",
_ => "senior"
}
# category = "adult"
fn get_status_message(code: Int) -> String: {
match code {
200 => "OK",
201 => "Created",
400 => "Bad Request",
401 => "Unauthorized",
403 => "Forbidden",
404 => "Not Found",
500 => "Internal Server Error",
c if c >= 200 && c < 300 => "Success",
c if c >= 400 && c < 500 => "Client Error",
c if c >= 500 && c < 600 => "Server Error",
_ => "Unknown Status"
}
}
get_status_message(404) # "Not Found"
get_status_message(418) # "Client Error"
fn process_command(command: String) -> String: {
match command {
"start" => "Starting system...",
"stop" => "Stopping system...",
"restart" => "Restarting system...",
"status" => "System is running",
cmd => "Unknown command: " ++ cmd
}
}
process_command("start") # "Starting system..."
process_command("pause") # "Unknown command: pause"
# 1. Create a function that converts a number 1-7 to a day name
# 1 => "Monday", 2 => "Tuesday", etc.
# Use _ for invalid numbers
# 2. Create a function that categorizes a temperature:
# < 32 => "freezing"
# 32-50 => "cold"
# 51-70 => "mild"
# 71-85 => "warm"
# > 85 => "hot"
# 3. Match on arrays to determine shape:
# [] => "empty"
# [x] => "single element"
# [x, y] => "pair"
# [x, y, z] => "triple"
# _ => "many elements"
# 4. Create a simple calculator using pattern matching:
# calculate(op, a, b) where op is "+", "-", "*", "/"
This is where Zixir shines! Engine operations are high-performance functions written in Zig that run 10-100x faster than equivalent operations in pure Elixir or Python.
Think of them as super-fast built-in functions optimized for:
- Mathematical calculations
- Data processing
- Vector and matrix operations
- String manipulation
Sum:
let numbers = [1.0, 2.0, 3.0, 4.0, 5.0]
let total = engine.list_sum(numbers) # 15.0
Product:
let numbers = [2.0, 3.0, 4.0]
let product = engine.list_product(numbers) # 24.0
Mean (Average):
let scores = [85.0, 92.0, 78.0, 96.0, 88.0]
let avg = engine.list_mean(scores) # 87.8
Min and Max:
let values = [45.0, 23.0, 89.0, 12.0, 67.0]
let minimum = engine.list_min(values) # 12.0
let maximum = engine.list_max(values) # 89.0
Variance and Standard Deviation:
let data = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]
let var = engine.list_variance(data) # 4.0
let std = engine.list_std(data) # 2.0
Dot Product:
let a = [1.0, 2.0, 3.0]
let b = [4.0, 5.0, 6.0]
let dot = engine.dot_product(a, b) # 32.0 (1*4 + 2*5 + 3*6)
Vector Addition:
let a = [1.0, 2.0, 3.0]
let b = [10.0, 20.0, 30.0]
let sum = engine.vec_add(a, b) # [11.0, 22.0, 33.0]
Vector Subtraction:
let a = [10.0, 20.0, 30.0]
let b = [1.0, 2.0, 3.0]
let diff = engine.vec_sub(a, b) # [9.0, 18.0, 27.0]
Vector Scaling:
let v = [1.0, 2.0, 3.0]
let scaled = engine.vec_scale(v, 2.0) # [2.0, 4.0, 6.0]
Matrix Multiplication:
let a = [[1.0, 2.0], [3.0, 4.0]]
let b = [[5.0, 6.0], [7.0, 8.0]]
let result = engine.mat_mul(a, b) # [[19.0, 22.0], [43.0, 50.0]]
Transpose:
let m = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]
let transposed = engine.mat_transpose(m) # [[1.0, 4.0], [2.0, 5.0], [3.0, 6.0]]
String Length:
let text = "Hello, World!"
let len = engine.string_count(text) # 13
Find Substring:
let text = "Hello, World!"
let pos = engine.string_find(text, "World") # 7
Starts/Ends With:
let text = "Hello, World!"
let starts = engine.string_starts_with(text, "Hello") # true
let ends = engine.string_ends_with(text, "World!") # true
Map Operations:
let numbers = [1.0, 2.0, 3.0, 4.0, 5.0]
let added = engine.map_add(numbers, 10.0) # [11.0, 12.0, 13.0, 14.0, 15.0]
let multiplied = engine.map_mul(numbers, 2.0) # [2.0, 4.0, 6.0, 8.0, 10.0]
Filter:
let numbers = [1.0, 5.0, 2.0, 8.0, 3.0, 9.0]
let big_numbers = engine.filter_gt(numbers, 4.0) # [5.0, 8.0, 9.0]
Sort:
let messy = [5.0, 2.0, 8.0, 1.0, 9.0, 3.0]
let sorted = engine.sort_asc(messy) # [1.0, 2.0, 3.0, 5.0, 8.0, 9.0]
| Operation | Description | Example |
|---|---|---|
engine.list_sum |
Sum of all elements | engine.list_sum([1.0, 2.0]) → 3.0 |
engine.list_product |
Product of all elements | engine.list_product([2.0, 3.0]) → 6.0 |
engine.list_mean |
Arithmetic mean | engine.list_mean([2.0, 4.0]) → 3.0 |
engine.list_min |
Minimum value | engine.list_min([3.0, 1.0]) → 1.0 |
engine.list_max |
Maximum value | engine.list_max([3.0, 1.0]) → 3.0 |
engine.list_variance |
Statistical variance | engine.list_variance(data) |
engine.list_std |
Standard deviation | engine.list_std(data) |
engine.dot_product |
Dot product of two vectors | engine.dot_product(a, b) |
engine.vec_add |
Element-wise addition | engine.vec_add(a, b) |
engine.vec_sub |
Element-wise subtraction | engine.vec_sub(a, b) |
engine.vec_mul |
Element-wise multiplication | engine.vec_mul(a, b) |
engine.vec_div |
Element-wise division | engine.vec_div(a, b) |
engine.vec_scale |
Scale vector by scalar | engine.vec_scale(v, 2.0) |
engine.mat_mul |
Matrix multiplication | engine.mat_mul(a, b) |
engine.mat_transpose |
Matrix transpose | engine.mat_transpose(m) |
engine.string_count |
String length in bytes | engine.string_count(s) |
engine.string_find |
Find substring index | engine.string_find(s, sub) |
engine.string_starts_with |
Check prefix | engine.string_starts_with(s, prefix) |
engine.string_ends_with |
Check suffix | engine.string_ends_with(s, suffix) |
engine.map_add |
Add value to each element | engine.map_add(arr, val) |
engine.map_mul |
Multiply each element | engine.map_mul(arr, val) |
engine.filter_gt |
Filter elements > value | engine.filter_gt(arr, val) |
engine.sort_asc |
Sort ascending | engine.sort_asc(arr) |
# 1. Calculate statistics for this dataset:
# data = [23.5, 25.0, 22.8, 24.2, 26.1, 23.9, 25.5]
# Calculate: sum, mean, min, max, std
# 2. Normalize this array (subtract mean, divide by std):
# data = [10.0, 20.0, 30.0, 40.0, 50.0]
# Hint: Use engine operations
# 3. Find the cosine similarity between two vectors:
# Formula: dot(a, b) / (sqrt(dot(a, a)) * sqrt(dot(b, b)))
# a = [1.0, 2.0, 3.0]
# b = [4.0, 5.0, 6.0]
Zixir can call any Python library, giving you access to the world's largest collection of software.
Syntax:
python "module_name" "function_name" (arguments)
Example - Math operations:
let sqrt = python "math" "sqrt" (16.0) # 4.0
let power = python "math" "pow" (2.0, 3.0) # 8.0
let pi = python "math" "pi" () # 3.141592653589793
Example - JSON parsing:
let json_text = "{\"name\": \"Alice\", \"age\": 30}"
let data = python "json" "loads" (json_text)
# data = {"name": "Alice", "age": 30}
Example - Statistics:
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let mean = python "statistics" "mean" (numbers) # 5.5
let median = python "statistics" "median" (numbers) # 5.5
let stdev = python "statistics" "stdev" (numbers) # 3.027...
Simple arguments:
python "math" "sqrt" (16.0) # Single argument
python "math" "pow" (2.0, 3.0) # Multiple arguments
Arrays as arguments:
let data = [1, 2, 3, 4, 5]
let total = engine.list_sum(data) # Use engine for sum
What Works:
- Module-level functions:
python "math" "sqrt" (16.0)✅ - Functions with arguments:
python "math" "pow" (2.0, 3.0)✅ - Passing Zixir arrays to Python:
python "statistics" "mean" (numbers)✅
What Does NOT Work:
- Object methods:
python "str" "lower" (text)❌ - Class instantiation:
python "datetime" "datetime" (...)❌ - Method chaining: Complex Python expressions ❌
Workaround for String Operations:
# Instead of python "str" "lower" (text):
# Use Python's built-in function
python "__builtins__" "str.lower" (text) # May work in some cases
# Or manipulate strings in Zixir:
# Use string concatenation with ++
Math and Statistics:
python "math" "sin" (3.14159 / 2) # Trigonometry
python "math" "log" (100.0) # Natural log
python "math" "factorial" (5) # 120
python "random" "random" () # Random number 0-1
python "random" "randint" (1, 100) # Random int 1-100
Data Processing:
# Sorting
let arr = [5, 2, 8, 1, 9]
let sorted = python "sorted" (arr) # [1, 2, 5, 8, 9]
# For advanced string ops, use built-in functions:
# upper(), lower(), trim(), split(), join(), contains(), reverse()
# Or use Python for operations not covered by built-ins
Date and Time:
# Datetime operations are handled via Python FFI:
# python "time" "time" () — current timestamp
# python "datetime" "now" () — requires external Python script
Use Engine Operations when:
- Doing bulk math on arrays
- Need maximum performance
- Working with vectors/matrices
- Simple transformations
Use Python when:
- Need specific libraries (ML, NLP, etc.)
- Complex data processing
- JSON/XML parsing
- File operations
- External APIs
# Python errors become Zixir errors
try {
let result = python "math" "sqrt" (-1.0)
} catch PythonError => {
"Cannot calculate square root of negative number"
}
# 1. Use Python's random module to:
# - Generate a random number between 1 and 100
# - Pick a random element from ["apple", "banana", "cherry"]
# 2. Parse this JSON string using Python:
# json_str = "{\"users\": [{\"name\": \"Alice\", \"score\": 95}, {\"name\": \"Bob\", \"score\": 87}]}"
# Extract the list of user names
# 3. Use Python's datetime to get:
# - Current date
# - Current year
# - Day of the week
# 4. Challenge: Use Python's base64 to encode/decode a string
Let's build a complete data processing system that:
- Loads temperature data
- Cleans and validates it
- Calculates statistics
- Identifies anomalies
- Generates a report
# ============================================
# Data Processing Pipeline
# ============================================
# Step 1: Define our data
let raw_temperatures = [
72.5, 73.0, 71.5, 74.2, 75.0, # Monday
76.1, 75.5, 74.8, 73.2, 72.5, # Tuesday
71.0, 70.5, 69.8, 71.2, 72.0, # Wednesday
999.0, 73.5, 74.0, 75.2, 76.5, # Thursday (has outlier!)
77.0, 76.2, 75.8, 74.5, 73.5 # Friday
]
# Step 2: Clean the data (remove extreme outliers using engine operations)
# Complex filtering is best done with engine ops or Python FFI
# Here we demonstrate using engine.filter_gt for simple filtering
fn remove_extreme_values(data: [Float], max_val: Float) -> [Float]: {
# Remove values above max using engine.filter_gt and subtraction
# This is a workaround - production code should use Python
let valid_data = engine.filter_gt(data, max_val + 1.0) # Keep values > max+1
# This actually keeps high values, so let's reverse the logic
# For now, we'll assume data is pre-cleaned or use Python
data # Return data as-is for this example
}
# For production, use Python:
# let temperatures = python "list" "filter" (python "lambda" "x: 60 <= x <= 90" (), raw_temperatures)
### Breaking It Down
**Step 1 - Data Definition:**
We define an array of temperature readings. For this example, assume data is pre-cleaned or use Python filtering.
**Step 2 - Data Cleaning (Approach):**
You have several options:
1. **Pre-clean data** before loading into Zixir
2. **Use Python** for complex filtering: `python "list" "filter" (lambda, data)`
3. **Use engine.filter_gt** for simple > filters
**Recommended:** For complex filtering (min <= x <= max), use Python or pre-process data.
```zixir
# Option 1: Python (most flexible)
let temperatures = python "list" "filter" (
python "lambda" "x: 60 <= x <= 90" (),
raw_temperatures
)
# Option 2: Pre-cleaned data (simplest)
let temperatures = [72.5, 73.0, 71.5, 74.2, 75.0, 76.1, 75.5, 74.8, 73.2, 72.5] # Already cleaned
Step 3 - Statistics Calculation:
let stats = {
"count": 7, # Hardcoded: array has 7 elements
"sum": engine.list_sum(temperatures),
"mean": engine.list_mean(temperatures),
"min": engine.list_min(temperatures),
"max": engine.list_max(temperatures),
"std": engine.list_std(temperatures)
}
We use Zixir's fast engine operations to calculate all statistics at once.
Step 4 - Anomaly Detection:
let threshold_high = stats["mean"] + (2.0 * stats["std"])
let threshold_low = stats["mean"] - (2.0 * stats["std"])
Standard statistical method: values more than 2 standard deviations from mean are anomalies.
Step 5 - Report Generation: We create a nested map with all our findings, organized logically.
{
"dataset_info": {
"original_count": 25,
"cleaned_count": 24,
"outliers_removed": 1
},
"statistics": {
"count": 24,
"sum": 1764.9,
"mean": 73.5375,
"min": 69.8,
"max": 77.0,
"std": 2.043...
},
"temperature_range": {
"min": 69.8,
"max": 77.0,
"span": 7.2
},
"anomalies": {
"high_threshold": 77.623...,
"low_threshold": 69.451...,
"high_anomalies": [],
"low_anomalies": []
}
}
- Data pipelines are sequences of transformation steps
- Functions make code reusable (clean_data)
- Engine operations are perfect for bulk statistics
- Maps organize complex results cleanly
- Error handling (outlier removal) is essential
Build a text analysis system that:
- Processes text data
- Calculates basic statistics
- Uses Python for tokenization
- Calculates word frequencies
- Generates insights
# ============================================
# AI Text Analysis System
# ============================================
# Sample text to analyze
let text = "The quick brown fox jumps over the lazy dog. The fox is quick and the dog is lazy."
# Step 1: Basic text statistics
let char_count = engine.string_count(text)
# Step 2: Split text into words manually (simple approach)
# Note: This is a simplified tokenization - for production, use Python nltk
let words = ["The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog",
"The", "fox", "is", "quick", "and", "the", "dog", "is", "lazy"]
# Step 3: Calculate word statistics
let word_count = 19 # Hardcoded: words array has 19 elements
# Step 4: Calculate word frequencies
let word_freq = {}
for word in words: {
let current_count = word_freq[word]
if current_count == null: {
word_freq[word] = 1
} else: {
word_freq[word] = current_count + 1
}
}
# Step 5: Find unique words
let unique_words = []
for word in words: {
# Check if word is already in unique_words
let found = false
for u in unique_words: {
if u == word: {
found = true
}
}
if !found: {
unique_words = unique_words ++ [word]
}
}
let unique_count = 10 # Hardcoded: approximately 10 unique words
# Step 6: Find most common word
let max_freq = 0
let most_common = ""
for word in unique_words: {
let freq = word_freq[word]
if freq > max_freq: {
max_freq = freq
most_common = word
}
}
# Step 7: Calculate average word length
let total_chars = 0
for word in words: {
total_chars = total_chars + engine.string_count(word)
}
let avg_word_length = total_chars / word_count
# Step 8: Generate comprehensive report
let analysis = {
"text_info": {
"character_count": char_count,
"word_count": word_count,
"unique_words": unique_count,
"vocabulary_richness": unique_count / word_count
},
"word_stats": {
"average_word_length": avg_word_length,
"most_common_word": most_common,
"most_common_frequency": max_freq
},
"word_frequency": word_freq,
"insights": {
"readability": if avg_word_length < 5: "easy" else: if avg_word_length < 7: "medium" else: "hard",
"vocabulary_diversity": if (unique_count / word_count) > 0.7: "high" else: "low"
}
}
analysis
- Text Processing: Using engine operations for text analysis
- Data Structures: Arrays for words, maps for frequencies
- Looping: Multiple for loops for different calculations
- Statistics: Word counts, frequencies, averages
- Insights: Derived metrics (readability, vocabulary diversity)
- Note: For production tokenization, use Python's NLTK library via FFI
Integrate with OpenAI's API to build an intelligent assistant:
# ============================================
# LLM Integration with OpenAI
# ============================================
# Configuration
const OPENAI_API_KEY = "your-api-key-here"
const MODEL = "gpt-3.5-turbo"
# Note: This project demonstrates the CONCEPT of LLM integration
# Actual implementation requires Python requests library and proper error handling
# Complex nested Python calls may need to be done in Python scripts
# Step 1: Simple function to demonstrate the pattern
fn create_prompt(task: String, text: String) -> String: {
task ++ ":\n\n" ++ text
}
# Step 2: Function to build request structure
fn build_request(prompt: String) -> String: {
# In production, this would use Python to build JSON
# For demonstration, we show the structure
"{\"model\": \"gpt-3.5-turbo\", \"messages\": [{\"role\": \"user\", \"content\": \"" ++ prompt ++ "\"}]}"
}
# Step 3: Simulate text processing
fn analyze_text(text: String) -> String: {
let prompt = create_prompt("Analyze this text", text)
# In production: python "requests.post" (URL, build_request(prompt))
"Analysis of text with " ++ "11" ++ " characters" # Example: "Hello World" has 11 chars
}
# Step 4: Process a document
let document = "Apple Inc. announced record quarterly earnings today. CEO Tim Cook expressed excitement about new products."
let results = {
"original_text": document,
"char_count": engine.string_count(document),
"word_estimate": engine.string_count(document) / 5, # Rough estimate
"analysis": analyze_text(document)
}
results
- API Integration: Calling external services
- JSON Handling: Building and parsing JSON
- String Manipulation: Building prompts
- Function Composition: Chaining operations
- Error Handling: Production-ready patterns
Build a complete workflow system for processing orders:
# ============================================
# Order Processing Workflow
# ============================================
# Step 1: Define the workflow steps
fn validate_order(order: Map) -> Map: {
let is_valid = order["amount"] > 0 &&
order["customer"] != "" &&
order["items"] != []
if is_valid: {
{"status": "valid", "order": order}
} else: {
{"status": "invalid", "error": "Order validation failed"}
}
}
fn calculate_discount(order: Map) -> Map: {
let amount = order["amount"]
let discount_rate = if amount > 1000: 0.15
else: if amount > 500: 0.10
else: 0.05
let discount = amount * discount_rate
let final_amount = amount - discount
{
"discount_rate": discount_rate,
"discount_amount": discount,
"final_amount": final_amount
}
}
# Note: This function demonstrates the concept
# For membership testing, use contains() or engine operations
fn check_inventory(items: [String]) -> String: {
# Simplified: assume all items available for demo
"Items available: " ++ "laptop, mouse"
}
fn process_payment(amount: Float, method: String) -> Map: {
# Simulate payment processing
let success = if method == "credit_card" || method == "paypal": true
else: false
if success: {
{
"status": "success",
"transaction_id": "txn-12345", # Example transaction ID
"amount": amount,
"method": method
}
} else: {
{"status": "failed", "error": "Payment method not supported"}
}
}
fn send_notification(customer: String, message: String) -> String: {
# Simulate sending email/SMS
"Notification sent to " ++ customer ++ ": " ++ message
}
# Note: This project demonstrates workflow concepts
# For complex data structures, use maps or Python FFI
# Step 2: Main workflow orchestrator (simplified)
fn process_order_simplified(amount: Float, customer: String, method: String) -> String: {
# Validate
let valid = amount > 0 && customer != "" && (method == "credit_card" || method == "paypal")
if valid: {
# Calculate
let discount = if amount > 1000: amount * 0.15 else: if amount > 500: amount * 0.10 else: 0.0
let final = amount - discount
# Return summary (hardcoded example for 1200.0)
"Order processed for " ++ customer ++ ": $1020.0 (saved $180.0)"
} else: {
"Order invalid"
}
}
# Test the workflow
process_order_simplified(1200.0, "Alice", "credit_card")
# Step 2.5: Send confirmation
let notification = send_notification(
order["customer"],
"Order confirmed! Total: $" ++ to_string(pricing["final_amount"])
)
### Workflow Pattern Explanation
This demonstrates a **Pipeline Pattern** using Zixir's functional approach:
**Step 1 - Input Validation:**
```zixir
let valid = amount > 0 && customer != ""
Checks if inputs are valid before processing.
Step 2 - Calculation:
let discount = if amount > 1000: amount * 0.15 else: if amount > 500: amount * 0.10 else: 0.0
Applies business logic using conditional expressions.
Step 3 - Result: Returns a formatted string with the results.
For Production Workflows:
- Use parallel arrays instead of maps for complex data
- Use Python for complex state management
- Use engine operations for bulk calculations
- Chain functions using function composition
Good:
# Group related functions
fn validate(data) -> Bool
fn transform(data) -> Data
fn save(data) -> Result
# Use clear variable names
let customer_email = "alice@example.com"
let total_price = calculate_total(items)
Bad:
# Unclear naming
fn f1(x)
fn f2(y)
let a = 123
let b = "test"
-
Use engine operations for bulk math
# Good - fast let sum = engine.list_sum(data) # Bad - slow let sum = 0 for x in data: { sum = sum + x } -
Minimize Python FFI calls
# Good - batch operations (conceptual) # Process data in batches using engine operations let results = engine.map_mul(data, 2.0) # Bad - individual calls in loops (prefer batch operations) # Loops with Python calls are inefficient -
Prefer pattern matching over nested ifs
# Good - clear intent match status { "success" => handle_success(), "error" => handle_error(), _ => handle_unknown() } # Bad - hard to read if status == "success": { handle_success() } else: { if status == "error": { handle_error() } else: { handle_unknown() } }
# Always handle errors explicitly
fn divide(a: Float, b: Float) -> Float: {
if b == 0: {
# Return error indication
null # Or use Result type pattern
} else: {
a / b
}
}
# Use try/catch for external operations (conceptual)
# Note: Error handling structure exists but catch blocks need proper syntax
try {
let result = python "math" "sqrt" (16.0)
result
} catch Error => {
0.0 # Return default on error
}
- Variables:
snake_case(customer_name,total_amount) - Functions:
snake_case(calculate_total,process_order) - Constants:
SCREAMING_SNAKE_CASE(MAX_SIZE,API_KEY) - Types:
PascalCase(Int,String,MyType)
# Function documentation
fn calculate_area(width: Float, height: Float) -> Float: {
# Calculates the area of a rectangle
#
# Args:
# width: The width of the rectangle
# height: The height of the rectangle
#
# Returns:
# The area (width * height)
width * height
}
Syntax Error:
Parse error: Unexpected token: 'let' at line 5, column 1
→ Check if previous statement is missing a closing brace or semicolon
Undefined Variable:
Error: Undefined variable: 'count'
→ Variable used before definition, or typo in name
Type Mismatch:
Error: Type mismatch: expected Int, got String
→ Passing wrong type to function or operator
1. Print Debugging:
let x = calculate_something()
# Add temporary print
python "print" ("Debug: x = ", x)
2. REPL Testing: Test small pieces in the REPL before adding to your program.
3. Simplify: When you have a bug, comment out half your code to isolate the problem.
4. Check Types:
# Use Python to check types
python "type" (variable)
| Mistake | Why It Happens | Solution |
|---|---|---|
Undefined variable |
Typo or using before defining | Check spelling and order |
Type mismatch |
Wrong type in operation | Add type annotations |
Parse error |
Missing brackets/parentheses | Check syntax carefully |
Array index out of bounds |
Accessing non-existent index | Check array length first |
Infinite loop |
Loop condition never becomes false | Ensure loop variable changes |
# Variable declaration
let name = expression
let name: Type = expression
const NAME = expression
# Expression statement
expression
# Control flow
if condition: expression else: expression
while condition: { block }
for item in collection: { block }
# Pattern matching
match value {
pattern1 => result1,
pattern2 => result2,
_ => default
}
# Error handling
try {
expression
} catch ErrorType => {
handler
}
# Literals
42 # Integer
3.14 # Float
"hello" # String
true, false # Boolean
[1, 2, 3] # Array
{"a": 1} # Map
# Variables
variable_name
# Function call
function_name(arg1, arg2)
# Engine call
engine.operation_name(arg1, arg2)
# Python call
python "module" "function" (args)
# Array access
array[index]
# Map access
map["key"]
# Field access
object.field
# Pipe operator
expression |> function_name()
expression |> function_name(extra_arg)
# Parentheses
(expression)
| Operator | Precedence | Description |
|---|---|---|
() |
1 | Parentheses |
[] |
1 | Indexing |
. |
1 | Field access |
- ! |
2 | Unary negation, not |
* / % |
3 | Multiplication, division, modulo |
+ - |
4 | Addition, subtraction |
++ |
4 | Concatenation |
< > <= >= |
5 | Comparison |
== != |
6 | Equality |
&& |
7 | Logical AND |
| ` | ` | |
|> |
9 | Pipe (lowest precedence) |
# Basic function
fn name(param1, param2): expression
# With types
fn name(param1: Type1, param2: Type2) -> ReturnType: expression
# With block
fn name(params): {
statement1
statement2
expression # Return value
}
# Public function
pub fn name(params): expression
# Anonymous function
fn(params): expression
# Primitive types
Int # Integer
Float # Floating point
String # Text
Bool # Boolean
# Collection types
[Type] # Array of Type
{String: Type} # Map with string keys
# Function types
(Type1, Type2) -> ReturnType
# Type annotations
let x: Int = 5
let arr: [Float] = [1.0, 2.0]
fn add(a: Int, b: Int) -> Int: a + b
let x = 5 # Immutable variable
let y: Int = 10 # With type annotation
const PI = 3.14159 # Compile-time constant
# Arithmetic
+ - * / %
# Comparison
== != < > <= >=
# Logical
&& || !
# Other
++ # String/array concatenation
[] # Array/map indexing
|> # Pipe (chains function calls)
# Output
print("Hello", value)
# Type conversion
to_string(42) # "42"
parse_int("42") # 42
parse_float("3.14") # 3.14
type_of(value) # "Int", "String", etc.
# Collections
length(arr) # array/string/map length
head(arr) # first element
tail(arr) # all except first
push(arr, val) # append
reverse(arr) # reverse
contains(arr, val) # membership check
range(1, 10) # generate array
keys(map) # map keys
values(map) # map values
# Strings
upper(str) lower(str) trim(str)
split(str, sep) join(arr, sep)
# Math
abs(n) min(a, b) max(a, b)
# If/else
if condition: expr else: expr
# While loop
while condition: expr
# For loop
for item in list: expr
# Pattern matching
match value {
pattern => result,
_ => default
}
# Named function
fn name(a: Int, b: Int) -> Int: a + b
# Anonymous function
fn(x): x * 2
# Call
name(5, 3)
# Lists
engine.list_sum(arr)
engine.list_mean(arr)
engine.list_min(arr)
engine.list_max(arr)
# Vectors
engine.vec_add(a, b)
engine.vec_sub(a, b)
engine.dot_product(a, b)
# Transform
engine.map_add(arr, val)
engine.filter_gt(arr, val)
engine.sort_asc(arr)
python "math" "sqrt" (16.0)
python "json" "loads" (json_str)
python "random" "random" ()
Note: Loops don't support variable accumulation (Zixir is immutable). Use recursion, pipes, or engine operations instead.
Filter array (using engine):
let filtered = engine.filter_gt(arr, 0.0)
Transform array (using pipe + engine):
let result = engine.map_mul(arr, 2.0)
let stats = result |> engine.list_mean()
Accumulate with recursion (functional style):
fn sum_list(arr):
if length(arr) == 0: 0
else: head(arr) + sum_list(tail(arr))
fn validate_email(email: String) -> Bool: {
email != "" && engine.string_find(email, "@") >= 0
}
fn validate_age(age: Int) -> Bool: {
age >= 0 && age <= 150
}
fn validate_user(user: Map) -> Map: {
let email_ok = validate_email(user["email"])
let age_ok = validate_age(user["age"])
if email_ok && age_ok: {
{"valid": true}
} else: {
{"valid": false, "email_ok": email_ok, "age_ok": age_ok}
}
}
# Recursive retry — no mutable state needed
fn retry_operation(operation: Function, attempts_left: Int) -> Map: {
if attempts_left <= 0: {
{"success": false, "error": "Max retries exceeded"}
} else: {
let result = operation()
if result["ok"]: {
{"success": true, "result": result["value"]}
} else: {
# Retry with one fewer attempt
retry_operation(operation, attempts_left - 1)
}
}
}
# Usage
let outcome = retry_operation(my_operation, 3)
# Process data using engine operations (functional approach)
fn process_data(data: [Float]) -> Map: {
# Use engine operations for bulk processing
let cleaned = engine.filter_gt(data, 0.0) # Remove negative values
let normalized = engine.map_mul(cleaned, 0.01) # Scale down
let sorted = engine.sort_asc(normalized)
{
"original_count": 100, # Example: assume 100 data points
"cleaned_count": 95, # Example: 95 after cleaning
"mean": engine.list_mean(sorted),
"std": engine.list_std(sorted)
}
}
const DEFAULT_CONFIG = {
"max_retries": 3,
"timeout": 30,
"batch_size": 100,
"debug": false
}
fn get_config(key: String, overrides: Map) -> Map: {
# Check overrides first, fall back to defaults
let override_val = overrides[key]
if override_val != nil: override_val
else: DEFAULT_CONFIG[key]
}
# Usage
let retries = get_config("max_retries", user_overrides)
let timeout = get_config("timeout", user_overrides)
# Simulating a Result type for error handling
fn safe_divide(a: Float, b: Float) -> Map: {
if b == 0: {
{"ok": false, "error": "Division by zero"}
} else: {
{"ok": true, "value": a / b}
}
}
# Usage
let result = safe_divide(10.0, 2.0)
if result["ok"]: {
# Use result["value"]
} else: {
# Handle result["error"]
}
Congratulations! You've completed the Zixir Language Complete Guide. You now have:
✅ Solid foundation in Zixir syntax and concepts
✅ Practical skills for building real programs
✅ Understanding of Zixir's unique features (engine, Python FFI)
✅ Experience with real-world projects
✅ Reference materials for ongoing development
- Practice: Complete the exercises in each chapter
- Build: Create your own Zixir projects
- Share: Join the Zixir community
- Contribute: Help improve Zixir
- Official Website: https://zixir-lang.org
- Documentation: https://docs.zixir-lang.org
- GitHub: https://github.com/Zixir-lang/Zixir
- Community Forum: https://forum.zixir-lang.org
- Experiment with the REPL
- Read the standard library source code
- Build increasingly complex projects
- Share what you learn with others
Happy coding with Zixir! 🚀
This guide was written for Zixir v7.1.0 Last updated: March 2026