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

O Paradigma Funcional de Programao

Programao Funcional
Lic. Matemtica e Cincias da Computao

Um programa um conjunto de definies. Uma definio associa um nome a um valor.

Programar definir estruturas de dados e funes para resolver um dado problema.


O interpretador (da linguagem funcional) actua como uma mquina de calcular:

2005 / 2006

l uma expresso, calcula o seu valor e mostra o resultado


Exemplo:

Um programa para converter valores de temperaturas em graus Celcius para graus Farenheit, e de graus Kelvin para graus Celcius. celFar c = c * 1.8 + 32 kelCel k = k - 273

Maria Joo Frade

( mjf@di.uminho.pt )

Departamento de Informtica Universidade do Minho

Depois de carregar este programa no interpretador Haskell, podemos fazer os seguintes testes:

> celFar 25 77.0 > kelCel 0 -273 >


3

Programa Resumido
Nesta disciplina estuda-se o paradigma funcional de programao, tendo por base a linguagem de programao Haskell. Programao funcional em Haskell. Conceitos fundamentais: expresses, tipos, reduo, funes e recursividade. Conceitos avanados: funes de ordem superior, polimorfismo, tipos indutivos, classes, modularidade e monades.

A um conjunto de associaes nome-valor d-se o nome de ambiente ou contexto (ou programa). As expresses so calculadas no mbito de um contexto e podem conter ocorrncias dos nomes definidos nesse contexto. O interpretador usa as definies que tem no contexto (programa) como regras de clculo, para simplificar (calcular) o valor de uma expresso. Exemplo:

celFar c = c * 1.8 + 32 kelCel k = k - 273 kelFar k = celFar (kelCel k)

> kelFar 300 80.6

kelFar 300

celFar (kelCel 300) (kelCel 300) * 1.8 + 32 (300 273) * 1.8 + 32 27 * 1.8 + 32 80.6

Estruturas de dados e algoritmos. Tipos abstractos de dados.


calculado pelas regras establecidas pelas definies fornecidas pelo programa.
2

Transparncia Referencial
No paradigma funcional, as expresses: so a representao concreta da informao; podem ser associadas a nomes (definies); denotam valores que so determinados pelo interpretador da linguagem. No mbito de um dado contexto, todos os nomes que ocorrem numa expresso tm um valor nico e imotvel. O valor de uma expresso depende unicamente dos valores das sub-expresses que a constituem, e essas podem ser substituidas por outras que possuam o mesmo valor. A esta caracteristica d-se o nome de transparncia referencial.

Um pouco de histria ...


1960s Lisp (untyped, not pure) 1970s ML (strongly typed, type inference, polymorphism)

1980s Miranda (strongly typed, type inference, polymorphism, lazy evaluation) 1990s Haskell (strongly typed, type inference, polymorphism, lazy evaluation, ad-hoc polymorphism, monadic IO)

Linguagens Funcionais
O nome de linguagens funcionais advm do facto de estas terem como operaes bsicas a definio de funes e a aplicao de funes.

Haskell
O Haskell uma linguagem puramente funcional, fortemente tipada, e com um sistema de tipos extremamente evoluido. A linguagem usada neste curso o Haskell 98. Exemplos de interpretadores e um compilador para a linguagem Haskell 98:

Nas linguagens funcionais as funes so entidades de 1 classe, isto , podem ser usadas como qualquer outro objecto: passadas como parmetro, devolvidas como resultado, ou mesmo armazenadas em estruturas de dados. Isto d s linguagens funcionais uma grande flexibilidade, capacidade de abstrao e modularizao do processamento de dados. As linguagens funcionais fornecem um alto nivel de abstrao, o que faz com que os programas funcionais sejam mais concisos, mais fceis de entender / manter e mais rpidos de desenvolver do que programas imperativos. No entanto, em certas situaes, os programas funcionias podem ser mais penalizadores em termos de eficincia.

Hugs Haskell User's Gofer System GHC Glasgow Haskell Compiler ( o que vamos usar ...)

www.haskell.org
6 8

Tipos

