Вы находитесь на странице: 1из 67

UNIVERSIDADE FEDERAL DO RIO GRANDE DO SUL INSTITUTO DE INFORMTICA BACHARELADO EM CINCIA DA COMPUTAO

VTOR BUJS UBATUBA DE ARAJO

Faz: uma linguagem funcional didtica

Prof. Dr. Lucio Mauro Duarte Orientador

Prof. Dr. Rodrigo Machado Co-orientador

Porto Alegre, dezembro de 2013

CIP CATALOGAO NA PUBLICAO Arajo, Vtor Bujs Ubatuba De Faz: uma linguagem funcional didtica / Vtor Bujs Ubatuba De Arajo. Porto Alegre: PPGC da UFRGS, 2013. 67 f.: il. Trabalho de concluso (graduao) Universidade Federal do Rio Grande do Sul. Bacharelado em Cincia da Computao, Porto Alegre, BRRS, 2013. Orientador: Lucio Mauro Duarte; Co-orientador: Rodrigo Machado. I. Duarte, Lucio Mauro. II. Machado, Rodrigo. III. Ttulo.

UNIVERSIDADE FEDERAL DO RIO GRANDE DO SUL Reitor: Prof. Carlos Alexandre Netto Vice-Reitor: Prof. Rui Vicente Oppermann Pr-Reitora de Graduao: Profa . Valquiria Link Bassani Diretor do Instituto de Informtica: Prof. Lus da Cunha Lamb Coordenador do CIC: Prof. Raul Fernando Weber Bibliotecrio-Chefe do Instituto de Informtica: Alexsander Borges Ribeiro

I never think of giving up. What use would that be? We cant win by giving up. R ICHARD S TALLMAN

AGRADECIMENTOS

Obrigado.

SUMRIO

LISTA DE ABREVIATURAS E SIGLAS . . . . . . . . . . . . . . . . . . . . LISTA DE FIGURAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . RESUMO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ABSTRACT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7 8 9 10 11 12 13 13 14 16 16 16 18 18 18 18 19 19 19 20 21 22 22 25 25 26 26 26 26 27 27 27

1 INTRODUO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1 Organizao do texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 LINGUAGENS FUNCIONAIS . . . . . . . . . . . . . . . . . . . . . . . 2.1 Conceitos bsicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 O uso de Racket no ensino de programao . . . . . . . . . . . . . . . . 3 AS LINGUAGENS HTDP . . . . . . 3.1 Construes sintticas . . . . . . . 3.1.1 Tipos de dados bsicos . . . . . . 3.1.2 Expresses aritmticas . . . . . . 3.1.3 Expresses relacionais e lgicas . 3.1.4 Declarao de variveis . . . . . . 3.1.5 Declarao e chamada de funes . 3.1.6 Expresses condicionais . . . . . 3.1.7 Estruturas de dados . . . . . . . . 3.1.8 Tipos mistos . . . . . . . . . . . . 3.1.9 Listas . . . . . . . . . . . . . . . 3.1.10 Denies locais . . . . . . . . . 3.1.11 Funes annimas . . . . . . . . . 3.1.12 Anlise . . . . . . . . . . . . . . 3.2 Sistema de tipos . . . . . . . . . . . 3.2.1 Anlise . . . . . . . . . . . . . . 4 A LINGUAGEM FAZ . . . . . . . 4.1 Construes sintticas . . . . . . 4.1.1 Tipos de dados bsicos . . . . . 4.1.2 Expresses aritmticas . . . . . 4.1.3 Expresses relacionais e lgicas 4.1.4 Blocos . . . . . . . . . . . . . . 4.1.5 Denio de variveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4.1.6 Denio e chamada de funes . . . . . . . . 4.1.7 Condicionais . . . . . . . . . . . . . . . . . . . 4.1.8 Expresses de bloco . . . . . . . . . . . . . . . 4.1.9 Retorno e sinalizao de erros . . . . . . . . . 4.1.10 O comando teste . . . . . . . . . . . . . . . 4.1.11 Denio de tipos no paramtricos . . . . . . 4.1.12 Enumeraes . . . . . . . . . . . . . . . . . . 4.1.13 Estruturas de dados . . . . . . . . . . . . . . . 4.1.14 Tipos mistos . . . . . . . . . . . . . . . . . . . 4.1.15 Denio de tipos paramtricos . . . . . . . . . 4.1.16 Listas . . . . . . . . . . . . . . . . . . . . . . 4.1.17 Denies locais . . . . . . . . . . . . . . . . 4.1.18 Funes annimas . . . . . . . . . . . . . . . . 4.1.19 Anlise . . . . . . . . . . . . . . . . . . . . . 4.2 Sistema de tipos . . . . . . . . . . . . . . . . . . 4.2.1 Tipos da linguagem . . . . . . . . . . . . . . . 4.2.2 Compatibilidade de tipos e unicao . . . . . 4.3 Semntica e tipos das construes da linguagem 4.4 Limitaes . . . . . . . . . . . . . . . . . . . . . 5 IMPLEMENTAO . . . . . . 5.1 O ambiente DrRacket . . . . 5.2 A implementao de Faz . . . 5.2.1 Anlise lxica e sinttica . . 5.2.2 Anlise semntica . . . . . . 5.2.3 Traduo . . . . . . . . . . . 5.2.4 Ambiente padro . . . . . . 5.2.5 Execuo interativa . . . . . 5.2.6 Integrao com DrRacket . . 5.2.7 Limitaes . . . . . . . . . . 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

27 28 28 28 28 28 29 29 29 29 31 32 32 32 36 36 40 43 47 48 48 49 49 50 51 51 51 52 52 53 57 57 57 57 58 59 60 60 62 64

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

EXPERIMENTO DE VALIDAO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7 TRABALHOS RELACIONADOS . . . . . 7.1 Linguagens baseadas no portugus . . . . 7.2 Linguagens funcionais de propsito geral 7.2.1 Famlia LISP . . . . . . . . . . . . . . . 7.2.2 Famlia ML . . . . . . . . . . . . . . . . 7.3 Linguagens funcionais didticas . . . . . . 7.4 Outras linguagens didticas . . . . . . . . 7.5 Tipagem esttica em Racket . . . . . . . . 8

CONCLUSO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

REFERNCIAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

LISTA DE ABREVIATURAS E SIGLAS

HtDP IS SICP

How to Design Programs Intermediate Student with Lambda Structure and Interpretation of Computer Programs

LISTA DE FIGURAS

Figura 2.1: Figura 2.2: Figura 2.3: Figura 3.1: Figura 3.2: Figura 3.3: Figura 3.4: Figura 3.5: Figura 3.6: Figura 4.1: Figura 4.2: Figura 4.3: Figura 4.4: Figura 4.5: Figura 4.6: Figura 4.7: Figura 4.8: Figura 4.9: Figura 5.1: Figura 5.2: Figura 6.1: Figura 6.2:

Clculo do fatorial em estilo imperativo. . . . . . . . . . . . . . . . . Clculo do fatorial em estilo funcional. . . . . . . . . . . . . . . . . Denio incorreta de uma funo que soma dois nmeros. . . . . . . Denio e uso de estruturas em IS . . . . . . . . . . . . . . . . . . Denio e uso de um tipo misto forma em IS . . . . . . . . . . . . Exemplo do uso de listas em IS . . . . . . . . . . . . . . . . . . . . Exemplo de cdigo com denies locais (delta, x1, x2) em IS . . Funo que realiza uma operao indicada por um smbolo sobre um valor numrico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Cdigo com erro de tipo . . . . . . . . . . . . . . . . . . . . . . . . Exemplo de condicional em Faz . . . . . . . . . . . . . . . . . . . . Exemplo do uso do comando teste em Faz . . . . . . . . . . . . . Denio e uso de estruturas em Faz . . . . . . . . . . . . . . . . . . Denio e uso de um tipo misto forma em Faz . . . . . . . . . . . . Denio de rvore binria genrica em Faz . . . . . . . . . . . . . . Exemplo do uso de listas em Faz . . . . . . . . . . . . . . . . . . . . Exemplo de cdigo com denies locais (delta, x1, x2) em Faz . . Funo que recebe um nmero ou uma string e produz um dado do mesmo tipo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exemplo funo polimrca em Faz . . . . . . . . . . . . . . . . . . Janela principal do ambiente DrRacket executando a linguagem IS . Janela principal do ambiente DrRacket executando a linguagem Faz . Programa para busca de caminho em grafo acclico em IS . . . . . . Programa para busca de caminho em grafo acclico em Faz . . . . . .

14 14 15 20 20 21 21 23 25 28 29 30 30 31 31 32 37 39 49 50 55 56

RESUMO

A linguagem de programao Racket e o ambiente DrRacket so utilizados em diversos cursos introdutrios de programao. O uso de uma linguagem funcional facilita a exposio de certos conceitos, tais como recurso estrutural, reuso de cdigo atravs de composio de funes e rotinas genricas atravs do uso de funes de alta ordem. Alm disso, o ambiente de desenvolvimento interativo propiciado pelo DrRacket facilita a criao, experimentao e teste de programas. Por outro lado, devido ao fato de Racket ser uma linguagem dinamicamente tipada, declaraes de tipos de dados e a noo de domnio dos argumentos de funes e dos campos de estruturas, conceitos frequentemente abordados em disciplinas introdutrias, no possuem uma representao direta na linguagem, sendo frequentemente representados por comentrios no cdigo. Alm disso, a sintaxe de Racket, baseada nas convenes do LISP, diverge das convenes sintticas utilizadas na notao matemtica tradicional e na maior parte das linguagens de programao. Acreditamos que esse desencontro entre os conceitos apresentados e as expectativas dos alunos de um lado, e os recursos sintticos e semnticos de Racket de outro, provoca diculdades de exposio e compreenso do contedo de tais disciplinas. Visando evitar esses problemas, desenvolvemos uma nova linguagem de programao, intitulada Faz. Essa linguagem incorpora um sistema de tipos semi-esttico, buscando permitir a expresso dos domnios dos dados manipulados pelo programa e ao mesmo tempo manter a exibilidade proporcionada pelo sistema de tipos de Racket. Alm disso, a linguagem emprega uma sintaxe concebida para facilitar a compreenso dos programas pelos alunos. Para isso, utiliza recursos notacionais da matemtica convencional e de outras linguagens de programao, bem como palavras-chave baseadas no portugus. A linguagem foi implementada como uma extenso do ambiente DrRacket, permitindo o uso de seus recursos interativos no desenvolvimento de programas na nova linguagem.

Palavras-chave: Linguagem de programao funcional, linguagem de programao didtica.

Faz: a didactical functional programming language

ABSTRACT

The Racket programming language and the DrRacket environment are used in various courses of introduction to programming. The use of a functional language makes it easier to present certain concepts, such as structural recursion, code reuse through function composition, and generic routines through higher-order functions. Moreover, the interactive development environment provided by DrRacket eases the creation, experimentation and testing of programs. On the other hand, because Racket is a dynamically typed programming language, data type declarations and the notion of domains of function arguments and structure elds, concepts often studied in introductory courses, do not have a direct representation in the language, being often represented by comments in the code. Moreover, the syntax of Racket, based in the conventions of LISP, diverges from the syntactical conventions used in traditional mathematical notation and most of the other programming languages. We believe that this mismatch between the concepts presented and the students expectations in addition to the syntactic and semantic resources of Racket cause difculties in the explanation and comprehension of the subject of such courses. Aiming to avoid these problems, we have developed a new programming language, named Faz. This language incorporates a semi-static type system, with the intent of enabling the expression of the domains of the data manipulated by the program while keeping the exibility provided by the type system of Racket. Moreover, the language employs a syntax devised to ease the comprehension of programs by the students, using notational resources from conventional mathematics and other programming languages, as well as Portuguese-based keywords. The language has been implemented as an extension to the DrRacket environment, allowing the use of its interactive features in the development of programs in the new language.

Keywords: functional programming language, introductory programming language.

11

INTRODUO

Linguagens de programao funcionais so utilizadas na academia e na indstria em diversas aplicaes, tais como inteligncia articial (NORVIG, 1992), prova automatizada de teoremas (KAUFMANN; MOORE, 1996) (BOVE; DYBJER; NORELL, 2009) (BARRAS et al., 1997), compiladores (MARLOW; JONES et al., 2012), sistemas de versionamento de software (ROUNDY, 2005), entre outras. Conceitos de programao funcional tambm possuem aplicao mais ampla, estendendo-se a sistemas escritos em linguagens no funcionais. Exemplos incluem algoritmos de processamento paralelo e distribudo baseados em MapReduce (DEAN; GHEMAWAT, 2004). H vrias linguagens funcionais atualmente em uso. Dentre elas, destacam-se Haskell (MARLOW et al., 2010), OCaml (LEROY et al., 2012), Erlang (ARMSTRONG et al., 1996) e as linguagens da famlia LISP (MCCARTHY, 1960), tais como Common LISP (STEELE JR., 1990), Clojure (HICKEY, 2012) e Scheme (KELSEY et al., 1998). No ensino de programao funcional, destaca-se a linguagem Racket1 , uma variante de Scheme. Racket utilizada em cursos introdutrios de programao na UFRGS e em diversas universidades dos Estados Unidos, tais como a University of Texas2 , a Northeastern University3 e a Rice University4 , usualmente em conjunto com o ambiente de programao DrRacket e o livro-texto How to Design Programs (FELLEISEN et al., 2001). O uso de uma linguagem funcional facilita a exposio de certos conceitos de programao, tais como recurso estrutural, reuso de cdigo atravs de composio de funes e rotinas genricas atravs do uso de funes de alta ordem (FELLEISEN et al., 2004). Alm disso, o ambiente de desenvolvimento interativo propiciado pelo DrRacket facilita a criao, experimentao e teste de programas, permitindo o teste de expresses e funes individuais, a visualizao do contedo de estruturas de dados e a indicao visual do ponto de ocorrncia de erros de sintaxe ou de execuo no cdigo. Por outro lado, a sintaxe de Racket, baseada nas convenes do LISP, diverge das convenes sintticas utilizadas na matemtica tradicional e na maior parte das linguagens de programao. Exemplos de divergncias incluem o uso de operadores aritmticos prexados (e.g., (+ 2 3) em vez de 2+3) e o posicionamento dos parnteses em chamadas de funes (e.g., (f x y) em vez de f(x,y)). Alm disso, devido ao fato de Racket ser uma linguagem dinamicamente tipada, declaraes de tipos de dados e a noo de domnio dos argumentos de funes e dos campos de dados estruturados, conceitos frequentemente abordados em disciplinas introdutrias, no possuem uma representao
http://racket-lang.org http://www.cs.utexas.edu/users/novak/cs307.html 3 http://www.ccs.neu.edu/racket/ 4 http://courses.rice.edu/admweb/swkscat.main?p_action=CATALIST &p_acyr_code=2013&p_subj=COMP
2 1

12

direta na linguagem; o livro-texto recorre ao uso de comentrios no cdigo para expressar esses conceitos. Consequentemente, o ambiente de programao ignora a informao de tipos e, portanto, no fornece ao aluno um feedback quanto correo da mesma. Esse desencontro entre os conceitos apresentados e as expectativas dos alunos de um lado, e os recursos sintticos e semnticos de Racket de outro, provoca diculdades de exposio e compreenso do contedo de tais disciplinas. Visando a evitar esses problemas, este trabalho prope uma nova linguagem de programao baseada em Racket, denominada Faz, destinada ao ensino de cursos introdutrios de programao funcional. A motivao para a criao de uma nova linguagem deriva da experincia com o ensino da disciplina de Fundamentos de Algoritmos na UFRGS utilizando o livro-texto How to Design Programs. Essa disciplina ministrada no primeiro ano dos cursos de graduao em Cincia da Computao e Biotecnologia. No curso de Cincia da Computao, a disciplina ministrada paralelamente com a disciplina de Algoritmos e Programao, que emprega a linguagem imperativa C. A linguagem desenvolvida emprega uma sintaxe concebida para facilitar a compreenso dos programas pelos alunos, utilizando, para isso, recursos notacionais da matemtica convencional e de outras linguagens de programao. Tais recursos incluem operadores aritmticos inxados e o uso de uma notao similar usada em teoria dos conjuntos para a expresso de tipos. A linguagem tambm emprega palavras-chave baseadas no portugus, tornando-a mais bem adaptada realidade brasileira e facilitando a leitura do cdigo por alunos iniciantes. Alm disso, a linguagem incorpora um sistema de tipos semi-esttico, buscando permitir a expresso dos domnios de dados manipulados pelo programa e, ao mesmo tempo, manter a exibilidade proporcionada pelo sistema de tipos de Racket. Com isso, objetiva-se permitir que os tipos de problemas abordados pelo How to Design Programs sejam facilmente transponveis para a nova linguagem. A linguagem foi implementada como parte do ambiente DrRacket. O cdigo em Faz analisado sinttica e semanticamente e posteriormente traduzido para a linguagem Racket. Isso torna possvel o reuso das funcionalidades do ambiente DrRacket a partir da nova linguagem e permite que os recursos interativos do ambiente possam ser utilizados no no desenvolvimento e teste de programas na nova linguagem. Este trabalho uma tentativa de, atravs da elaborao cuidadosa de uma nova linguagem com sintaxe e semntica apropriadas, reduzir as diculdades identicadas, produzindo uma linguagem mais facilmente compreensvel pelos alunos e diminuindo a distncia em termos sintticos entre o paradigma imperativo e o funcional, sem que se perca o carter funcional da linguagem e as vantagens que o acompanham.

1.1

Organizao do texto

O Captulo 2 apresenta conceitos bsicos sobre linguagens funcionais e seu uso no ensino de programao. O Captulo 3 apresenta um resumo das sublinguagens didticas de How to Design Programs, juntamente com uma anlise de suas vantagens e desvantagens em um contexto didtico. O Captulo 4 apresenta a nova linguagem, juntamente com uma discusso das decises de design tomadas e de alternativas consideradas em seu desenvolvimento. O Captulo 5 discute a implementao da linguagem no ambiente DrRacket. O captulo 6 apresenta os resultados de uma enquete realizada de maneira a vericar a opinio dos alunos quanto s linguagens How to Design Programs e a nova linguagem. O Captulo 7 discute trabalhos relacionados. O Captulo 8 apresenta uma concluso e discute trabalhos futuros.

13

LINGUAGENS FUNCIONAIS

Este captulo apresenta conceitos bsicos sobre programao funcional. Tambm ser feita uma breve introduo sobre o uso das linguagens funcionais Scheme e Racket no ensino de programao.

2.1

Conceitos bsicos

Linguagens funcionais so linguagens em que a computao expressa primariamente atravs da aplicao e composio de funes matemticas. Em uma linguagem imperativa, como Pascal, C ou Java, o resultado de uma chamada de funo ou mtodo frequentemente depende do estado do programa, representado por variveis ou atributos mutveis de objetos. Em contraste, em um programa puramente funcional, o resultado de uma chamada de funo, dados os mesmos argumentos, sempre o mesmo; no h expresses ou comandos com efeitos colaterais, i.e., que possuem algum efeito alm de produzir um valor de retorno. Essa propriedade conhecida como transparncia referencial, e facilita o raciocnio sobre o comportamento do programa, bem como a elaborao de testes (HUGHES, 1989). A literatura tradicionalmente classica linguagens funcionais em puras e impuras. Em linguagens puramente funcionais, tais como Haskell, efeitos colaterais so totalmente abolidos, ou tm seu uso restrito apenas a contextos limitados. Por outro lado, linguagens funcionais impuras, tais como Scheme e ML, permitem o uso livre de efeitos colaterais, mas desencorajam essa prtica, fornecendo construes de linguagem que favorecem a elaborao de programas puros. Uma vez que almejam eliminar ou reduzir o uso de alteraes de estado, linguagens funcionais usualmente no empregam comandos de iterao convencionais em linguagens imperativas, tais como for e while, visto que tais comandos dependem de mudanas de estado; em um programa puramente funcional, uma condio de parada tal como usada em um while retornaria sempre o mesmo valor-verdade, por exemplo. Em vez disso, programas funcionais usualmente expressam repetio por meio de funes denidas recursivamente, i.e., funes que chamam a si prprias durante sua execuo. Para demonstrar a diferena entre esses dois paradigmas, considere uma funo que calcula o fatorial de um nmero natural escrita em um estilo imperativo (Figura 2.1) e em um estilo funcional (Figura 2.2) em C. Na verso imperativa, o resultado calculado atravs de iterao, usando uma varivel mutvel como acumulador. Na verso funcional, o resultado calculado atravs da composio de chamadas de funo (o operador de multiplicao pode ser visto como uma funo de dois argumentos). Outra caracterstica do paradigma funcional o uso frequente de funes de alta ordem, isto , funes que recebem outras funes como argumento e/ou produzem outras

