2. Visual F# .NET

Transkrypt

2. Visual F# .NET
Język F#
Języki Programowania na Platformie .NET (część 2)
Tomasz Goluch
http://www.kaims.pl/∼goluch/
[email protected]
Słowa kluczowe języka
abstract, and, as, assert, base, begin, class, default,
delegate, do, done, downcast, downto, elif, else, end,
exception, extern, false, finally, for, fun, function,
global, if, in, inherit, inline, interface, internal, lazy,
let, let!, match, member, module, mutable, namespace, new,
not, null, of, open, or, override, private, public, rec,
return, return!, select, static, struct, then, to, true,
try, type, upcast, use, use!, val, void, when, while, with,
yield, yield!
Tomasz Goluch
Język F#
Składnia
Język F#posiada dwie składnie:
verbose
rzadziej stosowana,
mniej wrażliwa na wcięcia.
light
krótsza,
mniej tokenów (np. nie są wymagane: done, in i ;),
zamiast bloków:
begin – end, class – end,
struct – end, interface – end,
with – end stosowane są wcięcia,
zabronione są znaki tabulacji.
Tomasz Goluch
Język F#
Składnia
Różnica:
#light
let add a b c =
let ab = a + b
printfn "%d" ab
c - ab
let add a b c =
let ab = a + b in //’in’ specyfikuje zakres wiązania ab
printfn "%d" ab; //’;’ rozdziela wyrażenia
c - ab;;
//’;;’ koniec funkcji
Tomasz Goluch
Język F#
Dyrektywy preprocesora
#if #else #endif (Dyrektywy kompilacji warunkowej) – inne
zachowanie niż w typowych językach. Przykładowo, nie można
stosować wyrażeń logicznych zawierających symbole. Słowa true i
false nie mają specjalnego znaczenia. Nie ma dyrektywy #define
należy użyć opcji kompilatora bądź ustawień projektu do
definiowania symboli.
Tomasz Goluch
Język F#
Dyrektywy preprocesora
#[line] int
#[line] int string
#[line] int verbatim-string (dyrektywy wiersza) – Jeżeli kod
F#jest generowany na podstawie innych źródeł to można przekazać
informacje o numerach i nazwach plików z których został on
wygenerowany w celu łatwiejszego raportowanie błędów.
# 25
#line 25
#line 25 "C:\\Projects\\MyProject\\MyProject\\Script1"
#line 25 @"C:\Projects\MyProject\MyProject\Script1"
# 25 @"C:\Projects\MyProject\MyProject\Script1"
Tomasz Goluch
Język F#
Dyrektywy kompilatora
#light ["on"|"off"]
#indent ["on"|"off"] – Włącza/wyłącza składnię lekką light
dla zgodności z innymi wersjami ML (ang. Meta Language).
Dyrektywy #light i #indent są wymienne i mają taką samą
składnię i skutek. Domyślnie składnia lekka jest włączona. Składnia
verbose zawsze jest dostępna.
Tomasz Goluch
Język F#
Wartości
Wartości w F#mają przyjmować typ liczb całkowitych lub
zmiennoprzecinkowych, znaków, tekstu, list, sekwencji, tablic,
krotek, unii, rekordów, klas typów i wartości funkcji.
Do wiązania identyfikatora wartości z jej definicją służy słowo
kluczowe let:
let a = 1
let b = 100u
let str = "text"
// A function value binding.
let f x = x + 1
Tomasz Goluch
Język F#
Wartości
Dlaczego „immutable” ?
Domyślnie wszystkie wartości w F#nie mogą ulec zmianie w trakcie
wykonywania programu. Takie zmienne są łatwe do zarządzania w
środowisku wielowątkowym. Nie ma problemu z dylematem czy
zmienna może ulec zmianie jeśli została przekazana do innej
funkcji. Funkcje zachowują się jak typowe funkcje matematyczne.
Pozwala to na bardziej restrykcyjny tryb pracy kompilatorów i
lepszy stopień optymalizacji, a programistom na łatwiejsze
zrozumienie i pisanie poprawnego kodu. Kod języków funkcyjnych
jest prostszy do debuggowania.
Tomasz Goluch
Język F#
Zmienne
F# jednak nie jest czystym językiem programowania. Słowo
kluczowe mutable pozwala na definicję zmiennej. Przeważnie mają
one ograniczony zakres jako pole typu albo zmienna lokalna, co
pozwala na łatwiejszą kontrolę i mniejsze prawdopodobieństwo
zmiany wartości w niespodziewany sposób. Przypisanie wartości
początkowej wygląda identycznie a do zmiany wartości służy
operator przypisania: <- :
let mutable x = 1
x <- x + 1
Tomasz Goluch
Język F#
Słowo kluczowe let
Słowo kluczowe let służy do wiązania identyfikatora z wartością
lub funkcją:
// Wiązanie wartości:
let identifier-or-pattern [: type] =
expression
body-expression
// Wiązanie funkcji:
let identifier parameter-list [: return-type ] =
expression
body-expression
Tomasz Goluch
Język F#
Słowo kluczowe let
Wiązanie większej liczby identyfikatorów:
let i, j, k = (1, 2, 3)
Wiązane identyfikatory dostępne są dopiero po definicji, nie można
ich użyć w kodzie wcześniej:
// Error:
printfn "%d" x
let x = 100
// OK:
printfn "%d" x
Tomasz Goluch
Język F#
Słowo kluczowe let
Wiązanie funkcji:
let function1 a =
a + 1
let function2 (a, b) = a + b
let result =
let function3 (a, b) = a + b
100 * function3 (1, 2)
Tomasz Goluch
Język F#
Słowo kluczowe let
Przypisywanie typu:
let function1 (a: int) : int = a + 1
Tomasz Goluch
Język F#
Funkcje
Definicja funkcji:
// Bez rekurencji
let [inline] function-name parameter-list
[ : return-type ] = function-body
// Rekurencyjna
let rec function-name parameter-list
= recursive-function-body
Tomasz Goluch
Język F#
Operatory arytmetyczne
+ - * / % ** (operatory binarne) dodawanie, odejmowanie,
mnożenie, dzielenie, dzielenie modulo i potęgowanie. Dzielenie
dla typów całkowitych rzuca wyjątek
DivideByZeroException a dla zmiennoprzecinkowych
specjalne wartości (+/-)Infinity. Dla wyniku dzielenia
modulo znak jest taki sam jak znak pierwszego operandu.
+ - (operatory unarne) wartość dodatnia, ujemna.
Tomasz Goluch
Język F#
Operatory arytmetyczne
+ - * / % ** (operatory binarne) dodawanie, odejmowanie,
mnożenie, dzielenie, dzielenie modulo i potęgowanie. Dzielenie
dla typów całkowitych rzuca wyjątek
DivideByZeroException a dla zmiennoprzecinkowych
specjalne wartości (+/-)Infinity. Dla wyniku dzielenia
modulo znak jest taki sam jak znak pierwszego operandu.
+ - (operatory unarne) wartość dodatnia, ujemna.
= > < >= <= <> (binarne operatory porównania) równe,
większe niż, mniejsze niż, większe lub równe, mniejsze lub
równe, nierówne.
Tomasz Goluch
Język F#
Operatory arytmetyczne
+ - * / % ** (operatory binarne) dodawanie, odejmowanie,
mnożenie, dzielenie, dzielenie modulo i potęgowanie. Dzielenie
dla typów całkowitych rzuca wyjątek
DivideByZeroException a dla zmiennoprzecinkowych
specjalne wartości (+/-)Infinity. Dla wyniku dzielenia
modulo znak jest taki sam jak znak pierwszego operandu.
+ - (operatory unarne) wartość dodatnia, ujemna.
= > < >= <= <> (binarne operatory porównania) równe,
większe niż, mniejsze niż, większe lub równe, mniejsze lub
równe, nierówne.
Tomasz Goluch
Język F#
Operatory logiczne
&& || ^^^ (binarne operatory logiczne) koniunkcja (iloczyn
logiczny), alternatywa (suma logiczna). Wartości składowych
wyrażenia logicznego są wyliczane jedynie gdy wpływają na
wynik (short-circuit evaluation). Drugie wyrażenie nie jest
wyliczane jeśli (dla koniunkcji) pierwsze jest fałszywe a (dla
alternatywy) prawdziwe.
not (unarny operator logiczny) negacja.
Tomasz Goluch
Język F#
Operatory logiczne
&& || ^^^ (binarne operatory logiczne) koniunkcja (iloczyn
logiczny), alternatywa (suma logiczna). Wartości składowych
wyrażenia logicznego są wyliczane jedynie gdy wpływają na
wynik (short-circuit evaluation). Drugie wyrażenie nie jest
wyliczane jeśli (dla koniunkcji) pierwsze jest fałszywe a (dla
alternatywy) prawdziwe.
not (unarny operator logiczny) negacja.
Tomasz Goluch
Język F#
Operatory bitowe
&&& ||| ^^^ <<< >>> (binarne operatory bitowe)
koniunkcja (iloczyn logiczny), alternatywa (suma logiczna),
alternatywa wykluczająca (różnica symetryczna lub suma
modulo 2), przesunięcie bitowe w lewo i prawo. Drugi operator
przesunięcia bitowego jest typu int32.
~~~ (unarny operator bitowy) negacja.
Tomasz Goluch
Język F#
Operatory bitowe
&&& ||| ^^^ <<< >>> (binarne operatory bitowe)
koniunkcja (iloczyn logiczny), alternatywa (suma logiczna),
alternatywa wykluczająca (różnica symetryczna lub suma
modulo 2), przesunięcie bitowe w lewo i prawo. Drugi operator
przesunięcia bitowego jest typu int32.
~~~ (unarny operator bitowy) negacja.
Tomasz Goluch
Język F#
Przeciążanie operatorów
// Przeciążenie operatora klasy lub rekordu.
static member (operator-symbols) (parameter-list) =
method-body
// Przeciążenie operatora globalnego
let [inline] (operator-symbols) parameter-list =
function-body
Przeciążając operatory unarne należy zaznaczyć ten fakt przy
pomocy tyldy:
static member (~-) (v : Vector)
Tomasz Goluch
Język F#
Przeciążanie operatorów
type Vector(x: float, y : float) =
member this.x = x
member this.y = y
static member (~-) (v : Vector) =
Vector(-1.0 * v.x, -1.0 * v.y)
static member (*) (v : Vector, a) =
Vector(a * v.x, a * v.y)
static member (*) (a, v: Vector) =
Vector(a * v.x, a * v.y)
let v1 = Vector(1.0, 2.0)
let v2 = v1 * 2.0
let v3 = 2.0 * v1
let v4 = - v2
Tomasz Goluch
Język F#
Typy nullable – ?
Można konwertować typu nullable do „zwykłych” przy pomocy
operatorów takich jak: int, float... Możliwa jest również
konwersja pomiędzy różnymi typami nullable przy pomocy prefiksu
Nullable z przestrzeni nazw Microsoft.FSharp.Linq.
open Microsoft.Fsharp.Linq
let nullableInt = new System.Nullable<int>(10)
// Konwersja na inny typ nullable
let nullableFloat = Nullable.float nullableInt
// Konwersja na typ zwykły
printfn "%f" (float nullableFloat)
Wynik: 10.000000.
Tomasz Goluch
Język F#
Operator nullable – ?
Pozwala na pracę innych operatorów z wartościami null.
?>= ?> ?<= ?< ?= ?<> ?+ ?- ?* ?/ ?%
(dopuszczalne wartości null po lewej stronie)
?>= >? <=? <? =? <>? +? -? *? /? %?
(dopuszczalne wartości null po prawej stronie)
Tomasz Goluch
Język F#
Operator nullable – ?
Pozwala na pracę innych operatorów z wartościami null.
?>= ?> ?<= ?< ?= ?<> ?+ ?- ?* ?/ ?%
(dopuszczalne wartości null po lewej stronie)
?>= >? <=? <? =? <>? +? -? *? /? %?
(dopuszczalne wartości null po prawej stronie)
?>= ?>? ?<=? ?<? ?=? ?<>? ?+? ?-? ?*? ?/? ?%?
(dopuszczalne wartości null po obydwu stronach)
Tomasz Goluch
Język F#
Operator nullable – ?
Pozwala na pracę innych operatorów z wartościami null.
?>= ?> ?<= ?< ?= ?<> ?+ ?- ?* ?/ ?%
(dopuszczalne wartości null po lewej stronie)
?>= >? <=? <? =? <>? +? -? *? /? %?
(dopuszczalne wartości null po prawej stronie)
?>= ?>? ?<=? ?<? ?=? ?<>? ?+? ?-? ?*? ?/? ?%?
(dopuszczalne wartości null po obydwu stronach)
Tomasz Goluch
Język F#
Przykłady
Tomasz Goluch
Język F#
Przykłady
Liczby całkowite i podstawowe funkcje:
let integer = 176
// Prosta funkcja wykonująca działania arytmrtyczne
let integer2 = (integer/4 + 5 - 7) * 4
// Lista liczb z przedziału od 0 do 99
let numbers = [ 0 .. 99 ]
// Lista krotek zawierających liczby od 0 to 99
// oraz ich kwadraty
let tableOfSquares = [ for i in 0 .. 99 -> (i, i*i) ]
// Drukowanie zawartości listy (Generic Pretty-Printing %A)
printfn "Squares from 0 to 99 are:\n%A" tableOfSquares
Tomasz Goluch
Język F#
Przykłady
Liczby całkowite i podstawowe funkcje:
// Funkcja przyjmująca i zwracająca liczbę całkowitą
let func1 (x) = x*x + 3
// Nawiasy dla argumentów funkcji są opcjonalne
let func1 x = x*x + 3
// Wywołanie funkcji z przypisaniem wyniku do zmiennej
// Typ zmiennej wynika z typu zwracanego przez funkcję
let result1 = func1 4573
printfn "Square of 4573 + 3 is %d" result1
Tomasz Goluch
Język F#
Przykłady
Liczby całkowite i podstawowe funkcje:
// Opisanie typ parametru za pomocą:’(argument:typ)’
let func2 (x:int) = 2*x*x - x/5 + 3
let result2 = func2 (7 + 4)
// 243
printfn "The result of func2 (7 + 4) is %d" result2
let func3 x =
if x < 100.0 then
2.0*x*x - x/5.0 + 3.0
else
2.0*x*x + x/5.0 - 37.0
let result3 = func3 (6.5 + 4.5) // 242.800000
printfn "The result of func3 (6.5 + 4.5) is %f" result3
Tomasz Goluch
Język F#
Przykłady
Wartości logiczne
let boolean1 = true
let boolean2 = false
let boolean3 = not boolean1 && (boolean2 || false)
printfn "The expression value is %b" boolean3
// The expression value is false
Tomasz Goluch
Język F#
Przykłady
Napisy
let string1 = "Hello"
let string2 = "world"
// Znak @ ignoruje kody specjalne (literał dosłowny)
let string3 = @"c:\Program Files\"
// Użycie potójnego cytatu
let string4 = """He said "hello world" after you did"""
// Połączenie dwóch napisów ze spacą pomiędzy
let helloWorld = string1 + " " + string2
printfn "%s" helloWorld //Hello world
// Napis składjący się z pierwszych 7 znaków
let substring = helloWorld.[0..6]
printfn "%s" substring //Hello w
Tomasz Goluch
Język F#
Przykłady
Krotki (Tuples)
// Krotka liczb całkowitych
let tuple1 = (1, 2, 3)
// Funkcja zamieniająca kolejność dwóch elementów w krotce
// Jak pokazuje QuickInfo, jest to funkcja ogólna
let swapElems (a, b) = (b, a)
printfn "Swapping elements 1 i 2 = %A" (swapElems (1,2))
// Swapping elements 1 i 2 = (2, 1)
// Krotka składająca się z liczby całkowitej,
// napisu oraz liczby zmiennorzecinkowej podwójnej precyzji
let tuple2 = (1, "fred", 3.1415)
printfn "tuple1: %A
// tuple1: (1, 2, 3)
tuple2: %A" tuple1 tuple2
tuple2: (1, "fred", 3.1415)
Tomasz Goluch
Język F#
Przykłady
Listy
let list1 = [ ]
// Pusta lista
let list2 = [ 1; 2; 3 ] // Lista 3 elementów
// Nowa lista z ’42’ dodanym na początku
let list3 = 42 :: list2
// Lista liczb całkowitch od 1 do 1000
let numberList = [ 1 .. 1000 ]
Tomasz Goluch
Język F#
Przykłady
Listy
// Lista zawierająca wszystkie dni roku
let daysList =
[ for month in 1 .. 12 do
for day in 1 .. DateTime.DaysInMonth(2016, month)
do
yield DateTime(2016, month, day) ]
// Lista zawierająca krotki reprezentujące
// Współrzędne czarnych pól szachownicy
let blackSquares =
[ for i in 0 .. 7 do
for j in 0 .. 7 do
if (i+j) % 2 = 1 then
yield (i, j) ]
Tomasz Goluch
Język F#
Przykłady
Przetwarzanie list
// Podnosi liczby w liście do kwardatu,
// przekazując argument do List.map
// przy pomocy operatora pipeline: |>
let squares =
numberList
|> List.map (fun x -> x*x)
// Oblicza sumę kwadratów liczb podzielnych przez 3
let sumOfSquaresUpTo n =
numberList
|> List.filter (fun x -> x % 3 = 0)
|> List.sumBy (fun x -> x * x)
Tomasz Goluch
Język F#
Przykłady
Klasy
// Konstruktor klasy przyjmuje dwa argumenty: dx i dy,
// obydwa typu zmiennoprzecinkowego
type Vector2D(dx : float, dy : float) =
// Długość wektora obliczana jest podczas tworzenia obiektu
let length = sqrt (dx*dx + dy*dy)
// ’this’ określa nazwę identyfikatora dla samego siebie
// W metodach instancji, musi poprzedzać nazwy składowych
member this.DX = dx
member this.DY = dy
member this.Length = length
member this.Scale(k) = Vector2D(k * this.DX, k * this.DY)
Tomasz Goluch
Język F#
Przykłady
Klasy
// Instancja klasy Vector2D
let vector1 = Vector2D(3.0, 4.0)
// Pobranie nowego obieku przeskalowanego wektora,
// bez modyfikowania oryginalnego obiektu
let vector2 = vector1.Scale(10.0)
printfn "Length of vector1: %f Length of vector2: %f"
vector1.Length vector2.Length
// Length of vector1: 5.000000 Length of vector2: 50.000000
Tomasz Goluch
Język F#
Przykłady
Klasy generyczne
// ’T jest parametrem typu dla klasy
type StateTracker<’T>(initialElement: ’T) =
// Stany przechowywane w tablicy
let mutable states = [ initialElement ]
// Dodanie nowego elementu do listy stanów
member this.UpdateState newState =
// Użycie operatora <- w celu zmiany wartości
states <- newState :: states
// Pobranie całej historii stanów
member this.History = states
// Pobranie najnowszego stanu
member this.Current = states.Head
Tomasz Goluch
Język F#
Przykłady
Klasy generyczne
// Instancja typu ’int’ klasy StateTracker
// Parametr typu został wywnioskowany przez kompilator
let tracker = StateTracker 10
// Dodanie stanu
tracker.UpdateState 17
Tomasz Goluch
Język F#
Przykłady
Implementacja interfejsów
// Typ implementujący IDisposable
type ReadFile() =
let file = new System.IO.StreamReader("readme.txt")
member this.ReadLine() = file.ReadLine()
// Implementacja elementu interfejsu IDisposable
interface System.IDisposable with
member this.Dispose() = file.Close()
Tomasz Goluch
Język F#
Przykłady
Tablice
let array1 = [| |] // Pusta tablica
let array2 = [| "hello"; "world"; "and";
"hello"; "world"; "again" |]
let array3 = [| 1 .. 1000 |]
// Tablica zawiera jedynie słowa "hello" i "world"
let array4 = [| for word in array2 do
if word.Contains("l") then
yield word |]
// Modyfikacja elementu tablicy operatorem przypisania: <array2.[1] <- "WORLD!"
// Oblicza sumę długości słów rozpoczynających się od ’h’
let sumOfLengthsOfWords =
array2
|> Array.filter (fun x -> x.StartsWith "h")
|> Array.sumBy (fun x -> x.Length)
Tomasz Goluch
Język F#
Przykłady
Tablice
//
//
//
//
for word in array4 do
printfn "word: %s" word
word: hello
word: world
word: hello
word: world
// Tablica zainicjowana poprzez indeks,
// zawiera parzyste liczby od 0 do 2000
let evenNumbers = Array.init 1001 (fun n -> n * 2)
// Wycinek tablicy uzyskany przy użyciu "slicing notation"
let evenNumbersSlice = evenNumbers.[0..500]
Tomasz Goluch
Język F#
Przykłady
Sekwencje są wyliczane na żądanie oraz wyliczane ponownie przy
każdej iteracji. W F# sekwencja jest instancją
System.Collections.Generic.IEnumerable <’T>, co pozwala
na stosowanie funkcji Seq do list i tablic.
// Pusta sekwencja
let seq1 = Seq.empty
let seq2 = seq { yield "hello"; yield "world"; yield "and";
yield "hello"; yield "world"; yield "again" }
let numbersSeq = seq { 1 .. 1000 }
// Kolejna tablica zawierająca jedynie słowa "hello" i "world"
let seq3 =
seq { for word in seq2 do
if word.Contains("l") then
yield word }
Tomasz Goluch
Język F#
Przykłady
Sekwencje
let evenNumbers = Seq.init 1001 (fun n -> n * 2)
let rnd = System.Random()
// Nieskończony ciąg (losowy spacer)
// Używaj yield! w celu zwrócenia każdego elementu podsekwencji,
// podobnie jak w IEnumerable.SelectMany
let rec randomWalk x =
seq { yield x
yield! randomWalk (x + rnd.NextDouble() - 0.5) }
let first100ValuesOfRandomWalk =
randomWalk 5.0
|> Seq.truncate 100
|> Seq.toList
Tomasz Goluch
Język F#
Przykłady
Rekurencja
// Użycie ’let rec’ definiuje funkcję rekurencyjną
let rec factorial n =
if n = 0 then 1 else n * factorial (n-1)
// Ponieważ wszystkie wywołania rekurencyjne to
// tzw. rekurencja ogonowa, kompilator uruchomi je w pętli,
// co zwiększa wydajność i zmniejsza zużycie pamięci.
let rec greatestCommonFactor a b =
if a = 0 then b
elif a < b then greatestCommonFactor a (b - a)
else greatestCommonFactor (a - b) b
Tomasz Goluch
Język F#
Przykłady
Rekurencja
// Rekurencyjne obliczanie sumę listy liczb całkowitych
let rec sumList xs =
match xs with
| []
-> 0
| y::ys -> y + sumList ys
// Zmiana na rekurencję ogonową,
// przy użyciu funkcji pomocniczej z akumulatorem wyniku
let rec private sumListTailRecHelper accumulator xs =
match xs with
| []
-> accumulator
| y::ys -> sumListTailRecHelper (accumulator+y) ys
let sumListTailRecursive xs = sumListTailRecHelper 0 xs
Tomasz Goluch
Język F#
Przykłady
Rekordy – podobne do krotek ale posiadają nazwane wartości i
opcjonalnie mogą posiadać składowe „member”
// Definicja typu rekordu
type ContactCard =
{ Name
: string;
Phone
: string;
Verified : bool }
let contact1 = { Name = "Alf" ;
Phone = "(206) 555-0157" ;
Verified = false }
// Utworzenie kopii rekordu contact1, posiadającej
// inne wartości w polach ’Phone’ i ’Verified’
let contact2 = { contact1 with Phone = "(206) 555-0112";
Verified = true }
// Konwersja obiektu ’ContactCard’ na napis
let showCard c =
c.Name + " Phone: " + c.Phone +
(if not c.Verified then " (unverified)" else "")
Tomasz Goluch
Język F#
Przykłady
Unie dyskryminowane
type Suit =
// Kolory w kartach do gry
| Hearts
| Clubs
| Diamonds
| Spades
type Rank =
// Figury w kartach do gry
| Value of int // Figury od 2 .. 10
| Ace
| King
| Queen
| Jack
static member GetAllRanks() =
[ yield Ace
for i in 2 .. 10 do yield Value i
yield Jack
yield Queen
yield King ]
Tomasz Goluch
Język F#
Przykłady
Unie dyskryminowane
// Konwersja obiektu ’Card’ na napis
let showCard c =
let rankString =
match c.Rank with
| Ace -> "Ace"
| King -> "King"
| Queen -> "Queen"
| Jack -> "Jack"
| Value n -> string n
let suitString =
match c.Suit with
| Clubs -> "clubs"
| Diamonds -> "diamonds"
| Spades -> "spades"
| Hearts -> "hearts"
rankString + " of " + suitString
Tomasz Goluch
Język F#
Przykłady
Unie dyskryminowane
type Card =
{ Suit: Suit; Rank: Rank }
// Zwraca listę wszystkich karty z talii
let fullDeck =
[ for suit in [ Hearts; Diamonds; Clubs; Spades] do
for rank in Rank.GetAllRanks() do
yield { Suit=suit; Rank=rank } ]
// Drukuje wszystkie karty z talii
let printAllCards() =
for card in fullDeck do
printfn "%s" (showCard card)
Tomasz Goluch
Język F#
Przykłady
Opcje to wszelkiego rodzaju wartości z etykietą ’Some’ lub ’None’.
Są one szeroko stosowane w F# do reprezentowania przypadków w
których inne języki użyły by pustej referencji (null).
type Customer = { zipCode : decimal option }
Tomasz Goluch
Język F#
Przykłady
Opcje
// Klasa abstrakcyjna obliczająca strefę wysyłki dla podanego
// kodu pocztowego klienta, podaje implementacje dla
// abstrakcyjnych metod: ’getState’ i ’getShippingZone’.
[<AbstractClass>]
type ShippingCalculator =
abstract getState : decimal -> string option
abstract getShippingZone : string -> int
//
//
//
//
Zwracana strefa wysyłki zależy
od kodu pocztowego klienta.
Klient może jeszcze nie posiadać
kodu pocztowego lub może być on nieważny
member this.customerShippingZone(customer : Customer) =
customer.zipCode |> Option.bind this.getState
|> Option.map this.getShippingZone
Tomasz Goluch
Język F#
Przykłady
Dopasowanie wzorca
// Rekord zawierający imię i nazwisko osoby
type Person = {
First : string
Last : string
}
// definicja dyskryminowanej unii
// reprezentujacej 3 rodzaje pracowników
type Employee =
| Engineer of Person
// Manager posiada listę raportów
| Manager
of Person * list<Employee>
// Executive posiada również asystenta
| Executive of Person * list<Employee> * Employee
Tomasz Goluch
Język F#
Przykłady
Dopasowanie wzorca
// zlicza wszystkich podwładnych danego pracownika
// w hierarchii zarządania wliczając jego samego
let rec countReports(emp : Employee) =
1 + match emp with
| Engineer(id) ->
0
| Manager(id, reports) ->
reports |> List.sumBy countReports
| Executive(id, reports, assistant) ->
(reports |> List.sumBy countReports)
+ countReports assistant
Tomasz Goluch
Język F#
Przykłady
Dopasowanie wzorca
// znajduje wszystkich managers/executives
// o nazwisku "Dave" nie posiadających raportów
let rec findDaveWithOpenPosition(emps : Employee list) =
emps
|> List.filter(function
// [] matches the empty list
| Manager({First = "Dave"}, []) -> true
| Executive({First = "Dave"}, [], _) -> true
// ’_’ is a wildcard pattern that matches anything
// this handles the "or else" case
| _ -> false)
Tomasz Goluch
Język F#
Przykłady
Jednostki miary – kod można oznaczyć jednostką miary dokonując
arytmetyki na typach liczbowych
open Microsoft.FSharp.Data.UnitSystems.SI.UnitNames
[<Measure>]
type mile =
// Współczynnik konwersji: mila/metr:
// Metr jest zdefiniowany w SI.UnitNames
static member asMeter = 1600.<meter/mile>
// Odległość wyrażona za pomocą jednostek imperialnych
let d = 50.<mile>
// Odległość wyrażona za pomocą systemu metrycznego
let d2 = d * mile.asMeter
printfn "%A = %A" d d2
// 50.0 = 80000.0
// let error = d + d2 // Błąd kompilacji:
// units of measure do not match
Tomasz Goluch
Język F#
Przykłady
Programowanie równoległe tablic
let oneBigArray = [| 0 .. 100000 |]
// intensywne obliczenia CPU
let rec computeSomeFunction x =
if x <= 2 then 1
else computeSomeFunction (x - 1)
+ computeSomeFunction (x - 2)
// Równoległa mapa na dużej tablicy wejściowej
let computeResults() = oneBigArray
|> Array.Parallel.map (fun x -> computeSomeFunction (x % 20))
printfn "Parallel computation results: %A" (computeResults())
Tomasz Goluch
Język F#
Przykłady
Programowanie równoległe tablic
Parallel computation results: [|1; 1; 1; 2; 3; 5; 8; 13; 21;
34; 55; 89; 144; 233; 377; 610; 987; 1597; 2584; 4181; 1; 1;
1; 2; 3; 5; 8; 13; 21; 34; 55; 89; 144; 233; 377; 610; 987;
1597; 2584; 4181; 1; 1; 1; 2; 3; 5; 8; 13; 21; 34; 55; 89;
144; 233; 377; 610; 987; 1597; 2584; 4181; 1; 1; 1; 2; 3; 5;
8; 13; 21; 34; 55; 89; 144; 233; 377; 610; 987; 1597; 2584;
4181; 1; 1; 1; 2; 3; 5; 8; 13; 21; 34; 55; 89; 144; 233; 377;
610; 987; 1597; 2584; 4181; ...|]
Tomasz Goluch
Język F#
Przykłady
Wykorzystanie zdarzeń
// Utworzenie instancji Event w którego skład wchodzi
// punkt subskrypcji (event.Publish) oraz wyzwalacz zdarzenia
// (event.Trigger)
let simpleEvent = new Event<int>()
// dodanie uchwytu
simpleEvent.Publish.Add(
fun x -> printfn "handler added with Publish.Add: %d" x)
// zdarzenie wyzwalające
simpleEvent.Trigger(5)
Tomasz Goluch
Język F#
Przykłady
Wykorzystanie zdarzeń
// Utworzenie instancji Event przy pomocy standardowej
// konwencji .NET: (sender, EventArgs)
let eventForDelegateType = new Event<EventHandler,
EventArgs>()
// dodanie uchwytu
eventForDelegateType.Publish.AddHandler(
EventHandler(fun _ _ -> printfn "handler added with
Publish.AddHandler"))
// zdarzenie wyzwalające (należy zauważyć, że argument
// nadawcy powinien być zainicjalizowany)
eventForDelegateType.Trigger(null, EventArgs.Empty)
Tomasz Goluch
Język F#
Przykłady
Dostęp do baz danych przy pomocy dostawcy typów
//
//
//
#r
#r
#r
Jest to najprostszy sposób na dostęp dobazy SQL
Należy dodać referencje do System.Data,
System.Data.Linq, i FSharp.Data.TypeProviders.dll.
"System.Data"
"System.Data.Linq"
"FSharp.Data.TypeProviders"
open Microsoft.FSharp.Data.TypeProviders
// ConnectionString można zbudować wykorzystując
// Server Explorer.
Tomasz Goluch
Język F#
Przykłady
Dostęp do baz danych przy pomocy dostawcy typów
type SqlConnection = SqlDataConnection<ConnectionString =
@"Data Source=.\sqlexpress;
Initial Catalog=tempdb;
Integrated Security=True">
let db = SqlConnection.GetDataContext()
let table =
query { for r in db.Table do
select r }
// Zamiast SqlDataConnection można również użyć
// SqlEntityConnection, pozwalającego na dostęp
// do bazy przy użyciu Entity Framework.
Tomasz Goluch
Język F#
Przykłady
Dostęp do OData przy pomocy dostawcy typów
open System.Data.Services.Client
open Microsoft.FSharp.Data.TypeProviders
// Dane o konsumpcji oraz dochodach społeczeństwa
// z serwisu OData Azure Marketplace.
type Demographics = Microsoft.FSharp.Data.TypeProvider
.ODataService<ServiceUri =
"https://api.datamarket.azure.com/Esri/KeyUSDemographicsTrial/">
Tomasz Goluch
Język F#
Przykłady
Dostęp do OData przy pomocy dostawcy typów
let ctx = Demographics.GetDataContext()
// logowanie do konta Azure Marketplace na
// https://datamarket.azure.com/account/info
ctx.Credentials <- System.Net.NetworkCredential
("<your liveID>", "<your Azure Marketplace Key>")
let cities = query {
for c in ctx.demog1 do
where (c.StateName = "Washington")
}
for c in cities do
printfn "%A - %A" c.GeographyId c.PerCapitaIncome2010.Value
Tomasz Goluch
Język F#
Dziękuje za uwagę
Tomasz Goluch
Język F#

Podobne dokumenty