1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
|
---
language: Elm
contributors:
- ["Max Goldstein", "http://maxgoldste.in/"]
translators:
- ["Marcel dos Santos", "https://twitter.com/marcelgsantos"]
lang: pt-br
filename: learnelm-pt.elm
---
Elm é uma linguagem de programação funcional reativa que compila para (client-side)
JavaScript. Elm é estaticamente tipada, significando que o compilador captura a
maioria dos erros imediatamente e fornece uma mensagem de erro limpa e compreensível.
Elm é excelente para projetar interfaces de usuário e jogos para a web.
```haskell
-- Comentários de uma linha começam com dois traços.
{- Comentários de múltiplas linhas podem ser delimitados em um bloco como este.
{- Eles podem ser aninhados. -}
-}
{-- O Básico --}
-- Operações Aritméticas
1 + 1 -- 2
8 - 1 -- 7
10 * 2 -- 20
-- Cada número literal sem um ponto decimal pode ser um Int ou um Float.
33 / 2 -- 16.5 com divisão de ponto flutuante
33 // 2 -- 16 com divisão inteira
-- Exponenciação
5 ^ 2 -- 25
-- Booleanos
not True -- False
not False -- True
1 == 1 -- True
1 /= 1 -- False
1 < 10 -- True
-- Strings e caracteres
"Esta é uma string porque ela utiliza aspas duplas."
'a' -- caracteres entre aspas simples
-- Strings podem ser anexadas.
"Olá " ++ "mundo!" -- "Olá mundo!"
{-- Listas, Tuplas e Registros --}
-- Cada elemento em uma lista deve ter o mesmo tipo.
["the", "quick", "brown", "fox"]
[1, 2, 3, 4, 5]
-- O segundo exemplo também pode ser escrito com dois pontos.
[1..5]
-- Junte listas da mesma forma que strings.
[1..5] ++ [6..10] == [1..10] -- True
-- Para adicionar um item utilize "cons".
0 :: [1..5] -- [0, 1, 2, 3, 4, 5]
-- A cabeça e a cauda de uma lista são retornadas como uma Maybe. Em vez de
-- verificar cada valor para ver se ele é nulo, você lida com os valores
-- faltantes explicitamente.
List.head [1..5] -- Just 1
List.tail [1..5] -- Just [2, 3, 4, 5]
List.head [] -- Nothing
-- List.functionName siginifica que a função faz parte do módulo List.
-- Cada elemento em uma tupla pode ser de um tipo diferente, mas uma tupla
-- tem um comprimento fixo.
("elm", 42)
-- Acesse os elementos de um par com as funções first e second.
-- (Este é um atalho; nós iremos para o "caminho real" em breve.)
Tuple.first ("elm", 42) -- "elm"
Tuple.second ("elm", 42) -- 42
-- Uma tupla vazia ou "unidade" às vezes é utilizada como um placeholder.
-- É o único valor de seu tipo, também chamado de "Unit".
()
-- Registros são como tuplas mas os campos possuem nomes. A ordem dos campos
-- não importa. Observe que os valores dos registros utilizam sinais de igual,
-- e não dois-pontos.
{ x = 3, y = 7 }
-- Acesse um campo com um ponto e o nome do campo.
{ x = 3, y = 7 }.x -- 3
-- Ou com uma função acessora, que é um ponto e o nome do próprio campo.
.y { x = 3, y = 7 } -- 7
-- Atualiza os campos de um registro. (Ele já deve ter os campos.)
{ person |
name = "George" }
-- Atualiza vários campos de uma só vez utilizando os valores atuais.
{ particle |
position = particle.position + particle.velocity,
velocity = particle.velocity + particle.acceleration }
{-- Fluxo de Controle --}
-- Declarações if sempre devem ter um else e os valores devem ser do mesmo tipo.
if powerLevel > 9000 then
"WHOA!"
else
"meh"
-- Declarações if podem ser encadeadas.
if n < 0 then
"n é negativo"
else if n > 0 then
"n é positivo"
else
"n é zero"
-- Utilize declarações case para casar padrões entre diferentes possibilidades.
case aList of
[] -> "casa com uma lista vazia"
[x]-> "casa com uma lista de exatamente um item, " ++ toString x
x::xs -> "casa com uma lista de pelo menos um item cuja cabeça é " ++ toString x
-- O casamento do padrão acontece na ordem. Se colocarmos [x] por último, ele
-- nunca iria casar porque x::xs também casa (xs seria a lista vazia). Os
-- casamentos não "falham".
-- O compilador irá alertá-lo sobre casos faltantes ou extras.
-- Casa padrão com um Maybe.
case List.head aList of
Just x -> "A cabeça é " ++ toString x
Nothing -> "A lista estava vazia."
{-- Funções --}
-- A sintaxe do Elm é muito mínima, baseando-se principalmente em espaços em
-- branco em vez de parênteses e chaves. Não existe a palavra-chave "return".
-- Define uma função com seu nome, argumentos, um sinal de igual e o corpo.
multiply a b =
a * b
-- Aplica (chama) uma função passando seus argumentos (vírgulas não necessárias).
multiply 7 6 -- 42
-- Aplica parcialmente uma função passando somente alguns de seus argumentos.
-- Dando, em seguida, um novo nome a função.
double =
multiply 2
-- Constantes são semelhantes, exceto que não há argumentos.
answer =
42
-- Passa funções como argumentos para outras funções.
List.map double [1..4] -- [2, 4, 6, 8]
-- Ou escreva uma função anônima.
List.map (\a -> a * 2) [1..4] -- [2, 4, 6, 8]
-- Você pode casar um padrão na definição de funções quando há somente um caso.
-- Esta função recebe uma tupla em vez de dois argumentos.
-- Esta é a maneira que você normalmente vai desempacotar/extrair valores de tuplas.
area (width, height) =
width * height
area (6, 7) -- 42
-- Utilize chaves para casar o padrão de nomes de campos de um registro.
-- Utilize let para definir valores intermediários.
volume {width, height, depth} =
let
area = width * height
in
area * depth
volume { width = 3, height = 2, depth = 7 } -- 42
-- Funções podem ser recursivas.
fib n =
if n < 2 then
1
else
fib (n - 1) + fib (n - 2)
List.map fib [0..8] -- [1, 1, 2, 3, 5, 8, 13, 21, 34]
-- Outra função recursiva (utilize List.length em um código de verdade).
listLength aList =
case aList of
[] -> 0
x::xs -> 1 + listLength xs
-- Chamadas de funções acontecem antes de qualquer operador infixo.
-- Os parênteses indicam a precendência.
cos (degrees 30) ^ 2 + sin (degrees 30) ^ 2 -- 1
-- Primeiro degrees é aplicada em 30, então o resultado é passado para as
-- funções de trigonometria, que então é elevado ao quadrado e, por fim, a
-- adição acontece.
{-- Tipos e Anotações de Tipos --}
-- O compilador irá inferir o tipo de cada valor em seu programa.
-- Tipos iniciam com letra maiúscula. Leia x : T como "x é do tipo T".
-- Alguns tipos comuns que você pode ver no REPL do Elm.
5 : Int
6.7 : Float
"hello" : String
True : Bool
-- Funções têm tipos também. Leia -> como "vai para". Pense no tipo mais à
-- direita como o tipo do valor de retorno e os outros como argumentos.
not : Bool -> Bool
round : Float -> Int
-- Quando você define um valor, é uma boa prática escrever seu tipo acima dele.
-- A anotação é uma forma de documentação, que é verifica pelo compilador.
double : Int -> Int
double x = x * 2
-- Argumentos de uma função são passados entre parênteses.
-- Tipos com letra minúscula são tipos variáveis: eles podem ser de qualquer
-- tipo, desde que cada chamada seja consistente.
List.map : (a -> b) -> List a -> List b
-- "List.map é do tipo a-vai-para-b, vai para lista de a e vai para lista de b."
-- Existem três tipos especiais com minúsculas: number, comparable e appendable.
-- Numbers permite que você utilize aritmética em Ints e Floats.
-- Comparable permite você ordenar números e strings, como a < b.
-- Appendable permite que coisas possam ser combinadas com a ++ b.
{-- Type Aliases e Union Types --}
-- Quando você escreve um registro ou uma tupla, seu tipo já existe.
-- (Observe que os tipos de um registro utilizam dois-pontos e os valores de um
-- registro utilizam igual.)
origin : { x : Float, y : Float, z : Float }
origin =
{ x = 0, y = 0, z = 0 }
-- Você pode dar um bom nome para tipos existentes com um type alias.
type alias Point3D =
{ x : Float, y : Float, z : Float }
-- Se você cria um alias para um registro, você pode usar o nome como uma
-- função construtora.
otherOrigin : Point3D
otherOrigin =
Point3D 0 0 0
-- Mas ele ainda é do mesmo tipo, então você pode compará-los.
origin == otherOrigin -- True
-- Por outro lado, a definição de um union type cria um tipo que não existia
-- antes. Um union type é chamado assim porque ele pode ser uma de muitas
-- possibilidades. Cada uma das possibilidades é representada como uma "tag".
type Direction =
North | South | East | West
-- As tags podem levar outros valores de tipos conhecidos. Isso pode trabalhar
-- recursivamente.
type IntTree =
Leaf | Node Int IntTree IntTree
-- "Leaf" e "Node" são as tags. Tudo após uma tag é um tipo.
-- As tags podem ser usadas como valores ou funções.
root : IntTree
root =
Node 7 Leaf Leaf
-- Union types (e type aliases) podem utilizar tipos variáveis.
type Tree a =
Leaf | Node a (Tree a) (Tree a)
-- "O tipo árvore-de-a é uma folha ou um nó de a, árvore-de-a e árvore-de-a."
-- Casa padrão com union tags. As tags maiúsculas serão casadas de maneira exa-
-- ta. As variáveis minúsculas irão casar com qualquer coisa. Sublinhado também
-- casa com qualquer coisa, mas siginifica que você não o está utilizando.
leftmostElement : Tree a -> Maybe a
leftmostElement tree =
case tree of
Leaf -> Nothing
Node x Leaf _ -> Just x
Node _ subtree _ -> leftmostElement subtree
-- Isso é praticamente a própria linguagem. Agora vamos ver como organizar e
-- executar seu código.
{-- Módulos e Imports --}
-- As bibliotecas internas são organizadas em módulos, assim como quaisquer
-- bibliotecas de terceiros que você possa utilizar. Para grandes projetos,
-- você pode definir seus próprios módulos.
-- Coloque isso no topo do arquivo. Se for omitido, você está no Main.
module Name where
-- Por padrão, tudo é exportado. Você pode especificar as exportações de forma
-- explícita.
module Name (MyType, myValue) where
-- Um padrão comum é exportar um union type mas não suas tags. Isto é conhecido
-- como "tipo opaco" e é frequentemente utilizado em bibliotecas.
-- Importe código de outros módulos para utilizá-lo no seu código.
-- Coloque Dict no escopo para você poder chamar Dict.insert.
import Dict
-- Importe o módulo Dict e o tipo Dict para que suas anotações não tenham que
-- dizer Dict.Dict. Você ainda pode utilizar Dict.insert.
import Dict exposing (Dict)
-- Renomeie um import.
import Graphics.Collage as C
{-- Portas --}
-- Uma porta indica que você estará se comunicando com o mundo exterior.
-- Portas são permitidas somente no módulo Main.
-- Uma porta de entrada é apenas uma assinatura de tipo.
port clientID : Int
-- Uma porta de saída tem uma definição.
port clientOrders : List String
port clientOrders = ["Books", "Groceries", "Furniture"]
-- Não vamos entrar em detalhes, mas você configura callbacks no JavaScript
-- para enviar nas portas de entrada e receber nas portas de saída.
{-- Ferramentas de Linha de Comando --}
-- Compila um arquivo.
$ elm make MyFile.elm
-- A primeira vez que você fizer isso, o Elm instalará as bibliotecas internas
-- e criará o elm-package.json, onde a informação sobre seu projeto é mantida.
-- O reactor é um servidor que compila e roda seus arquivos.
-- Clique na chave ao lado dos nomes de arquivo para entrar no depurador de
-- viagem no tempo.
$ elm reactor
-- Teste expressões simples no Read-Eval-Print Loop.
$ elm repl
-- Pacotes são identificados pelo usuário e nome do repositório no GitHub.
-- Instale um novo pacote e registre-o no elm-package.json.
$ elm package install evancz/elm-html
-- Veja o que mudou entre as versões de um pacote.
$ elm package diff evancz/elm-html 3.0.0 4.0.2
-- O gerenciador de pacotes do Elm obriga o versionamento semântico, logo
-- mudanças de versões no minor nunca quebrará o seu build!
```
A linguagem Elm é supreendentemente pequena. Agora você pode olhar para quase
qualquer código-fonte em Elm e ter uma ideia aproximada do que está acontecendo.
No entanto, as possibilidades para código resistente a erros e de fácil
refatoração são infinitas!
Aqui estão algumas referências utéis.
* O [site do Elm](http://elm-lang.org/). Ele inclui:
* Links para os [instaladores](http://elm-lang.org/install)
* [Documentação](http://elm-lang.org/docs), incluindo [a referência de sintaxe](http://elm-lang.org/docs/syntax)
* Muitos [exemplos](http://elm-lang.org/examples) úteis
* Documentação para as [bibliotecas internas do Elm](http://package.elm-lang.org/packages/elm-lang/core/latest/). Tome nota de:
* [Basics](http://package.elm-lang.org/packages/elm-lang/core/latest/Basics), que é importada por padrão
* [Maybe](http://package.elm-lang.org/packages/elm-lang/core/latest/Maybe) e seu primo [Result](http://package.elm-lang.org/packages/elm-lang/core/latest/Result), comumente utilizados para valores faltantes e manipulação de erros
* Estruturas de dados como [List](http://package.elm-lang.org/packages/elm-lang/core/latest/List), [Array](http://package.elm-lang.org/packages/elm-lang/core/latest/Array), [Dict](http://package.elm-lang.org/packages/elm-lang/core/latest/Dict) e [Set](http://package.elm-lang.org/packages/elm-lang/core/latest/Set)
* [Codificação](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Encode) e [decodificação](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode) JSON
* [A Arquitetura Elm](https://github.com/evancz/elm-architecture-tutorial#the-elm-architecture). Uma dissertação pelo criador do Elm com exemplos sobre como organizar código em componentes.
* A [lista de e-mail do Elm](https://groups.google.com/forum/#!forum/elm-discuss). Todos são amigáveis e solícitos.
* [Escopo em Elm](https://github.com/elm-guides/elm-for-js/blob/master/Scope.md#scope-in-elm) e [Como Ler uma Anotação de Tipo](https://github.com/elm-guides/elm-for-js/blob/master/How%20to%20Read%20a%20Type%20Annotation.md#how-to-read-a-type-annotation). Mais sobre guias da comunidade sobre o básico de Elm escrito por desenvolvedores JavaScript.
Saia e escreva algum código Elm!
|