14

int fac(int n) { int result = 1; int i; for (i=1; i<=n; i++) result = result * i; return result; }

Figura 2.1: Clculo do fatorial em estilo imperativo.


int fac(int n) { if (n==0) return 1; else return n * fac(n-1); }

Figura 2.2: Clculo do fatorial em estilo funcional. funes como valor de retorno. Isso permite a denio de algoritmos genricos, em que uma lacuna no cdigo preenchida por um argumento funcional. Por exemplo, pode-se denir uma rotina genrica de ordenamento de listas de elementos de tipos quaisquer, passando como argumento para a rotina uma funo de comparao que determina a ordem desejada para os elementos.

2.2

O uso de Racket no ensino de programao

Scheme (SUSSMAN; JR., 1975) uma linguagem funcional impura da famlia LISP. Assim como outras linguagens dessa famlia, Scheme emprega uma sintaxe minimalista, baseada em expresses aninhadas delimitadas por parnteses, em que a aplicao de funes e operadores expressa uniformemente na forma (operador argumentos...). Por exemplo, uma expresso aritmtica como 2 3 + 4 5 expressa como (+ (* 2 3) (* 4 5)) em Scheme; de fato, + e * so funes em Scheme. O padro mais difundido de Scheme, o R5RS (KELSEY et al., 1998), dene uma linguagem bastante reduzida, oferecendo um mnimo de recursos sobre os quais funcionalidades mais avanadas podem ser denidas. O R5RS frequentemente utilizado como ncleo para implementaes de verses estendidas da linguagem. Racket, previamente conhecido como PLT Scheme (FLATT; PLT, 2010), uma dessas verses de Scheme, que dispe de uma grande variedade de bibliotecas e inclui funcionalidades como estruturas, um sistema de mdulos e sistemas avanados de macros, que permitem a denio de novas linguagens baseadas em Racket. O uso de Scheme em cursos introdutrios de Cincia da Computao foi popularizado pelo livro-texto Structure and Interpretation of Computer Programs (SICP) (ABELSON; SUSSMAN, 1985), utilizado na disciplina homnima no MIT e adotado por diversas universidades no mundo. O livro-texto How to Design Programs (HtDP) (FELLEISEN et al., 2001) foi elaborado de maneira a corrigir o que os autores identicaram como problemas com o uso do SICP como material introdutrio (FELLEISEN et al., 2004). Os autores apontam como vantagens do uso de uma linguagem funcional no ensino de programa-

15

(define (soma x y) x + y)

Figura 2.3: Denio incorreta de uma funo que soma dois nmeros. o o nmero reduzido de conceitos a serem apresentados e o fato de que o modelo de computao usado por linguagens funcionais pode ser visto como uma extenso da lgebra elementar, conhecida por alunos egressos do Ensino Mdio. Por outro lado, o HtDP d uma nfase maior parte de tcnicas de elaborao de programas e utiliza problemas de uma natureza mais familiar a alunos iniciantes em vez de problemas matemticos avanados e problemas relativos interpretao e compilao de linguagens, tais como abordados no SICP. A criao do HtDP parte de um projeto maior dos autores denominado Program by Design (anteriormente TeachScheme!)1 . O objetivo desse projeto promover o ensino de programao em instituies de ensino mdio e superior utilizando uma abordagem bem estruturada para a construo de programas. Alm do livro-texto, o projeto produziu a linguagem Racket e o ambiente grco de programao DrRacket. O HtDP no utiliza a linguagem Racket completa; em vez disso, o livro dene subconjuntos didticos da linguagem completa, progredindo de uma linguagem mais limitada (Beginner Student) para linguagens com mais funcionalidades (Intermediate Student, Advanced Student). A motivao por trs disso impedir que erros de programadores principiantes sejam interpretados como programas vlidos com um comportamento inesperado. Por exemplo, um usurio sem experincia com a linguagem Racket poderia tentar denir (incorretamente) uma funo como a da Figura 2.3. Na linguagem Racket completa, em vez de realizar a soma esperada pelo programador, o corpo da funo seria interpretado como trs expresses separadas, e o resultado da funo seria o valor da ltima expresso, i.e., y. Nas sublinguagens didticas, apenas uma expresso permitida no corpo da funo, produzindo uma mensagem de erro apropriada para o usurio no caso de um equvoco desse tipo. As sublinguagens didticas, bem como o Racket padro, apresentam outras divergncias com relao ao Scheme padro visando torn-las mais didticas, tais como a exibio de todos os tipos de valores com a mesma sintaxe baseada em construtores que usada para cri-los, e o uso dos nomes first e rest em vez de car e cdr para as funes de acesso aos campos de listas encadeadas.

http://www.programbydesign.org/

16

AS LINGUAGENS HTDP

As linguagens HtDP so subconjuntos didticos da linguagem Racket. Essas linguagens esto organizadas em uma progresso (Beginner Student, Beginner Student with List Abbreviations, Intermediate Student, Intermediate Student with Lambda, Advanced Student), cada linguagem adicionando recursos anterior. Como visto, a motivao para o uso de subconjuntos progressivamente maiores da linguagem completa evitar que erros comuns de alunos sejam interpretados como programas vlidos. A linguagem Advanced Student introduz operaes de atribuio; todas as linguagens anteriores so puramente funcionais, exceto por algumas funes para manipulao de grcos fornecidas por bibliotecas, que produzem efeitos colaterais, e de algumas funes como random e current-seconds, cujo valor de retorno varia a cada chamada. A linguagem Advanced Student no abordada na disciplina de Fundamentos de Algoritmos. As sees seguintes apresentam os recursos sintticos e semnticos da linguagem Intermediate Student with Lambda (IS). Tambm ser apresentada uma anlise das vantagens e desvantagens do uso dessa linguagem em um contexto didtico. Essa anlise baseia-se na experincia do autor deste trabalho como monitor da disciplina de Fundamentos de Algoritmos por seis semestres, durante os quais observou-se a recorrncia de uma srie de erros e dvidas entre os alunos.

3.1
3.1.1

Construes sintticas
Tipos de dados bsicos

H cinco tipos de dados bsicos que podem aparecer como constantes no cdigo de um programa: nmeros, booleanos, caracteres, strings e smbolos. 3.1.1.1 Nmeros

IS suporta diversos tipos de nmeros, tais como: Inteiros: 42, -1; Nmeros racionais: 355/113, -1/2; Nmeros em ponto utuante: 3.141592; Nmeros complexos, cujas partes podem ser de qualquer um dos tipos acima: 1-2i, 0+355/113i. IS faz uma distino entre nmeros exatos e inexatos: nmeros inteiros, racionais e nmeros complexos com componentes inteiras ou racionais so considerados exatos,

17

enquanto nmeros em ponto utuante so considerados inexatos e so prexados com #i. Ao contrrio do que ocorre na linguagem Racket completa, em IS nmeros escritos em notao decimal no cdigo (e.g., 1.5) so convertidos internamente para os nmeros racionais correspondentes. O objetivo disso trabalhar com nmeros exatos sempre que possvel, evitando arrendondamentos que ocorrem com operaes sobre nmeros em ponto utuante e que podem provocar confuso entre os alunos. Algumas operaes, tais como sqrt (raiz quadrada), podem produzir valores inexatos, indicados pelo prexo #i (e.g., #i1.4142135). O ambiente DrRacket pode ser congurado para exibir nmeros racionais em notao decimal, tornando seu uso mais transparente. A maior parte das operaes matemticas tratam os diversos tipos numricos de maneira transparente, permitindo a combinao de tipos distintos de nmeros e realizando converses automaticamente quando necessrio (e.g., possvel somar um inteiro e um nmero em ponto utuante). Algumas funes, tais como even?, que testa se um nmero inteiro par, produzem um erro de execuo se utilizadas com um nmero do tipo inapropriado. 3.1.1.2 Booleanos

Os dois valores-verdade da linguagem so true e false. Ao contrrio do que acontece em outras linguagens, como C e a linguagem Racket completa, em IS apenas esses dois valores podem ser usados em contextos que esperam valores-verdade, tais como expresses condicionais e operadores lgicos. Isso garante que se uma expresso nobooleana for usada em tal contexto, o usurio ser informado do erro em tempo de execuo. 3.1.1.3 Caracteres

Caracteres so representados atravs da sintaxe #\c, onde c um caracter literal ou, no caso de caracteres especiais, o nome do caracter (e.g., #\a, #\Newline). 3.1.1.4 Strings

Strings so sequncias de caracteres representadas, sintaticamente, pelos caracteres que as compem entre aspas (e.g., "hello, world"). Caracteres especiais podem ser indicados utilizando uma sintaxe similar da linguagem C, usando uma sequncia de caracteres iniciada por \ (e.g., \n para indicar uma quebra de linha). 3.1.1.5 Smbolos

Smbolos so um tipo de dados comumente encontrado nas linguagens da famlia LISP. Smbolos so constantes simblicas, representadas sintaticamente em IS como nome, onde nome o nome dado ao smbolo. A propriedade de implementao que distingue smbolos de strings que a linguagem garante que duas ocorrncias de um smbolo de mesmo nome no cdigo de um programa referenciam o mesmo objeto, e no meramente dois objetos com o mesmo contedo, como o caso com strings idnticas. Isso signica que uma comparao de dois smbolos por igualdades pode ser implementada mais ecientemente como uma mera comparao de ponteiros, em vez de uma comparao dos caracteres que os compem. Para os ns com que so usados ao longo de How to Design Programs, smbolos e strings so usualmente intercambiveis.

18

3.1.2

Expresses aritmticas

Expresses aritmticas so escritas em notao prexada, na forma:


(operador operandos...)

A maior parte das operaes aritmticas aceita dois ou mais argumentos. A exigncia dos parnteses em torno de cada operao elimina a necessidade de regras de precedncia.
(+ 2 3) (+ (* 2 3) (* 4 5)) (* (+ 2 3) (+ 4 5))

Uma expresso do tipo ax2 + bx + c pode ser escrita como


(+ (* a (expt x 2)) (* b x) c)}

3.1.3

Expresses relacionais e lgicas

IS utiliza funes de comparao distintas para cada tipo de dados. Por exemplo, a funo = realiza um teste de igualdade entre dois nmeros, string=? entre strings, symbol=? entre smbolos, e assim por diante. De maneira anloga, h funes tais como <, string<? e assim por diante para a comparao da ordem relativa de nmeros reais, caracteres e strings. A linguagem suporta os operadores lgicos convencionais (and, or, not). Assim como os operadores aritmticos, os operadores and e or so n-rios, computando a conjuno ou a disjuno de todos os seus argumentos. Assim como na linguagem C, os operadores and e or realizam avaliao em curto-circuito: seus argumentos so avaliados da esquerda para a direita, encerrando a avaliao assim que o resultado da expresso puder ser determinado. Por exemplo, em uma expresso como:
(or (> 5 2) (< 0 7))

apenas o primeiro argumento da disjuno ((> 5 2)) avaliado, j que se qualquer um dos argumentos da disjuno for verdadeiro, o resultado ser verdadeiro independentemente dos demais. A linguagem no possui funes explcitas para testar se dois valores so diferentes. Para isso, utilizam-se os operadores de igualdade em conjunto com a negao lgica. 3.1.4 Declarao de variveis

Variveis podem ser declaradas usando a forma:


(define nome expresso)

Na linguagem IS, assim como em muitas linguagens funcionais, variveis so imutveis. Isto , uma vez que um valor tenha sido associado varivel, no possvel atribuir um novo valor mesma. 3.1.5 Declarao e chamada de funes

Funes podem ser declaradas usando a forma:


(define (nome parmetros...) expresso)

Chamadas de funes so escritas com uma sintaxe anloga s operaes aritmticas (de fato, os operadores aritmticos so funes em IS): (nome argumentos...).

19

3.1.6

Expresses condicionais

Expresses condicionais so aquelas cujo resultado depende do resultado de um ou mais testes, representados por expresses booleanas. Em IS, expresses condicionais so escritas utilizando a forma cond:
;; sinal: nmero -> smbolo ;; Retorna um smbolo representando o sinal do nmero ;; passado como argumento. (define (sinal n) (cond [(< n 0) negativo] [(> n 0) positivo] [else neutro]))

O corpo da expresso condicional constitudo de uma ou mais clusulas, compostas por um par teste-resultado entre colchetes. Para computar o resultado da expresso condicional, o teste de cada clusula avaliado em sequncia, at que seja encontrado um teste cujo valor-verdade seja true, ou que a clusula else seja atingida. O resultado de tal clusula utilizado como o valor da expresso. Quando se deseja realizar apenas um teste, a forma mais simples (if teste valor-se-verdadeio valor-se-falso) pode ser utilizada. Ao contrrio do que ocorre na maior parte das linguagens imperativas, as formas cond e if so consideradas expresses, e podem ser utilizadas em qualquer contexto em que outras expresses possam ser usadas. Isso anlogo ao operador ternrio teste? valor-se-verdadeiro : valor-se-falso da linguagem C. A forma if usualmente evitada, por no possuir um delimitador explcito tal como else. 3.1.7 Estruturas de dados

Tipos de dados estruturados podem ser declarados usando a forma:


(define-struct nome-do-tipo (campos...))

Essa declarao cria um tipo estruturado com o nome e os campos especicados, bem como uma funo construtora de valores do novo tipo (make-tipo), uma funo predicado que testa se um dado valor pertence ao tipo (tipo?) e funes de projeo que retornam o valor de um dos campos dado um valor do tipo estruturado (tipo-campo). A Figura 3.1 apresenta a denio de um tipo estruturado pessoa com os campos nome, idade e sexo e exemplos das operaes citadas sobre valores desse tipo. 3.1.8 Tipos mistos

Embora o fato de IS ser uma linguagem dinamicamente tipada impea que o ambiente detecte erros de tipo em tempo de compilao, isso d uma maior exibilidade linguagem, permitindo escrever funes que trabalham com dados de diversos tipos facilmente. Visando a abordar essa ideia de maneira mais estruturada, How to Design Programs utiliza o conceito de tipos mistos, i.e., tipos compostos pela unio de outros tipos. Devido linguagem no suportar declaraes formais de tipo, tipos mistos so denidos informalmente por meio de comentrios no cdigo, como pode ser visto na Figura 3.2. Nesse trecho de cdigo, so denidos os tipos estruturados retngulo e crculo e um tipo misto, na forma de um comentrio, formado pela unio dos dois tipos estruturados. A seguir, denida uma funo rea, que aceita uma forma de qualquer um

20

; Definio do tipo de dados (define-struct pessoa (nome idade sexo)) ; Criao de uma instncia do tipo (define p (make-pessoa "Anna" 18 f)) ; Seleo de campos individuais (pessoa-nome p) ; devolve "Anna" (pessoa-idade p) ; devolve 18 (pessoa-sexo p) ; devolve f ; Predicado de pertinncia (pessoa? p) ; devolve true (pessoa? 5) ; devolve false

Figura 3.1: Denio e uso de estruturas em IS


