# Function Composition & Currying Design Plan - REVISED ## Current Issue Analysis ### Problem Statement The current function application implementation has a fundamental flaw for function composition: ```javascript f g x // Currently parsed as: apply(apply(f, g), x) // This fails because: apply(f, g) = NaN (f expects a number, not a function) // Then: apply(NaN, x) = Error ``` ### Root Cause 1. **Left-associative parsing**: `f g x` → `(f g) x` → `apply(apply(f, g), x)` 2. **Non-curried functions**: Functions expect specific argument types, not other functions 3. **Missing composition semantics**: No built-in understanding of function composition ## Design Decision: Simplified Approach ### Option 1: Full Currying (Haskell-style) ❌ **Why not**: Major architectural change, breaks existing code, complex implementation ### Option 2: Explicit Composition Only ✅ **RECOMMENDED** **Why this is better**: - **No ambiguity**: `f via g x` is always composition, `f g x` is always left-associative application - **Backward compatible**: All existing code works unchanged - **Clear intent**: Explicit composition makes code more readable - **No complex detection**: No need for runtime type checking - **Natural language**: `via` reads like English and is self-documenting ### Option 3: Hybrid Approach ❌ **Why not**: Overcomplicated, introduces ambiguity, harder to understand ## Recommended Solution: Explicit Composition Only ### 1. Keep Current Function Application - `f x` → `apply(f, x)` (immediate application) - `f g x` → `apply(apply(f, g), x)` (left-associative, as currently implemented) - Functions remain non-curried by default - Maintains current behavior for simple cases ### 2. Add Explicit Composition Keyword - `f via g` → `compose(f, g)` (explicit composition) - `f via g via h` → `compose(f, compose(g, h))` (right-associative) - `f via g x` → `apply(compose(f, g), x)` (composition then application) - Clear and explicit about intent ### 3. Fix and Enhance @ Operator - `@f` → function reference (fix current parsing issues) - `map(@f, [1,2,3])` → pass function as argument - `when x is @f then ...` → pattern matching on functions - Essential for higher-order programming ### 4. Enhanced Standard Library - Improve `compose` function to handle multiple arguments - Add `pipe` for left-to-right composition - Add `curry` and `uncurry` utilities for when needed ## Implementation Plan ### Phase 1: Lexer Enhancement - Add composition keyword (`via`) - Fix `@` operator parsing issues - Update token precedence ### Phase 2: Parser Enhancement - Add `parseComposition()` function - Fix `parsePrimary()` to handle `@` operator correctly - Implement explicit composition parsing ### Phase 3: Standard Library Enhancement - Improve `compose` function - Add `pipe` function - Add `curry`/`uncurry` utilities ### Phase 4: Testing & Validation - Test all composition scenarios - Ensure backward compatibility - Performance testing ## Syntax Examples ### Current (Working) ```javascript f : x -> x * 2; g : x -> x + 1; result1 : f x; // apply(f, x) = 10 result2 : f (g x); // apply(f, apply(g, x)) = 12 ``` ### Proposed (Enhanced) ```javascript f : x -> x * 2; g : x -> x + 1; result1 : f x; // apply(f, x) = 10 result2 : f via g x; // apply(compose(f, g), x) = 12 result3 : pipe(f, g) x; // apply(pipe(f, g), x) = 12 result4 : @f; // function reference to f result5 : map(@f, [1,2,3]); // [2, 4, 6] // Natural language examples data : [1, 2, 3, 4, 5]; result6 : data via filter via map via reduce; // Pipeline example result7 : x via abs via double via add(10); // Mathematical pipeline ``` ## Why `via` is Better Than `.` ### 1. **Natural Language** - `f via g x` reads like "f via g applied to x" - `data via filter via map` reads like "data via filter via map" - More intuitive for non-FP developers ### 2. **No Conflicts** - No confusion with decimal numbers - No conflict with object property access - Won't interfere with existing syntax ### 3. **Clear Intent** - Explicitly indicates composition - Self-documenting code - No ambiguity about what's happening ### 4. **Better Error Messages** - "Expected function after 'via'" is clearer than "Expected function after '.'" - More natural error reporting ### 5. **Accessibility** - Lower learning curve - No prior FP knowledge needed - Intuitive for beginners ## Backward Compatibility ### Guaranteed to Work - All existing function calls: `f x` - All existing operator expressions: `x + y` - All existing function definitions - All existing when expressions - All existing table operations ### New Features (Optional) - Explicit composition: `f via g` - Fixed function references: `@f` - Enhanced standard library functions ## Why This Approach is Better ### 1. Simplicity - No complex detection logic - No runtime type checking - Clear, predictable behavior ### 2. Clarity - `f g x` always means `(f g) x` - `f via g x` always means `f(g(x))` - No ambiguity about intent ### 3. Familiarity - `via` is intuitive and self-explanatory - No mathematical notation to learn - Easy to understand and teach ### 4. Flexibility - Users can choose when to use composition - No forced architectural changes - Easy to extend later if needed ## Next Steps 1. **Implement Phase 1**: Add composition keyword to lexer, fix @ operator 2. **Implement Phase 2**: Add composition parsing to parser 3. **Implement Phase 3**: Enhance standard library 4. **Test thoroughly**: Ensure all existing code still works 5. **Document**: Update language documentation 6. **Examples**: Create comprehensive examples ## Success Criteria - [ ] `f via g x` works correctly for function composition - [ ] `@f` works correctly for function references - [ ] All existing code continues to work unchanged - [ ] Performance impact is minimal - [ ] Error messages are clear and helpful - [ ] Documentation is comprehensive ## Conclusion The explicit composition approach using `via` is simpler, clearer, and more maintainable than the hybrid approach. It provides the functionality we need without the complexity and potential ambiguity of automatic detection. The `via` keyword makes the language more accessible and self-documenting, while maintaining all the power of functional composition. Combined with fixing the `@` operator, this gives us a powerful and clear functional programming language.