Upload
others
View
5
Download
0
Embed Size (px)
Citation preview
Programovací jazyk F#Mgr. Jiří Valůšek
Univerzita Palackého v Olomouci
12.10.2020
Co je F#
• Dr. Don Syme z Microsoft Research
• Open-source
• Cross-platform
• Functional-first
• Multiparadigmatický
• Silně typový
• .NET jazyk
• Common Language Infrastructure (CLI)
Co umožňuje
• Data science:• statistical analysis• machine learning• data visualization
• Interactive scripting (REPL)
• Tvobra aplikací:• desktopové• webové• mobilní• cloudové
• Běh v prohlížeči (Fable)
Online zdroje a literatura
• F# Software Foundation
https://fsharp.org/
• Try F#
https://try.fsharp.org/
• Learn F# in Y minutes
https://learnxinyminutes.com/docs/fsharp/
• F# Programming Wikibook
https://en.wikibooks.org/wiki/F_Sharp_Programming
Online zdroje a literatura
• Daniel Mohl. Building Web, Cloud, and Mobile Solutions with F♯. 2012. ISBN: 1449333761, 9781449333768
• Robert Pickering, Kit Eason. Beginning F# 4.0. 2016. ISBN: 1484213742, 9781484213742
• Antonio Cisternino, Adam Granicz, Don Syme. Expert F# 4.0. 2015. ISBN: 1484207424, 9781484207420
• Mathias Brandewinder. Machine Learning Projects for .NET Developers. 2015. ISBN: 1430267666, 9781430267669
F# na Windows
• Příkazový řádek• .NET Core SDK• dotnet fsi source.fsx
• Visual Studio Code• .NET Core SDK• Otevřete VSCode, stiskněte Ctrl+Shift+P a zadejte příkaz:ext install Ionide-fsharp
• Visual Studio
• JetBrains Rider• .NET Core SDK
F# na Linuxu
• Příkazový řádek• .NET Core SDK
• dotnet fsi source.fsx
• Visual Studio Code• .NET Core SDK
• Otevřete VSCode, stiskněte Ctrl+Shift+P a zadejte příkaz:
ext install Ionide-fsharp
• JetBrains Rider
F# na macOS
• Příkazový řádek• .NET Core SDK
• dotnet fsi source.fsx
• Visual Studio Code• .NET Core SDK
• Otevřete VSCode, stiskněte Cmd+Shift+P a zadejte příkaz:
ext install Ionide-fsharp
• Visual Studio for Mac
• JetBrains Rider
Komentáře a F# Interactive
• Komentáře// jednořádkový komentář
(* víceřádkový
komentář *)
• F# Interactive#if INTERACTIVE
// kód pro F# Interactive
#else
// kód mimo F# Interactive
#endif
Poznámka: Po zadání kódu do F# interactive se pro vyhodnocení zadá ;;
Funkcionální programování
• Deklarace proměnných/hodnotlet x = 5
let y = 6
let z = x + y
let a = 3.5
let text = "Jazyk F#"
let Česko = "Česká republika"
printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z
printfn "a: %f" a
printfn "text: %s" text
printfn "stát: %s" Česko
Funkcionální programování
• Deklarace funkcífun x y -> x + y
Funkcionální programování
• Deklarace funkcílet add = fun x y -> x + y
Funkcionální programování
• Deklarace funkcílet add x y = x + y
Funkcionální programování
• Deklarace funkcífun x y -> x + y // anonymní funkce
let add x y = x + y
let myPrint a b c =
printfn "1. %s" a
printfn "2. %s" b
printfn "3. %s" c
Funkcionální programování
• Vnořená funkcelet myFun a b =
let add x y = x + y
let sub x y = x - y
(add a (sub a b))
• Rekurzelet rec fib n =
if n = 0 then 0
elif n = 1 then 1
else fib (n - 1) + fib (n - 2)
Lightweight syntax
• F# je ve výchozím stavu white-space sensitive – používá tzv. lightweight syntax
• Pro vypnutí lightweight syntax stačí na začátek souboru přidat#light "off"
// Lightweight syntax
let f x =
let a = 1
let b = 2
x * b + a
// Verbose syntax
let f x =
let a = 1 in
let b = 2 in
x * b + a
Type inference
• Každá hodnota má typ, což zahrnuje i hodnoty, které jsou funkce.> let x = 1;;
val x : int = 1
> let s = "Ahoj";;
val s : string = "Ahoj"
> let add x y = x + y;;
val add : x:int -> y:int -> int
Type inference
• Je možné typ hodnoty definovat.> let add (x: float) (y: float) = x + y;;
val add : x:float -> y:float -> float
> let f x = x;;
val f : x:'a -> 'a
• Typy začínající ' jsou tzv. proměnné typy (generické typy).
Funkcionální programování
• Pettern Matchingmatch expr with
| pat1 -> result1
| pat2 -> result2
| pat3 when expr2 -> result3
| _ -> defaultResult
• Příkladlet rec fib n =
match n with
| 0 -> 0
| 1 -> 1
| _ -> fib (n - 1) + fib (n - 2)
Funkcionální programování
• Alternativní syntaxlet something = function
| test1 -> value1
| test2 -> value2
| test3 -> value3
• Příkladlet getPrice = function
| "banana" -> 0.79
| "watermelon" -> 3.49
| "tofu" -> 1.09
| _ -> nan // nan znamená speciální hodnotu "not a number"
Funkcionální programování
let getPrice taxRate = function
| "banana" -> 0.79 * (1.0 + taxRate)
| "watermelon" -> 3.49 * (1.0 + taxRate)
| "tofu" -> 1.09 * (1.0 + taxRate)
| _ -> nan
> getPrice 1.5 "tofu";;
val it : float = 2.725
Funkcionální programování
• Přiřazení promennélet rec fac = function
| 0 | 1 -> 1
| n -> n * fac (n - 1)
• Upozornění: pattern matching se vyhodnocuje shora dolů.
Funkcionální programování
• Koncová rekurzelet rec slowMultiply a b =
if b > 1 then
a + slowMultiply a (b - 1)
else
a
Tato funkce není koncově rekurzivní.
Funkcionální programování
let slowMultiply a b =
let rec loop acc counter =
if counter > 1 then
loop (acc + a) (counter - 1)
else
acc
loop a b
• Tato funkce je koncově rekurzivní.
Funkcionální programování
• Funkce vyššího řádulet square x = x * x
let cube x = x * x * x
let passFive f = f 5
printfn "%i" (passFive square)
printfn "%i" (passFive cube)
Funkcionální programování
• Curringlet add x y = x + y
let addFive = add 5
> addFive 12;;
val it : int = 17
Proč to funguje?
let add x y = x + y
let add = (fun x -> (fun y -> x + y))
Funkcionální programování
• Tuple (n-tice)let a = (1,2)
let b = (1,3,5)
let c = (1, "text")
let avg (a,b,c) = (a + b + c) / 3
let getPowTuple a = (a,a*a)
Funkcionální programování
let greeting (name, language) =
match (name, language) with
| ("Steve", _) -> "Howdy, Steve"
| (name, "English") -> "Hello, " + name
| (name, _) when language.StartsWith("Span") -> "Hola, " + name
| (_, "French") -> "Bonjour!"
| _ -> "DOES NOT COMPUTE"
• Přiřazení více proměnnýmlet val1, val2, ... valN = (expr1, expr2, ... exprN)
let x, y = (1,2)
Funkcionální programování
• Record (záznam)type recordName =
{ [ fieldName : dataType ] + }
type website =
{ Title : string;
Url : string }
let homepage = { Title = "Google"; Url = "http://www.google.com" }
Funkcionální programování
type coords = { X : float; Y : float }
let setX item newX =
{ item with X = newX }
let start = { X = 1.0; Y = 2.0 }
let finish = setX start 15.5
type coords = { X : float; Y : float }
let getQuadrant = function
| { X = 0.0; Y = 0.0 } -> "Origin"
| item when item.X >= 0.0 && item.Y >= 0.0 -> "I"
| item when item.X <= 0.0 && item.Y >= 0.0 -> "II"
| item when item.X <= 0.0 && item.Y <= 0.0 -> "III"
| item when item.X >= 0.0 && item.Y <= 0.0 -> "IV"
Funkcionální programování
• Discriminated uniontype unionName =
| Case1
| Case2 of datatype
| ...
• Příkladtype switchstate =
| On
| Off
> let x = On;;
val x : switchstate = On
Funkcionální programování
type tree =
| Leaf of int
| Node of int * tree * tree
let myTree1 =
Node(1,Leaf(2),Leaf(3))
let myTree2 =
Node(1,
Node(2,Leaf(3),Leaf(4)),
Leaf(5))
Funkcionální programování
• Option type• Union type, který má pouze dvě hodnoty: Some a None.
• Příkladlet safediv x y =
match y with
| 0 -> None
| _ -> Some(x/y)
Funkcionální programování
• Seznamlet list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
let list2 = 1::2::3::[] // použití cons operátoru ::
let list3 = List.init 5 (fun index -> index * 3) // použití List.init
let list4 = [1 .. 10] // použití list comprehensions
let list5 = ['a' .. 'f'] // použití list comprehensions
let sum l =
let rec sumStep counter = function
| [] -> counter
| h::t -> sumStep (counter + h) t
sumStep 0 l
Funkcionální programování
• Modul List:• List.rev
• List.filter
• List.map
• List.append nebo infixový operátor @
• List.choose – filter a map zároveň
• List.fold a List.foldBack
• List.find a List.tryFind – find při nenalezení prvku vyvolá vyjímku
Funkcionální programování
List.rev (List.map (fun x -> x * x) (List.filter (fun x -> x % 2 = 1) (List.init 8 (fun index -> index * 3))))
val it : int list = [441; 225; 81; 9]
Funkcionální programování
List.init 8 (fun index -> index * 3)
|> List.filter (fun x -> x % 2 = 1)
|> List.map (fun x -> x * x)
|> List.rev
val it : int list = [441; 225; 81; 9]
• Pipe-forward operátor |>let (|>) x f = f x
Funkcionální programování
• Sekvenceseq { expr }
• Příkladlet s = seq { 1 .. 10 }
Seq.iter (fun x -> printfn "%i" x) s
• Modul Seq:• Seq.append
• Seq.item – vrátí prvek na daném indexu
• Seq.take – vrátí první n prvků
• …
Funkcionální programování
• Množinalet s1 = Set.empty.Add(1).Add(2).Add(3)
let s2 = Set.ofList [1..10]
• Modul Set:• Set.add• Set.compare• Set.count• Set.difference• Set.intersect• Set.remove• Set.union
Funkcionální programování
• Maplet m1 =
Map.empty.
Add("cz", "Čeština").
Add("sk", "Slovenština").
Add("en", "Angličtině").
Add("de", "Němčina").
Add("ru", "Ruština")
let m2 = ["cz", "Čeština";"sk", "Slovenština";"en", "Angličtině";"de", "Němčina";"ru", "Ruština"] |> Map.ofList
m1.["en"]
• Modul Map
Imperativní programování
• Mutable proměnnélet mutable x = "Inicializováno"
printfn "%s" x
x <- "Aktualizováno"
printfn "%s" x
Imperativní programování
• if/then/else/elifif expr then
expr
if expr then
expr
else
expr
Imperativní programování
if expr then
expr
elif expr then
expr
elif expr then
expr
...
else
expr
• Operátory: =, <, <=, >, >=, <> (není rovno)
• Logické operátory: && (AND), || (OR), not (negace)
Imperativní programování
• For cyklusfor pattern in expr do
... // tělo cyklu
• While cykluswhile expr do
... // tělo cyklu
Imperativní programování
• Polelet array1 = [|1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
let array2 = [|1 .. 10|]
let array3 = [|'a' .. 'f'|]
array1.[0] // 1
array1.[3..5] // [|4; 5; 6|]
• Modul Array:• Array.zeroCreate – vytvoří pole zadané délky s výchozími hodnotami daného
datového typu• Array.create – vytvoří pole zadané délky se zadanou hodnotou• Array.init – vytvoří pole zadané délky, kde každý prvek je vygenerován
zadanou funkcí
.NET knihovny
• V F# je možné používat .NET knihovny.open System
let x = 100
let y = "metrů"
Console.WriteLine("Délka: {0} {1}", x, y)
Imperativní programování
• Mutable Collectionsopen System.Collections.Generic
• Seznam (List<'T>)let myList = List<int>()
myList.Add(1)
myList.Add(5)
myList.[1]
• Spojový seznam (LinkedList<'T>)
• Množina (HashSet<'T>)
Objektově orientované programování
type User(id : int, firstName : string, lastName : string) =
let fullName = firstName + " " + lastName // private proměnná
let mutable access = false // mutable private proměnná
do // funkce, která se provede po konstruktoru
printfn "Inicializováno"
member x.Id = id // public read-only proměnná
member x.Access // getter a setter
with get() = access
and set(value) = access <- value
member x.SayName = printfn "%s" fullName // public metoda
let user = new User(1,"Jan","Novák")
user.SayName
Paralelní programování
• Async Workflows:• 1. Tělo funkce, kterou chceme vykonávat asyncrhonně, uzavřeme do async{}.
• 2. Na funkce vracející asyncrhonní výpočet zavoláme funkci modulu Async.
• Modul Async:• Async.RunSynchronously – spustí asynchronní výpočet a počká na jeho
dokončení.
• Async.Parallel – provede předané asynchronní výpočty paralelně.
• Start – spustí paralelní výpočet a nepočká na jeho dokončení.
Paralelní programování
let mutable x = 0
let add = async{for _ in [1..1000000] do x <- x + 1}
[add;add]
|> Async.Parallel
|> Async.RunSynchronously
> printfn "%i" x;;
1350393
Paralelní programování
open System.Threading
let testAsync() =
let mutable counter = 0
let AsyncIncr n =
new Thread(fun () -> for i in 1 .. n do counter <- counter + 1)
let t1 = AsyncIncr 1000000
let t2 = AsyncIncr 1000000
t1.Start() // spusť t1 asynchronně
t2.Start() // spusť t2 asynchronně
t1.Join() // počkej, dokud t1 neskončí
t2.Join() // počkej, dokud t2 neskončí
counter
> [for a in 1 .. 5 -> testAsync()];;
val it : int list = [1008983; 1110948; 1394603; 1095137; 1168450]
Úkol
• Vytvořte modul MyMath, který bude obsahovat:• Funkci gcd, která bude počítat největšího společného dělitele dvou čísel.
• Funkce addFrac, subFrac, mulFrac, divFrac pro sčítání, odčítání, násobení a dělení zlomků (funkce budou vracet zlomky v základním tvaru).
• Funkci comb, která spočítá kombinační číslo.
• Modul vytvořte jako knihovnu (Visual Studio). Na začátek kódu přidejte: module MyMath
• Pro jednoduchost stačí, že budou všechny funkce počítat pouze s celými čísly.