(define-struct retngulo (lado altura) (define-struct crculo (raio)) ;; Uma forma : ;; - um retngulo; ou ;; - um crculo. ;; rea: forma -> nmero ;; Retorna a rea de uma forma. (define (rea f) (cond [(retngulo? f) (* (retngulo-lado f) (retngulo-altura f))] [(crculo? f) (* PI (expt (crculo-raio f) 2))] [else (error "Forma desconhecida")]))

Figura 3.2: Denio e uso de um tipo misto forma em IS dos tipos e computa sua rea, utilizando as funes-predicado retngulo? e crculo? para determinar qual tipo foi passado como argumento em tempo de execuo. 3.1.9 Listas

Listas so um tipo de dados estruturado nativo da linguagem IS. Em IS, listas so denidas indutivamente como: empty uma lista (vazia); Se x um valor qualquer e L uma lista, ento (cons x L) uma lista. Em termos de implementao, trata-se de listas simplesmente encadeadas. cons o construtor dos elos da lista. Cada elo possui dois componentes: um valor da lista e um ponteiro para o restante da lista. Um elo um valor estruturado cujos campos podem ser obtidos pelas funes de projeo first e rest. Os predicados empty? e cons? permitem testar se um valor uma lista vazia ou um elo (i.e., uma lista novazia), respectivamente. O predicado list? permite testar se algo uma lista (vazia ou

21

; Cria uma de uma lista de trs elementos e associa-a ; a uma varivel. (define lista (cons 1 (cons 2 (cons 3 empty)))) (first lista) (rest lista) (cons? lista) (cons? empty) (empty? lista) (empty? empty) (list? lista) (list? empty) (list? 42) ; devolve 1 ; devolve (cons 2 (cons 3 empty)) ; ; ; ; devolve devolve devolve devolve true false false true

; devolve true ; devolve true ; devolve false

Figura 3.3: Exemplo do uso de listas em IS


;; bhaskara: nmero nmero nmero -> lista-de-nmeros ;; Dados os coeficientes de uma equao do segundo grau, ;; retorna uma lista com suas razes reais. (define (bhaskara a b c) (local ((define delta (- (* b b) (* 4 a c)))) (cond [(< delta 0) empty] [else (local ((define x1 (/ (- (- b) (sqrt delta)) (* 2 a))) (define x2 (/ (+ (- b) (sqrt delta)) (* 2 a)))) (cond [(= delta 0) (list x1)] [else (list x1 x2)]))])))

Figura 3.4: Exemplo de cdigo com denies locais (delta, x1, x2) em IS no). (list? x) equivalente a (or (empty? x) (cons? x)). A Figura 3.3 demonstra a criao de uma lista contendo os valores 1, 2 e 3 e o uso das funes citadas. Para facilitar a criao de listas, a linguagem oferece uma funo list, que recebe um nmero arbitrrio de argumentos e retorna uma lista cujos elementos so os argumentos em sequncia, evitando uma sequncia de construtores cons aninhados. 3.1.10 Denies locais

A linguagem utiliza o operador local para introduzir denies de variveis e funes com escopo limitado. Sua sintaxe :
(local ( sequncia de formas define ) expresso na qual as definies so visveis)

A Figura 3.4 mostra um exemplo de funo com denies locais.

22

3.1.11

Funes annimas

A forma lambda uma construo sinttica que permite expressar funes sem que seja necessrio dar-lhes um nome, da mesma maneira que possvel construir valores estruturados sem que seja necessrio atribu-los a uma varivel. Sua sintaxe :
(lambda (parmetros da funo) corpo da funo)

O conceito de funo annima usualmente no abordado em disciplinas introdutrias, mas aqui apresentado para ns de comparao com a nova linguagem no captulo seguinte. 3.1.12 Anlise

Durante o ensino da disciplina de Fundamentos de Algoritmos utilizando a linguagem IS e seus subconjuntos, pde-se observar diversos pontos positivos e negativos da sintaxe da linguagem Racket de um ponto de vista didtico. Segue uma enumerao desses pontos. Tipos de dados primitivos. O uso transparente dos diversos tipos numricos um ponto positivo de IS em comparao a outras linguagens, pois permite que o aluno trabalhe com dados numricos de maneira similar s entidades matemticas que representam. Da mesma forma, o uso de nmeros exatos sempre que possvel, e a representao interna de nmeros decimais como racionais, evita preocupaes com questes de arredondamento. Por outro lado, a distino sinttica entre nmeros exatos e inexatos atravs de um prexo, embora teoricamente interessante, uma distrao desnecessria em uma disciplina introdutria. A sintaxe peculiar para representao de caracteres e o uso de uma sintaxe distinta para representao de caracteres especiais em caracteres e strings (#\Newline vs "\n") so aspectos desnecessariamente confusos da linguagem. A distino entre smbolos e strings relativamente arbitrria, e no h uma regra bem denida de quando cada um dos tipos deve ser usado. O tipo smbolo uma herana do LISP, em que smbolos so usados, entre outras coisas, para representar identicadores no cdigo em contextos de metaprogramao, em que programas manipulam cdigo como dados. No contexto de uma disciplina introdutria, no h uma necessidade para um tipo simblico distinto. Smbolos so tambm frequentemente usados em situaes em que outras linguagens utilizam enumeraes. A linguagem IS no prov nenhum meio para declarar enumeraes. A introduo de tal mecanismo eliminaria o principal caso de uso em que smbolos poderiam ser considerados mais apropriados do que strings. O uso de enumeraes declaradas tem ainda a vantagem de permitir ao ambiente indicar para o usurio usos de constantes no denidas, ao contrrio do que acontece em IS, onde qualquer smbolo pode ser usado sem declarao prvia e erros de digitao podem provocar falhas silenciosas em um programa. Expresses aritmticas. O uso da notao prexada delimitada por parnteses torna o agrupamento das operaes explcito, evitando a necessidade de regras de precedncia, e unica a sintaxe dos operadores aritmticos e das chamadas de funo. Por outro lado, essa notao diverge bastante da notao matemtica convencional e uma frequente fonte de confuso entre os alunos, especialmente em expresses maiores nas quais o aninhamento dos parnteses no evidente.

23

; Realiza a operao indicada sobre o valor. Se a operao ; for desconhecida, retorna o valor intacto. (define (calcula operao valor) (cond [(symbol=? operao quadrado) (* valor valor)] [(symbol=? operao mdulo) (abs valor)] [else valor])) (calcula abs -3) (calcula -3 abs) ; Chamada correta ; Chamada incorreta

Figura 3.5: Funo que realiza uma operao indicada por um smbolo sobre um valor numrico Expresses relacionais e lgicas. O uso de funes distintas para comparaes de valores de diferentes tipos benco em uma linguagem dinamicamente tipada, pois ajuda a detectar erros de tipo em tempo de execuo. Considere o cdigo na Figura 3.5, que realiza a operao indicada por um smbolo sobre um nmero. Se, ao chamar essa funo, a ordem dos argumentos for invertida, a funo symbol=? detectar o nmero passado no lugar do smbolo, produzindo um erro de execuo que ser noticado ao usurio. Por outro lado, se uma funo de comparao genrica fosse utilizada, os testes de igualdade produziriam false sem provocar erros (-3 diferente de quadrado e de mdulo), dicultando a deteco da chamada incorreta. Efetivamente, as funes de comparao de IS introduzem vericaes dinmicas de tipo no programa. Por outro lado, essas vericaes so teis primariamente para suprir a ausncia de um sistema de tipos esttico em IS. Como ser visto na Seo 3.2.1, essa ausncia de vericaes estticas de tipo dicultam a deteco precisa do ponto em que se encontram os erros de tipo do programa. Na presena de um sistema de tipos esttico, o uso de funes distintas de comparao para tipos diferentes torna-se desnecessrio. Declarao e chamada de funes. A colocao dos parnteses em torno da expresso completa (e.g., (f x y), em vez de apenas em torno dos argumentos (e.g., f(x,y)) provoca uma srie de confuses. Primeiro, a sintaxe diverge da conveno matemtica e da maior parte das linguagens de programao, que utilizam a segunda forma. Segundo, a sintaxe para denio de funes, anloga sintaxe da chamada, inconsistente com a sintaxe para denio de estruturas, que mantm o nome do tipo estruturado a ser denido isolado dos demais parmetros, como ser visto a seguir. Alm disso, o uso de define para denir tanto variveis quanto funes, ainda que simples, causa certa confuso. A oposio entre os operadores define (sem qualicadores indicando de que tipo de denio se trata) e define-struct (que indica explicitamente que trata-se de uma denio de estrutura) inconsistente e tambm provoca dvidas. A linguagem no possui nenhum mecanismo para a declarao formal dos tipos dos parmetros e de retorno das funes. Uma vez que esse um conceito importante para ns de organizao e documentao do cdigo, o livro-texto HtDP supre essa falta por meio de comentrios no cdigo indicando os tipos de entrada e sada de cada funo, denominados contratos. O fato de que tais comentrios no so analisados pela linguagem implica que os alunos no tm como testar a correo dessas declaraes por meio da execuo do programa, alm de desmotiv-los a escrev-las. Expresses condicionais. A ausncia de um delimitador explcito entre o teste e o resultado de cada clusula do cond so uma causa comum de confuso entre os alunos em

24

programas maiores, onde tanto o teste quanto o resultado so expresses mais complexas e difcil visualizar claramente que expresso est sendo delimitada por cada par de parnteses. O fato de que a linguagem baseada em expresses e o valor da expresso que constitui o corpo da funo implicitamente o valor de retorno da funo, sem o uso de uma palavra explcita como o return de linguagens imperativas, torna menos evidente que o valor do resultado de uma clusula da expresso condicional tambm o valor de retorno da funo como um todo. O uso de uma nica expresso condicional, em vez de uma cadeia de ifs e elses, para a realizao de mltiplos testes, evita aninhamento excessivo no cdigo e lembra a notao comumente usada na matemtica para indicar funes denidas por partes. Estruturas de dados. A sintaxe para declarao de estruturas apresenta uma inconsistncia em relao sintaxe para declarao de funes quanto colocao dos parnteses, como mencionado anteriormente. Alm disso, analogamente s funes, no possvel declarar os tipos dos campos das estruturas, sendo necessrio recorrer a comentrios. A sintaxe usada para as funes de projeo uma fonte notria de confuso entre os alunos. Erros frequentes incluem: esquecer o argumento sobre o qual a projeo deve ser realizada, utilizar o argumento como prexo em vez do nome do tipo (i.e., p-nome em vez de (pessoa-nome p) para extrair o campo nome de uma pessoa p), esquecer os parnteses em torno da expresso (por no ser claro que os seletores so funes), esquecer o prexo make- na chamada do construtor, confuso entre o nome do tipo e uma varivel contendo um valor do tipo, entre outros. Tipos mistos. A exibilidade proporcionada pelos tipos mistos explorada em diversos exerccios de How to Design Programs. Essa funcionalidade um ponto forte da linguagem IS. Por outro lado, IS sacrica toda a segurana esttica para atingir essa exibilidade, o que no estritamente necessrio. Listas. Listas so apenas um tipo particular de dado estruturado, mas a linguagem no as trata de maneira consistente com os tipos de dados denidos pelo usurio com a forma define-struct; IS utiliza nomes especiais para os operadores de construo e projeo que no seguem as mesmas convenes utilizadas para outros tipos estruturados, tais como cons em vez de make-cons e first em vez de cons-first. Se por um lado os nomes utilizados so mais concisos, por outro lado eles obscurecem a relao entre estruturas e listas. Alm disso, um argumento em favor de operadores mais concisos refora o fato de que os operadores para manipulao de estruturas denidas pelo usurio so demasiadamente verbosos. Se uma sintaxe mais simples fosse adotada para a manipulao de estruturas em geral, a mesma sintaxe poderia ser usada para listas sem prejuzo legibilidade do cdigo. Denies locais. Denies locais so frequentemente teis para simplicar expresses complexas em um trecho de cdigo, evitando o aninhamento excessivo de expresses e permitindo dar nomes signicativos a subexpresses. IS utiliza uma sintaxe desnecessariamente complexa para denies locais, em que a colocao do parnteses e a delimitao entre as denies e a expresso-resultado frequentemente confusa. Por ser uma forma distinta das denies globais, a apresentao do conceito de denio local usualmente postergada para o nal da disciplina, o que impede que os alunos se beneciem desse recurso no desenvolvimento de programas ao longo da disciplina, dicultando a compreenso e estruturao de programas maiores. Idealmente, a sintaxe para denies locais deveria ser o mais prxima possvel da sintaxe para denies globais, permitindo a introduo do conceito mais cedo na disciplina.

25

(define (dobro x) (* 2 x)) (define (f x y) (+ (dobro x) (dobro y))) (f 1 a)

Figura 3.6: Cdigo com erro de tipo

3.2

Sistema de tipos

IS uma linguagem dinamicamente tipada, i.e., erros de tipo, tais como desencontro entre os tipos e nmero de parmetros esperados por uma funo e os tipos e nmero de argumentos utilizados em uma chamada da funo s so detectados em tempo de execuo, quando uma operao primitiva da linguagem recebe um argumento de tipo invlido. Considere o cdigo na Figura 3.6. Esse cdigo dene uma funo que calcula o dobro de um nmero, uma funo f que calcula a soma do dobro de dois nmeros e faz uma chamada a f usando um nmero e um smbolo como argumentos. Ao avaliar essa chamada de funo, o argumento a ser passado para a funo f, que o passar funo dobro, que por sua vez o passar funo de multiplicao *. Somente ao tentar avaliar a multiplicao entre 2 e a a linguagem detectar o erro. 3.2.1 Anlise

Se por um lado a tipagem dinmica d uma certa exibilidade linguagem, permitindo a escrita de funes que trabalham com argumentos de tipos diversos de maneira mais livre, como visto anteriormente, por outro lado isso limita a capacidade do ambiente de indicar com preciso trechos de cdigo incorretos. Considere o cdigo da Figura 3.6. Embora o erro se encontre na chamada nal funo f, que foi escrita de maneira a trabalhar com nmeros, e no smbolos, a linguagem somente detectar o erro ao tentar realizar a operao de multiplicao entre 2 e a, indicando o trecho de cdigo no corpo da funo dobro como o ponto de erro. Cabe ento ao usurio determinar de que maneira o valor a chegou funo dobro. Outro problema da tipagem dinmica que, como j mencionado na Seo 3.1.12, a linguagem no permite a declarao formal dos tipos dos parmetros e de retorno das funes e dos campos de estruturas. Um sistema de tipos esttico evitaria esse problema: uma vez que os tipos dos parmetros das funes dobro e f tenham sido declarados e que as funes tenham sido consideradas corretas pelo sistema de tipos, a linguagem seria capaz de identicar a chamada a f como o ponto de erro, evitando a propagao do erro para outras funes.

26

A LINGUAGEM FAZ

Neste trabalho, foi desenvolvida uma nova linguagem de programao, intitulada Faz. A linguagem foi desenvolvida visando a evitar os problemas com as linguagens didticas HtDP identicados no captulo anterior, mas ao mesmo tempo manter suas vantagens em um contexto didtico. As sees seguintes apresentam os recursos sintticos e semnticos da nova linguagem, bem como uma discusso das decises de design tomadas e alternativas consideradas.

4.1
4.1.1

Construes sintticas
Tipos de dados bsicos

H quatro tipos de dados bsicos que podem aparecer como constantes no cdigo de um programa em Faz. Nmeros. A linguagem possui sintaxe para nmeros inteiros (e.g., 42, -1), nmeros em ponto utuante (e.g., 3.141592) e nmeros imaginrios (e.g., 1.5i). Nmeros racionais podem ser obtidos atravs do operador de diviso (e.g., 1/2). Nmeros complexos podem ser obtidos atravs da soma ou subtrao de um nmero real e um imaginrio (e.g., 1+2i). Diferentemente de IS, no h uma distino sinttica entre nmeros exatos e inexatos. Caracteres. Caracteres so representados atravs da sintaxe c, de maneira anloga linguagem C e derivadas (C++, Java, etc.). Caracteres especiais tambm so indicados utilizando uma sintaxe anloga a C, utilizando uma sequncia de caracteres iniciada por \ (e.g., \n para indicar o caractere de quebra de linha). Strings. A sintaxe para strings anloga de IS e C: os caracteres que compem a string so escritos entre aspas (e.g., "hello, world"). Caracteres especiais em strings so indicados utilizando a mesma sintaxe usada para caracteres especiais individuais (e.g., "\n" representa uma string contendo uma quebra de linha). Booleanos. As constantes verdadeiro e falso constituem os valores booleanos da linguagem. 4.1.2 Expresses aritmticas

Expresses aritmticas so escritas de maneira similar maioria das linguagens de programao, utilizando operadores inxados com as precedncias convencionais da notao algbrica. Parnteses podem ser usados para alterar a ordem de avaliao das expresses. Os operadores aritmticos +, -, * (multiplicao), / (diviso) e ^ (exponenciao) so suportados.

27

2+3 2*3 + 4*5 (2+3) * (4+5)

Uma expresso do tipo ax2 + bx + c pode ser escrita como


a*x^2 + b*x + c

4.1.3

Expresses relacionais e lgicas

Os operadores relacionais de Faz so anlogos aos da linguagem C: == (igualdade), != (diferena), <=, <, >, >=. Os mesmos operadores podem ser usados para comparar dados dos diferentes tipos, quando aplicveis. Os operadores lgicos so e, ou e no. Assim como em IS, os operandos de e e ou so avaliados em curto-circuito da esquerda para a direita. 4.1.4 Blocos

O cdigo em Faz estruturado em blocos, que denem o escopo das denies de variveis e funes da linguagem. Um bloco consiste de zero ou mais denies de variveis e funes locais, seguidas de um comando nal, que avaliado no escopo das declaraes. O comando nal produz um valor, que tomado como o valor do bloco. O comando nal pode ser um comando devolve expresso, anlogo ao return de linguagens imperativas, ou um comando condicional. Alternativamente, o comando nal pode ser da forma erro expresso, que no produz um valor de retorno, mas sinaliza um erro de execuo. As subsees seguintes descrevem cada um desses elementos. 4.1.5 Denio de variveis

Variveis podem ser declaradas usando a forma:


seja nome = expresso

Por padro, o tipo da varivel inferido a partir do tipo da expresso. Alternativamente, o tipo pode ser declarado explicitamente usando a forma:
seja nome tipo = expresso

Assim como em IS, variveis so imutveis. 4.1.6 Denio e chamada de funes

Funes podem ser declaradas usando a forma:


funo nome(param1 tipo1, param2 tipo2, ...) -> tipo de retorno corpo da funo

As declaraes de tipos dos parmetros e de retorno da funo so obrigatrias. O corpo da funo um bloco. Quando a funo chamada, o bloco avaliado e o valor produzido pelo comando nal do bloco retornado pela funo. Chamadas de funo possuem a forma funo(arg1, arg2, ...).

28

funo sinal(n Nmeros) -> Strings se n<0 devolve "negativo" se n==0 devolve "neutro" seno devolve "positivo"

Figura 4.1: Exemplo de condicional em Faz 4.1.7 Condicionais

Condicionais so comandos em Faz, e no expresses, como o caso em IS. Condicionais possuem a forma:
se expresso-teste1 bloco1 se expresso-teste2 bloco2 ... seno bloco

Se o condicional o comando nal de um bloco, o valor produzido pelo condicional tomado como o valor do bloco. Ao contrrio de IS, em Faz a clusula seno obrigatria. Isso ocorre porque a clusula seno implicitamente delimita o comando condicional. A Figura 4.1 apresenta um exemplo de condicional. 4.1.8 Expresses de bloco

Alm de poderem ocorrer como o corpo de uma funo ou de uma clusula de condicional, um bloco pode ser escrito entre parnteses. Nesse caso, o valor produzido pelo bloco capturado e pode ser utilizado como uma expresso. Por exemplo, 1 + (se 5>2 devolve 10 seno devolve 20) uma expresso vlida e produz o valor 11. 4.1.9 Retorno e sinalizao de erros

O comando devolve expresso computa o valor da expresso e o usa como o valor de retorno do bloco. O comando erro expresso computa o valor da expresso, que deve produzir uma string, e encerra a execuo do programa, emitindo ao usurio uma mensagem de erro contendo a string e o nome da funo onde ocorreu o erro. 4.1.10 O comando teste

Alm de denies de variveis, funes e tipos, o corpo do programa tambm pode conter expresses a serem avaliadas quando o programa for executado. Essas expresses possuem um papel similar a uma funo principal como main em C, com a diferena de que o valor computado pelas expresses automaticamente impresso. Na linguagem Faz, essas expresses so introduzidas pelo comando teste expresso. A Figura 4.2 demonstra a denio de uma funo e uma chamada mesma a ser avaliada quando da execuo do programa. 4.1.11 Denio de tipos no paramtricos

A palavra tipo usada para introduzir novos tipos de dados. A sintaxe :


tipo nome-do-tipo = componentes

Onde componentes uma das seguintes alternativas:

29

funo fac(n Nmeros) -> Nmeros se n==0 devolve 1 seno devolve n * fac(n-1) teste fac(5)

Figura 4.2: Exemplo do uso do comando teste em Faz O nome de um tipo j existente. Nesse caso, dene-se um sinnimo para esse tipo. Uma lista de construtores entre chaves, separados por vrgulas. Construtores podem ser nomes simples, permitindo a denio de enumeraes, ou da forma nome(param1 tipo1, param2 tipo2...), permitindo a denio de estruturas. Uma unio de outros componentes, escritos na forma componente1 U componente2, permitindo a denio de tipos mistos. 4.1.12 Enumeraes

Denindo-se um tipo em termos de construtores simples, efetivamente criam-se tipos enumerados. Por exemplo, a seguinte declarao dene uma enumerao de cores:
tipo Cores = { vermelho, verde, azul }

Alm do tipo em si, a declarao tambm dene as constantes vermelho, verde e


azul no programa.

4.1.13

Estruturas de dados

Denindo-se um tipo em termos de construtores com parmetros, criam-se tipos de dados estruturados. Uma vez denido o tipo de dados, pode-se criar novos valores do tipo invocando-se o construtor denido, extrair os campos de um valor estruturado atravs do operador de e testar se um valor pertence ao tipo atravs do operador . A Figura 4.3 demonstra a denio de um tipo de dados para representar pessoas, anlogo ao visto na Figura 3.1, e exemplos de operaes sobre valores desse tipo. 4.1.14 Tipos mistos

Tipos mistos so suportados diretamente em Faz na forma de unies de tipos. A Figura 4.4 demonstra a declarao de um tipo misto Formas, constitudo de retngulos e crculos, e a denio de uma funo rea, que aceita uma forma qualquer e computa sua rea, de maneira anloga ao cdigo da Figura 3.2. 4.1.15 Denio de tipos paramtricos

possvel denir tipos genricos parametrizados por outros tipos. A sintaxe anloga declarao de tipos no paramtricos, mas inclui uma lista de variveis de tipo introduzidas pela palavra de:
tipo nome-do-tipo de parmetros = componentes

30

# Definio dos tipos de dados tipo Sexos = { masculino, feminino } tipo Pessoas = { pessoa(nome Strings, idade Nmeros, sexo Sexos) } # Criao de uma instncia do tipo seja p = pessoa("Anna", 18, feminino) # Seleo de campos individuais nome de p # devolve "Anna" idade de p # devolve 18 sexo de p # devolve feminino # Teste de pertinncia p Pessoas # devolve verdadeiro 5 Pessoas # devolve falso

Figura 4.3: Denio e uso de estruturas em Faz

# Definio de tipos para cada forma tipo Retngulos = { retngulo(lado Nmeros, altura Nmeros) } tipo Crculos = { crculo(raio Nmeros) } # Definio do tipo misto tipo Formas = Retngulos U Crculos funo rea(f Formas) -> Nmeros # Retorna a rea de uma forma. se f Quadrados devolve lado de f * altura de f se f Crculos devolve pi * (raio de f)^2 seno erro "Forma desconhecida"

Figura 4.4: Denio e uso de um tipo misto forma em Faz

31

tipo rvores de ?X = { vazia, n(valor ?X, esquerda rvores de ?X, direita rvores de ?X) }

Figura 4.5: Denio de rvore binria genrica em Faz


# Cria uma de uma lista de trs elementos e # associa-a a uma varivel. seja lista = elo(1, elo(2, elo(3, vazio))) primeiro de lista resto de lista lista == vazio # devolve 1 # devolve elo(2, elo(3, vazio)) # devolve falso

resto de resto de resto de lista == vazio # devolve verdadeiro lista Listas de Nmeros vazio Listas de Nmeros 42 Listas de Nmeros # devolve verdadeiro # devolve verdadeiro # devolve falso

Figura 4.6: Exemplo do uso de listas em Faz Onde parmetros pode ser uma varivel de tipo, na forma ?var, ou uma lista de variveis de tipo entre parnteses separadas por vrgula. Por exemplo, um tipo genrico de rvores binrias pode ser denida como na Figura 4.5. A semntica das variveis de tipo e tipos paramtricos sero vistos em maior detalhe na Seo 4.2.1. 4.1.16 Listas

Listas so um tipo de dados paramtrico estruturado pr-denido em Faz. Esse tipo poderia ser denido em Faz como:
tipo Listas de ?X = { vazio, elo(primeiro ?X, resto Listas de ?X) }

Isto , uma lista pode ser vazia (representada pela constante vazio) ou um elo (anlogo ao cons de IS) constitudo por dois componentes: primeiro, o primeiro elemento da lista; e resto, uma lista contendo os elementos restantes, que novamente pode ser vazia ou outro elo. Por ser denida da mesma maneira que os outros dados estruturados, listas em Faz podem ser manipuladas utilizando os mesmos operadores vlidos para estruturas denidas pelo usurio. A Figura 4.6 demonstra a criao de uma lista contendo os valores 1, 2 e 3 e o uso de algumas operaes sobre listas. Assim como IS, Faz oferece uma sintaxe abreviada para a criao de listas: listas podem ser descritas listando-se seus elementos em ordem entre colchetes, separados por vrgulas. Por exemplo, [1,2,3] equivalente a elo(1, elo(2, elo(3, vazio))).

32

funo bhaskara(a Nmeros, b Nmeros, c Nmeros) -> Listas de Nmeros # Dados os coeficientes de uma equao do segundo grau, # retorna uma lista com suas razes reais. seja delta = b^2 - 4*a*c se delta < 0 devolve [] seno seja x1 = (-b - raiz(delta)) / (2*a) seja x2 = (-b + raiz(delta)) / (2*a) se delta == 0 devolve [x1] seno devolve [x1, x2]

Figura 4.7: Exemplo de cdigo com denies locais (delta, x1, x2) em Faz 4.1.17 Denies locais

Denies locais so feitas atravs da mesma sintaxe usada para denies globais; o bloco em que a denio ocorre dene seu escopo. A Figura 4.7 mostra um exemplo de funo com denies locais. 4.1.18 Funes annimas

Funes annimas podem ser expressas utilizando a forma funo, de maneira similar declarao de funes, omitindo-se o nome da funo e envolvendo-se a forma entre parnteses:
(funo (param1 tipo1, param2 tipo2, ...) -> tipo de retorno corpo da funo)

4.1.19

Anlise

Tipos de dados bsicos. Faz elimina smbolos como um tipo de dados da linguagem, removendo assim a ambiguidade no uso de smbolos e strings presente em IS. A sintaxe para caracteres foi alterada de modo a torn-la anloga das strings e mais prxima da sintaxe usada em outras linguagens de programao. Assim como IS, a linguagem possui um nico tipo numrico, que unica inteiros, racionais e complexos, tornando o comportamento dos nmeros mais prximo das entidades matemticas que representam. Por exemplo, no h uma diviso inteira distinta da diviso usual. Expresses aritmticas. Faz introduz operadores inxados na linguagem, tornando a sintaxe mais similar notao algbrica e evitando aninhamento excessivo de parnteses em expresses maiores. Buscou-se introduzir apenas operadores sucientemente familiares a alunos egressos do Ensino Mdio. Por exemplo, ao contrrio do que ocorre em linguagens como C, no h um operador inxado para o cmputo do resto de uma diviso; para isso, a funo resto utilizada. Com isso, buscou-se facilitar a compreenso de cdigo escrito na linguagem e evitar a introduo de regras de precedncia alm das j usuais na lgebra. Expresses relacionais e lgicas. Uma vez que as vericaes de tipos providas pelo uso de operadores de comparao distintos para cada tipo, como ocorre em Racket, tornam-se desnecessrias em uma linguagem com um sistema de tipos esttico, Faz usa os mesmos operadores para comparar dados dos diversos tipos, o que facilita a escrita de testes de comparao.

33

Comandos e blocos. A maior parte das linguagens imperativas faz uma distino entre expresses, i.e., construes que produzem um valor, e comandos, ou statements, construes que possuem apenas um efeito colateral e no produzem um valor. Por exemplo, na linguagem C, operaes aritmticas e construes com o operador ternrio ? so expresses, enquanto comandos como if, for, while e return so utilizados apenas por seus efeitos colaterais (controle de uxo) e no produzem valores que possam ser usados como parte de expresses maiores. Linguagens funcionais, por outro lado, geralmente eliminam essa distino, uma vez que nessas linguagens tende-se a escrever programas por meio de composio de valores e limita-se o uso de efeitos colaterais. Por exemplo, na maior parte das linguagens funcionais, a construo condicional if ou cond uma expresso que produz um valor, podendo ser utilizada como parte de uma expresso maior (similar ao operador ternrio ? em C). Da mesma forma, variveis locais frequentemente so introduzidas por meio de uma construo sinttica do tipo let var = valor in expresso, em que as variveis so visveis apenas na expresso, e a forma let como um todo produz como valor o resultado da expresso, podendo ser utilizada em uma expresso maior (e.g., 1 + (let x=3 in x*x) uma expresso vlida em Haskell e produz o valor 10). Uma vez que esse tipo de construo naturalmente permite aninhamento e as variveis so visveis apenas dentro da subexpresso, o conceito de bloco, frequentemente encontrado em linguagens imperativas como uma maneira de delimitar o escopo dos identicadores introduzidos, torna-se desnecessrio em uma linguagem funcional desse tipo. Essa divergncia entre linguagens imperativas e funcionais de natureza puramente sinttica; embora o paradigma funcional favorea uma eliminao da distino entre comandos e expresses, isso no estritamente necessrio para a manuteno do carter funcional de uma linguagem. Durante o projeto da linguagem desenvolvida neste trabalho, foi constatado que a introduo de comandos na linguagem possui uma srie de consequncias bencas para a clareza do cdigo: A introduo de um comando explcito para retorno de valores (devolve) torna mais evidente que o valor produzido por uma expresso o valor de retorno da funo como um todo, especialmente em casos em que o corpo da funo uma construo complexa, como um condicional. A organizao de comandos em blocos permite o uso da mesma construo para introduzir tanto denies globais como locais (i.e., no necessria uma forma especial como let para introduzir variveis locais). O uso de comandos permite que as prprias palavras-chave que introduzem cada comando sirvam como delimitador de comandos e expresses, eliminando a necessidade de pontuao explcita para delimitar o corpo de funes e de outras construes, sem perda de clareza, como ser visto mais adiante. Com base nisso, optou-se por uma sintaxe baseada em comandos e blocos, em vez de uma sintaxe puramente baseada em expresses. Porm, esses conceitos foram adaptados de forma a melhor adequ-los ao carter funcional da linguagem. Diferentemente do que ocorre em uma linguagem imperativa convencional, e similarmente s construes de linguagens funcionais, todo bloco em Faz produz um valor. Esse valor normalmente usado no cmputo do valor de retorno de funes, mas pode ser usado como parte de uma expresso, envolvendo o bloco entre parnteses, como visto na Seo 4.1.8.

34

Outra adaptao realizada advm do fato de que, diferentemente de linguagens imperativas, Faz no possui comandos de atribuio ou outros comandos que sejam invocados apenas por seu efeito colateral, e no por seu valor. Consequentemente, cada bloco possui, alm das declaraes de variveis e funes locais, exatamente um comando, que computa o valor de retorno do bloco. Em Faz, essa limitao incorporada na sintaxe da linguagem. Dessa forma, o comando nal indica implicitamente o m do bloco, uma vez que no pode haver mais comandos aps o comando nal. Isso elimina a necessidade de delimitadores explcitos de bloco, tais como palavras especiais de incio e m, chaves ou indentao signicativa1 . Denio de variveis. O uso da palavra seja para introduzir variveis usual em textos matemticos e prontamente compreensvel. Denio e chamada de funes. A linguagem introduz declaraes dos tipos dos parmetros e de retorno das funes, substituindo as anotaes de tipo na forma de comentrios frequentemente empregadas em IS. O uso da palavra funo para introduzir as denies de funo evita ambiguidades com outros tipos de denio. A sintaxe das chamadas de funo mais prxima da notao algbrica. Diferentemente das denies de variveis, em que o tipo da varivel inferido se no for declarado, denies de funes exigem a declarao explcita dos tipos dos parmetros e de retorno. H dois motivos principais por trs dessa deciso. Em primeiro lugar, no contexto de uma disciplina introdutria, interessante enfatizar a necessidade de documentar as interfaces das funes. Em segundo lugar, a presena de unies de tipos faz com que expresses que seriam detectadas como erros em um sistema de tipos convencionais possuam um tipo vlido em Faz. Por exemplo, uma construo como
se x<0 devolve 1 seno devolve "a"

seria detectada como um erro em uma linguagem estaticamente tipada convencional, mas seria aceita em Faz, onde a construo produz um valor do tipo Nmeros U Strings. Com declaraes de tipos explcitas nas funes, tais erros podem ser detectados no momento em que o tipo do corpo (e.g., Nmeros U Strings) no for compatvel com o tipo de retorno da funo (e.g., Nmeros). Condicionais. A organizao do cdigo em blocos, com uma palavra explcita para o retorno de um valor (devolve), prov uma separao mais explcita entre o teste e a resposta de cada clusula do condicional. O uso da palavra se para introduzir cada clusula tambm contribui para a legibilidade. A obrigatoriedade da clusula seno d a essa clusula a funo de delimitador do condicional. Isso, combinado com a delimitao implcita dos blocos de cada clusula e a exigncia de apenas um comando de retorno por bloco, permite que mltiplas clusulas sejam postas em sequncia sem a necessidade de criar aninhamentos de se/seno e sem provocar ambiguidade com uma possvel sequncia de condicionais distintos. Expresses de bloco. Como visto, a estruturao em comandos e blocos traz uma srie de benefcios linguagem. Por outro lado, a distino entre expresses e comandos de certa forma reduz a ortogonalidade das construes da linguagem. Expresses de bloco foram introduzidas na linguagem de modo a compensar essa perda, permitindo
Indentao signicativa um problema quando o cdigo copiado de slides de aula ou postado em outros meios que perdem a indentao do texto. Por outro lado, em uma linguagem em que a estrutura do cdigo pode ser reconstruda sem auxlio da indentao, possvel ao ambiente de programao realizar indentao automtica do cdigo.
1

35

o uso de comandos como expresses, e podem ser vistas como uma construo dual ao comando devolve, que permite usar uma expresso como o comando nal de um bloco. Embora essa dualidade possa ser vista como uma complicao desnecessria, considerouse-a aceitvel na elaborao da linguagem tendo em vista os benefcios trazidos pela introduo de comandos e blocos. Retorno e sinalizao de erros. O uso da palavra devolve torna mais explcito que a expresso que a segue o valor de retorno do bloco, especialmente em um comando mais complexo, como um condicional, diferentemente do que ocorre em IS, onde a ausncia de uma palavra explcita para indicao de retorno provoca dvidas entre alunos. Avaliao de expresses de teste. A ausncia de delimitadores explcitos de bloco d aos comandos da linguagem um papel secundrio de delimitadores. Um artefato disso a necessidade de uma palavra especial para a introduo de expresses a serem avaliadas na execuo do programa: diferentemente do que ocorre em IS, em que expresses podem ser escritas diretamente no corpo do programa, Faz requer um comando, para evitar que a expresso seja tomada como continuao do bloco anterior. Se por um lado isso exige a adio de um comando extra linguagem, por outro lado pode-se considerar que a palavra-chave contribui para a clareza do cdigo. Tipos denidos pelo usurio. A linguagem tenta explorar a analogia entre tipos e conjuntos, uma vez que o conceito de conjunto familiar a estudantes egressos do Ensino Mdio. Assim, a descrio dos tipos segue uma sintaxe similar descrio de conjuntos por extenso e compreenso. Da mesma forma, a linguagem usa o operador para indicar pertinncia a um tipo e o operador U para criar unies de tipos.2 A introduo de enumeraes compensa a eliminao de smbolos da linguagem, permitindo a introduo de constantes de maneira mais estruturada, evitando o problema existente em IS de que todo smbolo existe sem necessidade de declarao prvia, o que ocasionalmente faz com que erros de digitao passem desapercebidos no cdigo. A introduo de tipos de unio permite a denio formal de tipos mistos de maneira anloga ao que feito informalmente em IS, conferindo a Faz uma exibilidade anloga de IS de maneira mais estruturada. O uso da palavra de para a extrao de campos de um dado estruturado aproxima-se da linguagem natural (e.g., nome de p para extrair o campo nome de uma instncia p). O operador possui uma funo dupla, sendo usado tanto na declarao do tipo de uma varivel ou campo de estrutura quanto em testes de pertinncia. Embora o contexto torne em princpio evidente a funo do operador (e.g., um teste de pertinncia em se x Nmeros e uma declarao em seja x Nmeros = 42), essa duplicidade pode vir a ser um problema. Da mesma forma, o operador de atua tanto na seleo de campos de estruturas (e.g., nome de p) quanto na introduo de tipos paramtricos (e.g., Listas de Nmeros). Novamente, cada uma das funes em tese evidente pelo contexto em que o operador ocorre. Listas. A linguagem trata listas da mesma maneira que estruturas de dados denidas pelo usurio, tornando a relao entre listas e estruturas mais evidente e unicando os operadores usados para a manipulao de ambos. Denies locais. A organizao do cdigo em blocos elimina a necessidade de um comando especial para a introduo de denies locais: o escopo de uma denio
O ambiente DrRacket possui suporte ao Unicode, permitindo o uso de caracteres especiais, como . Pretende-se no futuro introduzir um atalho de teclado no ambiente para a insero desse smbolo. Alternativamente, o caractere : pode ser usado no lugar de . O operador U no um caractere especial, mas sim a letra U maiscula.
2

36

dado pelo bloco em que ela ocorre. Assim, a declarao de variveis locais simplicada, facilitando a apresentao do conceito em uma disciplina introdutria.

4.2

Sistema de tipos

Como visto no captulo anterior, a ausncia de um sistema de tipos esttico nas linguagens HtDP provoca uma srie de inconvenientes, tais como a impossibilidade de expressar formalmente os tipos dos argumentos e de retorno de funes e os tipos dos campos de estruturas e a impossibilidade de indicar ao usurio o ponto apropriado do cdigo em que ocorrem erros de tipo. Por outro lado, a tipagem dinmica oferece uma exibilidade s linguagens HtDP que no normalmente encontrada em linguagens estaticamente tipadas, permitindo a denio de funes que trabalham com dados de tipos diversos sem a necessidade de introduzir unies etiquetadas (tagged unions). Essa exibilidade explorada em diversos exerccios do livro-texto HtDP e um ponto positivo dessas linguagens. Visando a permitir a declarao formal dos tipos de dados manipulados pelo programa sem perder a exibilidade oferecida por um sistema de tipos dinmico, a linguagem Faz emprega um sistema de tipos semi-esttico. A linguagem exige que os tipos dos argumentos e de retorno de funes e os tipos dos campos de estruturas sejam declarados pelo usurio e o uso correto desses tipos vericado em tempo de compilao. Por outro lado, a linguagem introduz unies de tipos (PIERCE, 2002), permitindo a elaborao de programas que trabalham com dados de tipos diversos de maneira intuitiva. Esta seo descreve o sistema de tipos de Faz. A introduo de um sistema de tipos semi-esttico a principal divergncia semntica, e no puramente sinttica, entre Faz e as linguagens HtDP. Assim, sua elaborao e implementao constituem uma das principais contribuies do presente trabalho. 4.2.1 Tipos da linguagem

Tipos bsicos. Os tipos de dados bsicos da linguagem so Nmeros, Booleanos, Caracteres e Strings. Esses tipos contm os valores expressveis como constantes no cdigo por meio da sintaxe descrita na Seo 4.1.1. Universo e vazio. O tipo Tudo representa o universo de valores da linguagem e supertipo de todos os tipos. O tipo Nada um tipo vazio e subtipo de todos os tipos. O tipo Nada no pode ocorrer por si s, mas pode ocorrer como parmetro de um tipo paramtrico quando a instanciao do tipo no impe qualquer restrio sobre o parmetro. Por exemplo, o tipo da lista vazia [] Listas de Nada. Tipos funcionais. H innitos tipos da forma Funes(t1 , ..., tn ) -> tR , onde ti so tipos, representando o tipo das funes que recebem n argumentos dos tipos t1 , ..., tn e retornam um valor do tipo tR . Unies de tipos. Se s e t so tipos, ento s U t um tipo constitudo por todos os elementos de s e de t. Por exemplo, Nmeros U Strings um tipo que contm todos os nmeros e todas as strings. O emprego de unies de tipos torna possvel escrever funes que trabalham com dados de tipos diversos de maneira intuitiva. Na presena de unies de tipos, surge a questo de quais operaes so vlidas sobre um dado cujo tipo uma unio. Em linguagens com unies de tipo que empregam sistemas de tipos estticos convencionais, s so permitidas as operaes aplicveis a ambos os tipos que compem a unio. Por exemplo, se AB um tipo de estrutura com os campos a e b, BC um tipo de estrutura com os campos c e d, e x uma varivel do tipo AB U BC, ento uma expresso que extraia o campo b de x bem tipada, j que o campo b

37

funo f(x Nmeros U Strings) -> Nmeros U Strings se x Nmeros devolve x + x se x Strings devolve concatena_strings(x, x) seno erro "Tipo invlido"

Figura 4.8: Funo que recebe um nmero ou uma string e produz um dado do mesmo tipo garantidamente existe em x, mas no uma que extraia o campo a ou c, pois no possvel garantir que tal campo exista em x. Tais sistemas de tipos so seguros, pois permitem apenas as operaes cuja execuo sem erros possa ser garantida, mas impedem que certas operaes potencialmente corretas sejam tipadas. A linguagem Faz, por outro lado, permite que uma operao seja aplicada a um dado cujo tipo uma unio se ela for aplicvel a qualquer um dos tipos que compem a unio, emitindo apenas um aviso ao usurio caso a operao no seja aplicvel a ambos os tipos. Consequentemente, o sistema de tipos de Faz no oferece garantias to fortes quanto as de um sistema de tipos esttico convencional, mas confere uma maior exibilidade linguagem, permitindo que certos programas que seriam permissveis em uma linguagem dinamicamente tipada, como Racket, possam ser expressos em Faz. Por exemplo, considere a funo f denida na Figura 4.8. Essa funo recebe um nmero ou uma string e produz um dado do mesmo tipo. Em uma linguagem com um sistema de tipos esttico convencional, uma expresso do tipo f(1) + 2 seria rejeitada, pois ao tipo de retorno de f, Nmeros U Strings, no pode ser aplicada a operao de soma, j que strings no podem ser somadas. Em Faz, por outro lado, tal expresso permitida, produzindo apenas um aviso ao usurio. Para evitar a emisso do aviso, o usurio pode envolver o cdigo que opera sobre o tipo misto em um condicional: sempre que o teste de uma clusula de um condicional um teste de pertinncia da forma x tipo, o sistema de tipos considera que no bloco correspondente a essa clusula a varivel x possui o tipo especicado, uma vez que o bloco s ser executado se o teste de pertinncia for verdadeiro em tempo de execuo. Assim, a soma x + x no corpo da funo f na Figura 4.8 no produz um aviso, j que essa soma ocorre dentro de uma clusula de um condicional cujo teste garante que x um nmero. Tambm so aceitas como testes de especicao de tipo conjunes de expresses booleanas em que uma ou mais das expresses sejam testes de pertinncia. Por exemplo, em uma clusula do tipo:
se x Nmeros e y Nmeros e x > y devolve x-y

as variveis x e y possuem o tipo Nmeros. Isso se aplica tanto expresso x>y, pois a conjuno avaliada em curto-circuito e, portanto, a comparao s ser realizada se os testes de pertinncia forem verdadeiros, quanto ao bloco devolve x-y, pois este s ser avaliado se o teste como um todo for verdadeiro. Incidentalmente, esse tipo de anlise s permissvel sem restries em Faz devido ao carter puramente funcional da linguagem, que garante que os valores das variveis no sofrero alteraes aps os testes de pertinncia.

38

Tipos no paramtricos denidos pelo usurio. Cada construo da forma tipo t = componentes introduz um novo tipo no paramtrico t. Se componentes inclui uma lista de construtores entre chaves, ento cada construtor sem parmetros (i.e., item de enumerao) produzir uma constante do tipo t e cada construtor da forma nome(c1 t1 , ..., cn tn ) produzir uma funo do tipo Funes(t1 , ..., tn ) -> t. Um mesmo construtor no pode ocorrer em mais de uma declarao de tipo ou mais de uma vez em uma mesma declarao de tipo. Variveis de tipo e tipos paramtricos. Assim como diversas outras linguagens funcionais estaticamente tipadas, Faz suporta tipos paramtricos, isto , tipos parametrizados por outros tipos. Por exemplo, Listas um tipo paramtrico: para ser utilizado em um programa, necessrio fornecer um outro tipo como parmetro, atravs da palavra de, produzindo tipos como Listas de Nmeros, Listas de Strings, etc. Tipos paramtricos permitem a denio de estruturas de dados genricas, capazes de conter valores de tipos variados sem a necessidade de redenir a estrutura para cada tipo. Alm disso, Faz suporta polimorsmo paramtrico em funes. Isto , possvel denir funes cujo tipo contm variveis universalmente quanticadas. Por exemplo, uma funo como elo possui o tipo Funes (?X, Listas de ?X) -> Listas de ?X, indicando que a funo recebe um valor de um tipo qualquer e uma lista de valores do mesmo tipo e produz uma lista do mesmo tipo. Quando a funo chamada, as variveis so instanciadas com os tipos concretos dos argumentos utilizados, atravs de um algoritmo de unicao. Por exemplo, em uma chamada como elo(1, [2,3]), ?X unicado com Nmeros e Listas de ?X com Listas de Nmeros, de onde se conclui que ?X deve ser instanciado para Nmeros. O tipo do resultado da chamada, portanto, Nmeros. A presena de unies de tipos introduz uma complexidade maior no algoritmo de unicao ausente em outras linguagens funcionais. Por exemplo, enquanto em uma linguagem como Haskell uma chamada como elo(1, ["a"]) produziria um erro de tipo, em Faz a unicao de ?X com Nmeros e Listas de ?X com Listas de Strings vlida e produz a instanciao ?X = Nmeros U Strings. O tipo do resultado da chamada, portanto, Listas de (Nmeros U Strings), reetindo o fato de que a lista resultante contm tanto nmeros quanto strings. Variveis de tipo se comportam de maneira diferente no interior da funo polimrca que as introduzem e em uma chamada da funo. No interior da funo, uma expresso cujo tipo uma das variveis introduzidas pela funo pode assumir qualquer tipo concreto, dependendo dos argumentos com os quais a funo for chamada. Assim, a anlise de tipo trata essas variveis como tipos concretos sobre os quais no se tem nenhuma informao. Na chamada da funo, por outro lado, busca-se substituir as variveis de tipos pelos tipos concretos dos argumentos utilizados. Em outras palavras, as variveis introduzidas pela funo so no instanciveis no corpo da funo, mas so instanciveis quando na chamada da funo. A Figura 4.9 demonstra a denio de uma funo polimrca, compose, que recebe duas funes de um argumento, f e g, e produz sua funo composta, gf. A assinatura da funo introduz trs variveis de tipo, ?X, ?Y e ?Z. A assinatura indica que o tipo do retorno de f deve ser o mesmo do parmetro de g (?Y) e que os tipos do parmetro e de retorno da funo resultante so os mesmos do parmetro de f (?X) e do retorno de g (?Z), respectivamente. A funo compose dene localmente uma funo, composta, que recebe um argumento x do tipo ?X e produz um resultado do tipo ?Z, atravs da aplicao f(g(x)). Na denio de composta, ?X e ?Z referem-se s mesmas variveis

39

funo compose(f Funes(?X)->?Y, g Funes(?Y)->?Z) -> Funes(?X)->?Z funo composta(x ?X) -> ?Z devolve g(f(x)) devolve composta

Figura 4.9: Exemplo funo polimrca em Faz denidas na assinatura de compose: o escopo de uma varivel de tipo introduzida na assinatura de uma funo estende-se por todo o corpo da funo, incluindo denies internas. Do ponto de vista da funo composta, tais variveis so tipos concretos como quaisquer outros, uma vez que uma varivel de tipo no instancivel no corpo da funo que a introduz. A funo compose retorna a funo composta como resultado. Uma vez denida essa funo, considere a existncia das funes bool_para_num, do tipo Funes (Booleanos) -> Nmeros, e num_para_string, do tipo Funes (Nmeros) -> Strings. Em uma chamada como compose (bool_para_num, num_para_string), os tipos concretos dos argumentos sero unicados com os tipos abstratos dos parmetros de compose. O processo de unicao determinar que, para que a chamada da funo seja vlida, ?X dever ser substitudo por Booleanos, ?Y por Nmeros e ?Z por Strings. Consequentemente, a chamada produzir como resultado uma funo do tipo Funes (Booleanos) -> Strings, como esperado para a operao de composio. Tipos paramtricos denidos pelo usurio. Cada construo da forma tipo t de (p1 , ..., pn ) = componentes, onde p1 , ..., pn so variveis de tipo, introduz um novo tipo paramtrico. Se componentes inclui uma lista de construtores entre chaves, ento cada construtor sem parmetros produzir uma constante do tipo t de (Nada, ..., Nada) e cada construtor da forma nome(c1 t1 , ..., cn tn ) produzir uma funo do tipo Funes(t1 , ..., tn ) -> t de (x1 , ..., xn ), onde xi igual a pi se pi ocorre nos tipos dos campos do construtor e Nada caso contrrio. Por exemplo, uma denio como:
tipo T de (?X, ?Y) = { a(p1 ?X), b(p2 ?Y), c(p3 ?X, p4 ?Y), d }

produz os seguintes construtores e respectivos tipos:


a b c d Funes(?X) Funes(?Y) Funes(?X, T de (Nada, -> T de (?X, Nada) -> T de (Nada, ?Y) ?Y) -> T de (?X, ?Y) Nada)

Esse emprego do tipo Nada para indicar variveis de tipo no utilizadas no construtor tem base no fato de que Nada o subtipo de todos os tipos. Por exemplo, o fato de que a lista vazia [] possui o tipo Listas de Nada permite que uma lista vazia seja utilizada em contextos que esperam Listas de Nmeros, uma vez que Nada um subtipo de Nmeros. Os parmetros de um tipo s podem ser anulados dessa forma se for possvel construir valores do tipo resultante. Por exemplo, Listas de Nada um tipo vlido, pois contm o valor []. Por outro lado, se um tipo Inanulvel for denido como:

40

tipo Inanulvel de ?X = { foo(x ?X) }

ento uma expresso do tipo Inanulvel de Nada no aceita pelo vericador de tipos, pois no possvel construir valores desse tipo, uma vez que isso exigiria chamar o construtor foo com um argumento do tipo Nada e no existem valores de tal tipo. Em outras palavras, para que uma expresso seja bem tipada, ela deve possuir um tipo no vazio. Algumas outras linguagens, como Haskell, atribuem um tipo polimrco lista vazia (i.e., anlogo a Listas de ?X ao invs de Listas de Nada). Em Faz, optou-se pelo uso do tipo Nada nessas situaes por dois motivos. Em primeiro lugar, Faz, diferentemente de Haskell, possui uma relao de subtipagem em que o tipo Nada naturalmente aplicvel a essas situaes. Esse emprego do tipo Nada anlogo ao uso do tipo Nothing na linguagem Scala (LAUSANNE, 2013). Em segundo lugar, isso garante que apenas tipos funcionais contenham variveis de tipos abstratas, o que simplica o algoritmo de unicao. 4.2.2 Compatibilidade de tipos e unicao

Para que uma expresso possa ser usada como argumento de uma funo, operador ou no lado direito de uma denio de varivel ou para que um bloco possa ser usado como corpo de uma funo, necessrio que o tipo da expresso ou bloco seja compatvel com o tipo esperado pela funo, operador ou denio em que ocorre. Dois fatores devem ser levados em conta ao se denir compatibilidade entre tipos. Em primeiro lugar, a presena de unies de tipos induz uma relao de subtipagem baseada na continncia () de um tipo por outro. Por exemplo, Nmeros um subtipo de Nmeros U Strings, pois todo valor do primeiro tipo tambm um valor do segundo. Assim, uma expresso do tipo Nmeros compatvel com um contexto que espera o tipo Nmeros U Strings. Alm disso, Faz introduz a noo de compatibilidade parcial entre tipos, permitindo que uma expresso cujo tipo no um subtipo do tipo do contexto em que ocorre possa ser usada em tal contexto, desde que os tipos possuam uma interseco no vazia, emitindo um aviso ao usurio, como descrito na seo anterior. Por exemplo, uma expresso do tipo Nmeros U Strings pode ser utilizada como argumento de uma funo que espera Nmeros, produzindo um aviso, pois alguns valores de Nmeros U Strings so compatveis com Nmeros. Em segundo lugar, a compatibilidade de tipos polimrcos est sujeita escolha dos tipos para os quais as variveis de tipo sero instanciadas. Por exemplo, se f uma funo do tipo Funes (?X, ?X) -> ?X, a chamada f(5, "foo") ser bem tipada se a escolha do valor concreto de ?X for tal que o tipo de cada argumento seja um subtipo do parmetro correspondente, ou seja, se Nmeros ?X e Strings ?X. A anlise de tipos busca encontrar uma atribuio de tipos s variveis que satisfaa todas essas restries impostas pelos tipos dos argumentos utilizados. No exemplo citado, uma atribuio que satisfaz todas as restries ?X = Nmeros U Strings. Se a anlise produzir um conjunto de restries que no podem ser todas satisfeitas simultaneamente, ocorre um erro de tipo. Em resumo, a vericao de compatibilidade verica se o tipo de uma construo compatvel, parcialmente compatvel ou incompatvel com o tipo do contexto em que ocorre. Na presena de variveis de tipo, determina-se ainda quais so as restries sobre as possveis instanciaes concretas das variveis. Por m, substituem-se as variveis por tipos concretos que satisfaam as restries, se houverem. Seguem as regras utilizadas na vericao.

41

Universo e vazio. Todos os tipos so compatveis com Tudo. O tipo Nada compatvel com todos os tipos. Variveis instanciveis. Uma varivel instancivel ?X compatvel com qualquer tipo t, produzindo a restrio ?X t. Qualquer tipo t compatvel com ?X, produzindo a restrio t ?X. Dois tipos contendo variveis quanticadas so considerados incompatveis entre si, i.e., apenas um dos lados de uma relao de compatibilidade pode ser polimrco. Tipos primitivos. Tipos primitivos (Nmeros, Strings, Caracteres, Booleanos) s so compatveis entre si se forem iguais. Unies de tipos. Um tipo S compatvel com X U Y se S for compatvel com X ou com Y. Por exemplo, Nmeros compatvel com Nmeros U Strings. No caso de os graus de compatibilidade de S com X e com Y serem diferentes, opta-se pela opo mais compatvel. Se a vericao produzir restries sobre as variveis de tipo, opta-se pelo conjunto de restries da opo mais compatvel. X U Y compatvel com S se tanto X quando Y forem compatveis com S. Nesse caso, como ambas as alternativas devem ser compatveis, as restries produzidas por cada alternativa devem ser combinadas. O grau de compatibilidade o menos compatvel das duas alternativas. A unio das restries se d da seguinte maneira. Para toda varivel ?X, substituem-se todas as restries da forma3 Si ?X Ti por uma nica restrio S ?X T, onde S a unio de todos os Si e T a interseco de todos os Ti. Isto , na restrio resultante, busca-se reduzir a faixa de valores que a varivel pode assumir, escolhendo-se limites inferiores e superiores mais estreitos do que os das restries originais, de modo que todas as restries sejam satisfeitas. Variveis no instanciveis. Uma varivel no instancivel (i.e., uma varivel denida na assinatura de uma funo, quando usada no interior da funo) compatvel consigo mesma. Para os ns das demais regras aqui citadas, uma varivel no instancivel se comporta como um tipo simples qualquer. Por exemplo, se ?N uma varivel no instancivel e ?X uma varivel instancivel, ento ?N compatvel com ?X, produzindo a restrio ?N ?X sobre a varivel ?X. Tipos funcionais. Dois tipos funcionais so compatveis se possuem o mesmo nmero de parmetros, o tipo de retorno do primeiro for compatvel com o do segundo e os tipos dos parmetros do segundo forem compatveis com os do primeiro. Isto , a relao de subtipagem entre funes covariante com relao ao resultado e contravariante com relao aos parmetros. As restries produzidas pelas sub-relaes so combinadas e o grau de compatibilidade o menos compatvel produzido por qualquer uma das sub-relaes. Tipos denidos pelo usurio. Um tipo denido pelo usurio substitudo pelo lado direito de sua denio. Por exemplo, dada a denio:
tipo T1 = Nmeros U Strings tipo T2 = Strings U Caracteres

vericar a compatibilidade entre T1 e T2 equivalente a vericar a compatibilidade entre Nmeros U Strings e Strings U Caracteres. Alm de outros tipos e unies, o lado direito de uma denio de tipo pode conter listas de construtores. Duas listas de
Uma restrio da forma T ?X pode ser vista como uma abreviao de T ?X Tudo. Analogamente, ?X T pode ser vista como uma abreviao de Nada ?X T. Assim, todas as restries tm um formato uniforme.
3

42

construtores produzidas por tipos S de (S1, ... Sn) e T de (T1, ... Tn) so compatveis se S = T e cada Si for compatvel com o Ti correspondente. Por exemplo, dada a denio:
tipo Pares de (?X, ?Y) = { par(p1 ?X, p2 ?Y) }

o tipo Pares de (Nmeros, Booleanos) compatvel com Pares de (Nmeros U Strings, Caracteres U Booleanos), pois o nome do tipo o mesmo (Pares) e os parmetros de tipo correspondentes so compatveis. Assim como na chamada de funo, quaisquer restries produzidas so combinadas e o grau de compatibilidade o menos compatvel de qualquer uma das alternativas. Concretizao das restries. Como visto, a vericao de compatibilidade entre uma funo polimrca e seus argumentos em uma chamada produz um conjunto de restries. Essas restries so utilizadas para atribuir valores concretos s variveis quanticadas do tipo da funo. A atribuio ocorre da seguinte maneira. Para cada restrio da forma S ?X T: Se S = T, ento ?X = S. Isto , se os limites superior e inferior da varivel forem iguais, s h uma atribuio possvel, que utilizada. Se T = Tudo, ento ?X = S. Isto , se a restrio no impe qualquer limite superior, o limite inferior utilizado. Sse S = Nada, ento ?X = T. Isto , se a restrio no impe qualquer limite inferior, o limite superior utilizado. Caso contrrio, a atribuio considerada falha e um erro de compilao produzido. A ltima clusula acima implica que restries que aceitam mais de uma soluo (e.g.,
Nmeros ?X Nmeros U Strings, em que tanto ?X = Nmeros quanto ?X = Nmeros U Strings so solues vlidas) ou no aceitam qualquer soluo (e.g., Nmeros U Strings ?X Nmeros) so rejeitadas pela anlise semntica. Outra

implicao das clusulas que, na ausncia de restries sobre uma varivel, ela adquire o tipo Nada. Limitaes. A integrao de unies de tipos e polimorsmo paramtrico introduz diculdades ausentes nos sistemas de tipos de linguagens funcionais estaticamente tipadas convencionais, como Haskell. Para os ns do presente trabalho, foram adotadas algumas restries no uso de tipos paramtricos de maneira a evitar essas diculdades. Como visto, dois tipos polimrcos so considerados incompatveis entre si. No possvel passar uma funo polimrca como argumento para outra funo polimrca, por exemplo. Alm disso, faz-se a exigncia de que as restries impliquem uma atribuio nica para cada varivel. Finalmente, faz-se a exigncia de que unies contendo variveis de tipos devem ser disjuntas para quaisquer valores atribudos s variveis de tipo, evitando assim restries com mltiplas solues. Por exemplo, um tipo como (Listas de Nmeros) U (Listas de ?X) no vlido, pois a unio no disjunta quando ?X = Nmeros; em um tipo como (Listas de Nmeros) U (Listas de ?X), tanto ?X = Nada quanto ?X = Nmeros produziriam o mesmo tipo.

43

4.3

Semntica e tipos das construes da linguagem

A semntica das construes de Faz dada por sua traduo para construes equivalentes em Racket. A traduo de cada construo descrita nesta seo. A notao T[x] = y ser utilizada para indicar que a traduo de uma construo x em Faz a construo y em Racket. Tambm sero descritas as regras de tipo de cada construo. A expresso "tipo esperado"ser utilizada para indicar que o tipo de uma construo deve ser compatvel ou parcialmente compatvel com o tipo especicado. Expresses aritmticas. A avaliao dos operadores aritmticos (+, -, *, /, ^) se d da esquerda para a direita, respeitando as precedncias convencionais da notao algbrica. O tipo esperado dos operandos Nmeros, e o tipo do resultado Nmeros. A traduo das expresses aritmticas para Racket trivial:
T[e1+e2] T[e1-e2] T[e1*e2] T[e1/e2] T[e1^e2] T[+e1] T[-e1] = = = = = = = (+ T[e1] T[e2]) (- T[e1] T[e2]) (* T[e1] T[e2]) (/ T[e1] T[e2]) (expt T[e1] T[e2]) (+ T[e1]) (- T[e1])

Operaes relacionais e lgicas. Como visto, os operadores relacionais de Faz so aplicveis a quaisquer tipos de dados. O operador == possui um operador equivalente em Racket, equal?, que opera sobre quaisquer tipos. O operador != traduzido para a negao de uma expresso com equal?. Os demais operadores so traduzidos para uma funo polimrca especial do runtime de Faz4 Para que a operao seja permitida, os operandos devem possuir o mesmo tipo ou tipos distintos cuja interseco seja no vazia; nesse ltimo caso, um aviso emitido ao usurio. O resultado dessas operaes sempre do tipo Booleanos.
T[e1==e2] T[e1!=e2] T[e1<e2] T[e1<=e2] T[e1>=e2] T[e1>e2] = = = = = = (equal? T[e1] T[e2]) (not (equal? T[e1] T[e2])) (faz-cmp (faz-cmp (faz-cmp (faz-cmp < <= >= > char<? char<=? char>=? char>? string<? string<=? string>=? string>? T[e1] T[e1] T[e1] T[e1] T[e2]) T[e2]) T[e2]) T[e2])

Onde faz-cmp denida como:


(define (faz-cmp number-op char-op string-op e1 e2) (cond [(and (number? e1) (number? e2)) (num-op e1 e2)] [(and (char? e1) (char? e2)) (char-op e1 e2)] [(and (string? e1) (string? e2)) (string-op e1 e2)] [else (error "Valores no podem ser comparados")]))

Expresses lgicas so avaliadas da esquerda para a direita em curto-circuito. Sua traduo para Racket trivial. O tipo esperado dos operandos e o tipo do resultado da expresso so Booleanos.
Em uma linguagem sem unies de tipos, seria possvel analisar os tipos dos operandos e emitir a funo de comparao adequada em Racket na traduo. A presena de unies faz com que nem sempre os tipos concretos sejam conhecidos em tempo de compilao, impedindo essa abordagem.
4

44

T[e1 e e2] T[e1 ou e2]

= =

(and T[e1] T[e2]) (or T[e1] T[e2])

Blocos. Blocos so traduzidos para uma construo local de Racket.


T[<definio1> ... <definion> <comando final>] (local (T[<definio1>] ... T[<definion>]) T[<comando final>])

A traduo de cada um dos componentes do bloco ser vista adiante. A avaliao se d seguinte maneira. criado um novo ambiente de denies contendo cada um dos identicadores denidos pelos comandos de denio do bloco, inicialmente sem valor. Em seguida, cada um dos comandos de denio avaliado em sequncia e o valor atribudo pela denio (lado direito da igualdade no comando seja ou o corpo da funo no comando funo passa a valer para aquela denio. A expresso que computa o valor de uma varivel no pode se referir a variveis que ainda no estejam denidas no momento da avaliao (i.e., cuja denio ocorre depois no bloco). O corpo de uma funo, por outro lado, pode se referir a funes denidas posteriormente, permitindo assim a denio de funes mutuamente recursivas. Finalmente, o comando nal do bloco avaliado no escopo do ambiente de denies criado pelo bloco. O tipo do bloco o tipo do comando nal. Variveis. A traduo do comando seja trivial:
T[seja x = e1] T[seja x tipo = e1] = = (define T[x] T[e1]) (define T[x] T[e1])

A declarao de tipo, se houver, descartada na traduo, uma vez que Racket dinamicamente tipada. A avaliao consiste em avaliar o valor do lado direito da igualdade e atribu-lo varivel correspondente no ambiente de identicadores local. Se a denio inclui o tipo da varivel, o tipo esperado para e1 o tipo especicado; caso contrrio, o tipo de e1 tomado como o tipo da varivel. A ocorrncia de um identicador em uma expresso em Faz traduzida para um identicador equivalente em Racket, modicado para evitar conitos com identicadores pr-denidos de Racket e do runtime de Faz. O tipo do identicador obtido do ambiente de denies.
T[id] = id

Funes. A traduo de uma denio de funo trivial. Assim como nas denies de variveis, a informao de tipos perdida na traduo.
T[funo f(x1t1, ..., xntn) -> tR = (define (T[f] T[x1] ... T[xn]) <bloco>] T[<bloco>])

O tipo esperado para o bloco tR . Dentro do bloco, os identicadores x1, ..., xn esto denidos com os tipos especicados. A traduo de uma chamada de funo tambm trivial. Para avaliar a expresso, a funo e os argumentos so avaliados da esquerda para a direita. Em seguida, o bloco que compe o corpo da funo avaliado dentro de um ambiente de denies em que

45

cada um dos parmetros associado ao valor avaliado para os argumentos. Esse ambiente subordinado ao ambiente em que a denio foi avaliada, i.e., a linguagem usa escopo esttico ou lxico. O resultado da avaliao do bloco o resultado da aplicao da funo. Os tipos esperados para os argumentos so os tipos dos parmetros tais como especicados na denio da funo. O tipo da aplicao o tipo de retorno da funo.
T[f(e1, ..., en)] = (T[f] T[e1] ... T[en])

Condicionais. O comando condicional traduzido para um cond de Racket.


T[se e1 bloco1 ... seno blocon] = (cond [T[e1] T[bloco1]] ... [else T[blocon]])

Cada um dos testes avaliado em sequncia. O bloco correspondente ao primeiro teste que retornar verdadeiro avaliado e o valor produzido pelo bloco o valor do comando condicional. Os tipos esperados para as expresses de teste Booleanos. O tipo do condicional a unio dos tipos de cada um dos blocos. Expresses de bloco. A traduo e a avaliao so idnticas s de um bloco comum; como visto, a presena de comandos de bloco serve apenas para contornar a distino entre expresses e comandos em Faz. O tipo da expresso o tipo do bloco. Retorno e sinalizao de erros. A traduo do comando devolve e1 idntica traduo de e1. Como visto, o comando devolve o dual das expresses de bloco e serve apenas como ponte entre o mundo das expresses e dos comandos.
T[devolve e1] = T[e1]

Comandos de sinalizao de erro so traduzidos como:


T[erro e1] = (error nome T[e1])

Onde nome o nome da funo em que o comando ocorre. A avaliao consiste em avaliar e1 e gerar um erro de execuo contendo a mensagem produzida por e1 e o nome da funo em que o comando ocorre. O tipo esperado para e1 Strings. O tipo do comando Nada, o subtipo de todos os tipos; uma vez que o valor do comando nunca ser usado, pois o comando termina a execuo do programa, o comando pode ocorrer no contexto de qualquer tipo. O comando erro um caso especial em que um tipo vazio aceito pela linguagem. O comando teste. Assim como o comando devolve, a traduo do comando teste e1 idntica de e1.5 O tipo de e1 irrestrito, desde que a expresso seja bem tipada. Denies de tipos. O comando tipo cria novos tipos e construtores tal como descrito na seo anterior. Denies de construtores sem argumentos (i.e., itens de enumerao) so traduzidas para variveis cujo nome o nome do construtor, devidamente transformado para evitar conito com identicadores internos, e cujo valor o nome do construtor representado como um smbolo. Denies de construtores com argumentos (i.e., estruturas) so traduzidos para funes que recebem um argumento para cada campo do construtor e produzem um vetor cujo primeiro elemento o nome do construtor como um smbolo e os elementos restantes so, alternadamente, o nome de um campo e seu valor.
Uma implementao alternativa seria traduzir o comando teste e1 para cdigo que imprimisse a expresso e1 e seu valor, permitindo identicar na sada do programa que valor corresponde a que expresso.
5

46

T[tipo ... = { ..., x, ... }] = (define T[x] x) T[tipo ... = { ..., s(c1t1, ..., cntn), ... }] = (define (T[s] T[c1] ... T[cn]) (vector s c1 T[c1] ... cn T[cn]))

Seletores campos de estruturas. Expresses da forma campo de x so traduzidas para uma chamada a uma funo select do runtime de Faz:
T[c de x] = (select T[x] c)

A funo select recebe o nome de um campo e uma estrutura, representada como um vetor, e retorna o valor do campo correspondente, se houver. Por questes de compatibilidade com Racket, listas de Faz no so representadas como vetores, e sim como listas de Racket. Assim, listas so tratadas separadamente pela funo select. Uma vez que possvel dar o mesmo nome a campos de tipos estruturados distintos e possvel criar unies desses tipos, o tipo de uma expresso como campo de x depende dos tipos que x pode assumir. Especicamente, o tipo de campo de x a unio dos tipos de quaisquer campos campo denidos pelos construtores do tipo de x ou qualquer um de seus subtipos. Por exemplo, dadas as denies:
tipo Livros = { livro(cdigo Nmeros) } tipo Carros = { carro(cdigo Strings) } tipo Ambos = Livros U Carros seja a Livros = livro(42) seja b Carros = carro("ABC-1234") seja c Ambos = (se random(0,1)==0 devolve a seno devolve b)

o tipo de cdigo de a Nmeros, o tipo de cdigo de b Strings e o tipo de cdigo de c Nmeros U Strings. Testes de pertinncia. Alm dos construtores, a denio de um tipo t produz uma funo -t. Ao ser invocada, essa funo produz um predicado (i.e., outra funo) que recebe um argumento e testa se ele pertence ao tipo t. Se t um tipo paramtrico, ento -t recebe um argumento para cada parmetro do tipo. Cada argumento deve ser um teste de pertinncia. O predicado produzido pela chamada testa se seu argumento um smbolo correspondente a um construtor sem argumentos de t, um vetor correspondente a um construtor estruturado de t, ou um subtipo de t, atravs de chamadas a outros predicados. No caso dos construtores estruturados de tipos paramtricos, o predicado ainda testa se os campos com tipos paramtricos possuem os tipos especicados pelos argumentos da funo -t. Por exemplo, a denio do tipo rvores de ?X da Figura 4.5 produz a funo:
(define (-rvores ?X) (lambda (x) (or (eq? x vazia) (and (vector? x) (eq? (vector-ref x 0) n) (?X (select x valor)) ((-rvores ?X) (select x esquerda)) ((-rvores ?X) (select x direita))))))

47

Alm dos geradores de predicados gerados para tipos denidos pelo usurio, o runtime da linguagem contm geradores de predicados para os tipos nativos da linguagem. Testes de pertinncia da forma x t so traduzidas para chamadas de -t. Devido a limitaes da implementao, o tipo t no pode ser funcional e no pode conter variveis de tipo. O tipo esperado de x Tudo, i.e., qualquer expresso bem tipada aceita. O tipo do resultado da expresso Booleanos.
T[x t] = (Tpred[t] T[x])

onde:
Tpred[t] = (-t) Tpred[t de (t1, ..., tn)] = (-t Tpred[t1] ... Tpred[tn])

Listas. vazio uma varivel pr-denida no runtime da linguagem cujo valor empty, a lista vazia em Racket. elo, o construtor de listas de Faz, equivalente funo cons de Racket. Listas da forma [e1, ..., en] so traduzidas para uma chamada funo list de Racket. Os tipos de vazio e elo so como esperado dada a denio do tipo Listas na Seo 4.1.16, i.e., vazio tem o tipo Listas de Nada e elo tem o tipo Funes (?X, Listas de ?X) -> Listas de ?X. O tipo da construo [e1, ..., en] o mesmo da construo equivalente empregando os construtores elo e vazio.
T[[e1, ..., en]] = (list T[e1] ... T[en])

Funes annimas. Funes annimas so traduzidas para formas lambda em Racket. A tipagem de funes annimas anloga de funes declaradas.
T[(funo f(x1t1, ..., xntn) -> t <bloco>] = (lambda (T[x1] ... T[xn]) T[<bloco>])

4.4

Limitaes

Tanto IS quanto Faz no possuem mecanismos prprios para a execuo de operaes com efeitos colaterais. Isso diculta o tratamento de operaes de entrada e sada. IS no conta com nenhuma funo convencional de entrada e sada, uma vez que a linguagem foi concebida visando interao por meio da avaliao de expresses no ambiente DrRacket. Faz herda de IS essa limitao. IS d acesso a uma biblioteca grca, cujas funes possuem o efeito colateral de desenhar formas geomtricas na tela. Cada uma dessas funes retorna um booleano indicando sucesso ou falha da operao, o que permite o uso do operador lgico and para descrever sequncias de operaes. Faz permite a mesma abordagem. Tanto IS quanto Faz permitem a sinalizao de erros, mas no permitem seu tratamento, encerrando a execuo do programa no caso de um erro. No contexto de uma disciplina introdutria, essa limitao no signicativa. Quanto ao sistema de tipos, h algumas limitaes no uso de tipos polimrcos de maneira a evitar problemas com sua interao com unies de tipos, tal como descrito na Seo 4.2.2, bem como nos tipos que podem ser empregados em testes de pertinncia, como descrito na Seo 4.3.

48

IMPLEMENTAO

A linguagem Faz foi implementada como parte do ambiente DrRacket. Implementaes de novas linguagens para o ambiente DrRacket podem ser escritas na linguagem Racket completa, que conta com uma diversidade de bibliotecas, tais como geradores de analisadores lxicos e sintticos no estilo Lex (LESK; SCHMIDT, 1975) e Yacc (JOHNSON, 1975). Usualmente, novas linguagens so implementadas no ambiente DrRacket por meio da traduo do cdigo-fonte na nova linguagem para cdigo em Racket, que ento compilado e executado utilizando a mesma infraestrutura usada pela linguagem Racket. Este captulo descreve, em linhas gerais, o ambiente DrRacket e a implementao da linguagem Faz no mesmo.

5.1

O ambiente DrRacket

DrRacket (anteriormente DrScheme) um ambiente de desenvolvimento integrado que permite a edio, compilao e execuo de programas em uma variedade de linguagens. A linguagem principal do ambiente o Racket, mas tambm so suportadas outras linguagens baseadas em Scheme, tais como como as linguagens didticas HtDP e o padro R5RS, bem como uma verso de Algol 60 e algumas linguagens experimentais. O ambiente foi escrito de maneira a permitir a incorporao de novas linguagens de maneira modular. A janela principal do ambiente dividida em duas reas. A rea superior, denominada Denitions, usada para a edio de cdigo, onde podem ser escritas denies de variveis, funes e tipos de dados, bem como expresses a serem avaliadas quando o programa for executado. Uma vez escrito o programa, o usurio pode acionar o boto Run na barra de ferramentas da janela, fazendo com que o programa seja compilado e, se a compilao for bem sucedida, executado. A rea inferior da janela, denominada Interactions, exibe os resultados produzidos pelas expresses avaliadas na execuo do programa e fornece um prompt onde o usurio pode entrar com novas expresses e observar seus resultados. Isso permite ao usurio testar as funes denidas na janela Denitions com os argumentos que desejar e observar se os resultados correspondem ao esperado, sem a necessidade de alterar e recompilar o cdigo para cada teste. No necessrio escrever um programa completo com um ponto de partida tal como a funo main em C. Isso permite ao usurio testar suas funes medida em que as escreve, facilitando sua depurao. As Figuras 5.1 e 5.2 apresentam screenshots de interao com o ambiente DrRacket utilizando as linguagens IS e Faz, respectivamente.. A rea Denitions contm a denio de uma funo que computa o fatorial de um nmero natural. A rea Interactions apresenta a expresso digitada pelo usurio (fac(5)), seguida do resultado de sua avalia-

49

Figura 5.1: Janela principal do ambiente DrRacket executando a linguagem IS

o (120). No caso da linguagem Faz, tambm exibido o tipo da expresso (Nmeros).

5.2

A implementao de Faz

A implementao de Faz constituda por um conjunto de arquivos na linguagem Racket que implementam os diversos passos da compilao de cdigo, bem como a integrao da linguagem com o ambiente DrRacket. Esta seo descreve os principais componentes da implementao. 5.2.1 Anlise lxica e sinttica

O primeiro passo da compilao consiste da separao do texto que compe o cdigofonte em tokens, seguida da gerao de uma rvore de sintaxe abstrata. Para isso, so utilizadas as bibliotecas parser-tools/lex e parser-tools/yacc da linguagem Racket, que provem funcionalidade equiparvel s ferramentas Lex (LESK; SCHMIDT, 1975) e Yacc (JOHNSON, 1975). A rvore sinttica anotada com informao suciente para determinar o trecho do cdigo a que corresponde cada n, de maneira a permitir a noticao de erros para o usurio. A anlise lxica e sinttica est implementada no arquivo parse.rkt, que dene as estruturas de dados que representam a rvore sinttica e as regras da anlise lxica e da gramtica da linguagem. O arquivo tambm dene a funo parse-faz-from-port, principal ponto de entrada do mdulo, que produz a rvore sinttica de um programa lido de uma stream, ou porta na terminologia de Racket, representando um arquivo ou o contedo da janela Denitions ou Interactions.

50

Figura 5.2: Janela principal do ambiente DrRacket executando a linguagem Faz 5.2.2 Anlise semntica

Uma vez gerada a rvore sinttica, realizada a anlise semntica do cdigo. O nvel mais alto do cdigo de um programa composto por declaraes de variveis, funes e tipos e por comandos de avaliao de expresses. Em um primeiro passo, so processadas as declaraes de tipos. vericada a consistncia das declaraes, isto , a ausncia de declaraes duplicadas de tipos e construtores. Registram-se os novos tipos de dados denidos pelo usurio em uma lista de tipos conhecidos, bem como os nomes e os tipos dos campos de tipos estruturados, e o ambiente de denies de identicadores acrescido dos construtores de tipos. A seguir, processa-se o corpo do programa, que tratado como o bloco de nvel mais externo. Para cada bloco do programa, so coletadas as declaraes de variveis e funes. Para declaraes de variveis, o valor atribudo varivel sofre uma anlise de tipos. Se bem tipado, verica-se a compatibilidade entre o tipo declarado para a varivel e o tipo computado para o seu valor. Se a declarao no inclui explicitamente o tipo da varivel, o tipo do valor tomado como tipo da varivel. Para declaraes de funes, o bloco que compe o corpo analisado recursivamente e, se bem tipado, vericada a compatibilidade entre o tipo do corpo e o tipo de retorno da funo. Uma vez que a linguagem possui tipos de unio, a vericao de compatibilidade de tipos considera as relaes de subtipagem entre os tipos. A anlise de tipos se d primariamente por meio de duas funes: typecheck, que computa o tipo de um n da rvore sinttica, e compatible, que determina se o tipo computado para um n compatvel com o tipo esperado. Por exemplo, na anlise de uma expresso do tipo x+y, os tipos de x e y so computados e, em seguida, verica-se sua compatibilidade como o tipo esperado para os argumentos do operador +, isto , Nmeros. A funo compatible produz uma tupla (grau, restries), onde grau o grau de compatibilidade entre os dois tipos e restries o conjunto de restries sobre as variveis de tipos para

51

que haja a compatibilidade, tal como descrito na Seo 4.2.2. Outras funes importantes envolvidas na anlise semntica so solve-constraints, que realiza a combinao de restries sobre variveis, e apply-solution, que substitui as variveis de tipo por tipos concretos baseados em uma soluo. A anlise semntica est implementada no arquivo typecheck.rkt. 5.2.3 Traduo

Se a anlise semntica for bem sucedida, o prximo passo a ser realizado a traduo da rvore sinttica para cdigo Racket. Assim como nas demais linguagens da famlia LISP, o cdigo de um programa em Racket uma estrutura de dados baseada em listas aninhadas e outros elementos sintticos, tais como smbolos, usados para representar os identicadores da linguagem, bem como nmeros, strings e outras constantes que aparecem no cdigo. Em Racket, esses elementos sintticos so acrescidos de anotaes que permitem indicar a linha, coluna e arquivo onde o elemento foi encontrado, de maneira a possibilitar mensagens de erro mais signicativas, e o contexto em que o elemento deve ser avaliado, de maneira a evitar conitos entre identicadores de mesmo nome que ocorram em partes diversas do programa. Esse objeto contendo elementos sintticas e contexto denominado objeto sinttico. A etapa de traduo consiste em gerar estruturas sintticas de Racket a partir da rvore sinttica de Faz e das informaes de tipos coletadas durante a anlise semntica. A etapa de traduo est implementada no arquivo translate.rkt, cujo ponto de entrada a funo ast->scheme, que recebe um n da rvore sinttica abstrata de Faz e produz um objeto sinttico correspondente traduo do n para Racket. A traduo tal como descrito na Seo 4.3. 5.2.4 Ambiente padro

A linguagem conta com um ambiente padro de funes, constantes e tipos predenidos. O tipo Booleanos e seus construtores verdadeiro e falso, bem como o tipo Listas e seus construtores vazio e elo, so denidos diretamente como um trecho de cdigo em Faz que automaticamente includo no comeo de cada programa antes da compilao. Essas denies so utilizadas apenas para a anlise semntica, uma vez que, para manter compatibilidade com Racket, esses tipos so tratados especialmente pela etapa de traduo, traduzindo-os para os valores equivalentes de Racket. Outros elementos do ambiente padro incluem funes matemticas tais como resto, sen e cos e funes para manipulao dos tipos de dados primitivos, tais como concatena_listas e concatena_strings, bem como funes utilizadas internamente pelo runtime da linguagem, como a funo select, utilizada para selecionar campos de estruturas. O ambiente padro denido no arquivo stdenv.rkt. 5.2.5 Execuo interativa

Como visto, o ambiente DrRacket permite a entrada de expresses para avaliao na rea Interactions. O cdigo digitado nessa rea passa pelos mesmos passos de anlise lxica, sinttica e semntica, traduo para cdigo Racket e subsequente compilao. Diferentemente da anlise sinttica de um programa completo, a anlise de cdigo interativo utiliza um smbolo inicial alternativo, que permite que expresses apaream diretamente no cdigo sem a necessidade de serem introduzidas por uma palavra-chave como devolve ou teste, mas no permite a entrada de denies de variveis, funes

52

e tipos, que devem ser denidos exclusivamente na rea Denitions. Os outros passos de compilao so idnticos aos da compilao de um programa completo. 5.2.6 Integrao com DrRacket

Para adicionar suporte a uma nova linguagem no ambiente DrRacket, necessrio criar uma collection, i.e., uma coleo de mdulos Racket. A coleo deve estar organizada de maneira a implementar uma ferramenta do DrRacket, conforme descrito na documentao do ambiente (PLT DESIGN, 2013). Para tal, a coleo deve conter um arquivo info.rkt, que descreve o nome e outros metadados da ferramenta e os arquivos que a implementam. Convencionalmente, uma ferramenta implementada em um arquivo tool.rkt, que importa os outros arquivos da implementao, se houver. A ferramenta deve denir uma unit tool@, que contm funes a serem executadas para carregar a ferramenta. No caso de uma linguagem, a unit deve denir uma classe que implementa a drracket:language:language<%>. Essa interface contm uma diversidade de mtodos que so invocados pelo DrRacket na edio, compilao e execuo de cdigo na linguagem, bem como na congurao de parmetros da linguagem. Desses mtodos, os mais importantes so front-end/complete-program e front-end/interaction, invocados na compilao do cdigo na rea Denitions e Interactions, respectivamente. Esses mtodos recebem, como um de seus argumentos, uma stream de onde o cdigo a ser compilado pode ser lido e devem retornar um thunk, i.e., uma funo sem argumentos, que invocada sucessivamente pelo DrRacket. Cada invocao do thunk deve retornar um objeto sinttico representando o cdigo em Racket que ser compilado e avaliado pelo DrRacket e ter seu resultado apresentado ao usurio. No caso da linguagem Faz, tanto front-end/complete-program quanto frontend/interaction invocam a funo compile-faz-from-port, que recebe uma stream, realiza todos os passos de compilao j citados, armazena o resultado do passo de traduo em uma varivel e retorna um thunk que, cada vez que invocado, retorna o trecho de cdigo Racket traduzido correspondente a um comando do programa em Faz. Depois que todos trechos foram retornados, o thunk retorna eof, que sinaliza o m do programa. 5.2.7 Limitaes

A implementao atual da linguagem Faz apresenta algumas limitaes. O analisador lxico gerado pela biblioteca parser-tools/yacc relativamente limitado quanto a tratamento de erros, permitindo identicar a linha e a coluna do cdigo em que ocorreu um erro sinttico, mas no fornecendo contexto suciente para informar ao usurio a natureza exata do erro, o que diculta a depurao de erros de sintaxe. Esse problema pode ser resolvido reescrevendo-se o analisador sinttico manualmente, em vez de usar um analisador gerado mecanicamente. Outra possibilidade seria procurar uma biblioteca ou programa alternativo para a gerao do analisador. Neste trabalho, por simplicidade, optou-se por usar o gerador que acompanha a linguagem Racket. A implementao atual exige que os tipos utilizados em testes de pertinncia no contenham variveis de tipos ou tipos funcionais. No caso de tipos funcionais em particular, a traduo de Faz para Racket no preserva informao de tipo suciente para que um teste de pertinncia em tempo de execuo possa vericar os tipos dos argumentos e de retorno de um valor funcional; na prtica, entretanto, tais testes sobre funes so incomuns, especialmente no contexto de uma disciplina introdutria.

53

EXPERIMENTO DE VALIDAO

O presente trabalho foi desenvolvido com base na observao da recorrncia de certas diculdades entre os alunos no ensino da disciplina de Fundamentos de Algoritmos utilizando as linguagens didticas HtDP, conforme exposto nos Captulos 1 e 3. Como forma de validao, realizou-se uma enquete entre os alunos de Cincia da Computao da UFRGS de maneira a vericar se essas observaes reetem as experincias do alunos. A enquete foi realizada por meio de um formulrio online divulgado atravs da lista de discusso da graduao do Instituto de Informtica da UFRGS. Foram realizadas seis perguntas, divididas em trs categorias: Identicao. Em que semestre voc fez a disciplina de Fundamentos de Algoritmos? Com que outras linguagens de programao voc tem experincia (se houver)? Opinio. Quais foram as maiores diculdades que voc encontrou com a linguagem Scheme/Racket na disciplina? [Responda em ordem de diculdade (mais difcil primeiro). recomendado mas no obrigatrio preencher todos os trs campos.] Quais foram as maiores facilidades / pontos positivos que voc encontrou com a linguagem Scheme/Racket na disciplina? [Responda em ordem de positividade (mais positivo primeiro). recomendado mas no obrigatrio preencher todos os trs campos.] Comparao de linguagens. Foram apresentados dois programas, cada um escrito nas linguagens Racket (especicamente, IS) e Faz: um programa para o clculo das razes reais de uma equao do segundo grau a partir de seus coecientes (Figuras 3.4 e 4.7), escolhido por ser um programa simples empregando uma frmula conhecida; e um programa maior para encontrar um caminho entre dois ns em um grafo acclico (Figuras 6.1 e 6.2), escolhido por ser um programa visto na disciplina de Fundamentos de Algoritmos e por empregar diversas construes das linguagens, tais como condicionais, estruturas, listas e denies locais. Para cada programa, fez-se a pergunta: Em qual linguagem o programa mais fcil de compreender e seria mais fcil de escrever?, com as opes Scheme/Racket1 , A nova linguagem e Tanto faz.
O nome Scheme/Racket foi utilizado por serem os nomes convencionalmente usados ao se referir s linguagens didticas HtDP na disciplina e devido ao fato de a linguagem s ter passado a se chamar Racket em 2010.
1

54

Tabela 6.1: Preferncia dos alunos pelas linguagens Faz e Racket em diferentes programas Faz Racket Tanto faz Razes reais 55 (92%) 2 (3%) 3 (5%) Caminho em grafo 49 (82%) 7 (12%) 4 (7%) Alm das perguntas, deixou-se na enquete um espao para comentrios e observaes. Os dados brutos coletados esto disponveis online2 . 60 alunos responderam enquete. Para ambos os programas, a maioria dos alunos preferiu a sintaxe de Faz (Tabela 6.1). As principais diculdades reportadas pelos alunos com a linguagem IS podem ser classicadas em quatro grupos: Sintaxe, por 36 alunos (60%). Alm da sintaxe no geral, foram mencionados alguns problemas especcos, tais como diculdades com o uso excessivo de parnteses, notao prexada e denies locais. Paradigma funcional, por 32 alunos (53%). Problemas especcos mencionados incluem o uso de recurso e a ausncia de variveis mutveis. Tipos de dados, por 8 alunos (13%). Problemas especcos mencionados incluem a denio dos contratos como comentrios e a ausncia de um sistema de tipos esttico. Ambiente de desenvolvimento, por 3 alunos (5%). O nico problema especco mencionado foi a diculdade de encontrar os erros no cdigo. Como discutido na seo 3.2.1, a ausncia de tipagem esttica em parte responsvel por essa diculdade. As principais facilidades ou pontos positivos de IS citados pelos alunos podem ser classicados em: Facilidade para escrever algoritmos recursivos, por 20 alunos (33%). Facilidade para trabalhar com estruturas de dados, por 13 alunos (22%). Um aluno mencionou a facilidade do uso de estruturas em comparao linguagem C. Sintaxe, por 7 alunos (12%). Contato com o paradigma funcional, por 5 alunos (8%). Simplicidade, por 5 alunos (8%). Expressividade, isto , a habilidade de descrever algoritmos com pouco cdigo, por 4 alunos (7%). Cabe notar que esta pesquisa no tem o intuito de provar uma hiptese de maneira estatisticamente signicativa, mas sim apenas de dar uma ideia geral da experincia dos alunos com as linguagens HtDP e a disciplina de Fundamentos de Algoritmos e avaliar a aceitao da nova linguagem desenvolvida neste trabalho pelos mesmos.
2

http://inf.ufrgs.br/~vbuaraujo/tcc/

55

;; Um n uma estrutura ;; (make-n nome vizinhos) ;; onde nome um smbolo, ;; vizinhos uma lista-de-smbolos. (define-struct n (nome vizinhos)) ;; Um grafo uma lista-de-ns. ;; Um caminho : ;; 1. false (caminho invlido); ou ;; 2. uma lista-de-smbolos. ;; vizinhos: smbolo grafo -> lista-de-smbolos ;; Retorna uma lista dos vizinhos de um n. (define (vizinhos nome grafo) (cond [(empty? grafo) empty] [(symbol=? nome (n-nome (first grafo))) (n-vizinhos (first grafo))] [else (vizinhos nome (rest grafo))]))

;; encontra-caminho: smbolo smbolo grafo -> caminho ;; Dado um grafo e os nomes de dois ns, encontra um caminho entre ;; os ns no grafo. (define (encontra-caminho origem destino grafo) (cond [(symbol=? origem destino) (list origem)] [else (local ( (define tentativa (percorre-vizinhos (vizinhos origem grafo) destino grafo)) ) (cond [(false? tentativa) false] [else (cons origem tentativa)]))])) ;; percorre-vizinhos: lista-de-smbolos smbolo grafo -> caminho ;; Encontra um caminho entre qualquer uma das origens e o destino no grafo. (define (percorre-vizinhos origens destino grafo) (cond [(empty? origens) false] [else (local ( (define tentativa (encontra-caminho (first origens) destino grafo)) ) (cond [(false? tentativa) (percorre-vizinhos (rest origens) destino grafo)] [else tentativa]))])) ;; Exemplo de grafo. (define exemplo (list (make-n a (list b c)) (make-n b (list d e)) (make-n c (list e)) (make-n d empty) (make-n e empty))) ;; Teste. (encontra-caminho a e exemplo)

Figura 6.1: Programa para busca de caminho em grafo acclico em IS Das quatro principais classes de problemas mencionados com a linguagem IS, os problemas com a sintaxe e com tipos de dados foram diretamente abordados no desenvolvimento de Faz. Os problemas com o ambiente ainda so passveis de melhorias, embora a presena da vericao esttica de tipos reduza a diculdade de encontrar erros no cdigo. A diculdade de adaptao ao paradigma por alunos com experincia com linguagens imperativas um problema inerente proposta de se utilizar uma linguagem funcional no ensino de programao. Porm, com a reduo dos problemas com a sintaxe e tipos de dados, possvel que haja uma melhor compreenso do paradigma funcional por parte dos alunos, amenizando a transio entre os paradigmas. A nova linguagem, ao mesmo tempo em que reduz os problemas mencionados com IS, mantm seus aspectos positivos, derivados em grande parte do emprego do paradigma funcional.

56

tipo Ns = { n(nome Strings, vizinhos Listas de Strings) } tipo Grafos = Listas de Ns tipo Caminhos = Booleanos U Listas de Strings funo vizinhos(nome Strings, grafo Grafos) -> Listas de Strings # Devolve a lista de vizinhos de um n. se grafo == [] devolve [] se nome == nome de primeiro de grafo devolve vizinhos de primeiro de grafo seno devolve vizinhos(nome, resto de grafo) funo encontra_caminho(origem Strings, destino Strings, grafo Grafos) -> Caminhos # Dado um grafo e os nomes de dois ns, encontra um caminho entre # os ns no grafo. se origem == destino devolve [origem] seno seja tentativa = percorre_vizinhos(vizinhos(origem, grafo), destino, grafo) se tentativa == falso devolve falso seno devolve Elo(origem, tentativa) funo percorre_vizinhos(origens Listas de Strings, destino Strings, grafo Grafos) -> Caminhos # Encontra um caminho entre qualquer uma das origens e o destino no grafo. se origens == [] devolve falso seno seja tentativa = encontra_caminho(primeiro de origens, destino, grafo) se tentativa == falso devolve percorre_vizinhos(resto de origens, destino, grafo) seno devolve tentativa # Exemplo de grafo. seja exemplo = [ n("a", n("b", n("c", n("d", n("e", ]

["b", "c"]), ["d", "e"]), ["e"]), []), [])

# Teste. teste encontra_caminho("a", "e", exemplo)

Figura 6.2: Programa para busca de caminho em grafo acclico em Faz

57

TRABALHOS RELACIONADOS

Faz uma linguagem funcional didtica baseada no portugus com tipagem semiesttica. Este captulo discute outros trabalhos com cada uma dessas caractersticas para ns de comparao com o presente trabalho. Sero discutidas linguagens baseadas no portugus, linguagens funcionais de propsito geral e didticas e outras linguagens didticas no funcionais, bem como sistemas de tipos estticos para Racket.

7.1

Linguagens baseadas no portugus

Diversos cursos e materiais didticos empregam variantes do que se conhece por Portugus Estruturado, ou Portugol (MANZANO, 2006). Em sua forma original, Portugol foi concebido como uma forma de pseudo-cdigo, utilizado apenas como ferramenta notacional para descrever algoritmos, e no como uma linguagem executvel por computador. Posteriormente sua popularizao, surgiram implementaes para variantes mais rigorosamente denidas da linguagem, tais como o G-Portugol (SILVA, 2010), o Portugol Viana (VIANA, 2008), o Portugol IDE (MANSO; OLIVEIRA; MARQUES, 2009) e o Visualg (TONET, 2012). Todas as variantes de Portugol so linguagens imperativas reminiscentes da linguagem Pascal (WIRTH, 1971), no apresentando, portanto, as caractersticas que tornam o paradigma funcional vantajoso no ensino de programao citadas no Captulo 2 deste trabalho. No do conhecimento do autor outras linguagens funcionais baseadas no portugus.

