A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Elsa Carvalho 72 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

Apresentações semelhantes


Apresentação em tema: "Elsa Carvalho 72 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)"— Transcrição da apresentação:

1 Elsa Carvalho 72 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Certas abstracções, como por exemplo, imagens, datas, cartas de jogar, etc., são concretizadas, em linguagens que não suportam definição de tipos de raiz, com base em tipos pré-definidos na linguagem. Em Pascal, por exemplo, teremos que nos restringir aos construtores, record, enum e array e aos tipos primitivos integer, char, etc.. Assim, para representar anos (1991, 1992,...) podemos por exemplo escolher o tipo 0..3000. O compilador deixará passar ‘erros’ como ‘somar’ anos (1991 + 1992) operação que não faz sentido neste contexto. Definição de novos tipos

2 Elsa Carvalho 73 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Definição de novos tipos Resumindo: em sistemas de tipos que não suportem directamente as abstracções que queremos representar, o melhor a que podemos aspirar é a uma representação indirecta recorrendo a tipos e construções de tipos disponíveis, sujeitos a que o type checker interprete ‘erradamente’ os nossos conceitos. O ML ultrapassa estas limitações e possibilita a definição de tipos inteiramente novos. Isso irá ser mostrado de seguida, começando pelas formas mais simples.

3 Elsa Carvalho 74 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Estes tipos são equivalentes aos tipos de enumeração finita encontrados noutras linguagens (como seja o Pascal) e são introduzidos através da enumeração de constantes, como se vê de seguida. A palavra chave datatype indica a definição de um novo tipo, segue-se o nome do tipo, o símbolo “=” e as constantes (operações construtoras) separadas por “|”. datatype direction = Up | Down | Left | Right Esta definição introduz quatro novos valores distintos, cujo tipo é direction: Up: direction Down: direction Left: direction Right: direction Tipos com construtoras constantes

4 Elsa Carvalho 75 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Estes são os únicos valores definidos para este tipo. O novo tipo pode ser combinado com tipos existentes (de uma forma apropriada) e, como tal, podemos escrever expressões tal como: [Up, Down, Up, Up, Right] que é um valor do tipo direction list. No entanto, se tentarmos escrever [Right, 3] ser-nos-à indicado um erro de tipos, uma vez que uma lista só pode ser composta por elementos de um mesmo tipo. O que não é o caso: Right: direction 3: integer Tipos com construtoras constantes

5 Elsa Carvalho 76 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Temos outros exemplos, como sejam: datatype cardvalue = Two | Three |... | Queen | King | Ace datatype suit = Spades | Diamonds | Hearts | Clubs Qualquer tipo enumerado terá, automaticamente, o operador de igualdade definido, o que permite que valores desse tipo sejam comparados com =. Assim Up = Down é uma expressão válida, do tipo bool e com valor false. Tipos com construtoras constantes

6 Elsa Carvalho 77 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Tipos com construtoras constantes As novas constantes, introduzidas através da definição de tipos, também podem ser utilizadas no ‘pattern matching’, o que nos permite escrever funções, com argumentos do novo tipo, por análise de casos. Eis um exemplo fun clockwise Up = Right | clockwise Right = Down | clockwise Down = Left | clockwise Left = Up Daqui podemos extrapolar que o tipo desta função é: clockwise: direction  direction

7 Elsa Carvalho 78 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Tipos com construtoras paramétricas Vamos agora introduzir uma ligeira generalização que nos permite introduzir novos tipos com construtores que não são constantes. A diferença entre esta forma de definir tipos e a anterior está na possibilidade de introduzir parâmetros nas construtoras. Há que mencionar o tipo do parâmetro: a seguir ao nome da operação coloca-se a palavra chave of e depois o nome ou construção de um tipo. Por exemplo datatype card = Card of (cardvalue X suit) Neste caso card é o nome de um novo tipo e Card é uma construtora de valores do tipo card.

8 Elsa Carvalho 79 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Tipos com construtoras paramétricas O tipo da construtora é: Card: (cardvalue X suit)  card ou seja, pode ser aplicado a um argumento do tipo cardvalue x suit, produzindo um valor do tipo card. Assim, as seguintes expressões, são válidas: Card (Two, Diamonds) Card (King, Clubs) O teste implícito de igualdade estende-se a estes tipos. Intuitivamente Card (Queen, Spades) = Card (Queen, Diamonds) tem o valor false, pois Spades = Diamonds tem o valor false.

9 Elsa Carvalho 80 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Também neste caso as construtoras continuam a ser a forma de constituir padrões em parâmetros de funções acessórias. Por exemplo fun suitof (Card (v, s)) = s fun valueof (Card (v,s)) = v fun isheart(Card (cv, Heart)) = true | isheart(Card (cv, s)) = false Temos assim dois selectores e um predicado, cujos tipos podemos definir: suitof: card  suit valueof: card  cardvalue isheart: card  bool Tipos com construtoras paramétricas

10 Elsa Carvalho 81 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) É boa técnica de programação usar novos tipos mesmo quando existe na linguagem um tipo adequado para representar os valores pretendidos. Desta forma temos a garantia de uma verificação de tipos mais eficaz. Por exemplo, se queremos realizar cálculos com as idades e alturas de pessoas, representados por inteiros, podemos definir dois novos tipos: datatype altura = Alt of int datatype idade = Idade of int Assim as alturas terão a forma Alt (n) e as idades serão representadas por Idade (n), onde n: int. Tipos com construtoras paramétricas

