Topaz

Functional Library

Fully utilize Topaz functional programming library. Master all functional tools including higher-order functions, currying, composition, monads, and more.

Topaz provides a powerful functional programming library to support declarative and expressive code writing. Leverage all functional tools!

Higher-Order Functions

Basic Higher-Order Functions

// Function that takes a function as argument
function applyTwice<T>(func: (T) -> T, value: T) -> T {
    return func(func(value))
}

let double = (x: int) => x * 2
let result = applyTwice(double, 5)                    // 20

// Function that returns a function
function multiplier(factor: int) -> (int) -> int {
    return (value: int) => value * factor
}

let tripleFunction = multiplier(3)
let tripleResult = tripleFunction(7)                  // 21

// Conditional function application
function conditionalApply<T>(
    condition: (T) -> bool,
    func: (T) -> T,
    value: T
) -> T {
    if condition(value) {
        return func(value)
    } else {
        return value
    }
}

let doubleIfEven = conditionalApply(
    x => x % 2 == 0,
    x => x * 2,
    8
)                                                     // 16

print("Result: {result}")
print("Triple result: {tripleResult}")
print("Double if even: {doubleIfEven}")

Function Composition

// Basic function composition
function compose<A, B, C>(
    f: (B) -> C,
    g: (A) -> B
) -> (A) -> C {
    return (input: A) => f(g(input))
}

let add1 = (x: int) => x + 1
let multiply2 = (x: int) => x * 2
let composedFunction = compose(multiply2, add1)       // (x + 1) * 2

let composedResult = composedFunction(5)              // 12

// Multiple function composition
function pipe<T>(...functions: Array<(T) -> T>) -> (T) -> T {
    return (initialValue: T) => {
        return functions.reduce((acc, currentFunc) => currentFunc(acc), initialValue)
    }
}

let complexProcessing = pipe(
    (x: int) => x + 1,        // +1
    (x: int) => x * 2,        // *2
    (x: int) => x - 3,        // -3
    (x: int) => x / 2         // /2
)

let pipeResult = complexProcessing(10)                // 9.5

print("Composed result: {composedResult}")
print("Pipe result: {pipeResult}")

Partial Application

// Partial application function
function partial<A, B, C>(
    func: (A, B) -> C,
    firstArg: A
) -> (B) -> C {
    return (secondArg: B) => func(firstArg, secondArg)
}

let add = (a: int, b: int) => a + b
let add10 = partial(add, 10)
let partialResult = add10(5)                          // 15

// Multi-argument partial application
function partial3<A, B, C, D>(
    func: (A, B, C) -> D,
    first: A,
    second: B
) -> (C) -> D {
    return (third: C) => func(first, second, third)
}

let calculate = (x: int, y: int, z: int) => x * y + z
let partialCalculate = partial3(calculate, 2, 3)      // 2 * 3 + z
let finalResult = partialCalculate(4)                 // 10

print("Partial result: {partialResult}")
print("Final result: {finalResult}")

Currying

Basic Currying

// Manual currying
function curry2<A, B, C>(func: (A, B) -> C) -> (A) -> (B) -> C {
    return (a: A) => (b: B) => func(a, b)
}

function curry3<A, B, C, D>(func: (A, B, C) -> D) -> (A) -> (B) -> (C) -> D {
    return (a: A) => (b: B) => (c: C) => func(a, b, c)
}

// Apply currying
let add = (x: int, y: int) => x + y
let curriedAdd = curry2(add)
let add5 = curriedAdd(5)
let curryResult = add5(3)                             // 8

// Three-argument currying
let formula = (x: int, y: int, z: int) => x * y + z
let curriedFormula = curry3(formula)
let stepByStepCalc = curriedFormula(2)(3)(4)          // 10

print("Curry result: {curryResult}")
print("Step by step calc: {stepByStepCalc}")

Auto Currying

// Auto currying decorator
function autoCurry<T>(func: Function) -> Function {
    // Check argument count at runtime and auto-curry
    return function(...args: Array<T>) {
        if args.length >= func.arity {
            return func.apply(null, args)
        } else {
            return function(...additionalArgs: Array<T>) {
                return autoCurry(func).apply(null, [...args, ...additionalArgs])
            }
        }
    }
}