7.2
7.2.1

Linguagens funcionais de propsito geral


Famlia LISP

LISP (MCCARTHY, 1960) introduziu o paradigma de programao funcional, baseado na composio e aplicao de funes. Desde sua criao, surgiram diversos dialetos ou novas linguagens baseadas em LISP, de tal maneira que hoje em dia entende-se LISP como uma famlia de linguagens relacionadas. Os principais membros dessa famlia so: o Scheme (KELSEY et al., 1998), que por sua vez deu origem linguagem Racket e suas variantes, abordadas no Captulo 3 deste trabalho; o Common LISP (STEELE JR., 1990), uma linguagem criada com o intuito de unicar os diversos dialetos de LISP criados nas dcacas de 1970 e 1980, tais como o MACLISP (MOON, 1974), o Interlisp (TEITELMAN; GOODWIN; BOBROW, 1978) e o Lisp Machine Lisp (WEINREB; MOON, 1981); e Clojure (HICKEY, 2012), uma linguagem que executa sobre a mquina virtual da linguagem Java (ARNOLD; GOSLING; HOLMES, 2005) e possui funcionalidades de integrao com esse ambiente. Destas, Scheme e derivados tm sido frequentemente

58

utilizados no ensino de programao. Todas essas linguagens so dinamicamente tipadas e empregam uma sintaxe baseada em expresses aninhadas delimitadas por parnteses (e, no caso de Clojure e algumas variantes de Scheme, colchetes e chaves), tal como visto no Captulo 3. Common LISP uma linguagem funcional impura, incluindo diversas funes e macros para manipulao de estado. Scheme uma linguagem impura, mas d uma nfase maior construo de programas puros. Clojure, por sua vez, possui elementos impuros, mas d uma nfase ainda maior construo de programas puros, fornecendo diversas estruturas de dados imutveis em sua biblioteca padro. As vantagens e desvantagens das linguagens da famlia LISP em um contexto didtico so similares aos pontos citados no Captulo 3. 7.2.2 Famlia ML

