Topaz

Функциональная библиотека

Полностью используйте функциональную библиотеку Топаза. Освойте все функциональные инструменты: функции высшего порядка, каррирование, композицию, монады и многое другое.

Топаз предоставляет мощную библиотеку функционального программирования для поддержки декларативного и выразительного написания кода. Используйте все функциональные инструменты на полную мощность!

Функции высшего порядка

Базовые функции высшего порядка

// Функция, принимающая функцию как аргумент
function дваждыПрименить<T>(функция: (T) -> T, значение: T) -> T {
    return функция(функция(значение))
}

let удвоить = (x: int) => x * 2
let результат = дваждыПрименить(удвоить, 5)                    // 20

// Функция, возвращающая функцию
function множитель(коэффициент: int) -> (int) -> int {
    return (значение: int) => значение * коэффициент
}

let утроитель = множитель(3)
let результатУтроения = утроитель(7)                          // 21

// Условное применение функции
function условноеПрименение<T>(
    условие: (T) -> bool,
    функция: (T) -> T,
    значение: T
) -> T {
    if условие(значение) {
        return функция(значение)
    } else {
        return значение
    }
}

let удвоитьЕслиЧетное = условноеПрименение(
    x => x % 2 == 0,
    x => x * 2,
    8
)                                                             // 16

print("Результат: {результат}")
print("Результат утроения: {результатУтроения}")
print("Удвоить если четное: {удвоитьЕслиЧетное}")

Композиция функций

// Базовая композиция функций
function композиция<A, B, C>(
    f: (B) -> C,
    g: (A) -> B
) -> (A) -> C {
    return (входные: A) => f(g(входные))
}

let плюсОдин = (x: int) => x + 1
let умножитьНаДва = (x: int) => x * 2
let составнаяФункция = композиция(умножитьНаДва, плюсОдин)     // (x + 1) * 2

let результатКомпозиции = составнаяФункция(5)                 // 12

// Композиция множественных функций
function конвейер<T>(...функции: Array<(T) -> T>) -> (T) -> T {
    return (начальноеЗначение: T) => {
        return функции.reduce((аккумулятор, текущаяФункция) => текущаяФункция(аккумулятор), начальноеЗначение)
    }
}

let сложнаяОбработка = конвейер(
    (x: int) => x + 1,        // +1
    (x: int) => x * 2,        // *2
    (x: int) => x - 3,        // -3
    (x: int) => x / 2         // /2
)

let результатКонвейера = сложнаяОбработка(10)                 // 9.5

print("Результат композиции: {результатКомпозиции}")
print("Результат конвейера: {результатКонвейера}")

Частичное применение

// Функция частичного применения
function частичноеПрименение<A, B, C>(
    функция: (A, B) -> C,
    первыйАргумент: A
) -> (B) -> C {
    return (второйАргумент: B) => функция(первыйАргумент, второйАргумент)
}

let сложить = (a: int, b: int) => a + b
let прибавить10 = частичноеПрименение(сложить, 10)
let результатЧастичногоПрименения = прибавить10(5)           // 15

// Частичное применение трех аргументов
function частичное3<A, B, C, D>(
    функция: (A, B, C) -> D,
    первый: A,
    второй: B
) -> (C) -> D {
    return (третий: C) => функция(первый, второй, третий)
}

let вычислить = (x: int, y: int, z: int) => x * y + z
let частичноеВычисление = частичное3(вычислить, 2, 3)         // 2 * 3 + z
let финальныйРезультат = частичноеВычисление(4)               // 10

print("Результат частичного применения: {результатЧастичногоПрименения}")
print("Финальный результат: {финальныйРезультат}")

Каррирование

Базовое каррирование

// Ручное каррирование
function карри2<A, B, C>(функция: (A, B) -> C) -> (A) -> (B) -> C {
    return (a: A) => (b: B) => функция(a, b)
}

function карри3<A, B, C, D>(функция: (A, B, C) -> D) -> (A) -> (B) -> (C) -> D {
    return (a: A) => (b: B) => (c: C) => функция(a, b, c)
}

// Применение каррирования
let сложить = (x: int, y: int) => x + y
let каррированноеСложение = карри2(сложить)
let прибавить5 = каррированноеСложение(5)
let результатКарри = прибавить5(3)                           // 8

// Каррирование трех аргументов
let формула = (x: int, y: int, z: int) => x * y + z
let каррированнаяФормула = карри3(формула)
let пошаговоеВычисление = каррированнаяФормула(2)(3)(4)      // 10

