this repo has no description
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