// Usage example
let multiply = autoCurry((a: int, b: int, c: int) => a * b * c)

let method1 = multiply(2, 3, 4)                       // 24 (all args at once)
let method2 = multiply(2)(3)(4)                       // 24 (sequential application)
let method3 = multiply(2, 3)(4)                       // 24 (partial application)

let partialMultiply = multiply(2, 3)                  // Returns function
let completeMultiply = partialMultiply(4)             // 24

print("Auto curry results: {method1}, {method2}, {method3}")

Function Transformation Utilities

Memoization

// Basic memoization
function memoize<T, R>(func: (T) -> R) -> (T) -> R {
    let mut cache: Map<T, R> = Map.new()
    
    return (input: T) => {
        if cache.has(input) {
            return cache.get(input).unwrap()
        }
        
        let result = func(input)
        cache.set(input, result)
        return result
    }
}

// Fibonacci memoization
let fibonacci = memoize((n: int) => {
    print("Computing: fibonacci({n})")
    if n <= 1 { return n }
    return fibonacci(n - 1) + fibonacci(n - 2)
})

let fib10 = fibonacci(10)                             // 55 (no duplicate calculations)
let fib10Again = fibonacci(10)                        // 55 (returned from cache immediately)

// TTL memoization (Time To Live)
function memoizeWithTTL<T, R>(
    func: (T) -> R,
    ttl: int
) -> (T) -> R {
    let mut cache: Map<T, { result: R, timestamp: int }> = Map.new()
    
    return (input: T) => {
        let currentTime = Date.now()
        
        if cache.has(input) {
            let cacheEntry = cache.get(input).unwrap()
            if (currentTime - cacheEntry.timestamp) < ttl {
                return cacheEntry.result
            }
        }
        
        let result = func(input)
        cache.set(input, { result, timestamp: currentTime })
        return result
    }
}

print("Fibonacci 10: {fib10}")

Debouncing and Throttling

// Debounce function
function debounce<T>(
    func: (...T) -> void,
    delay: int
) -> (...T) -> void {
    let mut timerId: Option<int> = None
    
    return (...args: Array<T>) => {
        // Cancel existing timer
        match timerId {
            case Some(id) => clearTimeout(id)
            case None => {}
        }
        
        // Set new timer
        timerId = Some(setTimeout(() => {
            func(...args)
            timerId = None
        }, delay))
    }
}

// Throttle function
function throttle<T>(
    func: (...T) -> void,
    interval: int
) -> (...T) -> void {
    let mut lastCallTime = 0
    let mut timerId: Option<int> = None
    
    return (...args: Array<T>) => {
        let currentTime = Date.now()
        let timeSinceLastCall = currentTime - lastCallTime
        
        if timeSinceLastCall >= interval {
            func(...args)
            lastCallTime = currentTime
        } else if timerId.isNone() {
            timerId = Some(setTimeout(() => {
                func(...args)
                lastCallTime = Date.now()
                timerId = None
            }, interval - timeSinceLastCall))
        }
    }
}

// Usage examples
let searchFunction = (query: string) => {
    print("Executing search: {query}")
}

let debouncedSearch = debounce(searchFunction, 300)   // Execute after 300ms
let throttledSearch = throttle(searchFunction, 1000)  // Maximum 1 call per second

Functional Data Transformation

Lenses

// Basic lens implementation with explicit helper functions
struct Lens<S, A> {
    get: (S) -> A,
    set: (A, S) -> S
}

function createLens<S, A>(getter: (S) -> A, setter: (A, S) -> S) -> Lens<S, A> {
    return Lens { get: getter, set: setter }
}

function composeLens<S, A, B>(outer: Lens<S, A>, inner: Lens<A, B>) -> Lens<S, B> {
    return createLens(
        (value: S) => inner.get(outer.get(value)),
        (replacement: B, value: S) => {
            let focus = outer.get(value)
            let nextFocus = inner.set(replacement, focus)
            return outer.set(nextFocus, value)
        }
    )
}

function overLens<S, A>(lens: Lens<S, A>, transform: (A) -> A, value: S) -> S {
    let currentValue = lens.get(value)
    return lens.set(transform(currentValue), value)
}

// User struct
struct User {
    name: string,
    age: int,
    address: Address
}

struct Address {
    city: string,
    zipCode: string
}

