2005/2006
O trabalho divide-se numa base e nos anexos, devendo todos os trabalhos entregues implementar a base.
<termo> ::= <variável> (Variável) | (\<variável>.<termo>) (Abstracção) | (<termo> <termo>) (Aplicação) | (let <variável> = <termo> in <termo>) (let)Nesta sintaxe, o carácter barra-inclinada-para-trás ‘\’ faz o papel do símbolo ‘λ’ e as variáveis têm um nome constituído por uma única letra minúscula.
Para não sobrecarregar os termos com parêntesis, adoptam-se as seguintes convenções:
(let f = (\x.(\y.((\z.z) (x y)) y)) in (let g = (\x.(\y.(\z.(z ((x y) z))))) in (((g a) b) f)))poder-se-á escrever como
let f = \x.\y.(\z.z) (x y) y in let g = \x.\y.\z.z (x y z) in g a b f
Durante a fase da análise sintáctica, o programa apresentado deverá construir uma árvore de sintaxe abstracta, que servirá depois de base para a avaliação a efectuar.
Nesta parte do trabalho poderá ser considerado que uma substituição nunca ocasiona a captura de variáveis (ver o anexo A).
Um comentário inicia-se com o carácter ponto-e-vírgula ‘;’ ou pela sequência ‘->’ (caracteres menos e maior que) e estende-se até ao fim da linha. (A notação ‘->’ destina-se a anotar o código com a forma reduzida do termo-λ.)
<termo> ::= <inteiro> | + | - | * | /Quaisquer destes novos termos são constantes e não reduzem mais. No entanto, enquanto que os inteiros (sem sinal) não podem ser aplicados, os outros símbolos denotam funções com dois argumentos, que realizam as operações usuais.
Tratando-se de funções de dois argumentos, a sua aplicação a um argumento tem como resultado uma função de um argumento. Por exemplo, o termo ‘+ 5’ é uma função que soma 5 ao seu argumento. Assim, o termo
let f = + 5 in f 10reduzirá para o termo ‘15’.
Considera-se que a realização de uma destas operações corresponde a um passo de redução e que só poderá ser efectuada quando ambos os argumentos tiverem reduzido para inteiros. Assim, o termo
* (- 14 5) (\x.x x)só poderá reduzir até ‘* 9 (\x.x x)’, visto que ‘\x.x x’ não é um inteiro nem nunca reduzirá para um.
<termo> ::= (if <termo> then <termo> else <termo>) | = | true | false | <inteiro>onde ‘true’ e ‘false’ são constantes que correspondem aos valores lógicos e que se comportam como os inteiros. O termo ‘=’ é, também, uma constante e denota a função que testa se dois inteiros são iguais. A sua aplicação a dois argumentos só reduz para um valor lógico se aqueles reduzirem para inteiros (ver no anexo B o comportamento do inteiros e das funções com dois argumentos).
A construção if tem a mesma prioridade que a let e reduz, num passo, para o termo do ramo then, se a condição tiver reduzido para ‘true’, e para o termo else se a condição tiver reduzido para ‘false’. Se a condição não reduzir para um valor lógico, o termo if não pode reduzir.
Internamente, o resultado da análise sintáctica deverá ser uma árvore de sintaxe abstracta. Esta representação do termo lido poderá, depois, ser utilizada directamente no processo de redução do termo ou ser processada com o fito de obter uma representação considerada mais apropriada para o funcionamento do programa.
Se o termo lido pelo programa for
let f = \g.\v.g v in f (\x.\y.x y z) wele poderá ser escrito em qualquer uma das seguintes formas
let f = \g.\v.g v in f (\x.\y.x y z) w let f' = \g'.\v'.g' v' in f' (\x'.\y'.x' y' z) w let a = \b.\c.b c in a (\d.\e.d e z) w let x0 = \x1.\x2.x1 x2 in x0 (\x3.\x4.x3 x4 z) w let x0 = \x0.\x1.x0 x1 in x0 (\x0.\x1.x0 x1 z) w let f2 = \g0.\v1.g0 v1 in f2 (\x3.\y4.x3 y4 z) w (\f.f (\x.\y.x y z) w) (\g.\v.g v) (\f'.f' (\x'.\y'.x' y' z) w) (\g'.\v'.g' v) (\a.a (\b.\c.b c z) w) (\d.\e.d e) (\x0.x0 (\x1.\x2.x1 x2 z) w) (\x3.\x4.x3 x4) (\x0.x0 (\x1.\x2.x1 x2 z) w) (\x0.\x1.x0 x1) (\f2.f2 (\x3.\y4.x3 y4 z) w) (\g0.\v1.g0 v1)ou em alguma variante destas.
Deverá ser entregue uma makefile que proceda à compilação do programa através das invocações make ou make all, que provoque a sua execução através do comando make run e que apague os ficheiro criados na compilação através de make clean.
Os ficheiros Makefile, Main.java, lambda.cup e lambda.lex fornecidos podem constituir um ponto de partida, mas não têm de ser usados.
Usando a makefile fornecida, é possível passar argumentos ao interpretador usando o comando
make run ARGS='<argumentos>'Se o ficheiro termo.lambda contiver o termo-λ a avaliar, o comando
make run < termo.lambdafará com que o interpretador o leia.
(\x.\y.x y) zo interpretador escreverá no terminal, a menos do nome das variáveis ligadas e da inclusão de mais parêntesis
(\x.\y.x y) z -> \y.z y
xSaída:
xou
x -> x
\x.xSaída:
\x.x
(\x.x) ySaída:
(\x.x) y
-> y
x ySaída:
x y
x y ySaída:
x y y
f (\x.x) ySaída:
f (\x.x) y
(\x.x) (\y.y) zSaída:
(\x.x) (\y.y) z -> z
(\f.\x.f x) (\y.y) zSaída:
(\f.\x.f x) (\y.y) z -> z
\f.\x.f xSaída:
\f.\x.f x
(\f.\x.f x) (\y.y)Saída:
(\f.\x.f x) (\y.y) -> \x.x
let x = y in zSaída:
let x = y in z -> z
let i = \x.x in iSaída:
let i = \x.x in i -> \x.x
let i = \x.x in i kSaída:
let i = \x.x in i k -> k
Saída:let z = \a.\b.b in ; zero let s = \n.\c.\d.n c (c d) in ; sucessor s z -> \s.\z.s z ; um
(\z.(\s.s z) (\n.\c.\d.n c (c d))) (\a.\b.b) -> \c.\d.c d
\m.\n.\s.\z.m s (n s z)Saída:
\m.\n.\s.\z.m s (n s z)
(\x.\y.x y) (\x.x y)Saída:
(\x.\y.x y) (\x.x y) -> \y'.y' y
Saída:let z = \s.\z.z in let s = \n.\s.\z.n s (s z) in let u = s z in let d = s u in d u
(\z.(\s.(\u.(\d.d u) (s u)) (s z)) (\n.\s.\z.n s (s z))) (\s.\z.z) -> \z'.\z''.z' z''
213Saída:
213
+Saída:
+
+ 2Saída:
+ 2 -> + 2
+ 2 3Saída:
+ 2 3 -> 5
let f = + in f 5 10Saída:
(\f.f 5 10) + -> 15
let f = + 5 in f 10 -> 15Saída:
(\f.f 10) (+ 5) -> 15
Saída:let f = \x.+ (* x 2) 1 in f 1
(\f.f 1) (\x.+ (* x 2) 1) -> 3
Saída:let c = \n.n (+ 1) 0 in c (\s.\z.s (s (s (s (s (s (s z)))))))
(\c.c (\s.\z.s (s (s (s (s (s (s z)))))))) (\n.n (+ 1) 0) -> 7
* (- 14 5) (\x.x x)Saída:
* (- 14 5) (\x.x x) -> * 9 (\x.x x)
0 = 1Saída:
0 = 1
= 0 1Saída:
= 0 1 -> false
(if true then \x.\y.x else \x.\y.y) a bSaída:
(if true then \x.\y.x else \x.\y.y) a b -> a
(if = 1 0 then \x.\y.x else \x.\y.y) a bSaída:
(if = 1 0 then \x.\y.x else \x.\y.y) a b -> b
Termo:
Saída:let y = \f.(\x.f (x x)) (\x.f (x x)) in let g = \f.\n.if = n 0 then 1 else * n (f (- n 1)) in (y g) 5 -> 120 ; 5!
(\y.(\g.y g 5) (\f.\n.if = n 0 then 1 else * n (f (- n 1)))) (\f.(\x.f (x x)) (\x.f (x x))) -> 120
Saída:let z = \a.\b.b in ; zero let s = \n.\c.\d.n c (c d) in ; sucessor s z -> \s.\z.s z ; um
(\z.(\s.s z) (\n.\c.\d.n c (c d))) (\a.\b.b) -> (\s.s (\a.\b.b)) (\n.\c.\d.n c (c d)) -> (\n.\c.\d.n c (c d)) (\a.\b.b) -> \c.\d.(\a.\b.b) c (c d) -> \c.\d.(\b.b) (c d) -> \c.\d.c d
Faz parte da realização do trabalho a elaboração de exemplos (4 ou 5) que ilustrem quer o correcto funcionamento da implementação feita, quer eventuais problemas que não tenham sido completamente resolvidos.
O código entregue deverá funcionar na máquina alunos.di.uevora.pt.
O relatório deverá incluir:
Estes elementos deverão ser entregues através do moodle até às 20:00 do dia 4 de Junho de 2006. (Para evitar problemas com entregas em cima da hora limite, a entrega estará aberta até às 23:55, hora do moodle.) Se o relatório for entregue impresso, ele deverá ser colocado no cacifo de um dos docentes da cadeira até às 10:00 do dia 5 de Junho.
Os ficheiros a entregar deverão ser incluídos num arquivo .tar.gz ou .zip. O arquivo entregue deverá ter nome nnnnn-mmmmm.tar.gz (ou .zip), onde nnnnn e mmmmm deverão ser substituídos pelos números dos elementos do grupo. No caso dos trabalhos individuais, o nome do arquivo deverá ser nnnnn.tar.gz (ou .zip).
É da responsabilidade de cada grupo verificar e certificar-se de que o arquivo entregue contém exactamente os elementos que pretendiam entregar.
A cotação da várias partes do trabalho é a seguinte:
* - estes 2 valores são comuns aos dois anexos: em separado, cada um dos anexos B e C vale 4 valores; em conjunto, os dois anexos valem 6 valores.
Cotação Base 12 Anexo A 2 Anexo B 2 + 2* Anexo C 2 + 2* Anexo D 2
Só serão considerado os anexos cujas cotações somadas não excedam os 8 valores.
A realização e entrega deste trabalho são facultativas.
O trabalho deverá ser realizado somente por quem o entrega. A detecção de qualquer acto de cópia levará à anulação de todos os trabalhos envolvidos e à impossibilidade de obter aprovação à disciplina, este ano lectivo, por parte dos elementos dos grupos em questão. Os estudantes são encorajados a discutir a resolução das questões levantadas pelo trabalho, mas não deverão ver, dar a ver, emprestar ou pedir emprestado o código do trabalho, e só deverá ser entregue código feito pelos elementos do grupo.