print("Результат карри: {результатКарри}")
print("Пошаговое вычисление: {пошаговоеВычисление}")

Автоматическое каррирование

// Декоратор автоматического каррирования
function автоКарри<T>(функция: Function) -> Function {
    // Проверка количества аргументов во время выполнения и автоматическое каррирование
    return function(...аргументы: Array<T>) {
        if аргументы.length >= функция.arity {
            return функция.apply(null, аргументы)
        } else {
            return function(...дополнительныеАргументы: Array<T>) {
                return автоКарри(функция).apply(null, [...аргументы, ...дополнительныеАргументы])
            }
        }
    }
}

// Пример использования
let умножить = автоКарри((a: int, b: int, c: int) => a * b * c)

let способ1 = умножить(2, 3, 4)                              // 24 (все аргументы сразу)
let способ2 = умножить(2)(3)(4)                              // 24 (последовательное применение)
let способ3 = умножить(2, 3)(4)                              // 24 (частичное применение)

let частичноеУмножение = умножить(2, 3)                       // Возвращает функцию
let полноеУмножение = частичноеУмножение(4)                   // 24

print("Результаты автокарри: {способ1}, {способ2}, {способ3}")

Утилиты преобразования функций

Мемоизация

// Базовая мемоизация
function мемоизировать<T, R>(функция: (T) -> R) -> (T) -> R {
    let mut кэш: Map<T, R> = Map.new()
    
    return (входные: T) => {
        if кэш.has(входные) {
            return кэш.get(входные).unwrap()
        }
        
        let результат = функция(входные)
        кэш.set(входные, результат)
        return результат
    }
}

// Мемоизация для чисел Фибоначчи
let фибоначчи = мемоизировать((n: int) => {
    print("Вычисляем: фибоначчи({n})")
    if n <= 1 { return n }
    return фибоначчи(n - 1) + фибоначчи(n - 2)
})

let фиб10 = фибоначчи(10)                                    // 55 (без дублирующих вычислений)
let фиб10Снова = фибоначчи(10)                              // 55 (возвращено из кэша мгновенно)

// Мемоизация с TTL (Time To Live)
function мемоизацияСTTL<T, R>(
    функция: (T) -> R,
    ttl: int
) -> (T) -> R {
    let mut кэш: Map<T, { результат: R, временнаяМетка: int }> = Map.new()
    
    return (входные: T) => {
        let текущееВремя = Date.now()
        
        if кэш.has(входные) {
            let записьКэша = кэш.get(входные).unwrap()
            if (текущееВремя - записьКэша.временнаяМетка) < ttl {
                return записьКэша.результат
            }
        }
        
        let результат = функция(входные)
        кэш.set(входные, { результат, временнаяМетка: текущееВремя })
        return результат
    }
}

print("Фибоначчи 10: {фиб10}")

Устранение дребезга и дросселирование

// Функция устранения дребезга
function устранитьДребезг<T>(
    функция: (...T) -> void,
    задержка: int
) -> (...T) -> void {
    let mut idТаймера: Option<int> = None
    
    return (...аргументы: Array<T>) => {
        // Отменить существующий таймер
        match idТаймера {
            case Some(id) => clearTimeout(id)
            case None => {}
        }
        
        // Установить новый таймер
        idТаймера = Some(setTimeout(() => {
            функция(...аргументы)
            idТаймера = None
        }, задержка))
    }
}

// Функция дросселирования
function дросселировать<T>(
    функция: (...T) -> void,
    интервал: int
) -> (...T) -> void {
    let mut времяПоследнегоВызова = 0
    let mut idТаймера: Option<int> = None
    
    return (...аргументы: Array<T>) => {
        let текущееВремя = Date.now()
        let времяСПоследнегоВызова = текущееВремя - времяПоследнегоВызова
        
        if времяСПоследнегоВызова >= интервал {
            функция(...аргументы)
            времяПоследнегоВызова = текущееВремя
        } else if idТаймера.isNone() {
            idТаймера = Some(setTimeout(() => {
                функция(...аргументы)
                времяПоследнегоВызова = Date.now()
                idТаймера = None
            }, интервал - времяСПоследнегоВызова))
        }
    }
}

// Примеры использования
let функцияПоиска = (запрос: string) => {
    print("Выполняем поиск: {запрос}")
}