Haskell
Haskell is a general purpose, purely functional programming language incorporating many recent innovations in programming language design. Haskell provides higher-order functions, non-strict semantics, static polymorphic typing, user-defined algebraic datatypes, patternmatching, list comprehensions, a module system, a monadic I/O system, and a rich set of primitive datatypes, including lists, arrays, arbitrary and fixed precision integers, and floatingpoint numbers. Haskell is both the culmination and solidification of many years of research on lazy functional languages. (The Haskell 98 Report)

Os tipos servem para classificar entidades (de acordo con as suas caracteristicas). Em Haskell toda a expresso tem um tipo.

e :: T
Exemplos: 58 'a' [3,5,7] (8,'b') :: :: :: ::

significa que a expresso

e tem tipo T
do tipo

Int Char [Int] (Int,Char)

Inteiro Caracter Lista de inteiros Par com um inteiro e um caracter

Em Haskell, a verificao de tipos feita durante a compilao. O Haskell uma linguagem fortemente tipada, com um sistema de tipos muito evoludo (como veremos).
9 11

Valores & Expresses


Os valores so as entidades bsicas da linguagem Haskell. So os elementos atmicos. As expresses so obtidas aplicando funes a valores ou a outras expresses. O interpretador Haskell actua como uma calculadora ( read - evaluate - print loop ):

Tipos Bsicos
Bool Char Int Boleanos: Caracteres: True, False 'a', 'b', 'A', '1', '\n', '2', ... 1, -3, 234345, ... 2, -7, 75756850013434682, ... 3.5, -6.53422, 51.2E7, 3e4, ...

l uma expresso, calcula o seu valor e mostra o resultado. Exemplos:


> 5 5 + 6.7

Inteiros de tamanho limitado:

Integer Inteiros de tamanho ilimitado: Float Double () Nmeros de vrgula flutuante:

> 3.5 10.2

> 2 < 35 True > not True False > not ((3.5+6.7) > 23) True

Nm. vrg. flut. de dupla preciso: 3.5, -6.5342, 51.2E7, ... Unit () o seu nico elemento do tipo Unit.

10

12

Tipos Compostos
Produtos Cartesianos (T1,T2, ...,Tn)
(T1,T2,...,Tn) o tipo dos tuplos com o 1 elemento do tipo T1, 2 elemento do tipo T2, etc. Exemplos:
(1,5) :: (Int,Int) ('a',6,True) :: (Char,Int,Bool)

Definies
Uma definio associa um nome a uma expresso. nome = expresso nome tem que ser uma palavra comeada por letra minscula. A definio de funes pode ainda ser feita por um conjunto de equaes da forma: nome arg1 arg2 ... argn = expresso Quando se define uma funo podemos incluir informao sobre o seu tipo. No entanto, essa informao no obrigatria.
Exemplos: pi = 3.1415 areaCirc x = pi * x * x areaQuad = \x -> x*x areaTri b a = (b*a)/2 volCubo :: Float -> Float volCubo y = y * y * y

Listas [T]
[T] o tipo da listas cujos elementos so todos do tipo T. Exemplos: [2,5,6,8] :: [Integer] ['h','a','s'] :: [Char] [3.5,86.343,1.2] :: [Float]

Funes T1 -> T2
T1 -> T2 o tipo das funes que recebem valores do tipo T1 e devolvem valores do tipo T2. Exemplos: not :: Bool -> Bool ord :: Char -> Int
13

15

Funes
A operao mais importante das funes a sua aplicao. Se f :: T1 -> T2 e a :: T1 ento f a :: T2

Plimorfismo
O tipo de cada funo inferido automticamente pelo interpretador.
Exemplo:

Exemplos:

> not True False :: Bool > ord 'a' 97 ::Int > ord 'A' 65 :: Int > chr 97 'a' :: Char

Para a funo g definida por: Preservao de Tipos


O tipo das expresso preservado ao longo do processo de clculo.

g x = not (65 > ord x)

O tipo inferido

g :: Char -> Bool

Porqu ?

Qual ser o tipo de chr ?

Mas, h funes s quais possvel associar mais do que um tipo concreto.


Exemplos:

id x = x nl y = '\n'

