Closures e lambdas
Ações como valores: alta ordem, closures, lambdas e composição.
Ações são valores#
Uma ação pode ser guardada numa variável, passada como argumento e devolvida por outra ação:
dataforge
action dobro(x):
yield x * 2
f := dobro # guardada
out f(21) # 42
out [1, 2, 3].map(dobro) # passadaAlta ordem#
dataforge
action aplicar_duas_vezes(fn, valor):
yield fn(fn(valor))
out aplicar_duas_vezes(dobro, 5) # 20Closures#
Uma ação aninhada lembra o escopo onde foi criada:
dataforge
action fabrica_somador(n):
action somador(x):
yield x + n # 'n' vem do escopo de fora
yield somador
soma10 := fabrica_somador(10)
out soma10(5) # 15
out fabrica_somador(3)(4) # 7 — chamada encadeadaEstado que persiste#
dataforge
action criar_contador(inicio := 0):
estado := {"valor": inicio}
action proximo():
estado["valor"] := estado["valor"] + 1
yield estado["valor"]
yield proximo
c1 := criar_contador()
c2 := criar_contador(100)
out c1(), c1(), c1() # 1 2 3
out c2(), c2() # 101 102Cada chamada de criar_contador produz um contador com estado próprio. É o padrão de encapsulamento sem classe.
Lambdas#
Três grafias, todas equivalentes:
dataforge
quadrado := lambda x: x * x
soma := lambda a, b => a + b
constante := lambda: 42
out quadrado(7), soma(3, 4), constante()Com anotação de tipo, os parênteses são obrigatórios — sem eles, : iniciaria o corpo:
dataforge
lambda (n: Integer): n + 1Onde usam-se#
dataforge
out [1, 2, 3].map(lambda n: n * n)
out [1, 2, 3, 4].filter(lambda n: n % 2 is 0)
out [1, 2, 3].reduce(lambda a, b: a + b, 0)
out Col.sort_by(itens, lambda i: -i["preco"])Para lógica de mais de uma linha, prefira uma ação nomeada: ela pode ser testada isoladamente e o nome documenta a intenção.
Composição#
dataforge
action mais_um(x):
yield x + 1
action dobrar(x):
yield x * 2
composta := compose(dobrar, mais_um) # direita para esquerda
encadeada := pipe_fn(mais_um, dobrar) # esquerda para direita
out composta(5), encadeada(5) # 12 12Aplicação parcial#
dataforge
action multiplicar(a, b):
yield a * b
triplicar := partial(multiplicar, 3)
out triplicar(7) # 21
out [1, 2, 3].map(triplicar) # [3, 6, 9]Memoização#
dataforge
cache := {}
action fib(n):
given n smaller 2:
yield n
given cache.has(str(n)):
yield cache[str(n)]
valor := fib(n - 1) + fib(n - 2)
cache[str(n)] := valor
yield valor
out fib(30) # instantâneo — sem cache seriam milhões de chamadasA biblioteca também traz memoize pronto em Arcane.Functional.