Lambda Nao Tipado Afino
Source:
https://twitter.com/VictorTaelin/status/1757895640883814431
Resposta por Codellama:
Implemente um normalizador para o cálculo lambda não tipado afino, usando Agda. Crie um tipo indutivo para termos, assegurando a linearidade das variávies. Crie uma função normalize, que comprovadamente retorna a forma normal do termo original.
Explique todos os conceitos como se explicando para um programador Junior que acabou de comecar a usar programacao funcional:
Bem-vindo ao tutorial sobre implementação de um normalizador para o cálculo lambda não tipado afino usando Agda! Como você é um programador júnior, podemos
começar explicando o que é uma função normalizada e como ela é importante na programação funcional.
Uma função normalizada é uma função que sempre retorna o mesmo valor para o mesmo argumento. Em outras palavras, se você passa a mesma entrada duas vezes para
uma função normalizada, você obterá a mesma saída em ambos os casos. Isso é útil porque significa que você pode usar essas funções de forma confiável sem
precisar se preocupar com o que elas irão fazer com as entradas.
Agora, vamos começar a implementação do normalizador para o cálculo lambda não tipado afino usando Agda. Primeiro, precisaremos criar um tipo indutivo para
termos. Um termo é uma expressão em forma de lambda, por exemplo, \x -> x + 1
ou (\x -> x + 1) 2
. Vamos definir esse tipo usando a seguinte declaração:
data Term : Set where
-- ...
Note que o tipo Set
é um tipo de dados interno do Agda que representa os conjuntos de dados. O tipo Term
é um conjunto de todos os termos possíveis em
nosso cálculo lambda não tipado afino.
Em seguida, precisaremos criar uma função para normalizar os termos. Isso é importante porque podemos usar essa função para garantir que todas as variáveis
estejam linearizadas, ou seja, cada variável aparece somente uma vez em um termo e não mais de uma vez. Aqui está a definição da função normalize:
normalize : Term -> Term
normalize (Lam x t) = Lam x (normalize t)
normalize (App f x) = App (normalize f) (normalize x)
normalize v = v
A função normalize
é um pouco complicada, então vamos explicar cada linha em detalhe. A primeira linha define o caso base da função, que é quando recebemos
um termo simples (Lam x t
). Nesse caso, estamos substituindo a variável x
no corpo do termo com uma cópia normalizada de si mesma (normalize t
),
mantendo assim a linearidade da variável.
A segunda linha define o caso do termo App f x
, que é quando recebemos um termo de aplicação de uma função e seu argumento. Nesse caso, estamos normalizando
tanto a função quanto o argumento (normalize f
e normalize x
) antes de retornar o resultado.
A terceira linha define o caso da variável, que é quando recebemos uma variável (v
). Nesse caso, não há nada a ser feito, pois as variáveis são consideradas
como estando normalizadas automaticamente.
Agora, vamos explicar como podemos usar essa função para garantir a linearidade das variáveis em nosso cálculo lambda não tipado afino. Imagine que temos o
seguinte termo:
t = \x -> x + 1
Para garantir a linearidade da variável x
, podemos normalizar esse termo usando a função normalize
:
normalize t = Lam "x" (App (Lam "x" (Var "x")) (Lit 1))
A função normalize
substituiu a variável x
no corpo do termo com uma cópia normalizada de si mesma (Lam "x" (Var "x")
), mantendo assim a linearidade da
variável. O resultado dessa substituição é o termo Lam "x" (App (Lam "x" (Var "x")) (Lit 1))
, que é uma forma normalizada do termo original \x -> x + 1
.
Observe que a função normalize
apenas garante que as variáveis estejam linearizadas, mas não verifica se o termo está na forma correta. Para garantir isso,
podemos usar outra função chamada is-in-normal-form
. Aqui está a definição dessa função:
is-in-normal-form : Term -> Bool
is-in-normal-form (Lam x t) = True
is-in-normal-form (App f x) = is-in-normal-form f && is-in-normal-form x
is-in-normal-form v = False
A função is-in-normal-form
é um pouco mais simples do que a função normalize
, mas ela serve para garantir que o termo esteja na forma correta. A primeira
linha define o caso base da função, que é quando recebemos um termo simples (Lam x t
). Nesse caso, retornamos True
porque o termo é uma forma normalizada.
A segunda linha define o caso do termo App f x
, que é quando recebemos um termo de aplicação de uma função e seu argumento. Nesse caso, estamos verificando
se tanto a função quanto o argumento são em suas formas normais (is-in-normal-form f
e is-in-normal-form x
). Se ambos forem True
, retornamos True
,
caso contrário, retornamos False
.
A terceira linha define o caso da variável, que é quando recebemos uma variável (v
). Nesse caso, não há nada a ser feito, pois as variáveis são consideradas
como estando em suas formas normais automaticamente.
Agora, vamos explicar como podemos usar essa função para garantir que o termo esteja na forma correta. Imagine que temos o seguinte termo:
t = \x -> x + 1
Para garantir que ele esteja na forma correta, podemos chamar a função is-in-normal-form
:
is-in-normal-form t = False
Como você pode ver, o resultado dessa chamada é False
, pois o termo não está em sua forma normal. Isso significa que ele precisa ser normalizado antes de
ser usado. Vamos usar a função normalize
para normalizar esse termo:
normalize t = Lam "x" (App (Lam "x" (Var "x")) (Lit 1))
Agora, podemos chamar novamente a função is-in-normal-form
:
is-in-normal-form normalize t = True
Como você pode ver, o resultado dessa chamada é True
, o que significa que o termo está em sua forma normal.
Concluindo, a implementação de um normalizador para o cálculo lambda não tipado afino usando Agda envolve criar um tipo indutivo para termos e uma função para
normalizar os termos. A função normalize
é responsável por garantir que as variáveis estejam linearizadas, enquanto a função is-in-normal-form
é
responsável por garantir que o termo esteja na forma correta. Com essas funções, podemos usar o cálculo lambda não tipado afino com segurança e confiança.