Skip to content

Instantly share code, notes, and snippets.

@octaviogb
Created October 6, 2016 23:22
Show Gist options
  • Save octaviogb/55796bdabfbbe29b3d639eecdec91d82 to your computer and use it in GitHub Desktop.
Save octaviogb/55796bdabfbbe29b3d639eecdec91d82 to your computer and use it in GitHub Desktop.
haskell

Haskell

Para não covardes

por Octávio Turra



Para aprender algo novo, devemos esquecer conceitos antigos

-- livro de auto-ajuda


IF


IF

Instituto Federal

Instituto Federal


IF

Instituto Federal

Instituto Federal

Foi onde estudei....


Variável


Variável

variável

O humor da sua esposa, marido, namorado, rolo... etc


For


For

Fantastic For

...Aquele filme da Marvel


Piadas ruins grudam mais fácil na memória

-- contador de piadas ruins


Ok

agora que apagamos conceitos errados


$f(x) := x + x$


Qual o resultado de

$f(2) \mid f(x) := x + x$


$f(2) := 2 + 2 \therefore 3$


ops


$f(2) := 2 + 2 \therefore 4$


$f(x) := x + x$


$f(2) := 2 + 2$


$f(2) := 2 + 2 \therefore 4$


$f(x) := x = 2 \rightarrow x \wedge \lnot(x=2) \rightarrow x+x $


eita...!?


let f x = if x == 2 then 2 else x + x in f 2

$f(2) := if2 = 2then2else~2 + 2$


$\therefore f(2) = 2$


$f(x) := ifx > 0then~x+f(x-1)elsex$


let f x  = if x > 0 then (x + f x - 1) else x

let f 2  = if 2 > 0 then 2 + (f 2 - 1) else 2

let f 2  = if 2 > 0 
           then 2 + (if 1 > 0 then (
           	if 0 > 0 -- ops...isso é falso.. 
                         -- portanto paramos
           ) else 1)
           else 2
           

Bom... Daí temos a otimização de rabo...


A otimização de rabo é quando otimizamos as chamadas, pois já sabemos que ela bateu na condição


let f 2  = if 2 > 0 
           then 2 + (if 1 > 0 then (0) else 1)
           else 2
           

$f(2) \Rightarrow (2 + (1 + (0))) \therefore 3$


Falando em rabo


se isso fosse uma centopéia: [0, 1, 2, 3, 4]


[0, 1, 2, 3, 4]

0 : [1, 2, 3, 4]


[0] = cabeça

[1, 2, 3, 4] = rabo...


0 é a cabeça e o resto é o rabo


f x = let cabeca = head x; rabo = tail x in 
      if rabo == [] then cabeca
      else cabeca + f rabo
      

let f x = let cabeca = head x; rabo = tail x in 
      if rabo == [] then cabeca
      else cabeca + f rabo in f [0, 1, 2, 3, 4]
:: => 6

mas...eita.. e se a gente for mais fundo?


f (cabeca:rabo) = let cabeca = head x; rabo = tail x in 
                  if rabo == [] then cabeca
                  else cabeca + f rabo
                  

mas...ainda da pra ir mais


f [] = 0
f [cabeca] = cabeca
f [cabeca : rabo] = cabeca + f rabo

Dá tudo na mesma


Mas digamos que eu quisesse calcular quanto eu tenho na conta bancária, de acordo com as ações de saque ou depósito...


Então eu tenho duas Ações:

  • Saque de Valor
  • Depósito de Valor

Como eu expressaria isso em Haskell?


Primeiro, vamos criar um apelido para Valor

type Valor = Integer

Neste caso, meu valor vai ser um número inteiro


Certo, agora que tal descrevermos nossas ações?

type Valor = Integer

data Acao v = Deposito v | Saque v

Em Haskell, devemos ser explícitos, portanto, vamos dizer que nossa ação pode ser mostrada na tela, que ela é ordenável e que podemos comparar uma ação com a outra

type Valor = Integer

data Acao v = Deposito v | Saque v deriving (Show, Eq, Ord)

Lembrem-se, como uma linguagem declarativa, temos que ensinar nosso aplicativo como lidar com as coisas, então vamos ensinar o que é um Deposito e um Saque


traduzir (Deposito v) = v
traduzir (Saque v) = -v

Agora o nosso aplicativo sabe que um depósito é uma soma e um saque é uma subtração da nossa conta


Certo, precisamos criar a função que vai tratar as ações


Vamos primeiro definir os tipos:

conciliar :: [(Acao Valor)] -> Valor

Isto significa que conciliar vai receber uma coleção ([]) de Ações sobre Valores ((Acao Valor)) e vai devolver um Valor


conciliar :: [(Acao Valor)] -> Valor
conciliar acoes = foldl (+) 0 $ map traduzir acoes

o.O cuma?


agora conhecemos mais 2 funções

  • map
  • foldl

map

Basicamente é uma função que pega algo mapeável, no nosso caso a coleção de ações e aplica uma transformação, no nosso caso a tradução


map

Portanto, map traduzir [(Deposito 10), (Saque 5)] vai aplicar a função traduzir a cada item e devolver [10, -5]..


Simples?


foldl (reduce)

Essa é um pouco mais chatinha.... é uma função que aplica dobras (o.O) Ela vai receber uma função que tem 2 parâmetros:

(/acumulador atual -> ...)

Um valor inicial 0 e algo dobrável... no nosso caso, nossa coleção...


+

o +, como tudo no Haskell, é uma função também. A chamamos de função infixa, pois ela fica entre os 2 parâmetros que irá receber....


+

Então podemos traduzir assim:

(+) :: Num a => a -> a -> a

Que significa que (+) recebe 2 parâmetros do tipo número e devolve um número ^^


(+)

Utilizamos os () para dizer para o nosso programa que não vamos usar nossa função infixa e sim prefixa, ou seja:

(+) 1 2 = 1 + 2

foldl (reduce)

Enfim,

Nosso foldl vai somar cada item mapeado pela nossa função map e dar o resultado conciliado da nossa conta


Pausa estratégica para código...


Chega de aulinha


O nosso desafio se chama


A Sala


Vamos implementar um joguinho de aventura em texto.


Imaginemos que nosso personagem que se chama Walterly foi jogado em uma sala trancada.


Vamos dizer para Walterly o que ele deve fazer, para sair da sala


São 3 ações possívels:

  • Ver Algo
  • Pegar Algo
  • Falar Com Alguem
  • Usar Algo
  • Abrir Algo
  • Ok

A jogabilidade é bem simples. Começamos com uma descrição básica das sala.


O jogador vai digitar:

Fale com o segurança

E escreveremos na tela o resultado da conversa.


Digitamos

Ok

E voltamos a ter uma descrição da sala


Como nós que vamos criar o jogo, precisamos de um roteiro...


Bom, a sala tem um Segurança e uma Porta


Quando falamos com o Segurança ele deixará cair a chave


Pegamos a chave e a usamos


Enfim, abrimos a porta e vencemos


Ok, não foi o maior desafio de encarceramento do mundo, mas já dá para começar.


Entendidos?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment