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
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
|
---
language: F#
filename: learnfsharp-pt.fs
contributors:
- ["Scott Wlaschin", "http://fsharpforfunandprofit.com"]
- ["Adelar da Silva Queiróz", "https://adelarsq.github.io"]
lang: pt-br
---
F# é uma linguagem de propósito geral funcional e orientada a objetos. É livre, de código aberto e executa em Linux, Mac, Windows e outros.
Possui um sistema de tipagem poderoso que evita muitos erros em tempo de compilação. Para isto utilizando inferência de tipos, o que a faz se comportar como uma linguagem dinâmica.
A sintaxe é diferente das linguagens do estilo C (C, C#, Java, etc):
* Chaves não são usadas para delimitar blocos de código. Ao invés disso é utilizada indentação (semelhante ao Python).
* Espaços em branco são usados para separar parâmetros, ao invés de vírgulas.
Se você deseja executar o código abaixo, copie e cole em [https://try.fsharp.org](https://try.fsharp.org), que é um REPL online.
```fsharp
// comentários de linhas únicas usam barras duplas
(* comentários de linhas múltiplas usam o par (* . . . *)
-fim do comentário de linhas múltiplas- *)
// ================================================
// Sintaxe básica
// ================================================
// ------ "Variáveis" (mas não exatamente) ------
// A palavra reservada "let" define um valor imutável
let myInt = 5
let myFloat = 3.14
let myString = "hello" // note que nenhum tipo é necessário
// ------ Listas ------
let twoToFive = [2; 3; 4; 5] // Colchetes criam uma lista com
// ponto e vírgula como delimitadores
let oneToFive = 1 :: twoToFive // :: cria uma lista com um novo primeiro elemento
// O resultado é [1; 2; 3; 4; 5]
let zeroToFive = [0; 1] @ twoToFive // @ concatena duas listas
// IMPORTANTE: vírgulas nunca são usadas como delimitadores, somente ponto e vírgula!
// ------ Funções ------
// A palavra chave "let" também define nomes para funções.
let square x = x * x // Note que não são usados parêntesis
square 3 // Agora executando a função. Também sem parêntesis
let add x y = x + y // Não use add (x,y)! Isto significa algo
// completamente diferente.
add 2 3 // Agora execute a função.
// para definir uma função de múltiplas linhas apenas use indentação. Nenhum ponto e vírgula é necessário
let evens list =
let isEven x = x % 2 = 0 // Define "isEven"como uma sub função. Note
// que o operador de igualdade é um simples "=".
List.filter isEven list // List.filter é uma função da biblioteca padrão
// com dois parâmetros: uma função que retorna boolean
// e uma lista para verificar
evens oneToFive // Agora executando a função
// Usando parênteses é possível deixar mais clara a precedência. Neste exemplo,
// "map" é usado primeiro, com dois argumentos, então executa "sum" no resultado.
// Sem os parênteses, "List.map" seria passado como uma argumento para List.sum
let sumOfSquaresTo100 =
List.sum ( List.map square [1..100] )
// É possível redirecionar a saída de uma operação para a próxima usando pipe ("|>")
// Redirecimento de dados é algo comum em F#, similar a pipes Unix.
// Aqui é a mesma função sumOfSquares escrita com pipe
let sumOfSquaresTo100piped =
[1..100] |> List.map square |> List.sum // "square" foi definido anteriormente
// você pode definir lambdas (funções anônimas) usando a palavra reservada "fun"
let sumOfSquaresTo100withFun =
[1..100] |> List.map (fun x -> x * x) |> List.sum
// Em F# não há a palavra chave "return". Funções sempre
// retornam o valor da última expressão usada.
// ------ Casamento de padrões (Pattern Matching) ------
// Match..with.. é um poderoso case/switch.
let simplePatternMatch =
let x = "a"
match x with
| "a" -> printfn "x is a"
| "b" -> printfn "x is b"
| _ -> printfn "x is something else" // sublinhado combina com qualquer coisa
// F# não permite null por padrão -- deve-se usar um Option
// e então efetuar um casamento de padrão.
// Some(..) e None são análogos a Nullable
let validValue = Some(99)
let invalidValue = None
// Neste exemplo, match..with casa com "Some" e "None",
// e também desconstrói o valor em "Some" ao mesmo tempo.
let optionPatternMatch input =
match input with
| Some i -> printfn "input is an int=%d" i
| None -> printfn "input is missing"
optionPatternMatch validValue
optionPatternMatch invalidValue
// ------ Escrevando na tela ------
// As funções printf/printfn são similares às
// Console.Write/WriteLine encontradas no C#.
printfn "Printing an int %i, a float %f, a bool %b" 1 2.0 true
printfn "A string %s, and something generic %A" "hello" [1; 2; 3; 4]
// Exitem também as funções sprintf/sprintfn para formatação de dados
// em uma string, semelhante à String.Format do C#.
// ================================================
// Mais sobre funções
// ================================================
// F# é uma liguagem verdadeiramente funcional -- funções fazem
// parte das classes e podem ser combinadas facilmente para criar
// poderosos construtores
// Módulos podem usar um grupo de funções
// É necessário usar indentação para defini-las.
module FunctionExamples =
// define uma função de soma
let add x y = x + y
// básico uso de uma função
let a = add 1 2
printfn "1 + 2 = %i" a
// aplicação parcial de parâmetros
let add42 = add 42
let b = add42 1
printfn "42 + 1 = %i" b
// composição para combinar funções
let add1 = add 1
let add2 = add 2
let add3 = add1 >> add2
let c = add3 7
printfn "3 + 7 = %i" c
// funções de alta ordem
[1..10] |> List.map add3 |> printfn "new list is %A"
// listas de funções e mais
let add6 = [add1; add2; add3] |> List.reduce (>>)
let d = add6 7
printfn "1 + 2 + 3 + 7 = %i" d
// ================================================
// Listas e coleções
// ================================================
// Existem três tipos de coleções ordenadas:
// * Listas são o tipo mais básico de coleção imutável;
// * Arrays são mutáveis e mais eficientes;
// * Sequences são lazy e infinitas (semelhante a enumerator).
//
// Outras coleções incluem maps e conjuntos imutáveis
// mais todas as coleções padrões do .NET
module ListExamples =
// listas usam colchetes
let list1 = ["a"; "b"]
let list2 = "c" :: list1 // :: é usado para adicionar um elemento no início da lista
let list3 = list1 @ list2 // @ é o operador de concatenação
// list comprehensions (generators)
let squares = [for i in 1..10 do yield i * i]
// Um gerador de números primos
// - este usa a notação custa para casamento de padrões
// - (p::xs) significa 'primeiro :: cauda' da lista, e pode ser escrito como p :: xs
// isto significa que casa 'p' (o primeiro item da lista), e xs recebe o resto da lista
// que é chamdo de 'cons pattern'
// - usa a palavra chave 'rec', que é necessária quando se usa recursão
let rec sieve = function
| (p::xs) -> p :: sieve [ for x in xs do if x % p > 0 then yield x ]
| [] -> []
let primes = sieve [2..50]
printfn "%A" primes
// casamento de padrões (pattern matching) com listas
let listMatcher aList =
match aList with
| [] -> printfn "the list is empty"
| [first] -> printfn "the list has one element %A " first
| [first; second] -> printfn "list is %A and %A" first second
| first :: _ -> printfn "the list has more than two elements, first element %A" first
listMatcher [1; 2; 3; 4]
listMatcher [1; 2]
listMatcher [1]
listMatcher []
// recursão usando listas
let rec sum aList =
match aList with
| [] -> 0
| x::xs -> x + sum xs
sum [1..10]
// -----------------------------------------
// Funções da biblioteca padrão
// -----------------------------------------
// mapas
let add3 x = x + 3
[1..10] |> List.map add3
// filtros
let even x = x % 2 = 0
[1..10] |> List.filter even
// muito mais -- veja a documentação
module ArrayExamples =
// arrays usam colchetes com barra vertical
let array1 = [| "a"; "b" |]
let first = array1.[0] // acesso por índice usando ponto
// casamento de padrões (pattern matching) para arrays é feito da mesma forma que de listas
let arrayMatcher aList =
match aList with
| [| |] -> printfn "the array is empty"
| [| first |] -> printfn "the array has one element %A " first
| [| first; second |] -> printfn "array is %A and %A" first second
| _ -> printfn "the array has more than two elements"
arrayMatcher [| 1; 2; 3; 4 |]
// As funções da biblioteca padrão são as mesmas que para List
[| 1..10 |]
|> Array.map (fun i -> i + 3)
|> Array.filter (fun i -> i % 2 = 0)
|> Array.iter (printfn "value is %i. ")
module SequenceExamples =
// sequências usam chaves
let seq1 = seq { yield "a"; yield "b" }
// sequências podem usar yield e
// podem conter subsequencias
let strange = seq {
// "yield" adiciona um elemento
yield 1; yield 2;
// "yield!" adiciona uma subsequencia
yield! [5..10]
yield! seq {
for i in 1..10 do
if i % 2 = 0 then yield i }}
// teste
strange |> Seq.toList
// Sequências podem ser criadas usando "unfold"
// Este é um exemplo da série de Fibonacci
let fib = Seq.unfold (fun (fst,snd) ->
Some(fst + snd, (snd, fst + snd))) (0,1)
// teste
let fib10 = fib |> Seq.take 10 |> Seq.toList
printf "first 10 fibs are %A" fib10
// ================================================
// Tipos de dados
// ================================================
module DataTypeExamples =
// Todos os dados são imutáveis por padrão
// Tuplas são uma forma rápida de reprentar n elementos de tipos anônimos
// -- Use a vírgula para criar uma tupla
let twoTuple = 1, 2
let threeTuple = "a", 2, true
// Casamento de padrões (pattern match) para desconstruir
let x, y = twoTuple // atribui x = 1, y = 2
// ------------------------------------
// O tipo registro possui nomes nos campos
// ------------------------------------
// Use "type" com chaves para definir um registro
type Person = {First:string; Last:string}
// Use "let" com chaves para criar um registro
let person1 = {First="John"; Last="Doe"}
// Casamento de padrões para desconstruir
let {First = first} = person1 // atribui first="John"
// ------------------------------------
// Tipos union (variantes) possuem um conjunto de escolhas
// Somente um caso pode ser válido por vez.
// ------------------------------------
// Use "type" com barra/pipe para definir um union
type Temp =
| DegreesC of float
| DegreesF of float
// Use qualquer dos tipos para criar um
let temp1 = DegreesF 98.6
let temp2 = DegreesC 37.0
// Casamento de padrões deve cobrir todos os tipos de definidos para desconstruir
let printTemp = function
| DegreesC t -> printfn "%f degC" t
| DegreesF t -> printfn "%f degF" t
printTemp temp1
printTemp temp2
// ------------------------------------
// Tipos recursivos
// ------------------------------------
// Tipos podem ser combinados recursivamente de formas complexas
// sem ter que criar subclasses
type Employee =
| Worker of Person
| Manager of Employee list
let jdoe = {First="John"; Last="Doe"}
let worker = Worker jdoe
// ------------------------------------
// Modelando com tipos
// ------------------------------------
// Tipos union são muito bons para modelagem de estados sem usar flags
type EmailAddress =
| ValidEmailAddress of string
| InvalidEmailAddress of string
let trySendEmail email =
match email with // casamento de padrões
| ValidEmailAddress address -> () // envia
| InvalidEmailAddress address -> () // não envia
// A combinação de tipos union e registros juntos
// provê uma grande fundação para DDD (Domain Driven Design).
// Você pode criar centenas de pequenos tipos que refletem
// exatamente o seu domínio.
type CartItem = { ProductCode: string; Qty: int }
type Payment = Payment of float
type ActiveCartData = { UnpaidItems: CartItem list }
type PaidCartData = { PaidItems: CartItem list; Payment: Payment}
type ShoppingCart =
| EmptyCart // nenhum dado
| ActiveCart of ActiveCartData
| PaidCart of PaidCartData
// ------------------------------------
// Comportamento padrão para tipos
// ------------------------------------
// Tipos padrões possuem um padrão já definido, não precisando de codificação nenhuma.
// * Imutáveis
// * Impressão formatada para depuração
// * Igualdade e comparação
// * Serialização
// Impressão formatada usando %A
printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A"
twoTuple person1 temp1 worker
// Igualdade e comparação padrão.
// Um exemplo com cartas:
type Suit = Club | Diamond | Spade | Heart
type Rank = Two | Three | Four | Five | Six | Seven | Eight
| Nine | Ten | Jack | Queen | King | Ace
let hand = [ Club, Ace; Heart, Three; Heart, Ace;
Spade, Jack; Diamond, Two; Diamond, Ace ]
// ordenando
List.sort hand |> printfn "sorted hand is (low to high) %A"
List.max hand |> printfn "high card is %A"
List.min hand |> printfn "low card is %A"
// ================================================
// Padrões ativos (Active patterns)
// ================================================
module ActivePatternExamples =
// F# possui um tipo especial de casamento de padrões chamado "padrões ativos" ("active patterns")
// onde o padrão pode ser interpretado ou detectado dinamicamente.
// parêntesis e barra são a sintaxe para "padrões ativos"
// Você pode usar "elif" ao invés de "else if" em expressões condicionais.
// Elas são equivalentes em F#
// por exemplo, defina um "padrão ativo" para tratar tipos de caracteres...
let (|Digit|Letter|Whitespace|Other|) ch =
if System.Char.IsDigit(ch) then Digit
elif System.Char.IsLetter(ch) then Letter
elif System.Char.IsWhiteSpace(ch) then Whitespace
else Other
// ... e então use ele para interpretar de forma bem mais simples
let printChar ch =
match ch with
| Digit -> printfn "%c is a Digit" ch
| Letter -> printfn "%c is a Letter" ch
| Whitespace -> printfn "%c is a Whitespace" ch
| _ -> printfn "%c is something else" ch
// imprima a lista
['a'; 'b'; '1'; ' '; '-'; 'c'] |> List.iter printChar
// ------------------------------------------------
// FizzBuzz usando padrões ativos (active patterns)
// ------------------------------------------------
// É possível criar casamento de padrões parcial também
// Apenas use sublinhado para a definição, e retorne Some se casado.
let (|MultOf3|_|) i = if i % 3 = 0 then Some MultOf3 else None
let (|MultOf5|_|) i = if i % 5 = 0 then Some MultOf5 else None
// a função principal
let fizzBuzz i =
match i with
| MultOf3 & MultOf5 -> printf "FizzBuzz, "
| MultOf3 -> printf "Fizz, "
| MultOf5 -> printf "Buzz, "
| _ -> printf "%i, " i
// teste
[1..20] |> List.iter fizzBuzz
// ================================================
// Expressividade
// ================================================
module AlgorithmExamples =
// F# possui uma alta razão sinais/ruídos, assim o código
// é lido praticamento como se descreve o algoritmo
// ------ Exemplo: defina uma função que faça soma dos quadrados ------
let sumOfSquares n =
[1..n] // 1) pega todos os números de 1 a n
|> List.map square // 2) eleva ao quadrado cada um
|> List.sum // 3) soma os resultados
// teste
sumOfSquares 100 |> printfn "Sum of squares = %A"
// ------ Examplo: defina uma função de ordenação ------
let rec sort list =
match list with
// Se a lista está vazia
| [] ->
[] // retorna a lista vazia
// Se a lista não está vazia
| firstElem::otherElements -> // pega o primeiro elemento
let smallerElements = // extrai os elementos menores
otherElements // dos restantes
|> List.filter (fun e -> e < firstElem)
|> sort // e ordena eles
let largerElements = // extrai os elementos maiores
otherElements // dos restantes
|> List.filter (fun e -> e >= firstElem)
|> sort // e ordena eles
// Combine as 3 partes em uma nova lista e retorne ela
List.concat [smallerElements; [firstElem]; largerElements]
// teste
sort [1; 5; 23; 18; 9; 1; 3] |> printfn "Sorted = %A"
// ================================================
// Código assíncrono
// ================================================
module AsyncExample =
// F# possui suporte a funcionalidades para ajudar a escrever código assíncrono
// sem tornar o código difícil de manter ("pyramid of doom")
//
// O seguinte exemplo efetua download de um conjunto de páginas em paralelo.
open System.Net
open System
open System.IO
open Microsoft.FSharp.Control.CommonExtensions
// Obtém o conteúdo de cara página de forma assíncrona
let fetchUrlAsync url =
async { // a palavra chave "async" e chaves
// criam um objeto assíncrono
let req = WebRequest.Create(Uri(url))
use! resp = req.AsyncGetResponse()
// use! é uma atribuição assíncrona
use stream = resp.GetResponseStream()
// "use" dispara automaticamente close()
// no recurso no fim do escopo
use reader = new IO.StreamReader(stream)
let html = reader.ReadToEnd()
printfn "finished downloading %s" url
}
// uma lista de sites para fazer download
let sites = ["http://www.bing.com";
"http://www.google.com";
"http://www.microsoft.com";
"http://www.amazon.com";
"http://www.yahoo.com"]
// efetue
sites
|> List.map fetchUrlAsync // cria uma lista de tarefas assíncronas
|> Async.Parallel // coloca as tarefas para executarem em paralelo
|> Async.RunSynchronously // inicia cada uma
// ================================================
// Compatibilidade com .NET
// ================================================
module NetCompatibilityExamples =
// F# pode pode fazer praticamente tudo que C# pode fazer, e integra
// de forma simples com bibliotecas .NET e Mono
// ------- usando uma função de uma biblioteca existente -------
let (i1success, i1) = System.Int32.TryParse("123");
if i1success then printfn "parsed as %i" i1 else printfn "parse failed"
// ------- Implementando interfaces de forma simples! -------
// cria um novo objeto que implementa IDisposable
let makeResource name =
{ new System.IDisposable
with member this.Dispose() = printfn "%s disposed" name }
let useAndDisposeResources =
use r1 = makeResource "first resource"
printfn "using first resource"
for i in [1..3] do
let resourceName = sprintf "\tinner resource %d" i
use temp = makeResource resourceName
printfn "\tdo something with %s" resourceName
use r2 = makeResource "second resource"
printfn "using second resource"
printfn "done."
// ------- Código orientado a objetos -------
// F# também possui suporte a orientação a objetos.
// Possui suporte a classes, herança, métodos virtuais, etc.
// interface com tipo genérico
type IEnumerator<'a> =
abstract member Current : 'a
abstract MoveNext : unit -> bool
// classe base abstrata com métodos virtuais
[<AbstractClass>]
type Shape() =
// propriedades somente leitura
abstract member Width : int with get
abstract member Height : int with get
// método não virtual
member this.BoundingArea = this.Height * this.Width
// método virtual com implementação base
abstract member Print : unit -> unit
default this.Print () = printfn "I'm a shape"
// classe concreta que herda da classe base e sobrescreve
type Rectangle(x:int, y:int) =
inherit Shape()
override this.Width = x
override this.Height = y
override this.Print () = printfn "I'm a Rectangle"
// testes
let r = Rectangle(2, 3)
printfn "The width is %i" r.Width
printfn "The area is %i" r.BoundingArea
r.Print()
// ------- métodos de extensão -------
// Assim como em C#, F# pode extender classes já existentes com métodos de extensão.
type System.String with
member this.StartsWithA = this.StartsWith "A"
// testes
let s = "Alice"
printfn "'%s' starts with an 'A' = %A" s s.StartsWithA
// ------- eventos -------
type MyButton() =
let clickEvent = new Event<_>()
[<CLIEvent>]
member this.OnClick = clickEvent.Publish
member this.TestEvent(arg) =
clickEvent.Trigger(this, arg)
// teste
let myButton = new MyButton()
myButton.OnClick.Add(fun (sender, arg) ->
printfn "Click event with arg=%O" arg)
myButton.TestEvent("Hello World!")
```
## Mais Informações
Para mais demonstrações de F# acesse [why use F#](http://fsharpforfunandprofit.com/why-use-fsharp/).
Leia mais sobre F# em [fsharp.org](http://fsharp.org/) e [dotnet's F# page](https://dotnet.microsoft.com/languages/fsharp).
|