Novas definies de funes devero que ser escritas num ficheiro, que depois ser carregado no interpretador.

Qual ser o tipo destas funes ?

14

16

O problema resolvido recorrendo a variveis de tipo. Uma varivel de tipo representa um tipo qualquer. id :: a -> a nl :: a -> Char Em Haskell: As variveis de tipo representam-se por nomes comeados por letras minsculas
(normalmente a, b, c, ...).

O Haskell tem um enorme conjunto de definies (que est no mdulo Prelude) que carregado por defeito e que constitui a base da linguagem Haskell. Alguns operadores: Lgicos: && (e), || (ou), not (negao)

Numricos:

+, -, *, / (diviso de reais), ^ (exponenciao com inteiros), div (diviso inteira), mod (resto da diviso inteira), ** (exponenciaes com reais), log, sin, cos, tan, ...

Os tipos concretos usam nomes comeados por letras maisculas (ex: Bool, Int, ...). Quando as funes so usadas, as variveis de tipos so substitudas pelos tipos concretos adquados.
Exemplos:

Relacionais: == (igualdade), /= (desigualdade), <, <=, >, >= Condicional: if ... then ... else ... :: Bool Exemplo: :: a
> if (3>=5) then [1,2,3] else [3,4] [3,4] > if (ord 'A' == 65) then 2 else 3 2
19

id id nl nl

True 'a' False (volCubo 3.2)

id id nl nl

:: :: :: ::

Bool -> Bool Char ->Char Bool -> Char Float -> Char
17

Funes cujos tipos tm variveis de tipo so chamadas funes polimrficas. Um tipo pode conter diferentes variveis de tipo.
Exemplo: fst (x,y) = x fst :: (a,b) -> a

Mdulos
Um programa Haskell est organizado em mdulos. Cada mdulo uma coleco de funes e tipos de dados, definidos num ambiente fechado. Um mdulo pode exportar todas ou s algumas das suas definies. (...)

module Nome (nomes_a_exportar) where ... definies ...

Inferncia de tipos O tipo de cada funo inferido automticamente. O Haskell infere o tipo mais preciso de qualquer expresso.

Ao arrancar o interpretador do GHC, ghci, este carrega o mdulo Prelude (que contm um enorme conjunto de declaraes) e fica espera dos pedidos do utilizador.

possivel associar a uma funo um tipo mais especifico do que o tipo inferido automticamente.
Exemplo: seg :: (Bool,Int) -> Int seg (x,y) = y

ghci
___ ___ _ / _ \ /\ /\/ __(_) / /_\// /_/ / / | | / /_\\/ __ / /___| | \____/\/ /_/\____/|_| GHC Interactive, version 6.2.1, for Haskell 98. http://www.haskell.org/ghc/ Type :? for help.

Loading package base ... linking ... done. Prelude> 18 20

O utilizador pode fazer dois tipos de pedidos ao interpretador ghci: Calcular o valor de uma expresso. Prelude> 3+5 8 Prelude> (5>=7) || (3^2 == 9) True Prelude> fst (40/2,'A') 20.0 Prelude> pi 3.141592653589793 Prelude> aaa <interactive>:1: Variable not in scope: `aaa' Prelude> Executar um comando. Os comandos do ghci comeam sempre por dois pontos ( : ). O comando :? lista todos os comandos existentes Prelude> :? Commands available from the prompt: ...
21 23

Depois de carregar um mdulo, os nomes definidos nesse mdulo passam a estar disponveis no ambiente de interpretao

Prelude> kelCel 300 <interactive>:1: Variable not in scope: `kelCel' Prelude> :load Temp Compiling Temp ( Temp.hs, interpreted ) Ok, modules loaded: Temp. *Temp> kelCel 300 27 *Temp>

Inicialmente, apenas as declaraes do mdulo Prelude esto no ambiente de interpretao. Aps o carregamento do ficheiro Temp.hs, ficam no ambiente todas a definies feitas no mdulo Temp e as definies do Prelude.

Alguns comandos teis: :quit ou :q :type ou :t termina a execuo do ghci. indica o tipo de uma expresso. Prelude> :type (2>5) (2>5) :: Bool Prelude> :t not not :: Bool -> Bool Prelude> :q Leaving GHCi.

