Pular para o conteúdo

Funções de Ordem Superior

Nesta página

Uma função de ordem superior recebe ou devolve outra função. Em Zolo, o tipo fn(T) -> R descreve um valor funcional. Isso permite abstrair o como de uma operação sem repetir o quê:

apply_twice, fábrica multiplier, compose e os clássicos map/filter/reduce.

06-higher-order.zolo
Playground
// Feature: Higher-order functions

// Syntax: `fn f(g: fn(T) -> R)` — function as argument or return value.

// When to use: abstract the "how" over the "what" — strategy

// pattern, callbacks, decorators, pipeline transformations.


use std::Array

// Function takes a function and applies it twice.

fn apply_twice(f: fn(int) -> int, x: int) -> int {
  return f(f(x))
}

fn increment(x: int) -> int {
  return x + 1
}

fn square(x: int) -> int {
  return x * x
}

print(apply_twice(increment, 5))  // 7

print(apply_twice(square, 3))  // 81


// Function that RETURNS another function (factory).

fn multiplier(factor: int) {
  return |x| x * factor
}

let triple = multiplier(3)
let quad = multiplier(4)
print(triple(7))  // 21

print(quad(7))  // 28


// Composition: `compose(f, g)(x) == f(g(x))`.

fn compose(f: fn(int) -> int, g: fn(int) -> int) {
  return |x| f(g(x))
}

let inc_then_square = compose(square, increment)
print(inc_then_square(5))  // (5+1)^2 = 36


// Map/filter/reduce — bread-and-butter of higher-order.

let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

let doubled = nums.map(|x| x * 2)
let evens = nums.filter(|x| x % 2 == 0)
let sum = nums.reduce(|acc, x| acc + x, 0)

print(doubled)  // [2, 4, ..., 20]

print(evens)  // [2, 4, 6, 8, 10]

print(sum)  // 55

Quando a closure captura um let mut do escopo externo, ela pode acumular estado entre chamadas. Cada chamada à função fábrica cria uma instância independente — o equivalente leve a um objeto com um único método:

Contador, acumulador de média e padrão once (executa só na primeira chamada).

08-stateful-closures.zolo
Playground
// Feature: Stateful closures — closures with mutable state

// Syntax: a closure captures `let mut` from the outer scope

// and modifies that value across calls.

// When to use: counters, lightweight generators, "memory"

// without creating a struct, factories of incrementers.


// Classic counter — each call increments.

fn make_counter() {
  let mut count = 0
  return |step| {
    count = count + step
    return count
  }
}

let counter = make_counter()
print(counter(1))  // 1

print(counter(1))  // 2

print(counter(5))  // 7


// Counters are INDEPENDENT — each has its own `count`.

let c1 = make_counter()
let c2 = make_counter()
c1(10)
c1(10)
c2(1)
print(c1(0))  // 20 (accumulated 10+10)

print(c2(0))  // 1


// Accumulator with memory.

fn make_accumulator() {
  let mut total = 0
  let mut hits = 0
  return |x| {
    total = total + x
    hits = hits + 1
    return total / hits  // running integer average

  }
}

let avg = make_accumulator()
print(avg(10))  // 10

print(avg(20))  // 15

print(avg(30))  // 20

print(avg(40))  // 25


// "Once" — closure that only runs on the first call.

fn make_once(f: fn() -> int) {
  let mut done = false
  let mut result = 0
  return || {
    if !done {
      result = f()
      done = true
    }
    return result
  }
}

let init = make_once(|| 42)
print(init())  // 42

print(init())  // 42 (cached)

Desafio

Use make_counter do exemplo de closures com estado para criar dois contadores independentes, avance-os em ritmos diferentes e verifique que os valores não se misturam.

Veja também

Buscar no Zolo

9 resultados

enespt-br