// Lens definitions
let nameLens = createLens(
    (user: User) => user.name,
    (name: string, user: User) => user{ name }
)

let addressLens = createLens(
    (user: User) => user.address,
    (address: Address, user: User) => user{ address }
)

let cityLens = createLens(
    (addr: Address) => addr.city,
    (city: string, addr: Address) => addr{ city }
)

// Lens composition
let userCityLens = composeLens(addressLens, cityLens)

// Usage example
let user = User {
    name: "John Doe",
    age: 30,
    address: Address { city: "New York", zipCode: "12345" }
}

let newUser = userCityLens.set("Boston", user)
let modifiedUser = overLens(nameLens, name => name.toUpperCase(), newUser)

print("Original city: {userCityLens.get(user)}")      // "New York"
print("New city: {userCityLens.get(newUser)}")        // "Boston"
print("Updated name: {modifiedUser.name}")            // "JOHN DOE"

Functional Data Pipeline

// Data transformation pipeline
struct Pipeline<T> {
    data: T
}

function pipelineFrom<T>(data: T) -> Pipeline<T> {
    return Pipeline { data }
}

function pipelineMap<T, U>(pipeline: Pipeline<T>, transform: (T) -> U) -> Pipeline<U> {
    return Pipeline { data: transform(pipeline.data) }
}

function pipelineFilter<T>(pipeline: Pipeline<T>, condition: (T) -> bool) -> Pipeline<Option<T>> {
    if condition(pipeline.data) {
        return Pipeline { data: Some(pipeline.data) }
    } else {
        return Pipeline { data: None }
    }
}

function pipelineTap<T>(pipeline: Pipeline<T>, sideEffect: (T) -> void) -> Pipeline<T> {
    sideEffect(pipeline.data)
    return pipeline
}

function pipelineValue<T>(pipeline: Pipeline<T>) -> T {
    return pipeline.data
}

// Data processing example
let result = pipelineFrom("  Hello World  ")
    |> pipelineMap(_, s => s.trim())
    |> pipelineTap(_, s => print("After trim: '{s}'"))
    |> pipelineMap(_, s => s.toLowerCase())
    |> pipelineTap(_, s => print("Lowercase: '{s}'"))
    |> pipelineMap(_, s => s.split(" "))
    |> pipelineMap(_, arr => arr.join("-"))
    |> pipelineValue(_)                                // "hello-world"

print("Final result: {result}")

Monads

Maybe/Option Monad

// Option helpers expressed as namespaced functions
module Option {
    function map<T, U>(option: Option<T>, transform: (T) -> U) -> Option<U> {
        match option {
            case Some(value) => Some(transform(value))
            case None => None
        }
    }

    function flatMap<T, U>(option: Option<T>, func: (T) -> Option<U>) -> Option<U> {
        match option {
            case Some(value) => func(value)
            case None => None
        }
    }

    function filter<T>(option: Option<T>, condition: (T) -> bool) -> Option<T> {
        match option {
            case Some(value) if condition(value) => Some(value)
            case _ => None
        }
    }

    function orElse<T>(option: Option<T>, alternative: () -> Option<T>) -> Option<T> {
        match option {
            case Some(_) => option
            case None => alternative()
        }
    }
}

// Chaining example
let userData = Some("John Doe")

let processedResult = userData
    |> Option.filter(_, name => name.length > 2)
    |> Option.map(_, name => name.toUpperCase())
    |> Option.flatMap(_, name => {
        if name.startsWith("JOHN") {
            return Some("Greeting: Hello {name}")
        } else {
            return None
        }
    })
    |> Option.orElse(_, () => Some("Unknown user"))

print("Processed result: {processedResult}")          // Some("Greeting: Hello JOHN DOE")

Result Monad

// Result helpers expressed as namespaced functions
module ResultOps {
    function map<T, U, E>(result: Result<T, E>, transform: (T) -> U) -> Result<U, E> {
        match result {
            case Ok(value) => Ok(transform(value))
            case Err(error) => Err(error)
        }
    }

    function flatMap<T, U, E>(result: Result<T, E>, func: (T) -> Result<U, E>) -> Result<U, E> {
        match result {
            case Ok(value) => func(value)
            case Err(error) => Err(error)
        }
    }

