Функциональное
программирование
на F#
Богомолов Юрий
yuriy.bogomolov@gmail.com
1
Общие сведения
F# — мультипарадигмальный язык:
• Функциональное программирование:
o Строго типизированный язык с возможнос...
Общие сведения
F# — мультипарадигмальный язык:
• Императивное программирование:
o Изменяемые данные;
o Управление потоком ...
Общие сведения
F# — мультипарадигмальный язык:
• Объектно-ориентированное
программирование:
o Поддержка пользовательских т...
Типы данных
Тип данных Название
Целочисленный
sbyte, byte, int16, uint16, int/int32,
uint32, int64, uint64, bigint
С плава...
• Назначение символьного имени (≈ определение
переменной):
let x = 1
let y = 2
Или проще: let x, y = 1, 2
let z = x + y
• ...
• Строгая типизация:
let sign num =
if num > 0 then "positive"
elif num < 0 then "negative"
else 0;; // error FS0001 — нес...
• Хвостовая рекурсия — оптимальная рекурсия для
компилятора, т.к. преобразовывается в цикл.
• Применяется функциональный п...
• Функция, имеющая тело, но не имеющая имени.
• Аналог из C# — анонимные делегаты.
• Синтаксис:
(fun arg1 arg2 ... -> expr...
• Вычисление N-ного числа Фибоначчи:
let fib n =
match n with
| 0 -> 0
| 1 -> 1
| _ -> fib (n – 1) + fib (n – 2)
• Условия...
• Связывание переменных на лету:
let rec fact = function
| 0 | 1 -> 1
| n -> n * fact (n - 1)
• Использование guard’ов:
le...
• let numbers = [1; 2; 3; 4; 5]
• let numbers = [1..2..5] // аналогично ↑
• Оператор :: ("cons"):
let primes = 1 :: 3 :: 5...
• Использование генераторов:
o Синтаксис: [for x in collection do … yield expr]
[for a in 1..10 do yield (a, a*a)] // [(1,...
• Использование модуля List:
o rev — обращение списка:
List.rev [1..5] // [5;4;3;2;1]
o filter — фильтрация списка:
List.f...
• Являются алгебраическим типом данных.
• Представляют собой определенный набор
вариантов выбора. Дают возможность выявить...
• Пример: "выключатель"
type switchState =
| On
| Off
| Ranged of float
let toggle = function
| On -> Off
| Off -> On
| Ra...
• Пример: двоичные деревья
type tree =
| Leaf of int
| Node of tree * tree
let countLeaves tree =
let rec loop acc tree =
...
• Изменяемые данные:
• Ключевое слово mutable:
let mutable x = 1
x <- 10
• Ключевое слово ref:
let x = ref 1 // x = ref in...
• Пример: функция статического инкремента (а-ля
"генератор ID")
let incr =
let counter = ref 0
fun () ->
counter := !count...
• Цикл for диапазонов:
for var = start-expr to end-expr do
... // тело цикла
for i = 1 to 5 do
printfn "i: %i" i
Выведет:
...
• Цикл for для коллекций и последовательностей:
for pattern in expr do
... // тело цикла
let customers = ["John", 21; "Mar...
• Цикл while:
while expr do
... // тело цикла
let mutable i = 0
while i < 3 do
printfn "%i" i
i <- i + 1
Выведет:
0
1
2
22...
• Объявление и инициализация очень похожи на работу со
списками:
let names = [|"Mary"; "Kate"; "Jane"|]
Array.init 5 (fun ...
• Прямоугольные (массив массивов равной размерности):
let arr = Array2D.init<int> 2 3 (fun row col -> row+col)
arr = [| [|...
• Полезные функции модуля Array:
o fold, foldBack, map, filter, rev — аналогичны функциям
модуля List;
o append — соединяе...
Список Массив
Неизменяемый, может содержать
общие элементы с другими
списками
Константное время доступа к
элементам
Совпад...
• Неявный способ определения:
type TypeName optional-type-arguments arguments
[ as ident ] =
[ inherit type { as base } ]
...
• Неявный способ определения:
type MyPoint(x : int, y : int) = class
let mutable color = Color.Black
member this.X = x
mem...
• Явный способ определения:
type Point = class
val X : int
val Y : int
val Color : Color
new (x,y,c) as this =
{X = x; Y =...
• Абстрактные классы:
[<AbstractClass>]
type Shape() =
override x.ToString() = sprintf "%s, area = %f"
(x.GetType().Name) ...
• Пример перегрузки конструкторов:
type Line = class
val X1:int
val X2:int
val Y1:int
val Y2:int
new() =
{ X1 = 0; X2 = 0;...
• Общее описание инфиксного оператора:
let (operator) arg1 arg2 = ...
• Пример: оператор совпадения по шаблону
let (=~) ar...
Последовательности в F#
• Последовательность (sequence) — это список,
значение которого вычисляются «лениво», т.е. по
треб...
Асинхронность и параллелизм
• Модуль Async позволяет работать с асинхронными,
синхронными и параллельными вызовами функций...
• Пример: простой асинхронный веб-краулер
let extractLinksAsync html =
async {
return
System.Text.RegularExpressions.Regex...
• Пример: простой параллельный асинхронный веб-краулер
let extractLinks html = Regex.Matches(html, @"http://S+")
let getLi...
Ресурсы о F#
• Microsoft F# Developer Center:
http://msdn.microsoft.com/ru-ru/fsharp/default(en-
us).aspx
• Wikibooks: F# ...
38
?
Upcoming SlideShare
Loading in …5
×

Функциональное программирование на F#

3,342 views

Published on

Функциональное программирование на F# / DevCamp Винница.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
3,342
On SlideShare
0
From Embeds
0
Number of Embeds
1,310
Actions
Shares
0
Downloads
26
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Функциональное программирование на F#

  1. 1. Функциональное программирование на F# Богомолов Юрий yuriy.bogomolov@gmail.com 1
  2. 2. Общие сведения F# — мультипарадигмальный язык: • Функциональное программирование: o Строго типизированный язык с возможностью выведения типов; o Поддерживает каррирование функций, лямбда- функции, замыкания, композицию функций; o Использование совпадений с образцом (pattern- matching); o Алгебраические типы данных (discriminated unions). 2
  3. 3. Общие сведения F# — мультипарадигмальный язык: • Императивное программирование: o Изменяемые данные; o Управление потоком выполнения (условные переходы, циклы); o Изменяемые массивы, списки и словари; o Возможность использования изменяемых переменных. 3
  4. 4. Общие сведения F# — мультипарадигмальный язык: • Объектно-ориентированное программирование: o Поддержка пользовательских типов данных (записи, кортежи, классы); o Классы: • Наследование; • Перегрузка операторов; o Последовательные, параллельные, асинхронные вычисления. 4
  5. 5. Типы данных Тип данных Название Целочисленный sbyte, byte, int16, uint16, int/int32, uint32, int64, uint64, bigint С плавающей точкой float32, float, decimal Строковый char, string Логический bool Специальные unit, кортежи, последовательности, списки, размеченные объединения 5
  6. 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. 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. 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. 9. • Функция, имеющая тело, но не имеющая имени. • Аналог из C# — анонимные делегаты. • Синтаксис: (fun arg1 arg2 ... -> expr) let x = (fun x -> x * x) 2 // возвратит 4 9 F#: функциональная парадигма. Лямбда-функции
  10. 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. 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. 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. 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. 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. 15. • Являются алгебраическим типом данных. • Представляют собой определенный набор вариантов выбора. Дают возможность выявить ошибки на этапе компиляции. • Синтаксис: type unionName = | Case1 | Case2 as datatype | … 15 F#: функциональная парадигма. Размеченные объединения
  16. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 26. Список Массив Неизменяемый, может содержать общие элементы с другими списками Константное время доступа к элементам Совпадение с образцом Возможность произвольного доступа Поддерживает map и fold Поддерживает map и fold Линейное время доступа Не может содержать общие элементы с другими массивами Нет произвольного доступа к элементам — только последовательный доступ Нельзя менять размер на лету (только путем копирования через Array.append) 26 F#: императивная парадигма. Сравнение списков и массивов
  27. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  38. 38. 38 ?

×