Linguagem Haskell Anderson B. Pinheiro UFC – Universidade Federeal do Ceará – Linguagens de Programação - 2011 Sumário Introdução Paradigma Funcional Histórico Características Programação Listas Introdução Programação declarativa – preocupa-se em especificar o problema e a solução e não como encontrar a solução; Programação imperativa – preocupa-se em especificar as instruções que devem ser executadas em uma ordem definida; Objetivo estudar uma linguagem declarativa; Linguagem Funcional Haskell; Introdução Programação Funcional : A computação é tratada como uma avaliação de funções matemáticas; Ocorrendo o mapeamento dos valores de entrada nos valores de saída através de uma função; Introdução Funcional x Imperativo Método de computação: function application Método de computação: variable assignment Alto nível de abstração Programas mais simples Histórico 1920-1940: Alonso Church e Haskell Curry desenvolvem o cálculo lambda; 1960: John McCarthy desenvolve a primeira linguagem funcional denominada LISP (atribuição de variáveis); 1970 – 1980: Robin Miler e David Turner desenvolvem a primeira linguagem funcional moderna, conhecida como ML com inferência de tipos, tipos primitivos e avaliação preguiçosa; Histórico 1988: Um comitê de pesquisadores decide desenvolver uma linguagem puramente funcional; 1990: Surge a linguagem Haskell; 1998: A primeira versão estável Haskell 98; Anualmente são realizadas revisões na linguagem; Características Linguagem puramente funcional; Suporte a funções recursivas; List Comprehensions (map, filter, lambda); Avaliação preguiçosa; Sistema de tipos avançado: Polimorfismo de tipos, classes de tipos; IO usando monadas; Implementações GHC – O Glasgow Haskell Compiler gera código nativo de diferentes arquiteturas e pode também gerar código C; Hugs – interpretador de bytcode. Oferece rápida compilação e razoável velocidade de execução, dispõe de interface gráfica. Implementações - Hugs Disponível para download gratuitamente em: Requisitos: http://cvs.haskell.org/Hugs/pages/downloading.htm Microsoft Windows Debian GNU/Linux Fedora Core/Linux openSUSE/Linux FreeBSD Mac OS X Distribuição disponível de setembro de 2006 Programação Embora existam várias funções pré definidas, nas linguagens funcionais busca-se que os usuários criem suas próprias funções. As funções dos usuários são definidas em scripts, sendo este script salvo em um arquivo com a extensão .hs. Nos scripts constam definições de funções associando nomes com valores e tipos. Podem também ser incluídos comentários, incluindo -antes dos comentários. --Este é um comentário Tipos Básicos Linguagem fortemente tipada, toda função, variável, constante tem apenas um tipo de dado; Possui um sistema de dedução automática de tipos para funções sem definição de tipo explicito; Permite a definição de novos tipos com base nos tipos primitivos; Tipos Básicos Para definir que uma expressão E possui o tipo T escreve-se: E :: T Tipos Básicos O protótipo para os tipos de uma função segue a sequencia: Nome_func :: Tipo(ent1)->Tipo(ent2)->...->Tipo(saida) Tipos: Booleanos Operações definidas sobre booleanos: e: &&; ou: ||; negação: not; Tipos: Inteiros Operações definidas sobre inteiros: Tipos: Inteiros Tipos: Inteiros Podemos definir operadores personalizados em scripts: Ex: Hugs> 10 &&& 3 3 Tipos: Tipos Personalizados Para definir tipos próprios utiliza-se a declaração data: data Bool = True | False data Cor = Azul | Vermelho | Amarelo | Verde Tipos: Caracteres O tipo Char representa o conjunto de caracteres, dígitos e caracteres especiais: ‘a’, ‘7’; Tipos: Caracteres Os caracteres são ordenados pela tabela ASCII: Haskell> ‘a’ < ‘z’ True Haskell> ‘A’ < ‘a’ True Podem ser representados por seu valor na tabela: Haskell> ‘\100’ ‘d’ Tipos: Caracteres O tipo String representa uma lista de carateres; Uma string é representada entre “...”: Haskell> “Quem não gosta\nde Haskell?” “Quem não gosta de Haskell?” Podemos concatenar listas utilizando o operador ++: Haskell> “Preciso de” ++ “ novos exemplos” “Preciso de novos exemplos” Uma string é sinonimo de uma lista de caracteres: Haskell> “Haskell” == *‘H’, ‘a’, ‘s’, ‘k’, ‘e’, ‘l’, ‘l’+ True Tipos: Número em Ponto Flutuante O tipo Float representa os números em ponto flutuante; Podem ser representados na forma decimal (2.316) ou notação científica (231.6e-2); Além das operações básicas possui funções próprias; Tipos: Número em Ponto Flutuante O tipo Float representa os números em ponto flutuante; Podem ser representados na forma decimal (2.316) ou notação científica (231.6e-2); Além das operações básicas possui funções próprias: Tipos: Tuplas Em uma tupla é possível agregar mais de um tipo: Type Nome = String Type Idade = Int verIdade :: (String, Int) -> Idade verIdade (a,b) = b Haskell> verIdade (“Anderson”, 23) 23 Tipos: Funções Recursivas Os loops das linguagens imperativas podem ser implementados através de funções recursivas -- Função Fatorial fatorial :: Int -> Int fatorial 0 = 1 fatorial n = n*fatorial(n-1) Haskell> fatorial 3 6 Tipos: Funções Recursivas Os loops das linguagens imperativas podem ser implementados através de funções recursivas -- Função Fatorial fatorial :: Int -> Int fatorial 0 = 1 fatorial n = n*fatorial(n-1) Haskell> fatorial 3 6 Listas Podemos trabalhar com listas de diferentes tipos: [1,2,3,4,5] :: Int *‘L’, ‘i’, ‘s’, ‘t’, ‘a’, ‘s’+ :: Char [True, False] :: Bool Permite criar listas de listas, de tuplas ou de funções: [[1,2],[3,4],[5]] :: [[Int]] *(‘a’,9), (‘b’,10), (‘c’,11)+ :: *(Char,Int)] Uma lista vazia “[]” pode ser de qualquer tipo. Listas É possível representar lista de maneiras diferentes: --[a..b] – Lista de a até b com passo igual a 1 Haskell> [1..10] [1,2,3,4,5,6,7,8,9,10] --[a,b..c] – Lista de a até c com passo igual b-a Haskell> [1,3..10] [1,3,5,7,9] Listas (operadores) O operador “:” é um operador polimófico, utilizado para construção de listas: [5] = 5:[] [1,2,3,4,5] = 1:2:3:4:5:[] “++” utilizado para concatenação de listas: Haskell> [1,2]++[3,4]++[5] [1,2,3,4,5] Listas (construção) Toda lista é formada por um “head” e por um “tail” (x:xs): [1,2,3], x =1 e xs=[2,3] Exemplo: Soma de elementos em uma lista: Caso base: [] Passo indutivo: x + soma xs --Soma elementos somaLista :: [Int] -> Int somaLista [] = [] somaLista (x:xs) = x + somaLista xs Haskell> somaLista [1..10] 55 Compreensão de Listas É possível gerar novas listas com base em listas já existentes: Notação semelhante a notação de conjuntos da matemática: S = {x*2 | x E N, x2 > 3} Pode ocorrer em qualquer lugar onde ocorreria uma lista, sendo equivalente a uma lista: Haskell> [x*2 | x <- [0..10], x^2 > 3] [4,6,8,10,12,14,16,18,20] Compreensão de Listas [x*2 | x <- [0..10], x^2 > 3] Onde: x <- [0..10]: gerador, onde x representa cada elemento da lista; x^2>3: filtro que determina os elementos a serem operados; x*2: operação sobre cada elemento que satisfaz o filtro; Compreensão de Listas remove :: Char -> [Char] -> [Char] remove carac str = [ c | c <-str, c /= carac] Haskell > remove ‘ ‘ “Este exemplo remove os espaços em branco!” “Esteexemploremoveosespaçosembranco!” Listas - Definições As listas em geral são definidas para três casos: Folding – inserir um operador entre os elementos da lista; Filtering – filtrar alguns elementos; Mapping – aplicação de funções a todos os elementos. Para esses três casos existem funções pré-definidas: Foldr1 Filter Map Listas - Definições Genérica: foldr1 ()[x1,x2,...,xn] = x1 x2 ... xn foldr1 :: (t -> t -> t) -> [t] -> t foldr1 f [a] = a foldr1 f (a:b:x) = f a (foldr1 f (b:x)) Haskell > foldr1 (&&) [True, False, True] False Haskell > foldr1 (+) [1,2,3] 6 Listas - Definições Haskell: filter :: (t -> Bool) -> [t] -> [t] filter p [] = [] filter p (a:x) | p a = a: filter p x | otherwise = filter p x filter p x = [ a | a <- x, p a] par :: Int -> Bool par n = (n `mod` 2 == 0) Haskell > filter par [2, 4, 5, 6, 10, 11] [2, 4, 6, 10] Listas - Definições Haskell: map :: (t -> u) -> [t] -> [u] map f [] = [] map f (a:x) = f a : map f x map f list = [f a | a < -list] Haskell > map length *“Anderson”, “pedro”, ”Joao”+ [8, 5, 4] Listas – Funções Uteis Haskell: take::Int->[t]->[t] take _ [] = [] take 0 _ = [] take n (a:x) = a:take (n-1) x Haskell > take 3 [1, 2, 3, 4, 5, 6] [1, 2, 3] Listas – Funções Uteis Haskell: drop::Int->[t]->[t] drop _ [] = [] drop 0 _ = [] drop n (a:x) = drop (n-1) x Haskell > drop 3 [1, 2, 3, 4, 5, 6] [4,5, 6] Listas – Funções Uteis zip (a:x) (b:y) = (a,b) : zip x y zip _ _ = [] Haskell > zip [1, 3, 5] [2, 4, 6] [(1,2), (3, 4), (5, 6)] Haskell > zip [1, 3, 5] [2, 4, 6, 8, 10] [(1,2), (3, 4), (5, 6)] Listas – Funções Uteis zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] zipWith op [x1, x2, x3, ...] [y1, y2, y3, ...] = [op x1 y1, op x2, y2, op x3 y3, ...] Haskell > zipWith (+) [1, 3, 5] [2, 4, 6] [3,7,11] Referências http://haskell.tailorfontela.com.br/introduction#aboutthis-tutorial Cláudio Cesar de Sá, Márcio Ferreira da Silva, Haskell – Uma Abordagem Prática, Novatec Editora, 2006. http://www.macs.hw.ac.uk/~dubois/ProgramacaoHaskell. pdf - Du Bois, A R. Programação Funcional com a Linguagem Haskell.