Outra famlia importante de linguagens funcionais originou-se com a linguagem ML. Dentre as linguagens dessa famlia, destacam-se Standard ML (MILNER; TOFTE; MACQUEEN, 1997) e OCaml (LEROY et al., 2012). ML teve uma inuncia no desenvolvimento da linguagem Miranda (TURNER, 1985), que por sua vez inspirou as linguagens Haskell (MARLOW et al., 2010) e Clean (PLASMEIJER; EEKELEN, 2011). So linguagens estaticamente tipadas com polimorsmo paramtrico. Utilizam-se de uma sintaxe equacional: funes so geralmente denidas por partes na forma de equaes que dizem como uma chamada da funo com diferentes argumentos deve ser avaliada. Por exemplo, a funo fatorial em Haskell pode ser denida como:
fatorial 0 = 1 fatorial n = n * fatorial (n-1)

Nessas linguagens, a aplicao de funes escrita sem parnteses, justapondo o nome da funo e seus argumentos. Funes de mltiplos argumentos so tratadas como funes curried: uma funo de dois argumentos, por exemplo, tratada como uma funo que recebe um argumento e produz uma nova funo, que ento aplicada ao segundo argumento. Isso permite a aplicao parcial de funes. Por exemplo, dada a seguinte denio em Haskell:
soma x y = x+y