let поискСУстранениемДребезга = устранитьДребезг(функцияПоиска, 300)   // Выполнить через 300мс
let дроссельныйПоиск = дросселировать(функцияПоиска, 1000)           // Максимум 1 вызов в секунду

Функциональное преобразование данных

Линзы

// Базовая реализация линз с явными helper-функциями
struct Линза<S, A> {
    получить: (S) -> A,
    установить: (A, S) -> S
}

function создатьЛинзу<S, A>(получатель: (S) -> A, установщик: (A, S) -> S) -> Линза<S, A> {
    return Линза { получить: получатель, установить: установщик }
}

function скомпоноватьЛинзы<S, A, B>(внешняя: Линза<S, A>, внутренняя: Линза<A, B>) -> Линза<S, B> {
    return создатьЛинзу(
        (значение: S) => внутренняя.получить(внешняя.получить(значение)),
        (замена: B, значение: S) => {
            let текущийФокус = внешняя.получить(значение)
            let новыйФокус = внутренняя.установить(замена, текущийФокус)
            return внешняя.установить(новыйФокус, значение)
        }
    )
}

function изменитьЧерезЛинзу<S, A>(линза: Линза<S, A>, функция: (A) -> A, значение: S) -> S {
    let текущееЗначение = линза.получить(значение)
    return линза.установить(функция(текущееЗначение), значение)
}

// Структура пользователя
struct Пользователь {
    имя: string,
    возраст: int,
    адрес: Адрес
}

struct Адрес {
    город: string,
    почтовыйИндекс: string
}

// Определения линз
let линзаИмени = создатьЛинзу(
    (пользователь: Пользователь) => пользователь.имя,
    (имя: string, пользователь: Пользователь) => пользователь{ имя }
)

let линзаАдреса = создатьЛинзу(
    (пользователь: Пользователь) => пользователь.адрес,
    (адрес: Адрес, пользователь: Пользователь) => пользователь{ адрес }
)

let линзаГорода = создатьЛинзу(
    (адрес: Адрес) => адрес.город,
    (город: string, адрес: Адрес) => адрес{ город }
)

// Композиция линз
let линзаГородаПользователя = скомпоноватьЛинзы(линзаАдреса, линзаГорода)

// Пример использования
let пользователь = Пользователь {
    имя: "Иван Иванов",
    возраст: 30,
    адрес: Адрес { город: "Москва", почтовыйИндекс: "123456" }
}

let новыйПользователь = линзаГородаПользователя.установить("Санкт-Петербург", пользователь)
let измененныйПользователь = изменитьЧерезЛинзу(линзаИмени, имя => имя.toUpperCase(), новыйПользователь)

print("Исходный город: {линзаГородаПользователя.получить(пользователь)}")      // "Москва"
print("Новый город: {линзаГородаПользователя.получить(новыйПользователь)}")   // "Санкт-Петербург"
print("Измененное имя: {измененныйПользователь.имя}")                          // "ИВАН ИВАНОВ"

Конвейер функциональных данных

// Конвейер преобразования данных
struct Конвейер<T> {
    данные: T
}

function конвейерИз<T>(данные: T) -> Конвейер<T> {
    return Конвейер { данные }
}

function конвейерМап<T, U>(конвейер: Конвейер<T>, преобразование: (T) -> U) -> Конвейер<U> {
    return Конвейер { данные: преобразование(конвейер.данные) }
}

function конвейерФильтр<T>(конвейер: Конвейер<T>, условие: (T) -> bool) -> Конвейер<Option<T>> {
    if условие(конвейер.данные) {
        return Конвейер { данные: Some(конвейер.данные) }
    } else {
        return Конвейер { данные: None }
    }
}

function конвейерЭффект<T>(конвейер: Конвейер<T>, побочныйЭффект: (T) -> void) -> Конвейер<T> {
    побочныйЭффект(конвейер.данные)
    return конвейер
}

function значениеКонвейера<T>(конвейер: Конвейер<T>) -> T {
    return конвейер.данные
}

// Пример обработки данных
let результат = конвейерИз("  Привет Мир  ")
    |> конвейерМап(_, s => s.trim())
    |> конвейерЭффект(_, s => print("После обрезки: '{s}'"))
    |> конвейерМап(_, s => s.toLowerCase())
    |> конвейерЭффект(_, s => print("В нижнем регистре: '{s}'"))
    |> конвейерМап(_, s => s.split(" "))
    |> конвейерМап(_, массив => массив.join("-"))
    |> значениеКонвейера(_)                            // "привет-мир"

print("Финальный результат: {результат}")

