Haskell/Variáveis e funções: diferenças entre revisões

[edição verificada][revisão pendente]
Conteúdo apagado Conteúdo adicionado
m <references/>
Primeira tradução de en:Haskell/Variables and functions
Linha 1:
''Todos os exemplos deste capítulo pode ser salvos num arquivo e executados usando o GHC. Não inclua "Prelude>" em nenhum dos exemplos. Quando este comando aparecer, quer dizer que o código seguinte foi rodado no GHCi. Quando não houver o comando, basta copiar o código inteiro.''
Os exemplos deste capítulos podem ser incluidos em um arquivo e carregados pelo interpretador através do comando :load <nome do arquivo>
 
== Variáveis ==
Em Haskell, as variáveis não variam. Ou seja, tecnicamente, são constantes. Ou, equivalentemente, não existem variáveis como nas outras linguagens de programação.
 
No capítulo passado, usamos o GHCi como uma calculadora, o que é tão prático apenas para contas curtas. Para grandes cálculos e para escrever um programa em Haskell, geralmente temos que acompanhar e verificar resultados intermediários.
Na prática, variáveis assumem um valor quando são criadas, e este valor não muda nunca.
 
Podemos fazer isso atribuindo nomes. Chamas as chamadas ''variáveis''. Quando um programa é executado, cada variável é substituída por um ''valor'' ao qual ela se refere. Por exemplo, considere o seguinte
Uma variável é definida na forma:
<pre>
Prelude> let x = 3.14159265358979323846264338327950
</pre>
 
{{HaskellGHCi|1=
Para ver o valor da variável, basta escrevê-la:
Prelude> 3.141592653 * 5^2
<pre>
78.539816325
Prelude> x
}}
3.141592653589793
</pre>
 
Este foi o cálculo aproximado da área de um círculo de raio <code>5</code>, de acordo com a fórmula <math>A = \pi r^2</math>. Claro que se torna um processo bastante trabalhoso escrever todos os dígitos de <math>\pi \approx 3,141592653</math>, ou mesmo lembrar os primeiros 5. Por isso, para evitar repetições podemos fazer com a máquina se lembre destes valores uma única vez para que possamos usá-los sempre que necessário. Essa abstração nos deixa livre para focar em outras partes mais importantes. No caso deste exemplo, Haskell já possui uma variável chamada <code>pi</code> que armazena mais de 15 dígitos de <math>\pi</math>, o que deixa o código mais claro e ainda ganhamos em precisão nos resultados.
== Tipos ==
 
{{HaskellGHCi|1=
Ao fazer uma declaração da forma ''let identificador = valor'', Haskell tentará "chutar" o '''tipo''' da variável. Assim, o fragmento de código seguinte dará erro:
Prelude> pi
<pre>
3.141592653589793
Prelude> let x = 1.5
Prelude> let ypi =* 5^2
78.53981633974483
Prelude> x * y
}}
</pre>
O motivo é que ''x'' é um ''Double'' e ''y'' é um ''Integer'', e não existe multiplicação de ''Double'' por ''Integer''. Se quisermos definir uma variável ''Double'' mas definí-la usando um valor inteiro, devemos fazer:
<pre>
Prelude> let z = 10 :: Double
</pre>
 
Perceba que a variável <code>pi</code> e seu valor, <code>3.141592653589793</code>, trocados entre si nos cálculos.
Os tipos básicos da linguagem incluem:
 
