310 likes | 463 Views
Universidade Federal de Mato Grosso Campus Universitário do Araguaia Instituto de Ciências Exatas e da Terra Bacharelado em Ciência da Computação Paradigmas de Linguagens de Programação. Fundamentos de HaskelL. Acabias, Andressa, Gracyeli, Juliana, Juliano e Layo Barra do Garças, MT
E N D
Universidade Federal de Mato Grosso Campus Universitário do Araguaia Instituto de Ciências Exatas e da Terra Bacharelado em Ciência da Computação Paradigmas de Linguagens de Programação Fundamentos de HaskelL Acabias, Andressa, Gracyeli, Juliana, Juliano e Layo Barra do Garças, MT Junho de 2010
Funções e ProgramaçãoFuncional. Haskell: Origem e Paradigmas O interpretador Hugs ConceitosdaLinguagem
Funções e Programação Funcional Funções • Descrevem relações matemáticas especiais entre dois objetos, x e y=f(x). Onde x é chamado argumento da função f e y, que depende de x, é chamado imagem de x pela f. • Intuitivamente, uma função é uma maneira de associar a cada valor do argumento x um único valor da função f(x). Isso pode ser representado através de fórmulas, relacionamentos entre gráficos de conjuntos, tabelas de correspondências... • Este conceito é determinístico, ou seja, uma entrada a em uma função sempre produzirá um resultado x.
Funções e Programação Funcional Funções • O tipo de função mais comum é aquele onde o argumento e o valor da função são ambos numéricos, o relacionamento entre os dois é expresso por uma fórmula e o valor da função é obtido através da substituição direta dos argumentos. • Exemplo: Dada a definição: f(x) = x*x, se x = 2, então: f(x) = x*x f(2) = 2*2 f(2) = 4 Perceba o conceito de determinismo aplicado, já que sempre que x for 2 o resultado será 4.
Funções e Programação Funcional Programação Funcional • A programação funcional baseia-se no conceito de função e consiste basicamente na avaliação de expressões, que resolvem um problema específico, parte de um problema maior. • A função sempre e só devolve um valor. • Somente os parâmetros influenciam no valor de uma função. • Geralmente os códigos gerados em uma linguagem funcional é de ótima compreensão. O que é Avaliação de Expressão? É quando o interpretador tenta “resolver a conta”. A expressão é analisada em todos os aspectos e depois os parâmetros reais são usados para produzir um retorno/resultado da conta. dobro x = x^2 dobro 5 Exemplo de expressão em Haskell Parâmetro formal Definição da Função Parâmetro real Expressão
Funções e Programação Funcional Programação Funcional • As funções possuem: Um protótipo, que inclui os parâmetros, O corpo, que contém a função a ser analisada e O retorno, que será exibido ou passado a uma função chamadora. module Fatorial where fatorial ::Integer -> Integer fatorial 0 = 1 fatorial n | n > 0 = n * fatorial (n-1) Exemplo em Haskell de Fatorial
Funções e ProgramaçãoFuncional. Haskell: Origem e Paradigmas O interpretador Hugs ConceitosdaLinguagem
Haskell: Origem e Paradigmas Era uma vez... Haskell! • É enorme a potencialidade da avaliação preguiçosa em computadores através de linguagens funcionais, e esse conceito foi aplicado primeiramente em Miranda (que não era de domínio público), em 1985. Muitos entusiastas começaram a criar suas versões dessa linguagem. • Em setembro 1987 foi realizada uma conferência Functional Programming LanguagesandComputerArchitecture (FPCA '87), em Oregon. E ali criou-se um comitê com o objetivo de construir um padrão aberto para aquelas já várias linguagens. Isso consolidaria as linguagens existentes, servindo como base para pesquisas futuras no desenvolvimento de linguagens. • O objetivo era que a linguagem fosse de fácil ensino, deveria ser completamente descrita através de uma sintaxe e semântica formal e deveria estar disponível livremente. • A linguagem recebeu então o nome do matemático Haskell Curry já que seus estudos colaboraram efetivamente no projeto da linguagem.
Haskell: Origem e Paradigmas Avaliação Preguiçosa Mas o que é Avaliação Preguiçosa? Em resumo, a avaliação preguiçosa é uma técnica de otimização usada em programação funcional para atrasar a computação até um ponto em que o resultado da computação é considerado suficiente.
Haskell: Origem e Paradigmas Avaliação Preguiçosa • Na Avaliação Preguiçosa os argumentos de funções são avaliados somente quando necessário. Na função ao lado, por exemplo, se como x passássemos (21 + 33) * 8 não haveria necessidade de perder tempo avaliando a função, já que o retorno será sempre 7, independente do argumento. f(x) = 7 f((21+33)*8) = 7 O interpretador nem verificará ou calculará o parâmetro real, já que independente da entrada, o resultado é sempre 7. Exemplo de avaliação preguiçosa em Haskell
Haskell: Origem e Paradigmas Avaliação Preguiçosa Então é isso, Haskell além de simples ainda evita problemas. Por que então a gente ainda usa C? Porque Haskell não é tão adequada na programação de sistemas operacionais e drivers. Nas linguagens imperativas, como C,é comum a Programação Orientada a Improvisos Técnicos (POIT) para conseguir maior performance em uma determinada ocasião, o que não ocorre em Haskell.
Haskell: Origem e Paradigmas Era uma vez... Haskell! Logo do Haskell • Assim surge o Haskell! • Sua primeira versão foi definida em 1º de abril de 1990. • Seu último padrão semioficial é o Haskell 98. • A partir de 2006 começou o processo de definição do sucessor do Haskell 98, conhecido informalmente por Haskell Prime. • Influenciada pela linguagem Miranda e ML, Haskell difere por ser Funcional Pura.
Haskell: Origem e Paradigmas Interpretado ou Compilado • Haskell pode ser tanto interpretado quanto compilado. • O interpretador mais famoso é o Hugs, que será estudado mais a frente. • O compilador, e interpretador, Haskell é o TheGloriousGlasgow Haskell Compilation System, mais conhecido como Glasgow Haskell Compiler ou GHC. Versões do Hugs estão disponíveis para diversas plataformas, incluindo Windows, Unix, Mac OS X e Linux.
Haskell: Origem e Paradigmas Haskell é Fortemente Tipado • Em Haskell, conhecendo-se o tipo de operações e funções que compõe uma expressão é possível determinar o tipo do valor do resultado. Em linguagens de programação isto é equivalente a dizer que a linguagem é fortemente tipada. • Os tipos em Haskell são elementares ou estruturados. • Os elementares são os tipos: numérico (inteiro e real), lógicos e os caracteres. • Todo compilador/interpretador deve ser capaz de executar as operações básicas dos tipos primitivos.
Haskell: Origem e Paradigmas Haskell: Modular, Recursivo e Casa Padrões • Haskell é modular, ou seja, o desenvolvimento das funções é feito através de módulos. Em todo código fonte em Haskell, a primeira linha deve conter o nome do módulo iniciado com a letra maiúscula. Assim, através de “importações”, é possível reutilização de código. • Há também suporte a funções recursivas, ou seja, uma função é capaz de usar uma nova instância de si mesma para obtenção de dados. • O casamento de padrões verifica a presença de um padrão em um conjunto de dados. Em Haskell, por exemplo, quando definido um f 0 = 1, sempre que a função f for chamada com o parâmetro real 0 o retorno será 1.
Funções e ProgramaçãoFuncional. Haskell: Origem e Paradigmas O interpretador Hugs ConceitosdaLinguagem
O interpretador Hugs Hugs> :Origem • Em setembro de 1991, Mark Jones lançou um interpretador chamado Gofer, que era usado para um dialeto do Haskell de mesmo nome. • Em um dado momento, Mark Jones viu que o interpretador seria ótimo também para uso com Haskell. E então, no Dia dos Namorados de 1995 , Mark lançou Hugs (User'sGofer Haskell System, Sistema Haskell para usuário Gofer ou "Abraços", em português). • A última versão, Hugs 98, foi lançado em Janeiro de 1999. Mark manteve o projeto até Janeiro de 2000 .
O interpretador Hugs Por que usar Hugs? • O Hugs pretende ser uma aplicação bastante leve e portátil. • Ele é ideal para o início da aprendizagem em Haskell. • Em seu modo normal executa linha a linha. • Oferece várias ferramentas para execução ágil de Haskell. • Também dispõe de uma simples biblioteca gráfica.
O interpretador Hugs Hugs: Como Funciona Ler expressão • O interpretador Hugs funciona seguindo a ordem: • Assim sua principal funcionalidade é escrever expressões e solicitar ao sistema que as avalie. Entretanto podemos ousar mais e usar o ambiente para descrever novas funções a partir das primitivas, funções já oferecidas por padrão. Retornar valor encontrado Avaliar expressão
O interpretador Hugs Comandos do Hugs • A maioria dos comandos começam com : (dois pontos) • Os mais utilizados são: :loadarquivo >> carrega o arquivo Haskell arquivo.hs :reload >> repete o último comando load. :editarquivo.hs >> edita o arquivo no editor de texto padrão do sistema. :typeexpressao >> retorna o tipo da expressão. :infofuncao >> retorna informações sobre a função. :findfuncao >> abre o editor de textos no arquivo onde está a função :quit >> sai do sistema :? >> retorna uma lista dos comandos Hugs.
O interpretador Hugs Comandos do Hugs -> :iload • Todo arquivo contendo funções em Haskell deve ser salvo com a extensão .hs. • A função :loadserve para carregar esses arquivos .hs do disco. • Exemplo: Criei um arquivo chamado novo.hs Em novo.hs havia a seguinte função: • par x = (mod x 2) == 0 • Enfim, a função par não é padrão Hugs, antes de carregar o arquivo ela não estará disponível. Essa função (também conhecida como definição) nos diz que x só fará parte de par se o mod (uma função primitiva do tipo Inteiro que retorna o resto da divisão) de x por 2 for igual a zero.
O interpretador Hugs Comandos do Hugs -> :iload • Perceba que antes da chamada :load, a função par não era reconhecida pelo Hugs
O interpretador Hugs Comandos do Hugs -> :type e :info • Como previsto, a função :typeexibe o tipo da função par, no caso Bool (booleana). • A função :info, também como esperado, exibiu o protótipo da função. • A principal diferença entre :typee :infoé que :type exibirá o tipo da expressão, tanto a de um arquivo Haskell, quanto de uma expressão indicada no próprio Hugs. Já :infoexibe somente funções de um arquivo já carregado.
Funções e ProgramaçãoFuncional. Haskell: Origem e Paradigmas O interpretador Hugs ConceitosdaLinguagem
Conceitos da Linguagem Currying • Em Haskell, uma função de dois ou mais argumentos pode aceitá-los um de cada vez. Isto se chama curryng. Por exemplo: soma :: Int -> Int -> Int soma x y = x+y Essa função pega dois números inteiros como argumento e os soma. • Já que a avaliação um a cada vez, podemos criar uma nova definição, em que o parâmetro y esteja já definido, como na função incrementa: incrementa :: Int -> Int incrementa = soma 1 A função incrementa precisa receber somente o valor de x, y já será 1.
Conceitos da Linguagem Interpretando com o Hugs • Vamos testar a função soma e incrementa? • Em um arquivo de texto TesteIncremento.hs coloque o seguinte código: module TesteIncrementowhere --Prototipação: soma :: Int -> Int -> Int incrementa :: Int -> Int --Definições: soma x y = x+y incrementa = soma 1
Conceitos da Linguagem Abstração • Suponha que desejamos determinar a hipotenusa de um triângulo retângulo com catetos 10 e 4. Como conhecemos o teorema de Pitágoras (a2 = b2 + c2), podemos usar diretamente o Hugs para avaliar a seguinte expressão onde b seja 10 e c seja 4. > sqrt ((10.0 * 10.0)+ (4.0 * 4.0)) 10.7703 • A expressão que codificamos serve apenas para esta vez. Se em algum outro instante precisarmos avaliá-la, teremos que codificá-la novamente. Para evitar isso, é que damos nomes às nossas expressões, para que possamos usá-las repetidamente, apenas referenciando-as pelo seu nome. No caso acima, poderíamos escrever a definição: hipotenusaDe10e4 = sqrt ((10.0 * 10.0)+ (4.0 * 4.0)) • De posse dessa definição nossa máquina poderá avaliar a expressão sempre que dela precisarmos. Basta escrevê-la: > hipotenusaDe10e4 10.7703
Conceitos da Linguagem Generalização • Quando uma abstração se aplica a vários valores podemos generalizá-la. Assim, além de usá-la várias vezes para os mesmos valores, podemos também usá-la para valores diferentes. Esta ultima alternativa evidentemente facilita o seu reuso. • Há duas formas para fazer isso: • a) Elaborando a definição usando outras definições constantes. Por exemplo, no caso da definição acima para a hipotenusa, poderíamos escrever as definições a seguir: b = 10.0 c = 4.0 hipotenusa = sqrt (( b * b) + ( c * c)) • b) Uma forma mais geral é através do conceito de parametrização. Para o exemplo que estamos trabalhando, podemos escrever: hipotenusa b c = sqrt (( b * b) + ( c * c))
Conceitos da Linguagem Instanciação e Modularização • Quando temos uma generalização parametrizada, uma chamada dessa função é o conceito de Instanciação. Por exemplo, ao chamar a função hipotenusa passando os valores 2 e 3 temos aí uma instância da função. • Em geral, nossos problemas não serão tão simples e diretos quanto o exemplo acima. Quando nos deparamos com problemas maiores, um bom princípio é: • Divida para facilitar a conquista, modularize! • Basicamente modularizar consiste em quebrar o problema inicial em problemas menores, elaborar a solução para cada um dos problemas menores e depois combiná-las para obter a solução do problema inicial.
Conceitos da Linguagem Tipos de Dados • Haskell consegue determinar o tipo do valor de saída de uma expressão, isso a caracteriza como uma linguagem fortemente tipada. • Os tipos de dados primitivos são: • Inteiros (Int) • Booleanos (Bool) • Caracteres (Char) • Números de ponto flutuante (Float) • Todos os interpretadores Haskell são capazes, por padrão, de executar todas as manipulações desses tipos.
Sites e documentos pesquisados http://www.inf.ufrgs.br/gppd/disc/cmp134/trabs/T1/991/ProgFunc/pf.html http://www.marcosrodrigues6.hpg.ig.com.br/cap2.htm http://www.inf.ufsc.br/~barreto/trabaluno/pfcaetan.pdf http://pt.wikipedia.org/wiki/Haskell_(linguagem_de_programa%C3%A7%C3%A3o) http://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_funcional http://www.macs.hw.ac.uk/~dubois/ProgramacaoHaskell.pdf http://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_imperativa http://www.ebah.com.br/programacao-funcional-e-a-linguagem-haskell-pdf-a33896.html “Faça o que puder e espere pelo melhor.”