12_IO_Operations

IO Operations

What are IO Operations?

IO (Input/Output) operations allow your functional programs to interact with the outside world. Baba Yaga provides a minimal set of IO operations that keep side effects contained and explicit.

Basic Output

Simple Output

/* Output values to console */
..out "Hello, World!";
..out 42;
..out true;
..out {name: "Alice", age: 30};

Output with Expressions

/* Output computed values */
result : 5 + 3 * 2;
..out result;  /* Output: 11 */

/* Output function results */
double : x -> x * 2;
..out double 7;  /* Output: 14 */

/* Output table operations */
numbers : {1, 2, 3, 4, 5};
doubled : map @double numbers;
..out doubled;  /* Output: {2, 4, 6, 8, 10} */

Assertions

Assertions help you verify your program's behavior:

/* Basic assertions */
..assert 5 = 5;                    /* Passes */
..assert 3 + 2 = 5;                /* Passes */
..assert true;                     /* Passes */
..assert false;                    /* Fails with error */

/* Assertions with messages */
..assert "5 equals 5" 5 = 5;       /* Passes */
..assert "3 + 2 equals 5" 3 + 2 = 5; /* Passes */
..assert "This will fail" 1 = 2;   /* Fails with message */

Testing Functions

/* Test function behavior */
factorial : n -> 
  when n is
    0 then 1
    _ then n * (factorial (n - 1));

/* Test cases */
..assert "factorial 0 = 1" factorial 0 = 1;
..assert "factorial 1 = 1" factorial 1 = 1;
..assert "factorial 5 = 120" factorial 5 = 120;

Emit and Listen Pattern

The ..emit and ..listen pattern provides a way to interface functional code with external systems:

Emitting Events

/* Emit events with data */
..emit "user_created" {id: 123, name: "Alice"};
..emit "data_processed" {count: 42, success: true};
..emit "error_occurred" {message: "Invalid input", code: 400};

Listening for Events

/* Listen for specific events */
..listen "user_created" handle_user_created;
..listen "data_processed" handle_data_processed;
..listen "error_occurred" handle_error;

Event Handlers

/* Define event handlers */
handle_user_created : user_data -> 
  ..out "New user created:";
  ..out user_data.name;

handle_data_processed : result -> 
  when result.success is
    true then ..out "Processing successful: " + result.count + " items"
    false then ..out "Processing failed";

handle_error : error -> 
  ..out "Error: " + error.message;
  ..out "Code: " + error.code;

Input Operations

Reading Input

/* Read input from user */
name : ..in "Enter your name: ";
..out "Hello, " + name + "!";

/* Read and process input */
age_input : ..in "Enter your age: ";
age : parseInt age_input;
..out "You are " + age + " years old";

IO Best Practices

Keep Side Effects Explicit

/* Good: Clear IO operations */
process_data : data -> 
  result : transform data;
  ..out "Processing complete";
  ..emit "data_processed" result;
  result;

/* Avoid: Hidden side effects in pure functions */
bad_transform : data -> 
  ..out "Processing...";  /* Side effect in "pure" function */
  data * 2;

Use Assertions for Testing

/* Test your functions thoroughly */
is_even : x -> x % 2 = 0;
double : x -> x * 2;

/* Test individual functions */
..assert "0 is even" is_even 0 = true;
..assert "1 is not even" is_even 1 = false;
..assert "double 5 = 10" double 5 = 10;

/* Test composed functions */
doubled_evens : compose @double @is_even;
..assert "doubled_evens 6 = true" doubled_evens 6 = true;

Structured Output

/* Use tables for structured output */
user : {name: "Alice", age: 30, city: "NYC"};
..out "User Profile:";
..out "  Name: " + user.name;
..out "  Age: " + user.age;
..out "  City: " + user.city;

/* Or output the entire structure */
..out user;

Common Patterns

Data Processing Pipeline

/* Process data with IO feedback */
data : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
..out "Processing " + t.length data + " items";

is_even : x -> x % 2 = 0;
double : x -> x * 2;
sum : x -> reduce @add 0 x;

/* Process with progress updates */
evens : filter @is_even data;
..out "Found " + t.length evens + " even numbers";

doubled : map @double evens;
..out "Doubled values:";
..out doubled;

total : sum doubled;
..out "Sum of doubled evens: " + total;

/* Emit final result */
..emit "processing_complete" {input_count: t.length data, result: total};

Error Handling

/* Handle potential errors gracefully */
safe_divide : x y -> 
  when y = 0 then 
    ..emit "division_error" {dividend: x, divisor: y};
    "Error: Division by zero"
  _ then x / y;

/* Test error handling */
..out safe_divide 10 2;   /* 5 */
..out safe_divide 10 0;   /* Error: Division by zero */

Next Steps

Now that you understand IO operations, explore: