2. Общие сведения
F# — мультипарадигмальный язык:
• Функциональное программирование:
o Строго типизированный язык с возможностью
выведения типов;
o Поддерживает каррирование функций, лямбда-
функции, замыкания, композицию функций;
o Использование совпадений с образцом (pattern-
matching);
o Алгебраические типы данных (discriminated unions).
2
3. Общие сведения
F# — мультипарадигмальный язык:
• Императивное программирование:
o Изменяемые данные;
o Управление потоком выполнения (условные
переходы, циклы);
o Изменяемые массивы, списки и словари;
o Возможность использования изменяемых
переменных.
3
4. Общие сведения
F# — мультипарадигмальный язык:
• Объектно-ориентированное
программирование:
o Поддержка пользовательских типов данных
(записи, кортежи, классы);
o Классы:
• Наследование;
• Перегрузка операторов;
o Последовательные, параллельные, асинхронные
вычисления.
4
5. Типы данных
Тип данных Название
Целочисленный
sbyte, byte, int16, uint16, int/int32,
uint32, int64, uint64, bigint
С плавающей точкой float32, float, decimal
Строковый char, string
Логический bool
Специальные
unit, кортежи, последовательности,
списки, размеченные объединения
5
6. • Назначение символьного имени (≈ определение
переменной):
let x = 1
let y = 2
Или проще: let x, y = 1, 2
let z = x + y
• Определение функций:
let add x y = x + y
let addOne = add 1
o Вызов:
let sumXY = add x y // sumXY = 3
let sumX1 = addOne x // addX1 = 2
6
F#: функциональная парадигма
7. • Строгая типизация:
let sign num =
if num > 0 then "positive"
elif num < 0 then "negative"
else 0;; // error FS0001 — несовместимость
типов
• Внутренние функции:
let addOne x =
let add a b = a + b
add 1 x;;
• Рекурсия:
let rec fact n =
if n = 1 then 1
else fact (n – 1);;
7
F#: функциональная парадигма
8. • Хвостовая рекурсия — оптимальная рекурсия для
компилятора, т.к. преобразовывается в цикл.
• Применяется функциональный паттерн с
применением внутренней функции и
аккумулятора:
let fib n =
let loop acc1 acc2 = function
| n when n = 0I -> acc1
| n -> loop acc2 (acc1+acc2) (n-1I)
loop 0I 1I n
8
F#: функциональная парадигма
9. • Функция, имеющая тело, но не имеющая имени.
• Аналог из C# — анонимные делегаты.
• Синтаксис:
(fun arg1 arg2 ... -> expr)
let x = (fun x -> x * x) 2 // возвратит 4
9
F#: функциональная парадигма.
Лямбда-функции
10. • Вычисление N-ного числа Фибоначчи:
let fib n =
match n with
| 0 -> 0
| 1 -> 1
| _ -> fib (n – 1) + fib (n – 2)
• Условия совпадения можно комбинировать:
let rec factorial n =
match n with
| 0 | 1 -> 1
| _ -> n * factorial (n – 1)
10
F#: функциональная парадигма.
Совпадение с образцом
11. • Связывание переменных на лету:
let rec fact = function
| 0 | 1 -> 1
| n -> n * fact (n - 1)
• Использование guard’ов:
let sign = function
| 0 -> 0
| x when x < 0 -> -1
| x when x > 0 -> 1
11
F#: функциональная парадигма.
Совпадение с образцом
12. • let numbers = [1; 2; 3; 4; 5]
• let numbers = [1..2..5] // аналогично ↑
• Оператор :: ("cons"):
let primes = 1 :: 3 :: 5 :: 7 :: []
• Использование List.init:
List.init 5 (fun x -> x + 1) // [1; 2; 3; 4; 5]
List.init 5 (fun x -> x, x*x, x*x*x)
//[(0,0,0);(1,1,1);(2,4,8);(3,9,27);(4,16,64)]
12
F#: функциональная парадигма.
Работа со списками
13. • Использование генераторов:
o Синтаксис: [for x in collection do … yield expr]
[for a in 1..10 do yield (a, a*a)] // [(1,1), (2,4), (3,9), ...]
[for a in 1..3 do yield! [a..a+3]] // [1,2,3,4, 2,3,4,5, 3,4,5,6]
• Совпадение с образцом:
let rec sumList list =
match list with
| [] -> 0
| head::tail -> head + sumList tail
let reverse list =
let rec loop acc = function
| [] -> acc
| hd :: tl -> loop (hd :: acc) tl
loop [] list
13
F#: функциональная парадигма.
Работа со списками
14. • Использование модуля List:
o rev — обращение списка:
List.rev [1..5] // [5;4;3;2;1]
o filter — фильтрация списка:
List.filter (fun x -> x % 2 = 0) [1..10] // [2;4;6;8;10]
o map — применение функции к каждому элементу списка:
List.map (fun x -> x*x) [1..5] // [1;4;9;16;25]
o append (оператор @):
let numbers = [1..5] @ [6..10] // [1;2;3;4;5;6;7;8;9;10]
o find и tryFind:
List.find (fun x -> x = 1) [1..10] // возвратит 1
List.find (fun x -> x = 0) [1..10] // ошибка KeyNotFoundException
List.tryFind (fun x -> x = 0) [1..10] // возвратит None
o fold и foldBack
List.fold (+) 0 [1..100] //5050
14
F#: функциональная парадигма.
Работа со списками
15. • Являются алгебраическим типом данных.
• Представляют собой определенный набор
вариантов выбора. Дают возможность выявить
ошибки на этапе компиляции.
• Синтаксис:
type unionName =
| Case1
| Case2 as datatype
| …
15
F#: функциональная парадигма.
Размеченные объединения
16. • Пример: "выключатель"
type switchState =
| On
| Off
| Ranged of float
let toggle = function
| On -> Off
| Off -> On
| Ranged(brightness) -> 1.0 - brightness
let x = On
let y = toggle x
let z = toggle Ranged(0.3)
16
F#: функциональная парадигма.
Размеченные объединения
17. • Пример: двоичные деревья
type tree =
| Leaf of int
| Node of tree * tree
let countLeaves tree =
let rec loop acc tree =
match tree with
| Leaf(_) -> acc + 1
| Node(tree1, tree2) -> (loop acc tree1)
+ (loop acc tree2)
loop 0 tree
17
F#: функциональная парадигма.
Размеченные объединения
18. • Изменяемые данные:
• Ключевое слово mutable:
let mutable x = 1
x <- 10
• Ключевое слово ref:
let x = ref 1 // x = ref int {contents = 1}
Обращение к ссылочному типу данных:
let y = !x + 1 // y = 2
Присвоение:
x := 2 // x = ref int {contents = 2}
18
F#: императивная парадигма
19. • Пример: функция статического инкремента (а-ля
"генератор ID")
let incr =
let counter = ref 0
fun () ->
counter := !counter + 1
!counter
let id1 = incr() // id1 = 0
let id2 = incr() // id2 = 1
let id3 = incr() // id3 = 2
let id4 = incr() // id4 = 3
19
F#: императивная парадигма
20. • Цикл for диапазонов:
for var = start-expr to end-expr do
... // тело цикла
for i = 1 to 5 do
printfn "i: %i" i
Выведет:
i: 1
i: 2
i: 3
i: 4
i: 5
20
F#: императивная парадигма.
Циклы
21. • Цикл for для коллекций и последовательностей:
for pattern in expr do
... // тело цикла
let customers = ["John", 21; "Mary", 18; "Katy", 20]
for (name, age) in customers do
printfn "Name: %s, age: %d" name age
Выведет:
Name: John, Age: 21
Name: Mary, Age: 18
Name: Katy, Age: 20
21
F#: императивная парадигма.
Циклы
22. • Цикл while:
while expr do
... // тело цикла
let mutable i = 0
while i < 3 do
printfn "%i" i
i <- i + 1
Выведет:
0
1
2
22
F#: императивная парадигма.
Циклы
23. • Объявление и инициализация очень похожи на работу со
списками:
let names = [|"Mary"; "Kate"; "Jane"|]
Array.init 5 (fun index -> index + 1) // [|1;2;3;4;5|]
Array.create 3 "Hello" // [|"Hello"; "Hello"; "Hello"|]
Array.zeroCreate 5 // [|0;0;0;0;0|]
Доступ:
let kate = names.[1] // kate = "Kate"
Изменение:
names.[2] <- "Lucy"
Разделение (slicing):
let slice1 = names.[1..] // slice1 = [|"Kate"; "Jane"|]
let slice2 = names.[..1] // slice2 = [|"Mary"; "Kate"|]
23
F#: императивная парадигма.
Массивы
24. • Прямоугольные (массив массивов равной размерности):
let arr = Array2D.init<int> 2 3 (fun row col -> row+col)
arr = [| [|0; 1; 2|];
[|1; 2; 3|];
[|2; 3; 4|] |]
let zero = arr.[0, 0] // zero = 0
• Вложенные (список массивов не обязательно равной
размерности):
let jagged = [| for x in 1..3 do yield [|1..x|] |]
jagged = [| [|1|];
[|1; 2|];
[|1; 2; 3|] |]
jagged.[0].[0] = 0
24
F#: императивная парадигма.
Двухмерные массивы
25. • Полезные функции модуля Array:
o fold, foldBack, map, filter, rev — аналогичны функциям
модуля List;
o append — соединяет первый аргумент со вторым,
возвращает новый массив. Нет сокращенного имени.
o fill — заполняет массив от индекса Start до индекса
finish переданным значением value;
o iter — применяет переданную функцию ко всем
элементам массива. В отличии от map, не возвращает
нового массива;
o length — возвращает длину массива;
o sort — возвращает отсортированную копию массива;
o sortInPlace — сортирует элементы в массиве.
25
F#: императивная парадигма.
Массивы
26. Список Массив
Неизменяемый, может содержать
общие элементы с другими
списками
Константное время доступа к
элементам
Совпадение с образцом
Возможность произвольного
доступа
Поддерживает map и fold Поддерживает map и fold
Линейное время доступа
Не может содержать общие
элементы с другими массивами
Нет произвольного доступа к
элементам — только
последовательный доступ
Нельзя менять размер на лету
(только путем копирования через
Array.append)
26
F#: императивная парадигма.
Сравнение списков и массивов
27. • Неявный способ определения:
type TypeName optional-type-arguments arguments
[ as ident ] =
[ inherit type { as base } ]
[ let-binding | let-rec bindings ] *
[ do-statement ] *
[ abstract-binding | member-binding |
interface-implementation ] *
27
F#: объектная парадигма.
Определение классов
28. • Неявный способ определения:
type MyPoint(x : int, y : int) = class
let mutable color = Color.Black
member this.X = x
member this.Y = y
member x.Color = color
member x.SetColor(c:Color) = color <- c
member me.Print = printfn "X = %d Y = %d
Color = %A" me.X me.Y me.Color
end
28
F#: объектная парадигма.
Определение классов
29. • Явный способ определения:
type Point = class
val X : int
val Y : int
val Color : Color
new (x,y,c) as this =
{X = x; Y = y; Color = c}
then
printf "Point created at (%d;%d)" this.X
this.Y
member me.Print = printfn "X = %d Y = %d Color =
%A" me.X me.Y me.Color
end
29
F#: объектная парадигма.
Определение классов
30. • Абстрактные классы:
[<AbstractClass>]
type Shape() =
override x.ToString() = sprintf "%s, area = %f"
(x.GetType().Name) (x.Area())
abstract member Draw : unit -> unit
abstract member Area : unit -> float
type Circle(radius : float) =
inherit Shape
member x.Radius = radius
override x.Draw() = printfn "(Circle)”
override x.Area() = Math.PI * radius * radius
30
F#: объектная парадигма.
Определение классов
31. • Пример перегрузки конструкторов:
type Line = class
val X1:int
val X2:int
val Y1:int
val Y2:int
new() =
{ X1 = 0; X2 = 0; Y1 = 0; Y2 = 0 }
new(x1,x2,y1,y2) =
{ X1 = x1; X2 = x2; Y1 = y1; Y2 = y2 }
new(p1 : Point, p2 : Point) =
{ X1 = p1.X; X2 = p2.X; Y1 = p1.Y; Y2 = p2.Y }
end
31
F#: объектная парадигма.
Перегрузка методов
32. • Общее описание инфиксного оператора:
let (operator) arg1 arg2 = ...
• Пример: оператор совпадения по шаблону
let (=~) arg pattern = Regex.IsMatch(arg,
pattern)
Использование:
let result1 = "cat" =~ "dog" // result1 = false
let result2 = "catamorphism" =~ "cat*"
// result2 = true
32
F#: объектная парадигма.
Перегрузка операторов
33. Последовательности в F#
• Последовательность (sequence) — это список,
значение которого вычисляются «лениво», т.е. по
требованию.
let numbers = seq {0I .. 1000000000000I}
Или через использование генераторов:
let numbers = seq{for i in 0I..1000000000000I do
yield i}
let firstTen = Seq.take 10 numbers
// firstTen = [0;1;2;3;4;5;6;7;8;9]
let million = Seq.nth 1000000 numbers
// million = 1000000
33
34. Асинхронность и параллелизм
• Модуль Async позволяет работать с асинхронными,
синхронными и параллельными вызовами функций.
• Пример: простой синхронный веб-краулер
let getLinks url =
async {
let webClient = new WebClient()
printfn "Downloading %s" url
let html = webClient.DownloadString(url : string)
printfn "Got %d bytes" html.Length
let matches = Regex.Matches(html, @"http://S+")
printfn "Got %d links" matches.Count
return url, matches.Count
}
let result = Async.RunSynchronously(getLinks
"http://www.msn.com/")
34
35. • Пример: простой асинхронный веб-краулер
let extractLinksAsync html =
async {
return
System.Text.RegularExpressions.Regex.Matches(html,
@"http://S+")
}
let getLinks url =
async {
let webClient = new System.Net.WebClient()
let html = webClient.DownloadString(url : string)
let! links = extractLinksAsync html
return url, links.Count
}
let links = getLinks "http://www.msn.com/"
let result = Async.Run links
35
Асинхронность и параллелизм
36. • Пример: простой параллельный асинхронный веб-краулер
let extractLinks html = Regex.Matches(html, @"http://S+")
let getLinks url =
let webClient = new System.Net.WebClient()
let html = webClient.DownloadString(url : string)
extractLinks html
let download url =
let links = (getLinks url)
url, links.Count
let urls = [@"http://www.msn.com/";
@"http://www.microsoft.com/";
@"http://www.techdays.ru/"]
let result = seq { for u in urls -> async { return download u } }
|> Async.Parallel
|> Async.RunSynchronously
36
Асинхронность и параллелизм
37. Ресурсы о F#
• Microsoft F# Developer Center:
http://msdn.microsoft.com/ru-ru/fsharp/default(en-
us).aspx
• Wikibooks: F# Programming:
http://en.wikibooks.org/wiki/F_Sharp_Programming
• Don Syme's WebLog on F# and Related Topics:
http://blogs.msdn.com/dsyme/
• F# For Scientists: http://www.amazon.com/F-
Scientists-Jon-Harrop/dp/0470242116
• Beginning F#:
http://apress.com/book/view/1430223898
• Expert F#:
http://apress.com/book/view/1590598504
37