possvel escrever a seguinte denio:


incrementa = soma 1

Ou seja, soma, aplicada a apenas um argumento, 1, produz uma funo que espera o prximo argumento e soma 1 ao mesmo. As linguagens diferem na maneira como tratam polimorsmo, especialmente com relao aos tipos numricos. Em ML, constantes possuem um tipo xo (e.g., 1 do tipo int, enquanto 1.0 do tipo real). Os operadores aritmticos so polimrcos, permitindo usar os mesmos operadores com operandos dos diferentes tipos numricos, desde que ambos os operandos sejam do mesmo tipo; no h converso implcita entre os tipos. OCaml utiliza operadores distintos para os diferentes tipos numricos (e.g., + para inteiros e +. para reais). Em Haskell, tipos polimrcos so atribudos a constantes e a operadores por meio de um sistema de typeclasses. Por exemplo, 1 do tipo Num a => a, i.e., a constante pode ser instanciada para qualquer tipo a que implemente a

59

typeclass Num. Miranda utiliza um nico tipo numrico num que engloba tanto inteiros quanto nmeros em ponto utuante, evitando a questo do polimorsmo das constantes e operadores aritmticos. ML e OCaml so linguagens funcionais impuras, permitindo o uso de estado mutvel atravs de referncias e de funes de entrada e sada irrestritas. Haskell e Clean so linguagens puramente funcionais, restringindo a propagao de efeitos colaterais no programa. A sintaxe equacional para denio de variveis e funes nas linguagens da famlia ML, em especial Miranda, Haskell e Clean, bastante clara. Por outro lado, a sintaxe de Faz busca minimizar as diferenas sintticas entre o paradigma imperativo e o funcional, permitindo um foco maior nas diferenas semnticas entre os paradigmas. Haskell utiliza mais operadores inxados do que Faz, tais como : para construir listas (anlogo s funes cons em LISP e elo em Faz), !! para a indexao de listas e . para a composio de funes. Isso torna o cdigo mais compacto, mas por outro lado introduz novas regras de precedncia linguagem e pode tornar o cdigo menos legvel para um usurio que no esteja familiarizado com esses operadores. Os sistemas de tipos das linguagens da famlia ML so mais restritivos do que o de Faz. Por um lado, isso confere a essas linguagens maiores garantias estticas de segurana. Por outro lado, conforme visto na Seo 4.2.1, a presena de tipos de unio em Faz d uma maior exibilidade linguagem, permitindo que certos programas possveis em linguagens dinmicas tambm possam ser escritos em Faz sem que para isso seja necessrio abandonar completamente a tipagem esttica. Miranda e Faz unicam os tipos numricos, permitindo que operaes combinem nmeros inteiros e reais de maneira transparente. Isso benco em uma linguagem introdutria, pois permite trabalhar com nmeros como as entidades matemticas que representam, sem que o usurio tenha que se preocupar com sua representao interna. Por outro lado, tipos inteiros e reais distintos permitem a gerao de cdigo mais eciente.

