# 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 ```plaintext /* Output values to console */ ..out "Hello, World!"; ..out 42; ..out true; ..out {name: "Alice", age: 30}; ``` ### Output with Expressions ```plaintext /* 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: ```plaintext /* 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 ```plaintext /* 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 ```plaintext /* 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 ```plaintext /* Listen for specific events */ ..listen "user_created" handle_user_created; ..listen "data_processed" handle_data_processed; ..listen "error_occurred" handle_error; ``` ### Event Handlers ```plaintext /* 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 ```plaintext /* 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 ```plaintext /* 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 ```plaintext /* 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 ```plaintext /* 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 ```plaintext /* 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 ```plaintext /* 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: - [Error Handling](13_Error_Handling.md) for robust error management - [Integration Patterns](15_Integration_Patterns.md) for external system integration - [Best Practices](16_Best_Practices.md) for writing clean code