Um mdulo constitui um componente de software e d a possibilidade de gerar bibliotecas de funes que podem ser reutilizadas em diversos programas Haskell. Exemplo: Muitas funes sobre caracteres esto definidas no mdulo Char do GHC. Para se utilizarem declaraes feitas noutros mdulos, que no o Prelude, necessrio primeiro fazer a sua importao atravs da instruo:

import Nome_do_mdulo
:load ou :l Exemplo: carrega o programa (o mdulo) que est num dado ficheiro.

Exemplo.hs
module Exemplo where import Char letra :: Int -> Char letra n = if (n>=65 && n<=90) || (n>=97 && n<=122) then chr n else ' ' numero :: Int -> Char numero n = if (n>=48 && n<=57) then chr n else ' '
22 24

Considere o seguinte programa guardado no ficheiro Temp.hs Temp.hs module Temp where celFar c = c * 1.8 + 32 kelCel k = k - 273 kelFar k = celFar (kelCel k)

Os programas em Haskell tm normalmente extenso .hs (de haskell script)

Comentrios
possvel colocar comentrios num programa Haskell de duas formas:

O tipo funo associa direita.


Isto , f :: T1 -> T2 -> ... -> Tn -> T

-{- ... -}

O texto que aparecer a seguir a -- at ao final da linha ignorado pelo interpretador. O texto que estiver entre {- e -} no avaliado pelo interpretador. Podem ser vrias linhas.

uma forma abreviada de escrever f :: T1 -> (T2 -> (... -> (Tn -> T)...))

module Temp where -- de Celcius para Farenheit celFar c = c * 1.8 + 32 -- de Kelvin para Celcius kelCel k = k - 273 -- de Kelvin para Farenheit kelFar k = celFar (kelCel k) {- dado valor da temperatura em Kelvin, retorna o triplo com o valor da temperatura em Kelvin, Celcius e Farenheit -} kelCelFar k = (k, kelCel k, kelFar k)
25

A aplicao de funes associativa esquerda.


Isto , f x1 x2 ... xn

uma forma abreviada de escrever (...((f x1) x2) ...) xn

27

As funes test e test' so muito parecidas mas h uma diferena essencial:

test (x,y) = [ (not x), (y || x), (x && y) ] test' x y = [ (not x), (y || x), (x && y) ]

Tm tipos diferentes !

Exerccio: Considere a seguinte declarao das funes fun1, fun2 e fun3.

A funo test recebe um nico argumento (que um par de booleanos) e devolve uma lista de booleanos. test :: (Bool,Bool) -> [Bool] > test (True,False) A funo test' recebe dois argumentos, cada um do tipo Bool, e devolve uma lista de booleanos. test' :: Bool -> Bool -> [Bool] > test' True False A funo test' recebe um valor de cada vez. Realmente, o seu tipo : test' :: Bool -> (Bool -> [Bool]) > (test' True) False Mas os parentesis podem ser dispensados ! 26
28

fun1 (x,y) = (not x) || y fun2 a b = (a||b, a&&b) fun3 x y z = x && y && z

Qual ser o tipo de cada uma destas funes ? D exemplos da sua invocao.

Lista e String
[a]
o tipo das listas cujos elementos so todos do tipo a . [2,5,6,8] [(1+3,'c'),(8,'A'),(4,'d')] [3.5, 86.343, 1.2*5] ['O','l','a'] :: :: :: :: [Integer] [(Int,Char)] [Float] [Char]

Funes sobre String definidas no Prelude. Prelude.


words :: String -> [String] d a lista de palavras de um texto.

Exemplos:

unwords :: [String] -> String constri um texto a partir de uma lista de palavras. lines :: String -> [String] d a lista de linhas de um texto (i.e. parte pelo '\n' ).

['A', 4, 3, 'C'] [(1,5), 9, (6,7)]

No so listas bem formadas, porque os seus elementos no tm todos o mesmo tipo !