7.3

Linguagens funcionais didticas

LOGO (FOUNDATION, 2013) uma linguagem didtica baseada em LISP. Trata-se de uma linguagem multiparadigma, que incorpora elementos de programao funcional com comandos imperativos. A linguagem possui um enfoque em manipulao de texto e no desenho de grcos atravs de comandos que controlam um cursor, usualmente na forma de uma tartaruga, capaz de se movimentar pela tela e traar linhas. LOGO emprega uma sintaxe baseada em LISP. Em LOGO, entretanto, a maior parte dos parnteses so opcionais: o nmero de argumentos esperado por um operador usado para determinar a interpretao correta de um comando. Por exemplo, uma vez que os operadores sum e product aceitam dois argumentos por padro, um comando como
print product sum 2 3 sum 4 5

interpretado como:
print (product (sum 2 3) (sum 4 5))

Alm disso, LOGO suporta o uso de operadores aritmticos inxados. LOGO utiliza uma sintaxe peculiar para o acesso e atribuio de variveis. No acesso, variveis so escritas na forma :nome. A atribuio de um valor a uma varivel feita atravs do comando make "nome valor, onde "nome uma palavra, um tipo de dados equivalente

60

ao smbolo de Racket. LOGO utiliza escopo dinmico para as variveis: variveis denidas em uma funo so visveis em outras funes chamadas por ela. Assim como as demais linguagens da famlia LISP, LOGO dinamicamente tipada. A linguagem LOGO uma tentativa interessante de tornar a sintaxe de LISP mais acessvel a programadores iniciantes, eliminando a maior parte dos parnteses. Porm, a interpretao das expresses dependente do nmero de argumentos esperado por cada comando pode dicultar a compreenso de quais argumentos pertencem a cada comando. Alm disso, LOGO herda diversas peculiaridades dos LISPs clssicos abandonadas em Scheme, tais como escopo dinmico, a atribuio de valores a variveis por meio de smbolos e a manipulao de funes por meio de smbolos e listas e no como valores de primeira classe. Assim como os demais LISPs, LOGO dinamicamente tipado, o que incorre nos mesmos problemas com a tipagem dinmica mencionados no Captulo 3. Helium (HEEREN; LEIJEN; IJZENDOORN, 2003) um compilador e interpretador para a linguagem Haskell desenvolvido especicamente para o ensino dessa linguagem. Helium elimina certas funcionalidades de Haskell, tais como polimorsmo baseado em typeclasses, o que permite ao compilador detectar certos erros comuns entre iniciantes e emitir avisos e mensagens de erro mais apropriadas. A ideia anloga das sublinguagens didticas de How to Design Programs, como visto no Captulo 3 deste trabalho. As vantagens e desvantagens da linguagem em um contexto didtica so anlogas s de Haskell, discutidas na seo anterior.

7.4

Outras linguagens didticas

Pascal (WIRTH, 1971) foi uma das primeiras linguagens criadas tendo o ensino de programao como um de seus propsitos. Trata-se de uma linguagem imperativa, com tipagem esttica forte, que enfatiza os princpios da programao estruturada. Scratch (MALONEY et al., 2010) e Etoys (KAY, 2005) so linguagens e ambientes didticos baseados em Squeak (INGALLS et al., 1997), uma variante de Smalltalk (GOLDBERG; ROBSON, 1983). Em Scratch, programas so construdos por meio da composio visual de expresses e estruturas de controle. A linguagem tem um foco na criao de software multimdia. Etoys permite a criao e controle de objetos em um mundo virtual. Ambas as linguagens tm como pblico alvo crianas no Ensino Fundamental e Mdio. Assim como as variantes de Portugol, Pascal uma linguagem imperativa, no apresentando os benefcios do paradigma funcional. Por outro lado, Pascal tem a vantagem de poder ser utilizado como uma linguagem de propsito geral. Scratch e Etoys, alm de no serem linguagens funcionais, possuem um pblico alvo diferente: enquanto Scratch e Etoys so voltadas a estudantes do Ensino Fundamental e Mdio, com um enfoque em aplicaes multimdia e interativas, Faz voltada a estudantes de nvel superior, com um enfoque em programao mais convencional para manipulao de dados.

7.5

Tipagem esttica em Racket

Typed Racket, anteriormente conhecido como Typed Scheme (TOBINHOCHSTADT; FELLEISEN, 2008), uma tentativa de elaborar um sistema de tipos esttico sucientemente exvel para permitir o estilo de programao convencionalmente utilizado em Racket, em que tipos so combinados de forma mais livre do que em linguagens estaticamente tipadas convencionais, maneira dos tipos mistos

61

de HtDP, descritos na Seo 3.1.8. Assim como Faz, Typed Racket permite o uso de unies de tipos e emprega condicionais com predicados de tipos para selecionar entre os mltiplos tipos de uma varivel cujo tipo uma unio. Por outro lado, diferentemente de Faz, Typed Racket no possui a noo de compatibilidade parcial de tipos, o que faz com que a linguagem rejeite programas que seriam aceitos por Faz. Typed Racket permite a descrio de tipos mais elaborados do que Faz, tais como interseces de tipos e funes com nmero varivel de argumentos, o que confere uma maior exibilidade linguagem e permite dar tipos mais precisos a algumas funes. Por outro lado, os tipos de Typed Racket podem ser bastante complexos e de difcil compreenso, especialmente no contexto de uma disciplina introdutria. Typed Racket possui limitaes similares s de Faz no que diz respeito a polimorsmo paramtrico.

62

CONCLUSO

Neste trabalho foi elaborada a linguagem Faz, uma linguagem de programao visando a facilitar o ensino e a aprendizagem de cursos introdutrios de programao empregando o paradigma funcional. A linguagem foi desenvolvida visando a evitar os problemas encontrados no ensino de programao com as linguagens didticas How to Design Programs, baseadas em Racket. Diversas decises de projeto foram consideradas na elaborao da linguagem, buscando torn-la mais familiar e mais facilmente compreensvel a alunos brasileiros egressos do Ensino Mdio. Para isso, optou-se por adotar uma sintaxe baseada no portugus e na notao matemtica e de outras linguagens de programao. Tambm decidiu-se adotar uma organizao do cdigo baseada em blocos e uma distino entre comandos e expresses, o que, alm de tornar a linguagem mais legvel e tornar denies globais e locais de variveis e funes mais similares, reduz a distncia sinttica entre Faz e linguagens imperativas populares, como C. Isto torna linguagem mais familiar a alunos com experincia prvia nessas linguagens e permite focar o aprendizado nas diferenas semnticas entre as linguagens. Por outro lado, o uso de convenes da matemtica e de comandos em portugus torna a linguagem mais acessvel a alunos sem experincia prvia em programao. Finalmente, introduziu-se linguagem um sistema de tipos semi-esttico com unies de tipos, permitindo linguagem incorporar declaraes formais dos tipos de funes e estruturas de dados e, ao mesmo tempo, manter a exibilidade proporcionada pelo sistema de tipos dinmico de Racket. A linguagem foi implementada e integrada ao ambiente de desenvolvimento DrRacket. Para isso, foram implementados os passos de anlise lxica e sinttica do cdigo, utilizando para isso as bibliotecas de gerao de analisadores que acompanham a linguagem Racket, anlise semntica, incluindo vericao de tipos e coleta de informaes sobre as variveis, funes e tipos denidos pelo usurio, e a traduo do cdigo para a linguagem Racket a partir dos dados gerados pelos passos anteriores, permitindo assim reaproveitar a infraestrutura da linguagem Racket na implementao da nova linguagem. A linguagem Faz e sua atual implementao apresentam algumas limitaes, conforme visto nas Sees 4.4 e 5.2.7. Trabalhos futuros incluem a eliminao dessas limitaes. No que diz respeito linguagem, poderia ser interessante a adio de mecanismos sintticos para a execuo de efeitos colaterais em sequncia, o que permitiria a incorporao de funes convencionais de entrada e sada, cuja ausncia uma limitao herdada da linguagem IS. Quanto interface, melhorias incluem indicaes mais precisas de erros de sintaxe encontrados no cdigo e uma melhor adaptao do editor de cdigo do ambiente DrRacket s convenes sintticas da nova linguagem, especialmente com relao indentao automtica e colorao de sintaxe. Para isso, seria necessrio reescrever o analisador sinttico da linguagem e integrar ao ambiente DrRacket funes para a determinao da indentao e colorao corretas.

63

A implementao atual do sistema de tipos da linguagem tambm passvel de melhorias. Testes de pertinncia no admitem tipos contendo variveis. Testes de pertinncia a tipos funcionais em tempo de execuo (e.g., se f Funes (Nmeros) -> Nmeros) atualmente no so possveis, pois a informao dos tipos dos argumentos e de retorno das funes, presente em tempo de compilao, no preservada em tempo de execuo pela etapa de traduo do cdigo Faz para Racket. Possveis solues incluem alterar a representao das funes em tempo de execuo de maneira a incluir essa informao ou manter uma tabela relacionando cada funo com seu tipo. Na prtica, esse tipo de teste raro, especialmente no contexto de uma disciplina introdutria. A implementao atual do cmputo de interseces de tipos na combinao de restries limitada, retornando Nada caso os tipos no sejam idnticos. Essa restrio s afeta algumas funes polimrcas com parmetros de tipos funcionais quando a relao de subtipagem utilizada. O sistema de tipos em si apresenta limitaes no que diz respeito interao entre tipos paramtricos e unies de tipos. Tipos polimrcos so considerados incompatveis entre si. Isso implica que funes polimrcas, como compose (Figura 4.9), no admitem argumentos polimrcos. Alm disso, no caso geral, na presena de unies de tipos nem sempre h uma soluo nica para um conjunto de restries sobre variveis de tipos. A implementao atual rejeita conjuntos de restries com essa propriedade. Uma integrao mais completa entre tipos paramtricos e unies de tipos uma possvel melhoria. Outro trabalho futuro seria formalizar o sistema de tipos por meio de regras de inferncia lgica mais precisamente denidas, visando a vericar formalmente quais propriedades so garantidas ou no pelo sistema em comparao a sistemas de tipos mais convencionais. Finalmente, seria interessante experimentar a linguagem na prtica, empregando-a em uma disciplina de ensino de programao funcional, de maneira a vericar se as modicaes realizadas em relao s linguagens HtDP so efetivas em facilitar a exposio e compreenso dos conceitos pelos alunos.

64

REFERNCIAS

ABELSON, H.; SUSSMAN, G. Structure and Interpretation of Computer Programs. Cambridge, Mass., USA: MIT Press, 1985. ARMSTRONG, J. et al. Concurrent Programming in ERLANG. [S.l.]: Prentice Hall, 1996. ARNOLD, K.; GOSLING, J.; HOLMES, D. The Java Programming Language. 4th.ed. [S.l.]: Addison-Wesley Professional, 2005. BARRAS, B. et al. The Coq proof assistant reference manual: Version 6.1. Acesso em setembro de 2013, http://hal.archives-ouvertes.fr/docs/00/06/99/ 68/PDF/RT-0203.pdf. BOVE, A.; DYBJER, P.; NORELL, U. A brief overview of Agdaa functional language with dependent types. In: Theorem Proving in Higher Order Logics. [S.l.]: Springer, 2009. p.7378. DEAN, J.; GHEMAWAT, S. MapReduce: simplied data processing on large clusters. In: SYMPOSIUM ON OPERATING SYSTEMS DESIGN & IMPLEMENTATION - VOLUME 6, 6., Berkeley, CA, USA. Proceedings. . . USENIX Association, 2004. p.1010. (OSDI04). FELLEISEN, M. et al. How to Design Programs. [S.l.]: MIT Press, 2001. FELLEISEN, M. et al. The Structure and Interpretation of the Computer Science Curriculum. Journal of Functional Programming, West Sussex, v.10, n.1113, Sept./Nov. 2004. FLATT, M.; PLT. Reference: racket-lang.org/tr1/. Racket. Acesso em outubro de 2013, http://

FOUNDATION, L. Logo Foundation. Acesso em outubro de 2013, http://el. media.mit.edu/logo-foundation/index.html. GOLDBERG, A.; ROBSON, D. Smalltalk-80: the language and its implementation. [S.l.]: Addison-Wesley Longman Publishing Co., Inc., 1983. HEEREN, B.; LEIJEN, D.; IJZENDOORN, A. van. Helium, for learning Haskell. In: ACM SIGPLAN WORKSHOP ON HASKELL, 2003. Proceedings. . . [S.l.: s.n.], 2003. p.6271.

65

HICKEY, R. Clojure documentation. Acesso em setembro de 2013, http:// clojure.org/documentation. HUGHES, J. Why Functional Programming Matters. The Computer Journal, [S.l.], v.32, n.2, p.98107, 1989. INGALLS, D. et al. Back to the future: the story of Squeak, a practical Smalltalk written in itself. ACM SIGPLAN Notices, [S.l.], v.32, n.10, p.318326, 1997. JOHNSON, S. C. Yacc: Yet Another Compiler-Compiler. [S.l.]: Bell Laboratories Murray Hill, NJ, 1975. v.32. KAUFMANN, M.; MOORE, J. S. ACL2: An industrial strength version of Nqthm. In: COMPUTER ASSURANCE, 1996. COMPASS96,SYSTEMS INTEGRITY. SOFTWARE SAFETY. PROCESS SECURITY. PROCEEDINGS OF THE ELEVENTH ANNUAL CONFERENCE ON. Anais. . . [S.l.: s.n.], 1996. p.2334. KAY, A. Squeak Etoys, Children & Learning. Acesso em outubro de 2013, ftp://debian.ofset.org/speeches/jrfernandez/malaga08/doc/ etoys_n_learning.pdf. KELSEY, R. et al. Revised5 Report on the Algorithmic Language Scheme. ACM SIGPLAN Notices, New York, NY, USA, v.33, n.9, p.2676, Sept. 1998. LAUSANNE cole Polytechnique Fdrale de. Scala documentation. Acesso em outubro de 2013, http://www.scala-lang.org/documentation/. LEROY, X. et al. The OCaml system release 4.00: Documentation and users manual. Acesso em setembro de 2013, http://caml.inria.fr/pub/docs/ manual-ocaml/index.html. LESK, M. E.; SCHMIDT, E. Lex: a lexical analyzer generator. [S.l.]: Bell Laboratories Murray Hill, NJ, 1975. MALONEY, J. et al. The Scratch Programming Language and Environment. ACM Transactions on Computing Education (TOCE), [S.l.], v.10, n.4, p.16, 2010. MANSO, A.; OLIVEIRA, L.; MARQUES, C. G. Ambiente de Aprendizagem de Algoritmos Portugol IDE. In: VI CONFERNCIA INTERNACIONAL DE TIC NA EDUCAO CHALLENGES 2009. Actas. . . Braga: Centro de Competncia da Universidade do Minho, 2009. MANZANO, J. LPPLinguagem de Projeto de Programao: proposta de padronizao da estrutura sinttica de uma linguagem de projeto de programao a ser denida para a rea de desenvolvimento de software para pases com idioma portugus. THESIS, So Paulo, v.6, p.4458, Setembro 2006. MARLOW, S. et al. Haskell 2010 Language Report. Acesso em setembro de 2013, http://www.haskell.org/onlinereport/haskell2010. MARLOW, S.; JONES, S. P. et al. The Glasgow Haskell Compiler. In: The Architecture of Open Source Applications. [S.l.]: Lulu Press, 2012. v.2.

66

MCCARTHY, J. Recursive functions of symbolic expressions and their computation by machine, Part I. Communications of the ACM, New York, NY, USA, v.3, n.4, p.184 195, Apr. 1960. MILNER, R.; TOFTE, M.; MACQUEEN, D. The Denition of Standard ML. Cambridge, MA, USA: MIT Press, 1997. MOON, D. A. MACLISP Reference Manual. [S.l.]: Massachusetts Institute of Technology, 1974. NORVIG, P. Paradigms of articial intelligence programming: case studies in Common LISP. [S.l.]: Morgan Kaufmann, 1992. PIERCE, B. C. Types and Programming Languages. [S.l.]: The MIT Press, 2002. p.206207. PLASMEIJER, R.; EEKELEN, M. van. Clean Language Report version 2.2. Acesso em outubro de 2013, http://clean.cs.ru.nl/download/doc/ CleanLangRep.2.2.pdf. PLT DESIGN, I. Racket Documentation: drracket plugins. Acesso em outubro de 2013, http://docs.racket-lang.org/tools/. ROUNDY, D. Darcs: distributed version management in Haskell. In: ACM SIGPLAN WORKSHOP ON HASKELL, 2005. Proceedings. . . [S.l.: s.n.], 2005. p.14. SILVA, T. G-Portugol Manual. Acesso em outubro de 2013, http://gpt. berlios.de/manual_big/manual.html. STEELE JR., G. L. Common LISP: the language (2nd ed.). Newton, MA, USA: Digital Press, 1990. SUSSMAN, G. J.; JR., G. L. S. Scheme: an interpreter for extended lambda calculus. In: MEMO 349, MIT AI LAB. Anais. . . [S.l.: s.n.], 1975. TEITELMAN, W.; GOODWIN, J.; BOBROW, D. G. Interlisp Reference Manual. [S.l.]: Xerox Palo Alto Research Centers, 1978. TOBIN-HOCHSTADT, S.; FELLEISEN, M. The design and implementation of Typed Scheme. In: ACM SIGPLAN NOTICES. Anais. . . [S.l.: s.n.], 2008. v.43, n.1, p.395 406. TONET, B. Software Visualg 2.0. Acesso em outubro de 2013, http: //www.cefetsp.br/edu/adolfo/disciplinas/lpro/materiais/ visualg.pdf. TURNER, D. A. Miranda: a non-strict functional language with polymorphic types. In: FUNCTIONAL PROGRAMMING LANGUAGES AND COMPUTER ARCHITECTURE. Anais. . . [S.l.: s.n.], 1985. p.116. VIANA, P. Melhoria do Processo de Ensino-Aprendizagem nas disciplinas de Programao e Algoritmos. Acesso em outubro de 2013, http://portugolviana. estg.ipvc.pt/.

67

WEINREB, D.; MOON, D. The Lisp Machine Manual. ACM SIGART Bulletin, [S.l.], n.78, p.1010, 1981. WIRTH, N. The programming language Pascal. Acta informatica, [S.l.], v.1, n.1, p.35 63, 1971.

Вам также может понравиться