== Arquivos de código em Haskell ==
{| class="wikitable" style="font-size: 85%; width: 100%"
 
|-
Além de fazer cálculos esporadicamente no GHCi, você pode salvar seus códigos num arquivo Haskell, que são arquivos de texto com a extensão <tt>.hs</tt>. É recomendável usar um editor de texto próprio para programação (cf. [[w:Editor de texto|artigo da Wikipédia sobre editores de texto]]). A grande maioria deles possuem a capacidade ''realçar a sintaxe'', isto é, colorir o código fonte de modo a facilitar a leitura. Vim e Emacs são duas opções bastante populares entre programadores.
! Tipo de dado !! Descrição !! Classes !! Exemplo da sintaxe
 
|-
Para ajudar na organização, crie também um novo diretório (uma pasta de arquivos) em seu computador para salvar os arquivos Haskell que você cria quando estiver resolvendo os exercícios deste livro. Vamos lá, crie um diretório chamado <tt>HaskellWikibook</tt>, por exemplo, e dentro dele, um arquivo chamado <tt>Varfun.hs</tt> contendo o seguinte código:
| <code>Bool</code> || [[Enumeração]] de valores [[booleano]]s, que permitem certas operações lógicas, como [[conjunção lógica|conjunção]] (<code>&&</code>), [[disjunção lógica|disjunção]] (<code>&#124;&#124;</code>) e negação (<code>not</code>). || Read, Show, Eq, Ord, Enum, Bounded || <code>True</code><br /><code>False</code>
 
<source lang = "haskell">
r = 5.0
</source>
 
Este programa define a variável <code>r</code> como sendo o valor <code>5.0</code>.
 
Nota: certifique-se de que não há espaços em branco no começo das linhas, porque Haskell é sensível a espaços.
 
Depois abra um terminal no diretório <tt>HaskellWikibook</tt> que você criou, execute o GHCi e carregue o arquivo <tt>Varfun.hs</tt> usando o comando <code>:load</code>:
 
{{HaskellGHCi|1=
Prelude> :load Varfun.hs
[1 of 1] Compiling Main ( Varfun.hs, interpreted )
Ok, modules loaded: Main.
}}
 
É bom saber que <code>:load</code> pode ser abreviado para <code>:l</code>: <code>:l Varfun.hs</code>.
 
Se o GHCi retornar um erro como <code>Could not find module 'Varfun.hs'</code>, isso quer dizer que você provavelmente está no diretório errado. Tente o comando <code>:cd</code> para mudar o diretório corrente de dentro do GHCi (por exemplo, <code>:cd HaskellWikibook</code>).
 
Depois que o arquivo estiver carregado na sessão do GHCi, você vai ver a linha de comando mudar de "Prelude" para "*Main". Agora você pode usar a varíavel <code>r</code> que você definiu no arquivo.
 
{{HaskellGHCi|1=
*Main> r
5.0
*Main> pi * r^2
78.53981633974483
}}
 
Acabamos de calcular a área de um círculo de raio 5,0 usando a fórmula <math>\pi r^2</math>. O que aconteceu aqui é que usamos <code>r</code> que definimos no arquivo <tt>Varfun.hs</tt>, e <code>pi</code>, que já está definido em outro lugar.
 
Agora, vamos fazer esse valor ser mais fácil de ser acessado ao definirmos um nome para ele também. Abra o arquivo novamente e mude seu conteúdo para:
 
<source lang = "haskell">
r = 5.0
area = pi * r ^ 2
</source>
 
Salve-e e recarregue-o no GHCi usando <code>:reload</code>, ou simplesmente <code>:r</code>:
 
{{HaskellGHCi|1=
*Main> :reload
Compiling Main ( Varfun.hs, interpreted )
Ok, modules loaded: Main.
*Main>
}}
 
Agora temos duas variávels: <code>r</code> e <code>area</code>.
 
{{HaskellGHCi|1=
*Main> area
78.53981633974483
*Main> area / r
15.707963267948966
}}
 
{{nota|A palavra <code>let</code> é o que deveríamos usar para definir novas variáveis diretamente no GHCi, sem precisar editar um arquivo de código. Mesmo que possa ser prático fazer isso, nem sempre é o caso para tarefas mais complexas. É preferível usar arquivos nesses casos.}}
 
== Comentários ==
Além do código em si, arquivos de código fonte podem conter texto conhecidos como ''cometários'', que são ignorados pelo compilador. Em Haskell existem dois tipos de comentários. Primeiro, aqueles que começam com <code>--</code> e que vão até o final da linha:
 
<source lang = "haskell">
x = 5 -- x is 5.
y = 6 -- y is 6.
-- z = 7 -- z is not defined.
</source>
 
Nestes casos, <code>x</code> e <code>y</code> são realmente definidos no código, mas <code>z</code> não é.
 
O segundo tipo do comentário é deliminado por <code>{- ... -}</code> e podem se abranger mais de uma linha:
<source lang = "haskell">
answer = 2 * {-
bloco de cometário de mais de uma linha e...
-} 3 {- comentário no meio da linha -} * 7
</source>
 
Comentários são usados para explicar partes de um programa ou para fazer qualquer tipo de anotação acerca de algum contexto. É importante frisar que exagerar na quantidade de comentários pode, na verdade, dificultar a leitura do código em si, e comentários desatualizados podem também gerar confusões.
 
== Variáveis em linguagems imperativas ==
Os leitores familiares com linguagens de programação imperativa perceberão que as variáveis em Haskell se comportam de maneira bem diferente que as variáveis em C, por exemplo.
Se você não possui experiência prévia com programação, pode pular esta seção, apesar de que ela pode te ajudar a entender as situações em que pessoas comparam o comportamento de Haskell em relação a outras linguagens. Muitos livros sobre Haskell fazem isso, por exemplo.
 
''Programação imperativa'' trata as variáveis como posições na memória da máquina. Essa abordagem está relacionada com o funcionamento básico de um computador. Programas imperativos dizem explicitamente ao computador o que devem fazer. Linguagens de alto nível, que podem estar bastante distantes destes conceitos, ainda retém parte deles no sentido de que ainda usam esse padrão de programação "passo-a-passo". Em contraste a isso, ''programação funcional'' proporciona uma maneira diferente de pensar, usando termos matemáticos e deixando de lado as instruções diretas ao computador, que são traduzidas apenas compilador para algo que o computador possa interpretar e processar.
 
Vejamos um exemplo. O código a seguir não funcionaria em Haskell:
 
<source lang = "haskell">
r = 5
r = 2
</source>
 
Um programador de linguagens imperativas leria isto como sendo: primeiro, definir <code>r = 5</code> e depois redefinir para <code>r = 2</code>. Em Haskell, entretanto, o compilador responderia este código com um erro: "múltiplas declarações de <code>r</code>". Dentro de um escopo definido, uma variável de Haskell é definida uma única vez, e sua definição não pode mudar.
 
As variaáveis de Haskell parecem ''invariáveis'', mas a verdade é que elas se comportam como variáveis matemáticas. Na Matemática, você nunca vê uma variável mudar de valor num mesmo problema, e a mesma coisa acontece em Haskell.
 
De forma mais precisa, as variáveis de Haskell são ''imutáveis'': elas variam apenas de acordo com os datos que entramos no programa. Não podemos definir <code>r</code> de dois jeitos diferentes num mesmo código, mas podemos mudar este valor se mudarmos de arquivo. Vamos mudar o código acima para:
 
<source lang = "haskell">
r = 2.0
area = pi * r ^ 2
</source>
 
Claro que vai funcionar. Mudamos <code>r</code> no único lugar em que ele está definido, e isso muda seu valor em todo o resto do programa.
 
Em problemas reais, os programas em Haskell deixam ''alguns'' valores indefinidos no código. Esses valores são definidos mais tarde, quando o programa adquire dados de um arquivo ou ação externa. Mas por enquanto, vamos nos ater a definir variáveis internamente. Vamos aprender sobre interações com o mundo exterior no capítulos futuros.
 
Aqui temos mais um exemplo da grande diferença entre Haskell com as linguagens imperativas:
 
<source lang = "haskell">
r = r + 1
</source>
 
Em vez de "incrementar o valor de <code>r</code>", isto é, atualizar o valor já armazenado na memória, este código em Haskell é a definição recursiva e <code>r</code>, ou seja, ele foi definido em termos de si mesmo. Não se preocupe, pois explicaremos [[Haskell/Recurssão|recurssão]] mais tarde. Neste caso específico, se <code>r</code> tiver sido definido com algum valor anterior, o compilador retornaria uma mensagem de erro, como explicamos anteriomente. Se <code>r</code> tiver sido definido com um valor de 5, fazer <code>r = r + 1</code> é o mesmo que tentar dizer que <math>5 = 5 + 1</math> na Matemática, o que está obviamente errado.
 
Já que os valores não mudam dentro de um mesmo programa, variáveis podem ser definidas na ordem em que quisermos. Por exemplo, os dois códigos a seguir são exatamente a mesma coisa:
 
{|border="0"
|-
||<source lang = "haskell">
| <code>Char</code> || Enumeração de caracteres [[16-bit]], [[Unicode]]. A faixa dos primeiro 128 caracteres é idêntica ao [[ASCII]]. || Read, Show, Eq, Ord, Enum, and Bounded || <code>'a'</code>
y = x * 2
|-
x = 3
| <code>Double</code> || [[Ponto flutuante]] com maior intervalo e precisão que <code>Float</code> || RealFloat ||
</source>
|-
||<source lang = "haskell">
| <code>Either</code> || || Eq, Ord, Read, Show ||
x = 3
|-
y = x * 2
| <code>Float</code> || [[Ponto flutuante]] || RealFloat || <code>6553.612</code><br />321.6e-3
</source>
|-
| <code>IO</code> || Tipo abstrato para operações de [[E/S]], como <code>putStr</code>, <code>print</code>, <code>getChar</code>, <code>getLine</code> e <code>readIO</code>. || Monad, Functor ||
|-
| <code>IOError</code> || Tipo abstrato para erros nas operações de E/S com <code>IO</code>. || Show, Eq ||
|-
| <code>Int</code> || [[Inteiro (tipo de dado)|Inteiro]] que cobre, pelo menos, o intervalo de valores [-2^29, 2^29 - 1]. || Integral || <code>123</code>
|-
| <code>Integer</code> || [[Inteiro (tipo de dado)|Inteiro]] de [[Bigint|precisão ilimitada]], com as mesmas funções e operadores de <code>Int</code> || Integral || <code>123</code>
|-
| <code>Maybe</code> || Lida com valores opcionais ou ilegais sem terminar o programa e sem usar o <code>IOError</code> de <code>IO</code>. || Eq, Ord, Read, Show ||
|-
| <code>Ordering</code> || || Eq, Ord, Bounded, Enum, Read, Show ||
|-
| <code>String</code> || [[Cadeia de caracteres]], representada sob forma de lista de <code>Char</code>. A sintaxe tanto pode ser de lista quanto a abreviação, entre [[aspas]]. || || <code>"Texto"</code><br /><code>['T','e','x','t','o']</code>
|-
| Tuplas || Tipo de dado algébrico de definição de registros heterogêneos, [[tupla]]s. A quantidade máxima de elementos depende da implementação, mas a quantidade mínima de quinze elementos é sempre garantida.<ref>The Haskell 98 Report, s. 6.1.4</ref> || Eq, Ord, Bounded, Read, Show || <code>('A',11,True)</code>
|-
| Listas || Tipo de dado algébrico de definição de registros homogêneos [[lista]]s. Entre os operadores disponíveis encontra-se <code>!!</code>, que retorna o n-ésimo elemento da lista, e <code>++</code>, que [[concatenação|concatena]] duas listas distintas de mesmo tipo. Relacionado a concatenação, há o operador <code>:</code>, que adiciona um elemento no topo de uma lista. || Eq, Ord || <code>[1,2,3,4]</code><br /><code>[1..4]</code><br /><code>(1:(2:(3:(4:[]))))</code>
|}
 
Em Haskell não temos essa noção de que "<code>x</code> foi declarado antes de <code>y</code>", ou o contrário. Claro, para usarmos <code>y</code> ainda precisamos do valor de <code>x</code>, mas a ordem não nos interessam, e nem ao compilador.
 
== Funções ==
Mudar o programa todas as vezes em que quisermos calcular a área de um círculo diferente é tedioso e nos limita a um círculo por vez. Poderíamos calcular duas áreas dubplicando todas as contas em nosso código, definindo <code>r2</code> e <code>area2</code>:<ref>Podemos ver aqui que os nomes de variáveis podem contar números e letras. Entretanto, toda variável ''deve'' começar com um letra minúscula, que pode ser seguida por outras letras (também maiúsculas), números, traço (_) ou apóstrofe (').</ref>
Em Haskell, funções não usam parêntesis. O que em matemática costuma representar-se por ''f(x)'' e ''f(x,y)'' aparece no código como ''f x'' e ''f x y''.
 
<source lang = "haskell">
r = 5
area = pi * r ^ 2
r2 = 3
area2 = pi * r2 ^ 2
</source>
 
Para evitarmos essa repetição incessante, é preferívemos simplesmente uma ''função'' para calcular a área e aplicá-la a diferentes raios.
 
Uma ''função'' recebe um ''argumento'' (ou ''parâmetro'') e retorna um resultado, exatamente como na Matemática. Em Haskell, as funções são definidas da mesma forma que as variáveis, exceto que temos que dizer quais são seus argumentos do lado esquerdo da expressão. Por exemplo, o código a seguir define <code>area</code>, cujo argumento é <code>r</code>:
 
<source lang = "haskell">
area r = pi * r ^ 2
</source>
 
Observe a sintáxe: o nome da função vem primeiro (<code>area</code>), seguido de um espaço em branco e de seu argumento (<code>r</code>). Depois vem o sinal <code>=</code>, e a definição da função, que usa o argumento de entrada em seu cálculo.
 
Agora podemos testar diferentes valores de raio e ''chamar'' a função com eles. Salve o código acima num arquivo, abra-o no GHCi, e experimente:
 
{{HaskellGHCi|1=
*Main> area 5
78.53981633974483
*Main> area 3
28.274333882308138
*Main> area 17
907.9202768874502
}}
 
Acabamos de ''chamar'' a função com diferentes valores e calculamos a área de três círculos diferentes.
 
Matematicamente, o calculo da área pode ser representado por <math>A(r) = \pi \cdot r ^ 2</math>. Para calcular as áreas, faríamos <math>A(5) = 78.54</math> ou <math>A(3) = 28.27</math>. Haskell também funciona com parênteses, mas eles são geralmente omitos por convenção para deixar o código menos carregado de símbolos e mais legível.
 
Mesmo assim, parênteses ainda são usados para agrupar ''expressões'' (qualquer código que retorne algum valor) que devem ser calculadas todas juntas. Veja como as seguintes expressões são interpretadas de formas diferentes:
 
<source lang = "haskell">
5 * 3 + 2 -- 15 + 2 = 17 (multiplicação feita antes da adição)
5 * (3 + 2) -- 5 * 5 = 25 (parenteses forçam a adição a ser computada primeiro)
area 5 * 3 -- (area 5) * 3
area (5 * 3) -- area 15
</source>
 
Da mesma forma que a multiplição acontece antes que a adição, perceba que as funções de Haskell tem hierarquia de ''precedência'' maior que qualquer outro operador, seja <code>+</code> ou <code>*</code>, por exemplo.
 
== Avaliação de expressões ==
O que exatamente acontece quando entramos uma expressão no GHCi? Depois que pressionamos "enter", ela é avaliada. Isso significa que cada função vai ser substituida por sua definição e as contas serão realizadas até que um único valor final reste. Por exemplo, ao executarmos <code>area 5</code> o seguinte acontece:
 
<pre> area 5
=> { replace the left-hand side area r = ... by the right-hand side ... = pi * r^2 }
pi * 5 ^ 2
=> { replace pi by its numerical value }
3.141592653589793 * 5 ^ 2
=> { apply exponentiation (^) }
3.141592653589793 * 25
=> { apply multiplication (*) }
78.53981633974483</pre>
 
Quando usamos o GHCi, o resultado de ''aplicar'' ou ''chamar'' a função, que segue o procedimento acima, vai aparecer na tela.
 
Agora, mais algumas funções:
 
<source lang = "haskell">
dobrar x = 2 * x
quadruplicar x = double (double x)
quadrado x = x * x
metade x = x / 2
</source>
 
{{HaskellExercícios|1=
* Explique como GHCi avaliaria <code>quadruplicar 5</code>}.
* Defina uma função que subtraia 12 da metade de seu argumento.}}
 
== Parâmetros múltiplos ==
Funções também podem ter mais que um argumento. Por exemplo, para calcular a área de um retângulo precisamos de seu comprimento e de sua largura:
 
<source lang = "haskell">
areaRetang a b = a * b
</source>
 
{{HaskellGHCi|1=
*Main> areaRetang 5 10
50
}}
 
Outro exemplo é a área de um triângulo, <math>A = \frac{bh}{2}</math>:
 
<source lang="haskell">
areaTriang b h = (b * h) / 2
</source>
 
{{HaskellGHCi|1=
*Main> areaTriang 3 9
13.5
}}
 
Como você pode ver, os argumentos são separados por espaços. É por isso que as vezes você precisa usar parênteses para agrupar expressões. Por exemplo, não se pode escrever o quádruplo de um valor como sendo
 
<source lang = "haskell">
quadruple x = double double x -- error
</source>
 
Isso aplicaria a função <code>double</code> sobre dois argumentos: <code>double</code> e <code>x</code>. É possível, sim, que ''funções sejam argumentos de outras funções'', como veremos mais tarde, mas isso não é o que queremos aqui. Para fazer esta função funcionar precisamo suar parênteses:
 
<source lang = "haskell">
quadruple x = double (double x)
</source>
 
Os argumento são sempre passados na ordem em que aparecem. Por exemplo:
 
<source lang = "haskell">
menos x y = x - y
</source>
 
{{HaskellGHCi|1=
*Main> menos 10 5
5
*Main> menos 5 10
-5
}}
 
Aqui, <code>menos 10 5</code> avalia a expressão <code>10 - 5</code>, enquanto que <code>menos 5 10</code> avalia <code>5 - 10</code> devido a mudança na ordem do argumentos.
 
{{HaskellExercícios|1=
* Escreva uma função para calcular o volume de uma caixa.
* Aproximadamente, de quantas pedras as famosas pirâmides de Gizé feitas? Dica: você vai precisar estimar o volume da pirâmide e o volume de cada bloco de pedra.
}}
 
== Combinando funções ==
 
Claro que você pode usar funções outras funções para definir suas próprias, bem como você já o fez usando adição, <code>+</code>, ou multiplicação, <code>*</code>. Na verdade, operadores também são definidos como funções em Haskell. Por exemplo, para calcular a área de um quadrado, podemos reutulizar a função que calcula a área de um retângulo:
 
<source lang = "haskell">
areaRetang a b = a b
areaQuad l = areaRetang l l
</source>
 
{{HaskellGHCi|1=
*Main> areaQuad 5
25
}}
 
Afinal de contas, um quadrado é um retângulo de lados iguais.
 
{{HaskellExercícios|1=
* Escreva uma função que calcula o volume de um cilindro. O volume de um cilindro é a área da base, que é um círculo, multiplicada pela altura. Como você já programou a função da área de um círculo neste capítulo, você pode reutilizá-la aqui.}}
 
== Definindo funções locais ==
=== Usando <code>where</code> ===
Quando definimos uma função, às vezes precisamos calcular valores intermediários, mas que são ''locais'' e usados apenas dentro daquela função. Considere a [[w:teorema de Herão|fórmula de Herão]]: <math>A = \sqrt{p(p-a)(p-b)(p-c)}</math>, sendo <math>p</math> o metade do perímetro do triângulo. Este é o cálculo da área de um triângulo de lados <code>a</code>, <code>b</code> e <code>c</code>:
 
<source lang = "haskell">
herao a b c = sqrt (s * (s - a) * (s - b) * (s - c))
where
s = (a + b + c) / 2
</source>
 
A variável <code>s</code> representa a metade do perímetro. Seria tedioso e propenso a erros se tivéssemos que escrever <code>(a + b + c)/2</code> toda vez que precisássemos deste valor dentro de <code>herao</code>. <code>sqrt</code> calcula a raiz quadrada do seu argumento (lembre-se de ''square root'', no inglês).
 
Simplesmente escrever as definições separadamente não funcionaria. Veja:
 
<source lang = "haskell">
herao a b c = sqrt (p * (p - a) * (p - b) * (p - c))
p = (a + b + c) / 2 -- a, b, and c are not defined here
</source>
 
O compilador reclamaria que <code>a</code>, <code>b</code> e <code>c</code> só estão disponíveis no lado direito de <code>herao</code>, enquanto que a definição de <code>s</code> não faz parte do lado direito de <code>herao</code>. Para que ela seja embutida lá, usamos a palavra-chave <code>where</code>.
 
Perceba que tanto <code>where</code> quanto a definição de <code>s</code> estão ''indentadas'' por 4 espaços em branco. Isso é importante para delimitar o que está dentro do que. Vejamos outros exemplos do uso de <code>where</code>:
 
<source lang = "haskell">
areaTriangTrig a b c = c * altura / 2 -- usando trigonometria
where
cosa = (b ^ 2 + c ^ 2 - a ^ 2) / (2 * b * c)
sina = sqrt (1 - cosa ^ 2)
altura = b * sina
areaTriangHerao a b c = resultado -- usa a fórmula de Herão
where
resulto = sqrt (p * (p - a) * (p - b) * (p - c))
p = (a + b + c) / 2
</source>
 
== Escopo ==
Observe atentamente o exemplo anterior: perceba que usamos as variáveis <code>a</code>, <code>b</code>, <code>c</code> duas vezes, uma cada função definida. Como pode isso?
 
Considere o seguinte procedimento no GHCi:
 
{{HaskellGHCi|1=
Prelude> let r = 0
Prelude> let area r = pi * r ^ 2
Prelude> area 5
78.53981633974483
}}
 
Seria estranho se retornasse <code>0</code> para as áreas por causa da definição anterior de <code>let r = 0</code>. Isso não acontece porque na segunta vez que digitamos <code>r</code> estamos nos referindo a um <code>r</code> ''diferente''. Parece confuso, mas pense no seguinte: muitas pessoas se chamam João, mesmo assim, numa situação em que há apenas um João presente, podemos falar "João" sem nenhuma confusão. Em programação, essa noção de contexto é chamada de ''[[w:Escopo (computação)|escopo]]''.
 
Não vamos nos aprofundar nos detalhes técnicos que envolvem o escope por agora, mas tenha em mente que o valor de um parâmetro é exatamente aquilo que você passa à função, independente de como você o chamou na definição da função. Assim sendo, nomear as variáveis de modo apropriado ajuda bastante a leitura do código por humanos.
 
== Resumo ==
Assim, a declaração de uma função tem a forma:
<pre>
Prelude> let areaq lado = lado^2
</pre>
Ou seja, definimos que a função ''areaq'' (área do quadrado) é a função que pega ''lado'' e retorna o seu quadrado.
 
# Variáveis armazenam valores (que podem ser qualquer expressão em Haskell).
Uma função para calcular a hipotenusa de um triângulo retângulo é:
# Variáveis não mudam seus valores dentro de um mesmo escopo.
<pre>
# Funções são úteis para escrever programas reutilizáveis.
Prelude> let hipotenusa cateto1 cateto2 = sqrt(cateto1^2 + cateto2^2)
# Funções podem aceitar mais de um parâmetro.
</pre>
 
== Notas ==
Linha 83 ⟶ 369:
 
[[en:Haskell/Variables and functions]]
{{AutoCat}}