Exemplos:
Prelude> words "aaaa bbbb cccc\tddddd eeee\nffff gggg hhhh" ["aaaa","bbbb","cccc","ddddd","eeee","ffff","gggg","hhhh"] Prelude> unwords ["aaaa","bbbb","cccc","ddddd","eeee","ffff","gggg","hhhh"] "aaaa bbbb cccc ddddd eeee ffff gggg hhhh" Prelude> lines "aaaa bbbb cccc\tddddd eeee\nffff ["aaaa bbbb cccc\tddddd eeee","ffff gggg hhhh"] Prelude> reverse "programacao funcional" "lanoicnuf oacamargorp" 29 31 gggg hhhh"

String
Exemplo:

O Haskell tem pr-definido o tipo String como sendo [Char]. .

Os valores do tipo String tambm se escrevem de forma abreviada entre haskell > Ola True

equivalente a ['h','a','s','k','e','l','l'] == ['O','l','a']

Algumas funes sobre listas definidas no Prelude. Prelude.


head :: [a] -> a tail :: [a] -> [a]

Listas por Compreenso


Inspirada na forma de definir conjuntos por compreenso em linguagem matemtica, a linguagem Haskell tem tambm mecanismos para definir listas por compreenso.

calcula o primeiro elemento da lista. calcula a lista sem o primeiro elemento. d um segmento inicial de uma lista. d um segmento final de uma lista.

take :: Int -> [a] -> [a] drop :: Int -> [a] -> [a] reverse :: [a] -> [a] last :: [a] -> a Exemplos:
Prelude> head [3,4,5,6,7,8,9]

{ 2x | x {n|n

{10,3,7,2} } {9,8,-2,-10,3} 0

[ 2*x | x <- [10,3,7,2] ] = [20,6,14,4]

n+2

10 }
= [8,-2,3]

calcula a lista invertida.

[ n | n <- [9,8,-2,-10,3] , 0<=n+2, n+2<=10 ]

calcula o ltimo elemento da lista.

{4,7, ... , 19}


Prelude> drop 3 [3,4,5,6,7,8,9]

[4,7..19] = [4,7,10,13,16,19] [1..7] = [1,2,3,4,5,6,7]

3
Prelude> tail ['a','b','c','d']

['b','c','d'] Prelude> take 3 [3,4,5,6,7,8,9] [3,4,5]

[6,7,8,9] Prelude> reverse [3,4,5,6,7,8,9] [9,8,7,6,5,4,3] Prelude> last ['a','b','c','d'] 'd'


30

{ (x,y) | x {3,4,5}

y {9,10} }

[ (x,y) | x <- [3,4,5], y <- [9,10] ] = [(3,9),(3,10),(4,9),(4,10),(5,9),(5,10)]


32