11 Elsa Carvalho 82 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) As construtoras Alt: int  altura Idade: int  idade realizam as conversões apropriadas entre inteiros e os novos tipos. Isto torna-se vantajoso, uma vez que, embora seja possível somar inteiros, essa não é uma operação comum entre idades e alturas (por exemplo). Com a introdução destes tipos, a operação Alt 190 + Idade 30 dará origem a um erro, pelo verificador de tipos. Tipos com construtoras paramétricas

12 Elsa Carvalho 83 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Suponhamos que se pretende introduzir um tipo autor e um tipo livro. Os autores são usualmente representados por strings (o nome), mas pretende-se um caso especial para um autor anónimo - ‘Anon’. De igual modo um livro será representado pelo seu título (uma string) e por uma lista de autores, mas pretende-se distinguir entre livros de capa dura e livros de capa ‘mole’. Uma forma de o fazer é definir: datatype autor = Autor of string | Anon datatype livro = Paperback of (string x autor list) | Hardback of (string x autor list) Tipos com construtoras alternativas

13 Elsa Carvalho 84 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Estas definições introduzem os tipos autor e livro, bem como as quatro construtoras Autor: string  autor Anon: autor Paperback: (string x autor list)  book Hardback: (string x autor list)  book Desta forma é possível criar objectos do tipo livro e autor de diferentes maneiras: val estelivro = Hardback (“Elements of Functional Programming”, [Autor “C.M.P.Read”]) val outrolivro = Paperback (“O Desconhecido”, [Anon]) Tipos com construtoras alternativas

14 Elsa Carvalho 85 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Correspondentemente, funções definidas por emparelhamento de padrões (‘pattern matching’) com os tipos livro e autor terão de ter mais do que um caso: fun titulo (Paperback (s, al)) = s | titulo (Hardback (s, al)) = s fun listaautores (Paperback (s, al)) = al | listaautores (Hardback (s, al)) = al fun capamole (Paperback (s, al)) = true | capamole (Hardback (s, al)) = false Tipos com construtoras alternativas

15 Elsa Carvalho 86 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Note-se que novos tipos são, essencialmente, uniões disjuntas dos tipos componentes que aparecem como argumentos das construtoras. Além disso, podemos pensar nas construtoras, como funções que distinguem os valores dessa união para que se saiba qual o tipo componente a que pertencem. Para ilustrar essa ideia vai-se construir um tipo mix, que é a união (disjunta) dos tipos int e string: datatype mix = Int of int | Str of string Tipos com construtoras alternativas

16 Elsa Carvalho 87 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Podemos pensar nas construtoras Int: int  mix Str: string  mix como etiquetas para os inteiros/strings de forma a constituírem valores do tipo mix. Uma lista mista de inteiros e strings pode agora ser construída dentro do sistema de tipos com o tipo mix list: val mix1 = [Str “ola”, Int 3, Str “hello”, Int 5, Int 8] Tipos com construtoras alternativas

17 Elsa Carvalho 88 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Além disso, podemos extrair, dessa lista, os inteiros (por exemplo) sem que estes se confundam com os valores do tipo string: fun getints [] = [] | getints(Int n::x) = n::getints x | getints(Str s::x) = getints x Temos que: mix1: mix list getints: mix list  int list e getints mix1 = [3, 5, 8] Tipos com construtoras alternativas

18 Elsa Carvalho 89 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Assume-se que a definição de tipos pode ser recursiva e, desta forma, o novo tipo pode aparecer como parte do argumento de uma construtora desse mesmo tipo. Por exemplo: datatype ficheiro = Text of string | Directoria of ficheiro list Isto diz-nos que um ficheiro ou é definido pelo seu nome ou é uma directoria. Neste último caso pode ser composta por uma lista de (sub) ficheiros. As construtoras tem os tipos Text: string  ficheiro Directoria: ficheiro list  ficheiro Tipos recursivos

19 Elsa Carvalho 90 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Assim, um exemplo de um valor do tipo ficheiro será: val fich1 = Directoria [Text “f1”, Text “f2”, Directoria [Text “f3”, Directoria [ ]], Text “f4” ] onde o valor fich1: ficheiro é uma directoria com uma lista de quatro sub-ficheiros. O terceiro sub-ficheiro é também uma directoria com dois sub-ficheiros, um dos quais é uma directoria vazia. Tipos recursivos

20 Elsa Carvalho 91 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) As novas definições de tipos até agora apresentadas têm todas a mesma forma genérica. Um novo nome de um tipo é introduzido, juntamente com um número finito de funções construtoras, cada uma sendo ou uma constante ou tendo um argumento de um tipo especificado. O tipo dos argumentos pode envolver referências recursivas ao novo tipo. Em geral, podemos querer introduzir diversos novos tipos simultaneamente, onde os argumentos das construtoras podem ser de qualquer um dos novos tipos. Tipos mutuamente recursivos

21 Elsa Carvalho 92 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) Isto permite recursão mútua entre os tipos, como mostra o exemplo seguinte: datatype part = Basicpart of string | Compoundpart of (string x components list) and components = Quantity of (part x int) Aqui as construtoras têm os tipos: Basicpart: string  part Compoundpart: (string x components list)  part Quantity: (part x int)  components Tipos mutuamente recursivos

22 Elsa Carvalho 93 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06) O tipo definido acima representa peças simples e compostas. Uma peça simples é da forma Basicpart “partA” ou Basicpart “partB” em que a string é o identificador da peça. Uma peça composta é por exemplo “partC” em cuja composição entram 3 unidades da “partA” e 5 unidades da “partB”. val partC = Compoundpart (“partC”, [Quantity (Basicpart “partA”, 3), Quantity (Basicpart “partB”, 5)]) Tipos mutuamente recursivos


Carregar ppt "Elsa Carvalho 72 Universidade da Madeira Departamento de Matemática e Engenharias Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)"

Apresentações semelhantes


Anúncios Google