Pular para o conteúdo

Ações

Funções em DataForge: parâmetros, tipos, aridade, closures, lambdas, decoradores e defer.

Declarar#

dataforge
action somar(a, b):
    yield a + b

out somar(2, 3)     # 5

yield devolve o valor e encerra a ação. Sem yield, a ação devolve void.

Parâmetros#

Valores padrão#

dataforge
action criar(nome, papel := "leitor", ativo := yes):
    yield {"nome": nome, "papel": papel, "ativo": ativo}

out criar("Ana")                  # papel = "leitor"
out criar("Bruno", "admin")

Argumentos nomeados#

dataforge
action retangulo(largura := 1, altura := 1):
    yield largura * altura

out retangulo(altura := 5, largura := 3)     # 15 — fora de ordem

Tipos#

dataforge
action media(nums: Cluster) -> Float:
    yield sum(nums) / len(nums)

out media([1, 2, 3])     # 2.0

Parâmetros e retorno são verificados. A mensagem de erro nomeia exatamente o parâmetro:

text
parameter 'nums' of action 'media' declared as Cluster but got String

Aridade verificada#

Chamar com argumentos a mais ou a menos dispara erro — e o analisador estático acha isso antes de executar:

dataforge
action f(a, b):
    yield a + b

# f(1)          -> action 'f' is missing argument(s): b
# f(1, 2, 3)    -> action 'f' takes 2 argument(s) but 3 were given

Recursão#

dataforge
action fatorial(n):
    given n smaller_eq 1:
        yield 1
    yield n * fatorial(n - 1)

out fatorial(6)     # 720

Recursão infinita vira StackOverflowError_ após 1000 quadros, com o nome da ação culpada na mensagem. Recursões legítimas de até ~900 níveis funcionam.

Ações de alta ordem e closures#

dataforge
action fabrica_somador(n):
    action somador(x):
        yield x + n          # 'n' vem do escopo de fora — isso é a closure
    yield somador

soma10 := fabrica_somador(10)
out soma10(5)                  # 15
out fabrica_somador(3)(4)      # 7 — chamada encadeada

Lambdas#

Três grafias, todas equivalentes:

dataforge
dobro := lambda x: x * 2
soma := lambda a, b => a + b
fixo := lambda: 42

out [1, 2, 3].map(lambda n: n * n)              # [1, 4, 9]
out [1, 2, 3, 4].filter(lambda n: n % 2 is 0)   # [2, 4]

Decoradores#

mark @nome envolve uma ação com outra, sem alterar seu corpo:

dataforge
action com_log(fn):
    action envolvida(x):
        out $"  [log] chamada com {x}"
        yield fn(x)
    yield envolvida

mark @com_log
action triplo(x):
    yield x * 3

out triplo(5)
saída
  [log] chamada com 5
15

defer#

Agenda um bloco para rodar quando a ação terminar — em qualquer caminho de saída, inclusive por erro:

dataforge
action com_recurso():
    abrir()
    defer:
        fechar()          # roda aconteça o que acontecer
    processar()
    yield "pronto"

Vários defer rodam em ordem inversa (LIFO), que é a ordem correta para desmontar recursos dependentes. Detalhes em Tratamento de erros.