this repo has no description
at main 8.2 kB view raw
1* Type 2 3No Haskell tambem conseguimos declarar aliases para tipos customizaveis, a vantagem disso sera para nao repetir logicas perante o nosso codigo e tambem deixar ele mais declarativo, dando nomes para declaracoes conseguimos que outras pessoas consigam compreender melhor o nosso codigo. 4 5Segue um exemplo de caso nao usarmos: 6#+begin_src haskell 7:{ 8troco :: (Integer, String, Double) -> (Integer, String, Double) -> Double 9troco (idProd, nome, preco) (idCli, nomeCli, pago) = pago - preco 10:} 11#+end_src 12 13Dessa forma declarada, conseguimos saber o que cada um significa e a diferenca entre eles, porem para alguem que deseja utilizar essa funcao e querer usar ela, pode ficar um pouco confusa em saber como podera utilizar e que ordem passar os argumentos, ja que nao temos como diferencias o dados passados sem olhar a implementacao 14#+begin_src haskell 15prod = (1, "queijo", 100) 16cli = (1, "Lucas", 200) 17 18troco prod cli 19troco cli prod 20#+end_src 21 22Criando um custom type, podemos criar tipos com aliases que melhor descrevem os argumentos que nossa funcao devera receber e o que cada um significa. 23Para declararmos um custom type utilizamos a palavra reservada ~type~ do Haskell. 24 25Utilizando no exemplo acima a funcao poderia ficar assim: 26#+begin_src haskell 27type Produto = (Integer, String, Double) 28type Cliente = (Integer, String, Double) 29 30:{ 31troco :: Produto -> Cliente -> Double 32troco (idProd, nome, preco) (idCli, nomeCli, pago) = pago - preco 33:} 34#+end_src 35 36Desta forma podemos deixar mais claro a intencao da nossa funcao e seus argumentos 37 38Porem, ainda assim o usuario ainda pode inverter a ordem dos dados passados, ele pode passar um ~Cliente~ no lugar do ~Produto~ e nossa funcao ira aceitar, porem ira retornar o valor errado. 39Como apenas criamos um alias para as funcoes que possuem o mesmo tipo, o Haskell nao ira diferenciar os tipos pelos aliases, o que ira ocorrer na hora da compilacao do projeto sera a seguinte etapa: 401. Ira substituir no programa todos os lugares que apontam para os aliases e colocar o tipo 412. Ira realizar a validacao dos tipos para ver se batem 42 43Com isso, como nossos tipos sao a mesma tupla, a linguagem nao ira diferenciar e ira aceitar. 44 45** Generic 46Tambem podemos declarar aliases de forma generica, sem especificar o tipo hardcoded e deixando apenas para quando formos implementar/usar. 47Para declarar eh algo bem semelhante a declaracao de funcao: 48#+begin_src haskell 49type Assoc k v = [(k,v)] 50 51:{ 52find :: Eq k => k -> Assoc k v -> v 53find k t = head [v | (k', v) <- t, k'==k] 54:} 55#+end_src 56 57Desta forma criamos o alises ~Assoc~ que recebe dois valores de forma generica, nao precisamos definir o ~k~ ou o ~v~, essa definicao soh sera feita quando os dados que forem passados para a funcao. 58 59** Recursion 60Nao podemos criar types de forma recursiva, entao a seguinte declaracao de uma arvore nao eh possivel com types: 61#+begin_src haskell 62type binaryTree a = (binaryTree a, a, binaryTree a) 63#+end_src 64 65* Custom types 66Tambem podemos declarar tipos customizaveis 67 68#+begin_src haskell 69 data Shape = Circle Float Float Float | Rectangle Float Float Float Float 70#+end_src 71 72#+RESULTS: 73: Rectangle :: Float -> Float -> Float -> Float -> Shape 74 75#+begin_src haskell 76 :{ 77 surface :: Shape -> Float 78 surface (Circle _ _ r) = pi * r ^ 2 79 surface (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1) 80 :} 81 82 surface $ Circle 10 20 10 83 surface $ Rectangle 0 0 100 100 84#+end_src 85 86#+RESULTS: 87: 10000.0 88 89Utilizando o =derinving= keyword podemos fazer com que o Haskell consiga printar os nossos tipos customizaveis junto com seus valores 90 91#+begin_src haskell 92 data Shape = Circle Float Float Float | Rectangle Float Float Float Float deriving (Show) 93 94 (Circle 10 20 5, Rectangle 50 230 60 90) 95#+end_src 96 97#+RESULTS: 98: Prelude> (Circle 10.0 20.0 5.0,Rectangle 50.0 230.0 60.0 90.0) 99 100* Record syntax 101Record syntax eh utilizado para facilitar na hora de criarmos types mais complexos e com mais dados. 102Imagine um type do tipo =Person= onde iremos precisar do primeiro nome, ultimo nome, idade, altura, telefone and sorvete favorito. 103Podemos descrever esse tipo desta forma; 104#+begin_src haskell 105 data Person = Person String String Int Float String String deriving (Show) 106 107 let guy = Person "Buddy" "LastName" 43 184.2 "1234-5678" "Chocolate" 108 guy 109#+end_src 110 111#+RESULTS: 112: Prelude> Prelude> Person "Buddy" "LastName" 43 184.2 "1234-5678" "Chocolate" 113 114Mas se usarmos o =record syntax= para declarar a o mesmo tipo, temos uma sintaxe mais amigavel e facil de ler 115#+begin_src haskell 116 :{ 117 data Person = Person { firstName :: String 118 , lastName :: String 119 , age :: Int 120 , height :: Float 121 , phoneNumber :: String 122 , flavour :: String 123 } deriving (Show) 124 :} 125 126 let guy = Person { firstName = "Buddy 2", lastName = "LastName", age = 43, height = 184.2, phoneNumber = "1234-5678", flavour = "Chocolate" } 127 guy 128#+end_src 129 130#+RESULTS: 131: Prelude> Prelude> Person {firstName = "Buddy 2", lastName = "LastName", age = 43, height = 184.2, phoneNumber = "1234-5678", flavour = "Chocolate"} 132 133A vantagem tambem aparece na hora de printarmos o tipo, onde tambem podemos ver os campos e seus repectivos valores. 134 135** Estrutura de dados recursiva 136Vamos criar uma arvore binaria em Haskell :) 137 138#+begin_src haskell 139 :{ 140 data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show, Read, Eq) 141 142 treeInsert :: (Ord a) => a -> Tree a -> Tree a 143 treeInsert x EmptyTree = Node x EmptyTree EmptyTree 144 treeInsert x (Node a left right) 145 | x == a = Node x left right 146 | x < a = Node a (treeInsert x left) right 147 | x > a = Node a left (treeInsert x right) 148 149 treeElem :: (Ord a) => a -> Tree a -> Bool 150 treeElem x EmptyTree = False 151 treeElem x (Node a left right) 152 | x == a = True 153 | x < a = treeElem x left 154 | x > a = treeElem x right 155 :} 156 157 let nums = [8,6,4,1,7,3,5] 158 let numsTree = foldr treeInsert EmptyTree nums 159 treeElem 8 numsTree 160#+end_src 161 162#+RESULTS: 163: Prelude> Prelude> Prelude> True 164 165* Typeclasses 166A typeclass defines some behavior (like comparing for equality, comparing for ordering, enumeration) and then types that can behave in that way are made instances of that typeclass. The behavior of typeclasses is achieved by defining functions or just type declarations that we then implement. So when we say that a type is an instance of a typeclass, we mean that we can use the functions that the typeclass defines with that type. 167#+begin_src haskell 168 :{ 169 class Eq a where 170 (==) :: a -> a -> Bool 171 (/=) :: a -> a -> Bool 172 x == y = not (x /= y) 173 x /= y = not (x == y) 174 175 data TrafficLight = Red | Yellow | Green 176 177 instance Eq TrafficLight where 178 Red == Red = True 179 Green == Green = True 180 Yellow == Yellow = True 181 _ == _ = False 182 183 instance Show TrafficLight where 184 show Red = "Red light" 185 show Green = "Green light" 186 show Yellow = "Yellow light" 187 :} 188 189 Red 190#+end_src 191 192#+RESULTS: 193: Prelude> Red light 194 195** Yes-no typeclasses 196Let's create the way that the javascript treats values as truthy and falsy in Haskell, for exemple, the following examples: 197#+begin_src javascript 198 if (0) console.log("YEAH!") else console.log("NO!") 199 if ("") console.log("YEAH!") else console.log("NO!") 200 if (false) console.log("YEAH!") else console.log("NO!") 201 if ("WHAT") console.log("YEAH!") else console.log("NO!") 202#+end_src 203 204In Haskell, we can only use the value inside a =if= when is of type =Bool=, but now let's implement a function that'll have this behaviour: 205#+begin_src haskell 206 :{ 207 class YesNo a where 208 yesno :: a -> Bool 209 210 instance YesNo Int where 211 yesno 0 = False 212 yesno _ = True 213 214 instance YesNo [a] where 215 yesno [] = False 216 yesno _ = True 217 218 instance YesNo Bool where 219 yesno = id 220 221 instance YesNo (Maybe a) where 222 yesno (Just _) = True 223 yesno Nothing = False 224 225 yesnoIf :: (YesNo y) => y -> a -> a -> a 226 yesnoIf yesnoVal yesResult noResult = if yesno yesnoVal then yesResult else noResult 227 :} 228 229 yesnoIf (Just 500) "YEAH!" "NO!" 230#+end_src 231 232#+RESULTS: 233: Prelude> "YEAH!" 234