Монады

Монада Maybe/Option

// Помощники Option в виде функций пространства имён
module Option {
    function мапить<T, U>(опция: Option<T>, преобразование: (T) -> U) -> Option<U> {
        match опция {
            case Some(значение) => Some(преобразование(значение))
            case None => None
        }
    }

    function плоскоМапить<T, U>(опция: Option<T>, функция: (T) -> Option<U>) -> Option<U> {
        match опция {
            case Some(значение) => функция(значение)
            case None => None
        }
    }

    function фильтровать<T>(опция: Option<T>, условие: (T) -> bool) -> Option<T> {
        match опция {
            case Some(значение) if условие(значение) => Some(значение)
            case _ => None
        }
    }

    function илиИначе<T>(опция: Option<T>, альтернатива: () -> Option<T>) -> Option<T> {
        match опция {
            case Some(_) => опция
            case None => альтернатива()
        }
    }
}

// Пример цепочки вызовов
let данныеПользователя = Some("Иван Иванов")

let обработанныйРезультат = данныеПользователя
    |> Option.фильтровать(_, имя => имя.length > 2)
    |> Option.мапить(_, имя => имя.toUpperCase())
    |> Option.плоскоМапить(_, имя => {
        if имя.startsWith("ИВАН") {
            return Some("Приветствие: Привет {имя}")
        } else {
            return None
        }
    })
    |> Option.илиИначе(_, () => Some("Неизвестный пользователь"))

print("Обработанный результат: {обработанныйРезультат}")      // Some("Приветствие: Привет ИВАН ИВАНОВ")

Монада Result

// Helper-функции для Result в пространстве имён
module ResultИнструменты {
    function map<T, U, E>(результат: Result<T, E>, преобразование: (T) -> U) -> Result<U, E> {
        match результат {
            case Ok(значение) => Ok(преобразование(значение))
            case Err(ошибка) => Err(ошибка)
        }
    }

    function flatMap<T, U, E>(результат: Result<T, E>, функция: (T) -> Result<U, E>) -> Result<U, E> {
        match результат {
            case Ok(значение) => функция(значение)
            case Err(ошибка) => Err(ошибка)
        }
    }

    function mapError<T, E, F>(результат: Result<T, E>, функция: (E) -> F) -> Result<T, F> {
        match результат {
            case Ok(значение) => Ok(значение)
            case Err(ошибка) => Err(функция(ошибка))
        }
    }

    function recover<T, E>(результат: Result<T, E>, функцияВосстановления: (E) -> T) -> T {
        match результат {
            case Ok(значение) => значение
            case Err(ошибка) => функцияВосстановления(ошибка)
        }
    }
}

// Безопасные цепочки операций
function безопасноеДеление(числитель: float, знаменатель: float) -> Result<float, string> {
    if знаменатель == 0.0 {
        return Err("Нельзя делить на ноль")
    }
    return Ok(числитель / знаменатель)
}

function безопасныйКореньКвадратный(значение: float) -> Result<float, string> {
    if значение < 0.0 {
        return Err("Нельзя вычислить квадратный корень отрицательного числа")
    }
    return Ok(Math.sqrt(значение))
}

let результатВычисления = Ok(16.0)
    |> ResultИнструменты.flatMap(_, значение => безопасноеДеление(значение, 4.0))    // 16 / 4 = 4
    |> ResultИнструменты.flatMap(_, значение => безопасныйКореньКвадратный(значение)) // √4 = 2
    |> ResultИнструменты.map(_, значение => значение * 2)                              // 2 * 2 = 4
    |> ResultИнструменты.mapError(_, ошибка => "Сбой вычисления: {ошибка}")
    |> ResultИнструменты.recover(_, ошибка => {
        print("Произошла ошибка: {ошибка}")
        return 0.0
    })

print("Результат вычисления: {результатВычисления}")             // 4.0

Функциональные паттерны

Паттерн стратегия

// Функциональный паттерн стратегия
enum СтратегияСортировки {
    БыстраяСортировка,
    СортировкаСлиянием,
    СортировкаПузырьком
}

function сортироватьСо<T>(
    массив: Array<T>,
    стратегия: СтратегияСортировки,
    функцияСравнения: (T, T) -> int
) -> Array<T> {
    let функцияСортировки = match стратегия {
        case БыстраяСортировка => быстраяСортировка
        case СортировкаСлиянием => сортировкаСлиянием
        case СортировкаПузырьком => сортировкаПузырьком
    }
    
    return функцияСортировки(массив, функцияСравнения)
}

function быстраяСортировка<T>(массив: Array<T>, сравнить: (T, T) -> int) -> Array<T> {
    // Реализация быстрой сортировки
    if массив.length <= 1 { return массив }
    
    let опорныйЭлемент = массив[массив.length / 2]
    let меньшие = массив.filter(x => сравнить(x, опорныйЭлемент) < 0)
    let равные = массив.filter(x => сравнить(x, опорныйЭлемент) == 0)
    let большие = массив.filter(x => сравнить(x, опорныйЭлемент) > 0)
    
    return [
        ...быстраяСортировка(меньшие, сравнить),
        ...равные,
        ...быстраяСортировка(большие, сравнить)
    ]
}

// Пример использования
let массивЧисел = [64, 34, 25, 12, 22, 11, 90]
let отсортированныйМассив = сортироватьСо(
    массивЧисел,
    БыстраяСортировка,
    (a, b) => a - b
)

print("Отсортированный массив: {отсортированныйМассив}")

Паттерн наблюдатель

// Функциональный паттерн наблюдатель
struct Наблюдаемый<T> {
    подписчики: Array<(T) -> void>
}

function создатьНаблюдаемый<T>() -> Наблюдаемый<T> {
    return Наблюдаемый { подписчики: [] }
}

function подписатьНаблюдаемый<T>(наблюдаемый: Наблюдаемый<T>, колбэк: (T) -> void) -> Наблюдаемый<T> {
    return наблюдаемый{ подписчики: [...наблюдаемый.подписчики, колбэк] }
}

function отправитьНаблюдаемому<T>(наблюдаемый: Наблюдаемый<T>, значение: T) {
    наблюдаемый.подписчики.forEach(колбэк => колбэк(значение))
}

function мапитьНаблюдатель<T, U>(преобразование: (T) -> U, колбэк: (U) -> void) -> (T) -> void {
    return значение => колбэк(преобразование(значение))
}

function фильтроватьНаблюдатель<T>(условие: (T) -> bool, колбэк: (T) -> void) -> (T) -> void {
    return значение => {
        if условие(значение) {
            колбэк(значение)
        }
    }
}

// Пример использования
let наблюдательКоординат = фильтроватьНаблюдатель(
    событие => событие.тип == "клик",
    мапитьНаблюдатель(
        событие => событие.координаты,
        координаты => print("Позиция клика: {координаты}")
    )
)

let наблюдательДвойногоКлика = фильтроватьНаблюдатель(
    событие => событие.двойнойКлик,
    событие => print("Обнаружен двойной клик")
)

let потокКликов0 = создатьНаблюдаемый()
let потокКликов1 = подписатьНаблюдаемый(потокКликов0, наблюдательКоординат)
let потокКликов2 = подписатьНаблюдаемый(потокКликов1, наблюдательДвойногоКлика)

// Отправка событий
отправитьНаблюдаемому(потокКликов2, { тип: "клик", координаты: [100, 200], двойнойКлик: false })
отправитьНаблюдаемому(потокКликов2, { тип: "клик", координаты: [300, 400], двойнойКлик: true })

Продвинутые функциональные техники

Y комбинатор

// Y комбинатор для реализации рекурсивных функций
function Y<T>(функция: ((T) -> T) -> (T) -> T) -> (T) -> T {
    return function(аргумент: T) -> T {
        return функция(Y(функция))(аргумент)
    }
}

// Факториал через Y комбинатор
let факториал = Y((рекурсивнаяФункция: (int) -> int) => (n: int) => {
    if n <= 1 {
        return 1
    } else {
        return n * рекурсивнаяФункция(n - 1)
    }
})

let факториал5 = факториал(5)                         // 120

// Фибоначчи через Y комбинатор
let фибоначчиY = Y((рекурсивнаяФункция: (int) -> int) => (n: int) => {
    if n <= 1 {
        return n
    } else {
        return рекурсивнаяФункция(n - 1) + рекурсивнаяФункция(n - 2)
    }
})

let фиб8 = фибоначчиY(8)                              // 21

print("Y комбинатор факториал(5): {факториал5}")
print("Y комбинатор фибоначчи(8): {фиб8}")

Ленивые вычисления

// Ленивые вычисления с явным переходом состояния
struct Ленивый<T> {
    функцияВычисления: () -> T,
    кэш: Option<T>
}

