A Linguagem µScheme

Propaganda
A Linguagem µScheme
António Menezes Leitão
3 de Maio de 2010
1
Introdução
É cada vez mais usual as grandes aplicações incorporarem uma linguagem
de scripting que permita fazer pequenos (e grandes) programas que usam
as APIs dessas aplicações. Por exemplo, AutoCAD disponibiliza AutoLisp e VB, Blender disponibiliza Python, e Gimp disponibiliza Script-Fu
e Python. Uma vez que, em geral, a capacidade de fazer scripts eficientes nestas aplicações não é um requisito fundamental, opta-se antes por
disponibilizar linguagens que sejam simples, fáceis de aprender, e fáceis de
implementar.
2
Objectivos
Pretende-se que implemente, em Java, uma linguagem de scripting para
Java. Essa linguagem denomina-se µScheme1 e pretende ser usada como
linguagem de extensão para aplicações Java.
A linguagem µScheme é sintática e semanticamente semelhante à linguagem Scheme na sua versão R4RS (o standard desta linguagem encontra-se
disponı́vel em http://people.csail.mit.edu/jaffer/r4rs_toc.html) e,
por este motivo, este enunciado não explica o que poderá ser encontrado
em qualquer manual de Scheme (ver, por exemplo, http://mitpress.mit.
edu/sicp/) mas sim as diferenças fundamentais entre µScheme e Scheme.
Pretende-se que crie a classe ist.leic.pa.MScheme e que nesta classe
exista um método estático denominado repl, que não recebe quaisquer argumentos e que, uma vez invocado, lê uma expressão do standard input,
escreve o resultado da avaliação dessa expressão no standard output e envia
o possı́vel erro para o standard error, repetindo esta sequência até atingir o
fim de ficheiro ou até que um erro seja gerado.
As próximas secções detalham um pouco mais a linguagem a implementar.
1
O nome µScheme pronuncia-se “micro-scheme.”
1
2.1
Tipos de Dados
Como versão simplificada de Scheme que é, a linguagem µScheme reduz ao
mı́nimo o conjunto de tipos e operações disponı́veis sobre esses tipos. Em
µScheme existem os seguintes tipos de dados pré-definidos:
number O tipo number é usado em todas as operações aritméticas e é o tipo
de objecto que é produzido quando se lê a representação externa de
qualquer número. Este tipo é implementado directamente com o tipo
Java BigDecimal. Isso permite garantir precisão total em todas as
operações matemáticas realizadas, bem como evitar qualquer limite
arbitrário quanto à dimensão dos números. Como se verá adiante, isto
não é limitação para o uso das APIs de Java pois existem funções que
convertem do tipo BigDecimal para os outros tipos numéricos usuais
que também são manipuláveis em Scheme (embora não possam ser
lidos directamente).
function As funções são considerado um tipo de dados primitivo na linguagem que é criado como resultado da avaliação de expressões lambda.
pair µScheme, à semelhança da linguagem Scheme, disponibiliza algumas
operações elementares para a construção de pares de objectos. No entanto, o conjunto de operações é (intencionalmente) muito mais limitado, existindo apenas cons, car, cdr, e null?. Outras funções podem
ser adicionadas através da normal definição de funções em µScheme.
boolean Existe um tipo booleano que se caracteriza por ter dois valores
representados pelos sı́mbolos #t e #f. Qualquer operação relacional
produz um destes valores. Estes sı́mbolos avaliam para eles próprios.
string O tipo string corresponde directamente ao tipo string de Java,
sendo possı́vel ler directamente valores deste tipo.
Tipos “Estrangeiros” Qualquer objecto Java (seja de que tipo for) pode
ser usado em µScheme. À semelhança dos números, estes objectos
avaliam para eles próprios.
Para simplificar o desenvolvimento do seu avaliador de µScheme, a cadeira fornece uma implementação em Java (que os alunos podem modificar
livremente ou reimplementar por completo) das operações read, display, e
newline capazes de ler e escrever os tipos number, pair, boolean e string.
2.2
Limitações da Linguagem µScheme
µScheme simplifica substancialmente a linguagem Scheme em diversas áreas:
2
Recursão µScheme usa recursão como estrutura de controle mais genérica
mas, contráriamente à linguagem Scheme, µScheme não é recursiva
de cauda, i.e., qualquer invocação (recursiva ou não recursiva e em
posição de cauda ou não) consome espaço. Isto implica que ciclos
com um número indeterminado de repetições podem fazer abortar o
programa.
Iteração µScheme não providencia quaisquer estruturas de controle de iteração.
Em particular, não existem operações de repetição do tipo do, ou named lets.
Avaliação Diferida µScheme não providencia as formas para avaliação
diferida delay ou force.
Continuações µScheme não permite qualquer reificação de continuações
e, consequentemente, também não implementa retorno de múltiplos
valores.
Macros µScheme não providencia macros higiénicas.
2.3
Funções
A linguagem µScheme providencia as seguintes funções pré-definidas:
• +, *, -, /. Aceitam qualquer número de argumentos numéricos e produzem um resultado numérico.
• =, >, >=, <, <=. Aceitam dois argumentos numéricos e produzem um
resultado booleano.
• eq?. Aceita dois argumentos e testa se são o mesmo objecto. Note-se
que este procedimento não é apropriado para testar números, mesmo
que pequenos.
• cons, car, cdr, null?. Operações básicas para manipular pares e
listas.
• jtype: Dada uma string representando o nome de um tipo em Java,
produz um objecto representando esse tipo.
• jconstructor: Dada a representação de um tipo e qualquer número
de representações de outros tipos, produz um objecto representando o
construtor do primeiro tipo cuja assinatura coincide com os restantes
tipos.
• jnew: Dada a representação de um construtor e dados os argumentos
apropriados para esse construtor, invoca o construtor e produz uma
representação do objecto construı́do.
3
• jmethod: Dada a representação de um tipo, dada uma string e qualquer número de representações de outros tipos, produz um objecto
representando o método definido no primeiro tipo cujo nome é igual à
string e cuja assinatura coincide com os restantes tipos.
• jcall: Dada a representação de um método, dada a representação
de um objecto e dados os argumentos apropriados para esse método,
invoca o método e produz uma representação do objecto resultante
construı́do. Se o método em questão for estático, o segundo argumento
é ignorado.
• jbyte: recebe um number e produz o byte correspondente em Java.
• jshort: recebe um number e produz o short correspondente em Java.
• jint: recebe um number e produz o int correspondente em Java.
• jlong: recebe um number e produz o long correspondente em Java.
• jfloat: recebe um number e produz o float correspondente em Java.
• jdouble: recebe um number e produz o double correspondente em
Java.
• jboolean: recebe um boolean e produz o boolean correspondente em
Java.
• jchar: recebe uma string de um só elem e produz o char correspondente em Java.
• jstring: recebe uma string e produz a instância de java.lang.String
correspondente em Java. Dada a coincidência entre o tipo µScheme
string e o tipo Java java.lang.String, esta função deverá ser trivial
de implementar.
• jnull: não recebe argumentos e produz o null em Java.
2.4
µScheme como Linguagem de Scripting de Java
Uma das grandes vantagens da linguagem µScheme é a sua capacidade para
interagir com as bibliotecas da linguagem Java. A tı́tulo de exemplo, considere a seguinte expressão µScheme que calcula a raiz quadrada do número
2.0:
(let ((math-class (jtype "java.lang.Math")))
(let ((sqrt-method (jmethod math-class "sqrt" (jtype "double"))))
(jcall sqrt-method math-class (jdouble 2.0))))
4
Naturalmente, deverá ser possı́vel definir funções µScheme que “escondam” as invocações e as conversões de valores. Por exemplo, considere a
seguinte interacção (onde intercalamos o input com o output):
(let ((math-class (jtype "java.lang.Math")))
(let ((sqrt-method
(jmethod math-class "sqrt" (jtype "double"))))
(define (math-sqrt arg)
(jcall sqrt-method math-class (jdouble arg)))))
...
(math-sqrt 2.0)
1.4142135
2.5
Extensões
Se pretender, pode fazer as extensões que achar apropriadas que possam valorizar ainda mais o seu trabalho. Tenha em conta que essa valorização será,
no máximo, de dois valores a somar à nota que obtiver pela implementação
do que foi pedido nas outras secções.
Algumas das extensões que poderão ser interessantes são:
• Aproximar o conjunto de funções e tipos do µScheme dos existentes
em Scheme
• Implementação de novos operadores (e.g., o defun do Common Lisp)
• Implementação de macros
• Implementação de lazy evaluation
• Implementação de futures
• Tratamento de arrays
• Tratamento de excepções
• Operações para obtenção dos valores dos fields dos objectos Java
3
Código
A sua implementação de µScheme deverá funcionar em Java 6.
O código desenvolvido deverá estar escrito no melhor estilo que for
possı́vel, permitindo a sua fácil leitura e dispensando excessivos comentários.
É sempre preferı́vel ter código mais claro com poucos comentários do que
ter código obscuro com muitos comentários.
O código deverá ser modular, divido em funcionalidades com responsabilidades especı́ficas e reduzidas. Cada módulo deverá ter um curto comentário
a descrever o seu objectivo.
5
4
Apresentação
Não se pretende que faça um relatório do seu trabalho mas sim uma apresentação pública. Esta deverá ser em Inglês, preparada para ter 15 minutos
de duração (aproximadamente 8 slides), deverá centrar-se nas opções arquitecturais tomadas e poderá incluir os detalhes que considere relevantes.
Pretende-se que consiga “vender” a sua solução ao seus colegas e ao corpo
docente.
5
Formato da entrega
O projecto é entregue por via electrónica através do Portal Fénix. Cada
grupo deverá entregar um único ficheiro comprimido em formato ZIP, com o
nome mscheme.zip. Na raı́z do ficheiro ZIP deverão estar obrigatoriamente:
• o directório src com o código fonte desenvolvido (quer em Java, quer,
eventualmente, em Scheme);
• o directório lib com quaisquer bibliotecas necessárias à compilação
e/ou execução do projecto;
• o ficheiro p2.pdf com os slides da apresentação do trabalho;
• o ficheiro build.xml para compilar o código Java e gerar o mscheme.jar.
O formato aceite para os slides de apresentação do trabalho é o PDF. O
ficheiro com a apresentação tem de estar na raı́z do ficheiro ZIP e tem de
ter o nome p2.pdf.
O ficheiro build.xml é um ficheiro de Ant (http://ant.apache.org)
e deve produzir na mesma localização o ficheiro mscheme.jar com todo
o código Java necessário para executar o avaliador de µScheme. O alvo de
omissão do build.xml deve efectuar o trabalho descrito, ou seja, simplesmente executar numa shell
$ ant
deve produzir o resultado esperado (mscheme.jar).
6
Avaliação
Os critérios de avaliação incluem:
• A qualidade das soluções desenvolvidas.
• A clareza dos programas desenvolvidos.
6
• A qualidade da apresentação pública.
Em caso de dúvidas, o corpo docente poderá pedir explicações sobre o
funcionamento do projecto desenvolvido, incluı́ndo eventuais demonstrações.
7
Plágio
Considera-se plágio o uso de quaisquer fragmentos de programas que não
tenham sido fornecidos pelos docentes da disciplina. Não se considera plágio
o uso de ideias cedidas por terceiros desde que seja feita a devida atribuição.
Esta disciplina segue normas muito rı́gidas relativamente ao plágio. Quaisquer projectos que sejam considerados plagiados serão anulados, independentemente de quem plagiou e de quem tiver sido plagiado, independentemente de o plágio ter sido autorizado, ou não, pela parte plagiada.
Isto não deverá ser impedimento para a troca salutar de ideias e para a
normal camaradagem e entreajuda que deve existir entre colegas. Contudo,
sugere-se que nunca cedam fragmentos de programas sob pena de quem os
recebe não os entender e se limitar a plagiá-los com maior ou menos esforço
de “camuflagem.”
8
Notas Finais
Não se esqueça da Lei de Murphy.
9
Prazos
O código e os slides da apresentação deverão ser entregues via fénix, até às
20:00 do dia 4 de Junho.
As apresentações irão decorrer nas aulas práticas seguintes à entrega.
Apenas um elemento do grupo irá fazer a apresentação que não poderá exceder os 15 minutos. Esse elemento será escolhido pelo docente no momento
da apresentação.
7
Download