[PL] F# Wprowadzenie – listy i unie oraz wyszukiwanie wzorców
Kontynuując rozpoczęty artykuł o F#. Powracamy do interpretera FSI aby poeksperymentować dalej ze składnią.
Listy w F#:
Pusta lista:
> let emptyList = [];;
val emptyList : 'a list
Elementy listy:
> let listOneItem = "one" :: [];;
val listOneItem : string list = ["one"]
> let listTwoItems = "one" :: "two" :: [];;
val listTwoItems : string list = ["one"; "two"]
Listy wspierają tylko jeden typ składników:
> let badList = "one" :: 123 :: "three" :: [];;
let badList = "one" :: 123 :: "three" :: [];;
-----------------------^^^
stdin(5,24): error FS0001: This expression has type
int
but is here used with type
string
Oczywiście można listy zadeklarować w łatwiejszy sposób:
> let easyList = ["A"; "B"; "C"];;
val easyList : string list = ["A"; "B"; "C"]
A tak możemy łaczyć listy:
> let listLetters = easyList;;
val listLetters : string list = ["A"; "B"; "C"]
> let listNumbers = ["1";"2";"3"];;
val listNumbers : string list = ["1"; "2"; "3"]
> let listCombined = listLetters @ listNumbers;;
val listCombined : string list = ["A"; "B"; "C"; "1"; "2"; "3"]
Wyszukiwanie wzorców:
W zasadzie podobnie do C#, chociaż F# ma więcej możliwości wychodzących poza standardowe konstrukcje z C#. Poniżej przykłady:
> let patternMatching x = match x with | 0 -> printfn "Value is 0" | 1 -> printf
- n "Value is 1" | 2 -> printfn "Value is 2";;
val patternMatching : int –> unit
> let andTrue x = match x with | (true, true) -> true | _ -> false;;
val andTrue : bool * bool -> bool
Krótki test:
> andTrue(false,true);;
val it : bool = false
> andTrue(true,true);;
val it : bool = true
Spróbujmy się za pomocą powyższej składni pobawić ciągiem Fibonacci’ego:
> let rec fib x = match x with | 0 -> 0 | 1 -> 1 | _ -> fib(x-1) + fib(x-2);;
val fib : int -> int
I znajdzmy 42 liczbę:
> fib 42;;
val it : int = 267914296
Typy i unie:
Od tego momentu może zamiast fsi.exe proponuję utworzyć w Visual Studio 2010 nowy projekt F# (aplikacja konsolowa). Po jej utworzeniu dostaniemy plik program.fs zawierający jedną wdzięczną linijkę komentarza:
// Learn more about F# at https://fsharp.net
Krótki test zanim przejdziemy dalej, czyli Hello World zaczynamy jak na poniższym obrazku:
Intellisense po przestrzeniach .NETowych jak widać działa tak jakbyśmy oczekiwali, konstrukcja jest trochę inna niż przy innych projektach konsolowych, i nasze “Hello World”, tak naprawdę może zawierać jedną linijkę:
System.Console.WriteLine("Hello World\n")
W takim razie spróbujmy zdefiniować własne typy na przykładzie poniższego prostego programiku:
//proste typy
type ItemName = string
type UnitPrice = float
type Percent = float
//definicja rekordu:
type OrderItem = {
ItemOrdered : ItemName;
Quantity : int;
UnitPrice : UnitPrice;
Discount : Percent;
}
//przykład rekordu
let myOrder = { ItemOrdered="Pants"; Quantity=1; UnitPrice=12.38; Discount=10.0}
//kontrolnie jaki typ zostanie zwrócony?
System.Console.WriteLine("myOrder type is: " + myOrder.ToString())
let key = System.Console.ReadKey()
Ten programik powinien zwrócić: myOrder type is: Program+OrderItem
Ciekawą konstrukcją są unie i ich wykorzystanie, oto przykład z temperaturą
//Unia, przykład konwersji temperatur
type temperature =
| Celcius of float
| Fahrenheit of float
| Kelvin of float
let t1 = Celcius 32.0
let t2 = Fahrenheit 98.3
let t3 = Kelvin 5.0
let conv2F x =
match x with
| Celcius x -> Fahrenheit (x * 9.0/5.0 + 32.0)
| Fahrenheit x -> Fahrenheit x
| Kelvin x -> Fahrenheit (x * 9.0/5.0 - 459.67);;
let convResult = conv2F t1
Jak spojrzymy w wartość convResult to zobaczymy:
Możliwości takich unii łatwo sobie wyobrazić. Przy okazji proszę zwrócić uwagę na składnię związaną z wyszukiwaniem wzorców (match x with), w tym przypadku wykorzystaną, aby rozpoznać w jakim formacie temperaturę ma nasz pojemnik.