function создатьЛенивое<T>(функцияВычисления: () -> T) -> Ленивый<T> {
    return Ленивый { функцияВычисления, кэш: None }
}

function вычислитьЛенивое<T>(ленивое: Ленивый<T>) -> { lazy: Ленивый<T>, value: T } {
    match ленивое.кэш {
        case Some(значение) => return { lazy: ленивое, value: значение }
        case None => {
            let вычисленноеЗначение = ленивое.функцияВычисления()
            let кэшированноеЛенивое = ленивое{ кэш: Some(вычисленноеЗначение) }
            return { lazy: кэшированноеЛенивое, value: вычисленноеЗначение }
        }
    }
}

function мапитьЛенивое<T, U>(ленивое: Ленивый<T>, преобразование: (T) -> U) -> Ленивый<U> {
    return создатьЛенивое(() => {
        let вычисленное = вычислитьЛенивое(ленивое)
        return преобразование(вычисленное.value)
    })
}

// Бесконечная последовательность
struct ЛениваяПоследовательность<T> {
    генератор: (int) -> T
}

function создатьЛенивуюПоследовательность<T>(генератор: (int) -> T) -> ЛениваяПоследовательность<T> {
    return ЛениваяПоследовательность { генератор }
}

function взятьИзЛенивойПоследовательности<T>(
    последовательность: ЛениваяПоследовательность<T>,
    количество: int
) -> Array<T> {
    let mut результат: Array<T> = []
    for i in 0..<количество {
        результат.push(последовательность.генератор(i))
    }
    return результат
}

function мапитьЛенивуюПоследовательность<T, U>(
    последовательность: ЛениваяПоследовательность<T>,
    преобразование: (T) -> U
) -> ЛениваяПоследовательность<U> {
    return создатьЛенивуюПоследовательность(индекс => преобразование(последовательность.генератор(индекс)))
}

function фильтроватьЛенивуюПоследовательность<T>(
    последовательность: ЛениваяПоследовательность<T>,
    условие: (T) -> bool
) -> ЛениваяПоследовательность<T> {
    return создатьЛенивуюПоследовательность(индекс => {
        let mut текущийИндекс = 0
        let mut найденныйСчетчик = 0

        while true {
            let значение = последовательность.генератор(текущийИндекс)
            if условие(значение) {
                if найденныйСчетчик == индекс {
                    return значение
                }
                найденныйСчетчик += 1
            }
            текущийИндекс += 1
        }
    })
}

// Кэшируемое ленивое значение
let дорогоеЗначение0 = создатьЛенивое(() => "topaz".toUpperCase())
let первоеВычисление = вычислитьЛенивое(дорогоеЗначение0)
let дорогоеЗначение1 = первоеВычисление.lazy
let второеВычисление = вычислитьЛенивое(дорогоеЗначение1)
let ленивыйРазмер = мапитьЛенивое(дорогоеЗначение1, значение => значение.length)
let вычисленныйРазмер = вычислитьЛенивое(ленивыйРазмер)

print("Первое ленивое значение: {первоеВычисление.value}")       // "TOPAZ"
print("Кэшированное ленивое значение: {второеВычисление.value}") // "TOPAZ"
print("Преобразованное ленивое значение: {вычисленныйРазмер.value}") // 5

// Бесконечная последовательность натуральных чисел
let натуральныеЧисла = создатьЛенивуюПоследовательность(i => i + 1)
let первые10Натуральных = взятьИзЛенивойПоследовательности(натуральныеЧисла, 10) // [1, 2, 3, ..., 10]

// Извлечение только четных чисел
let четнаяПоследовательность = фильтроватьЛенивуюПоследовательность(натуральныеЧисла, x => x % 2 == 0)
let первые5Четных = взятьИзЛенивойПоследовательности(четнаяПоследовательность, 5) // [2, 4, 6, 8, 10]

// Последовательность квадратов
let последовательностьКвадратов = мапитьЛенивуюПоследовательность(натуральныеЧисла, x => x * x)
let первые5Квадратов = взятьИзЛенивойПоследовательности(последовательностьКвадратов, 5) // [1, 4, 9, 16, 25]

print("Первые 10 натуральных: {первые10Натуральных}")
print("Первые 5 четных: {первые5Четных}")
print("Первые 5 квадратов: {первые5Квадратов}")

Функциональная библиотека Топаз обеспечивает декларативное и выразительное программирование. Используйте функции высшего порядка, монады, ленивые вычисления и многое другое для написания более элегантного и безопасного кода!