Listas infinitas
{5,10, ... } { x | x
[5,10..] = [5,10,15,20,25,30,35,40,45,50,55,...

Padres (patterns)
Um padro uma varivel, uma constante, ou um esquema de um valor atmico (isto , o resultado de aplicar construtores bsicos dos valores a outros padres). No Haskell, um padro no pode ter variveis repetidas (padres lineares). Exemplos: = [0,8,46,216,...

par(x) }
[ x^3 | x <- [0..], even x ]

Padres x True 4 (x,y,(True,b)) ('A',False,x) [x,'a',y]

Tipos a Bool Int (a,b,(Bool,c)) (Char,Bool,a) [Char]

No padres [x,'a',1] (4*6, y) Porqu ?

Mais exemplos:
Prelude> ['A'..'Z']

"ABCDEFGHIJKLMNOPQRSTUVWXYZ" Prelude> ['A','C'..'X'] "ACEGIKMOQSUW" Prelude> [50,45..(-20)] [50,45,40,35,30,25,20,15,10,5,0,-5,-10,-15,-20] Prelude> drop 20 ['a'..'z'] "uvwxyz" Prelude> take 10 [3,3..] [3,3,3,3,3,3,3,3,3,3]
33

Quando no nos interessa dar nome a uma varivel, podemos usar _ que representa uma varivel annima nova. Exemplos: snd (_,x) = x segundo (_,y,_) = y
35

Equaes e Funes
Uma funo pode ser definida por equaes que relacionam os seus argumentos com o resultado pretendido. Exemplos:

Exemplos:

soma :: (Int,Int) -> Int -> (Int,Int) soma (x,y) z = (x+z, y+z)

triplo x = 3 * x dobro y = y + y perimCirc r = 2*pi*r perimTri x y z = x+y+z minimo x y = if x>y them y else x

outro modo seria


soma w z = ((fst w)+z, (snd w)+z)

Qual mais legvel ?


exemplo :: (Bool,Float) -> ((Float,Int), Float) -> Float exemplo (True,y) ((x,_),w) = y*x + w exemplo (False,y) _ = y em alternativa, poderiamos ter exemplo a b = if (fst a) then (snd a)*(fst (fst b)) + (snd b) else (snd a)

As equaes definem regras de clculo para as funes que esto a ser definidas. nome arg1 arg2 ... argn = expresso
Nome da funo (iniciada por letra minscula). Argumentos da funo. Cada argumento um padro.
(cada varivel no pode ocorrer mais do que uma vez)

O tipo da funo inferido tendo por base que ambos os lados da equao tm que ter o mesmo tipo.
34 36

Reduo
O clculo do valor de uma expresso feito usando as equaes que definem as funes como regras de clculo. Uma reduo um passo do processo de clculo ( usual usar o smbolo
denotar esse paso)

Lazy Evaluation (call-by-name)


dobro (triplo (snd (9,8)))

(triplo (snd (9,8)))+(triplo (snd (9,8))) (3*(snd (9,8))) + (triplo (snd (9,8))) (3*(snd (9,8))) + (3*(snd (9,8))) (3*8) + (3*(snd (9,8))) 24 + (3*(snd (9,8))) 24 + (3*8) 24 + 24 48

Cada reduo resulta de substituir a instncia do lado esquerdo da equao (o redex) pelo respectivo lado direito (o contractum). Exemplos: Relembre as seguintes funes triplo x = 3 * x dobro y = y + y snd (_,x) = x nl x = '\n' 21

Com a estrategia lazy os parametros das funes s so calculados se o seu valor fr mesmo necessrio. nl (triplo (dobro (7*45)) '\n'

Exemplos:

triplo 7

3*7

A instncia de (triplo x) resulta da substituio [7/x]. snd (9,8)

A lazy evaluation faz do Haskell uma linguagem no estrita. Esto , uma funo aplicada a um valor indefinido pode ter em Haskell um valor bem definido. nl (3/0) '\n'

A instncia de snd (_,x) resulta da substituio [9/_,8/x].


37

A lazy evaluation tambm vai permitir ao Haskell lidar com estruturas de dados infinitas.
39

Podemos definir uma funo recorrendo a vrias equaes. A expresso dobro (triplo (snd (9,8))) pode reduzir de trs formas distintas:
dobro (triplo (snd (9,8))) dobro (triplo (snd (9,8))) dobro (triplo (snd (9,8))) dobro (triplo 8) dobro (3*(snd (9,8))) (triplo (snd (9,8)))+(triplo (snd (9,8)))

Exemplo:

h h h h

:: (Char,Int) -> Int ('a',x) = 3*x ('b',x) = x+x (_,x) = x

Todas as equaes tm que ser bem tipadas e de tipos coincidentes. Cada equao usada como regra de reduo. Quando uma funo aplicada a um argumento, a equao que selecionada como regra de reduo a 1 equao (a contar de cima) cujo padro que tem como argumento concorda com o argumento actual (pattern matching). Exemplos: h ('a',5) h ('b',4) h ('B',9) 3*5 4+4 9 15 8

A estratgia de reduo usada para o clculo das expresses uma caracterstica essencial de uma linguagem funcional. O Haskell usa a estratgia lazy evaluation (call-by-name), que se caracteriza por escolher para reduzir sempre o redex mais externo. Se houver vrios redexes ao mesmo nvel escolhe o redex mais esquerda (outermost; leftmost). Uma outra estratgia de reduo conhecida a eager evaluation (call-by-value), que se caracteriza por escolher para reduzir sempre o redex mais interno. Se houver vrios redexes ao mesmo nvel escolhe o redex mais esquerda (innermost; leftmost).

Note: Podem existir vrias equaes com padres que concordam com o argumento
actual. Por isso, a ordem das equaes importante, pois define uma prioridade na escolha da regra de reduo. O que acontece se alterar a ordem das equaes que definem h ?
38 40

Funes Totais & Funes Parciais


Uma funo diz-se total se est definida para todo o valor do seu domnio. Uma funo diz-se parcial se h valores do seu domnio para os quais ela no est definida (isto , no capaz de produzir um resultado no conjunto de chegada). Exemplos: conjuga :: (Bool,Bool) -> Bool conjuga (True,True) = True conjuga (x,y) = False

Definies Locais
Uma definio associa um nome a uma expresso. Todas as definies feitas at aqui podem ser vistas como globais, uma vez que elas so visveis no mdulo do programa aonde esto. Mas, muitas vezes til reduzir o mbito de uma declarao. Em Haskell h duas formas de fazer definies locais: utilizando expresses let ... in ou atravs de clusulas where junto da definio equacional de funes.

Funo total

Exemplos: let c = 10 (a,b) = (3*c, f 2) f x = x + 7*c in f a + f b

Porqu ?
> testa 5 320 > c Variable not in scope: `c' > f a Variable not in scope: `f' Variable not in scope: `a'

parc :: (Bool,Bool) -> Bool parc (True,False) = False parc (True,x) = True

242

Funo parcial

Porqu ?

testa y = 3 + f y + f a + f b where c = 10 (a,b) = (3*c, f 2) f x = x + 7*c

As declaraes locais podem ser de funes e de identificadores (fazendo uso de padres).


41 43

Tipos Simnimos
O Haskell pode renomear tipos atravs de declaraes da forma:

Layout
Ao contrrio de quase todas as linguagens de programao, o Haskell no necessita de marcas para delimitar as diversas declaraes que constituem um programa. Em Haskell a identao do texto (isto , a forma como o texto de uma definio est disposto), tem um significado bem preciso. Regras fundamentais: 1. Se uma linha comea mais frente do que comeou a linha anterior, ento ela deve ser considerada como a continuao da linha anterior. Se uma linha comea na mesma coluna que a anterior, ento elas so consideradas definies independentes. Se uma linha comea mais atrs do que a anterior, ento essa linha no pretence mesma lista de definies. definies do mesmo gnero devem comear na mesma coluna exemplo :: Float -> Float -> Float exemplo x 0 = x exemplo x y = let a = x*y b = if (x>=y) then x/y else y*x c = a-b in (a+b)*c

type Nome p1 ... pn = tipo


parmetros (variveis de tipo) Exemplos: type Ponto = (Float,Float) type ListaAssoc a b = [(a,b)]

2. 3. Ou seja:

Note que no estamos a criar tipos novos, mas apenas nomes novos para tipos j existentes. Esses nomes devem contribuir para a compreenso do programa. Exemplo:

distOrigem :: Ponto -> Float distOrigem (x,y) = sqrt (x^2 + y^2)

Exemplo:

O tipo String outro exemplo de um tipo sinnimo, definido no Prelude. type String = [Char]
42

44

Operadores
Operadores infixos como o + , * , && , ... , no so mais do que funes. Um operador infixo pode ser usado como uma funo vulgar (i.e., usando notao prefixa) se estiver entre parentesis. Exemplo: Note que

Funes com Guardas


Em Haskell possvel definir funes com alternativas usando guardas. Uma guarda uma expresso booleana. Se o seu valor for True a equao correspondente ser usada na reduo (seno tenta-se a seguinte). Exemplos: sig x y = if x > y then 1 else if x < y then -1 else 0 sig x y | x > y = 1 | x < y = -1 | x == y = 0

(+) 2 3

equivalente a

2+3

(+) :: Int -> Int -> Int

Podem-se definir novos operadores infixos. (+>) :: Float -> Float -> Float x +> y = x^2 + y

equivalente a

ou a
Funes binrias podem ser usadas como um operador infixo, colocando o seu nome entre ` `. Exemplo: mod :: Int -> Int -> Int 3 `mod` 2 equivalente a mod 3 2 sig x | | | y x > y = 1 x < y = -1 otherwise = 0

otherwise equivalente a True.


45 47

Cada operador tem uma prioridade e uma associatividade estipulada. Isto faz com que seja possvel evitar alguns parentesis. Exemplo: x + y + z x + 3 * y equivalente a equivalente a (x + y) + z x + (3 * y)

Exemplo:

Raizes reais do polinmio

a x + b x + c

A aplicao de funes tem prioridade mxima e associativa esquerda. Exemplo: f x * y equivalente a (f x) * y

raizes :: (Double,Double,Double) -> (Double,Double) raizes (a,b,c) = (r1,r2) where r1 = (-b + r) / (2*a) r2 = (-b r) / (2*a) d = b^2 4*a*c r | d >= 0 = sqrt d | d < 0 = error raizes imaginarias error uma funo pr-definida que permite indicar a mensagem de erro devolvida pelo interpretador. Repare no seu tipo error :: String -> a
> raizes (2,10,3) (-0.320550528229663,-4.6794494717703365) > raizes (2,3,4) *** Exception: raizes imaginarias
46 48

possvel indicar a prioridade e a associatividade de novos operadores atravs de declaraes. infixl num op infixr num op infix num op

Listas
[T] o tipo das listas cujos elementos so todos do tipo T -- listas homogneas .
[3.5^2, 4*7.1, 9+0.5] :: [Float] [(253, Braga ), (22, Porto ), (21, Lisboa )] :: [(Int,String)] [[1,2,3], [1,4], [7,8,9]] :: [[Integer]]

Recorrncia
Como definir a funo que calcula o comprimento de uma lista ? Temos dois casos:
Se a lista fr vazia o seu comprimento zero. Se a lista no fr vazia o seu comprimento um mais o comprimento da cauda da lista.

Na realidade, as listas so construidas custa de dois construtores primitivos:

a lista vazia [] o construtor (:), que um operador infixo que dado um elemento x de tipo a [] :: [a] (:) :: a -> [a] -> [a]
[1,2,3] uma abreviatura de 1:(2:(3:[])) que igual a 1:2:3:[] porque (:) associativa direita. Portanto: [1,2,3] = 1:[2,3] = 1:2:[3] = 1:2:3:[]
49

length [] = 0 length (x:xs) = 1 + length xs Esta funo recursiva uma vez que se invoca a si prpria (aplicada cauda da lista). A funo termina uma vez que as invocaes recursivas so feitas sobre listas cada vez mais curtas, e vai chegar ao ponto em que a lista vazia. length [1,2,3] = length (1:[2,3]) 1 1 1 1 3 + + + + length [2,3] (1 + length [3]) (1 + (1 + length [])) (1 + (1 + 0))

e uma lista l de tipo [a], constroi uma nova lista com x na 1 posio seguida de l.

Em linguagens funcionais, a recorrncia a forma de obter ciclos.


51

Os padres do tipo lista so expresses envolvendo apenas os construtores : e [] (entre parentesis), ou a representao abreviada de listas. head (x:xs) = x tail (x:xs) = xs
> head [3,4,5,6] 3 > tail HASKELL ASKELL > head [] *** exception > null [3.4, 6.5, -5.5] False > soma3 [5,7] 13

Mais alguns exemplos de funes j definidas no mdulo Prelude:

Qual o tipo destas funes ? As funes so totais ou parciais?

sum [] = 0 sum (x:xs) = x + sum xs

Qual o tipo destas funes ? So totais ou parciais ?

null [] = True null (x:xs) = False

last [x] = x last (_:xs) = last xs

Podemos trocar a ordem das equaes ?

soma3 soma3 soma3 soma3 soma3

:: [Integer] -> Integer [] = 0 (x:y:z:t) = x+y+z (x:y:t) = x+y (x:t) = x

elem x [] = False elem x (y:ys) | x == y = True | otherwise = elem x ys

(++) :: [a] -> [a] -> [a] [] ++ l = l (x:xs) ++ l = x : (xs ++ l)

Em soma3 a ordem das equaes importante ? Porqu ?


50 52

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