    function mapError<T, E, F>(result: Result<T, E>, func: (E) -> F) -> Result<T, F> {
        match result {
            case Ok(value) => Ok(value)
            case Err(error) => Err(func(error))
        }
    }

    function recover<T, E>(result: Result<T, E>, recoveryFunc: (E) -> T) -> T {
        match result {
            case Ok(value) => value
            case Err(error) => recoveryFunc(error)
        }
    }
}

// Safe operation chaining
function safeDivide(numerator: float, denominator: float) -> Result<float, string> {
    if denominator == 0.0 {
        return Err("Cannot divide by zero")
    }
    return Ok(numerator / denominator)
}

function safeSquareRoot(value: float) -> Result<float, string> {
    if value < 0.0 {
        return Err("Cannot calculate square root of negative number")
    }
    return Ok(Math.sqrt(value))
}

let calculationResult = Ok(16.0)
    |> ResultOps.flatMap(_, value => safeDivide(value, 4.0))          // 16 / 4 = 4
    |> ResultOps.flatMap(_, value => safeSquareRoot(value))           // √4 = 2
    |> ResultOps.map(_, value => value * 2)                           // 2 * 2 = 4
    |> ResultOps.mapError(_, error => "Calculation failed: {error}")
    |> ResultOps.recover(_, error => {
        print("Error occurred: {error}")
        return 0.0
    })

print("Calculation result: {calculationResult}")      // 4.0

Functional Patterns

Strategy Pattern

// Functional strategy pattern
enum SortStrategy {
    QuickSort,
    MergeSort,
    BubbleSort
}

function sortWith<T>(
    array: Array<T>,
    strategy: SortStrategy,
    compareFunc: (T, T) -> int
) -> Array<T> {
    let sortFunc = match strategy {
        case QuickSort => quickSort
        case MergeSort => mergeSort
        case BubbleSort => bubbleSort
    }
    
    return sortFunc(array, compareFunc)
}

function quickSort<T>(array: Array<T>, compare: (T, T) -> int) -> Array<T> {
    // QuickSort implementation
    if array.length <= 1 { return array }
    
    let pivot = array[array.length / 2]
    let smaller = array.filter(x => compare(x, pivot) < 0)
    let equal = array.filter(x => compare(x, pivot) == 0)
    let larger = array.filter(x => compare(x, pivot) > 0)
    
    return [
        ...quickSort(smaller, compare),
        ...equal,
        ...quickSort(larger, compare)
    ]
}

// Usage example
let numberArray = [64, 34, 25, 12, 22, 11, 90]
let sortedArray = sortWith(
    numberArray,
    QuickSort,
    (a, b) => a - b
)

print("Sorted array: {sortedArray}")

Observer Pattern

// Functional observer pattern
struct Observable<T> {
    subscribers: Array<(T) -> void>
}

function createObservable<T>() -> Observable<T> {
    return Observable { subscribers: [] }
}

function subscribeObservable<T>(observable: Observable<T>, callback: (T) -> void) -> Observable<T> {
    return observable{ subscribers: [...observable.subscribers, callback] }
}

function emitObservable<T>(observable: Observable<T>, value: T) {
    observable.subscribers.forEach(callback => callback(value))
}

function mapObserver<T, U>(transform: (T) -> U, callback: (U) -> void) -> (T) -> void {
    return value => callback(transform(value))
}

function filterObserver<T>(condition: (T) -> bool, callback: (T) -> void) -> (T) -> void {
    return value => {
        if condition(value) {
            callback(value)
        }
    }
}

// Usage example
let clickPositionObserver = filterObserver(
    event => event.type == "click",
    mapObserver(
        event => event.coordinates,
        coords => print("Click position: {coords}")
    )
)

let doubleClickObserver = filterObserver(
    event => event.doubleClick,
    event => print("Double click detected")
)

let clickStream0 = createObservable()
let clickStream1 = subscribeObservable(clickStream0, clickPositionObserver)
let clickStream2 = subscribeObservable(clickStream1, doubleClickObserver)

// Emit events
emitObservable(clickStream2, { type: "click", coordinates: [100, 200], doubleClick: false })
emitObservable(clickStream2, { type: "click", coordinates: [300, 400], doubleClick: true })

Advanced Functional Techniques

Y Combinator

// Y combinator for recursive function implementation
function Y<T>(func: ((T) -> T) -> (T) -> T) -> (T) -> T {
    return function(arg: T) -> T {
        return func(Y(func))(arg)
    }
}

// Factorial using Y combinator
let factorial = Y((recursiveFunc: (int) -> int) => (n: int) => {
    if n <= 1 {
        return 1
    } else {
        return n * recursiveFunc(n - 1)
    }
})

let factorial5 = factorial(5)                         // 120

// Fibonacci using Y combinator
let fibonacciY = Y((recursiveFunc: (int) -> int) => (n: int) => {
    if n <= 1 {
        return n
    } else {
        return recursiveFunc(n - 1) + recursiveFunc(n - 2)
    }
})

let fib8 = fibonacciY(8)                              // 21

print("Y combinator factorial(5): {factorial5}")
print("Y combinator fibonacci(8): {fib8}")

Lazy Evaluation

// Lazy evaluation with explicit state transitions
struct Lazy<T> {
    computeFunc: () -> T,
    cache: Option<T>
}

function createLazy<T>(computeFunc: () -> T) -> Lazy<T> {
    return Lazy { computeFunc, cache: None }
}

function forceLazy<T>(lazy: Lazy<T>) -> { lazy: Lazy<T>, value: T } {
    match lazy.cache {
        case Some(value) => return { lazy, value }
        case None => {
            let computedValue = lazy.computeFunc()
            let cachedLazy = lazy{ cache: Some(computedValue) }
            return { lazy: cachedLazy, value: computedValue }
        }
    }
}

function mapLazy<T, U>(lazy: Lazy<T>, transform: (T) -> U) -> Lazy<U> {
    return createLazy(() => {
        let forced = forceLazy(lazy)
        return transform(forced.value)
    })
}

// Infinite sequence
struct LazySequence<T> {
    generator: (int) -> T
}

function createLazySequence<T>(generator: (int) -> T) -> LazySequence<T> {
    return LazySequence { generator }
}

function takeLazySequence<T>(sequence: LazySequence<T>, count: int) -> Array<T> {
    let mut result: Array<T> = []
    for i in 0..<count {
        result.push(sequence.generator(i))
    }
    return result
}

function mapLazySequence<T, U>(sequence: LazySequence<T>, transform: (T) -> U) -> LazySequence<U> {
    return createLazySequence(index => transform(sequence.generator(index)))
}

function filterLazySequence<T>(sequence: LazySequence<T>, condition: (T) -> bool) -> LazySequence<T> {
    return createLazySequence(index => {
        let mut currentIndex = 0
        let mut foundCount = 0

        while true {
            let value = sequence.generator(currentIndex)
            if condition(value) {
                if foundCount == index {
                    return value
                }
                foundCount += 1
            }
            currentIndex += 1
        }
    })
}

// Cached lazy value
let expensiveValue0 = createLazy(() => "topaz".toUpperCase())
let firstForce = forceLazy(expensiveValue0)
let expensiveValue1 = firstForce.lazy
let secondForce = forceLazy(expensiveValue1)
let mappedLength = mapLazy(expensiveValue1, value => value.length)
let mappedForce = forceLazy(mappedLength)

print("First lazy value: {firstForce.value}")         // "TOPAZ"
print("Cached lazy value: {secondForce.value}")       // "TOPAZ"
print("Mapped lazy value: {mappedForce.value}")       // 5

// Natural numbers infinite sequence
let naturalNumbers = createLazySequence(i => i + 1)
let first10Naturals = takeLazySequence(naturalNumbers, 10)   // [1, 2, 3, ..., 10]

// Extract even numbers only
let evenSequence = filterLazySequence(naturalNumbers, x => x % 2 == 0)
let first5Evens = takeLazySequence(evenSequence, 5)           // [2, 4, 6, 8, 10]

// Square sequence
let squareSequence = mapLazySequence(naturalNumbers, x => x * x)
let first5Squares = takeLazySequence(squareSequence, 5)       // [1, 4, 9, 16, 25]

print("First 10 naturals: {first10Naturals}")
print("First 5 evens: {first5Evens}")
print("First 5 squares: {first5Squares}")

Topaz functional library enables declarative and expressive programming. Use higher-order functions, monads, lazy evaluation, and more to write more elegant and safe code!