Upgrade to Pro — share decks privately, control downloads, hide ads and more …

6 встреча — Функциональное программирование (Д. Борисенков)

6 встреча — Функциональное программирование (Д. Борисенков)

6 встреча Smolensk Computer Science Club
Презентация Дмитрия Борисенкова про функциональное программирование
ВКонтакте: http://vk.com/scsc6

Smolensk Computer Science Club

February 22, 2013
Tweet

More Decks by Smolensk Computer Science Club

Other Decks in Programming

Transcript

  1. Принципы 02.03.2013 Функциональное программирование 7 Pattern matching Lazy Evaluations Infinite

    collections 1st class functions Pure functions partial application memoization collection generators Core ideas
  2. Pattern matching 02.03.2013 Функциональное программирование 8 X, y, x =

    1, 2, 3 { } { } exception error: no match of right hand side value {1,2,3}
  3. Pattern matching 02.03.2013 Функциональное программирование 9 X, y, x =

    1, 2, 1 { } { } exception error: no match of right hand side value {1,2,3} X = 1 Y = 2
  4. Pattern matching 02.03.2013 Функциональное программирование 10 match (1,2,3) with x,

    y, z when x = z -> printf "%A" (x, y) | _ -> printf "Match error" FSharp (1, 2, 3) match { case (x, y, z) if (x == z) => print((x, y)) case _ => print("Match error") } f (x, y, z) |x==z = print (x, y) |otherwise = print "Matching error" scala haskell
  5. Стрелка Кнута 02.03.2013 Функциональное программирование 11 ↑ = � ,

    = 1; 1, = 0; ↑−1 ↑ − 1 , 𝑜 3 ↑↑ 2 = 3 ↑ 3 ↑↑ 1 = 33↑↑1 = 33↑ 3↑↑0 = 333↑↑0 = 331 = 27
  6. Стрелка Кнута 02.03.2013 Функциональное программирование 12 ↑ = � ,

    = 1; 1, = 0; ↑−1 ↑ − 1 , 𝑜 template<unsigned N, unsigned b, unsigned a> struct Arrow{ enum { value = Arrow2<N-1, Arrow2<N, b-1, a>::value, a>::value }; }; template<unsigned N, unsigned a> struct Arrow<N, 0, a>{ enum { value = 1 }; }; C++
  7. Стрелка Кнута 02.03.2013 Функциональное программирование 13 ↑ = � ,

    = 1; 1, = 0; ↑−1 ↑ − 1 , 𝑜 template<unsigned b, unsigned a> struct Arrow<1, b, a>{ enum { value = a*Arrow2<1, b-1, a>::value }; }; template<unsigned a> struct Arrow<1, 0, a>{ enum { value = 1 }; }; C++
  8. Стрелка Кнута 02.03.2013 Функциональное программирование 14 ↑ = � ,

    = 1; 1, = 0; ↑−1 ↑ − 1 , 𝑜 int main() { std::cout << Arrow<2,2,3>::value; return 0; } C++ 27
  9. Стрелка Кнута 02.03.2013 Функциональное программирование 15 ↑ = � ,

    = 1; 1, = 0; ↑−1 ↑ − 1 , 𝑜 arrow :: Int -> Int -> Int -> Int arrow n 0 a = 1 arrow 1 b a = a*(arrow 1 (b-1) a) arrow n b a = arrow (n-1) (arrow n (b-1) a) a main = print (arrow 2 2 3) Haskell
  10. ADT & Tree pattern matching 02.03.2013 Функциональное программирование 16 type

    ‘a List = Nil | Node of ‘a * ‘a List type ‘a BinTree = Leaf of ‘a | Node of ‘a * ‘a BinTree * ‘a BinTree let printValue = function Leaf(x) -> printf "%A" x | Node (x, _, _) -> printf "%A" x FSharp
  11. ADT & Tree pattern matching 02.03.2013 Функциональное программирование 17 struct

    Tree { union { int value; struct { int value; struct Tree *left; struct Tree *right; } branches; } data; enum { LEAF, NODE } selector; }; C
  12. Scala & Pattern matching 02.03.2013 Функциональное программирование 20 abstract class

    Tree[T] case class Leaf[T](value: T) extends Tree[T] case class Node[T](value: T, left: Tree[T], right: Tree[T]) extends Tree[T] Scala
  13. 1st class functions 02.03.2013 Функциональное программирование 22 public static double

    factorial (int n) { double result = 1; for (int i = 1; i <= n; i++){ result *= i; } return result; } public static double taylor_e_step(double x, int i){ return Math.pow(x, i)/factorial(i); } Java
  14. 1st class functions 02.03.2013 Функциональное программирование 23 public static double

    taylor_e (double x, int st_count){ double result = 0; for (int i = 0; i < st_count; i++) result += taylor_e_step(x, i); return result; } Java
  15. 1st class functions 02.03.2013 Функциональное программирование 25 𝑡𝑡𝑡𝑡_𝑒(, ) =

    � 𝑡𝑡𝑡𝑡_𝑒_𝑠𝑠𝑠(, ) =0 𝑓𝑓𝑓𝑓𝑓𝑓𝑓𝑓() = � =1 𝑝𝑝𝑝𝑝𝑝(, ) = � =1
  16. 1st class functions 02.03.2013 Функциональное программирование 26 𝑖𝑖𝑖 𝑓, 𝑏,

    𝑒𝑒, 𝑑𝑑𝑑 = Если bgn>end: 𝑑𝑑𝑑 Иначе: 𝑓(𝑏, 𝑖𝑖𝑖(𝑓, 𝑏 + 1, 𝑒𝑒, 𝑑𝑑𝑑))
  17. 1st class functions 02.03.2013 Функциональное программирование 28 def iter (f:

    (Double, Double) => Double, a: Double, b: Double, i: Double): Double = { if (a > b) i else f(iter(f,a+1,b,i), a) } Scala let rec iter f a b i = if a>b then i else f (iter f (a+1) b i) a FSharp
  18. 1st class functions 02.03.2013 Функциональное программирование 29 val factorial =

    (n: Int) => iter((y,i)=>y*i, 1, n, 1.0) val pow = (x: Double, n: Int) => iter((y,i)=>y*x, 1, n, 1.0) def taylor_e_step (x: Double, n: Int) = pow(x,n)/factorial(n) def taylor_e (x: Double, st_count: Int) = iter((y, n) => y+taylor_e_step(x, n.toInt), 0, st_count, 0.0) Scala
  19. 1st class functions 02.03.2013 Функциональное программирование 30 let pow x

    n = iter (fun y i -> y*x) 1 n 1.0 let factorial n = iter (fun y i -> y*(float i)) 1 n 1.0 let taylor_e_step x n = pow x n / fact n let taylor_e x = iter (fun y n -> y+taylor x n) 0 15 0.0 FSharp
  20. Протестируем 02.03.2013 Функциональное программирование 32 let main argv = let

    stopWatch = Stopwatch.StartNew() ignore <| taylor_e 2.0 5000 stopWatch.Stop() printfn "%f" stopWatch.Elapsed.TotalMilliseconds 0 FSharp ~85ms FSharp ~50ms CSharp VS
  21. Шаг назад 02.03.2013 Функциональное программирование 33 let rec factorial =

    function 0 -> 1.0 |n -> ((float)n)*factorial(n-1) let rec power x n = match n with 0 -> 1.0 |n -> x * (power x (n-1)) FSharp ~150ms FSharp
  22. Хвостовая рекурсия 02.03.2013 Функциональное программирование 34 let rec factorial0 acc

    n = if n=0 then acc else factorial0 (float(n) * acc) (n - 1) let factorial = factorial0 1.0 FSharp ~60ms FSharp let rec power0 acc x n = match n with 0 -> acc |n -> power0 (acc*x) x (n-1) let power = power0 1.0 FSharp
  23. C# наносит ответный удар 02.03.2013 Функциональное программирование 35 static double

    taylor_rec(double x, int step_ct){ double result = 1.0; double prev = 1.0; for (int i = 1; i < step_ct; i++) { prev = prev * x / i; result += prev; } return result; } СSharp ~0.2ms СSharp
  24. Новая надежда 02.03.2013 Функциональное программирование 36 let memoize (f: 'a

    -> 'b) = let t = new Dictionary<'a,'b>() fun n -> if t.ContainsKey(n) then t.[n] else let res = f n t.Add(n,res) res FSharp
  25. Новая надежда 02.03.2013 Функциональное программирование 37 ~90ms FSharp let mfactorial

    = memoize factorial let power2 = power 2.0 let mpower2 = memoize power2 let taylor_e_step n = mpower2 n / mfactorial n FSharp
  26. Мемоизация рекурсии (хак) 02.03.2013 Функциональное программирование 38 let rec memfactorial

    = function 0 -> 1.0 |n -> ((float)n)*mfactorial(n-1) and mfactorial = memoize memfactorial let rec mempower = function _,0 -> 1.0 |x,n -> x * mpower (x,n-1) and mpower = memoize mempower FSharp ~10ms FSharp
  27. Y-Combinator 02.03.2013 Функциональное программирование 40 fact = λx. if x=1

    then 1 else x*fact(x-1) fact = (λf.λx. if x=1 then 1 else x*f(x-1)) fact fact = F fact Y F = F (Y F) Y = (λh.(λx. h (x x)) (λx. h (x x))) Y F = (λh.(λx. h (x x)) (λx. h (x x))) F = = (λx. F (x x)) (λx. F (x x)) = = F ((λx. F (x x)) (λx. F (x x))) = F (Y F) FSharp
  28. Y-Combinator 02.03.2013 Функциональное программирование 41 type Y<'T> = Rec of

    (Y<'T> -> 'T) (*let y mk = let f' (Rec f as g) = mk (f g) f' (Rec f') *) // Y Combinator let y mk = let f' (Rec f as g) = mk (fun y -> f g y) f' (Rec f') FSharp
  29. Мемоизация рекурсии 02.03.2013 Функциональное программирование 42 let createDic (key:'a) (value:'b)

    = Dictionary<'a, 'b> () let yMem mk = let dic = createDic defaultof<'a> defaultof<'b> let f' (Rec f as g) = mk (fun y -> f g y) let f'' = f' (Rec f') fun x -> if dic.ContainsKey(x) then dic.[x] else let answer = f'' x dic.[x] <- answer answer FSharp http://fssnip.net/1q
  30. Мемоизация рекурсии 02.03.2013 Функциональное программирование 43 http://fssnip.net/1q let facttrc n

    k m = if n = 0 then k 1.0 else m (n - 1) (fun r1 -> let r = r1 * (float n) in k r) let powtrc v k m = let x, n = v if n = 0 then k 1.0 else m (x, n - 1) (fun r1 -> let r = r1 * x in k r) FSharp
  31. Мемоизация рекурсии 02.03.2013 Функциональное программирование 44 http://fssnip.net/1q let memoizeTailRecursion f

    = let dic = createDic defaultof<'TArg1> defaultof<'TResult> let rec f' a k = match dic.TryGetValue(a) with | true, r -> k r | _ -> f a (fun r -> dic.[a] <- r k r) f' (fun a -> f' a id) FSharp
  32. Функции высшего порядка 02.03.2013 Функциональное программирование 46 Map: Fold: (A

    -> B) -> A+ -> B+ (A -> B -> A) -> A -> B+ -> A let rec map f = function [] -> [] | h::t -> (f h)::(map f t) let rec fold f acc = function [] -> acc | h::t -> fold f (f acc h) t
  33. Функции высшего порядка 02.03.2013 Функциональное программирование 47 Filter: (A ->

    Bool) -> A+ -> A+ let rec filter p = function [] -> [] | h::t -> if p h then h::(filter p t) else (filter p t)
  34. Infinite collections 02.03.2013 Функциональное программирование 48 Задача: сгенерировать списки чисел

    размером от 2 до N, такие что сумма элементов списка дает простое число
  35. Решение 02.03.2013 Функциональное программирование 49 [[[2,3],[3,2],[3,4],[4,3]],[[2,2,3],[2,3,2],[ 3,2,2],[3,4,4],[4,3,4],[4,4,3]]] isNaturalAndSimple n =

    (n > 0 && (not $ or $ map (\n1 -> n `rem` n1 == 0) [2..n-1])) ifSumSimple b e = map ((filter $ isNaturalAndSimple . sum) . (foldl1 (liftA2 (++))) . (map $ map (:[])) . (flip replicate $ [b..e])) [2..] main = print $ take 2 $ ifSumSimple 2 4 haskell
  36. Решение 02.03.2013 Функциональное программирование 50 [[2,3],[3,2]] isNaturalAndSimple n = (n

    > 0 && (not $ or $ map (\n1 -> n `rem` n1 == 0) [2..n-1])) ifSumSimple b e = map ((filter $ isNaturalAndSimple . sum) . (foldl1 (liftA2 (++))) . (map $ map (:[])) . (flip replicate $ [b..e])) [2..] main = print $ take 2 $ concat $ ifSumSimple 2 4 haskell
  37. Бесконечные списки 02.03.2013 Функциональное программирование 51 main = l $

    concat $ ifSumSimple 2 4 where l t = do print $ length $ show $ take 100 t l $ drop 100 t haskell main = do l a print a where a = concat $ ifSumSimple 2 4 l t = do print $ length $ show $ take 100 t l $ drop 100 t haskell
  38. Бесконечные списки 02.03.2013 Функциональное программирование 52 main = l $

    concat $ ifSumSimple 2 4 where l t = do print $ length $ show $ take 100 t l $ drop 100 t haskell main = do l a print a where a = concat $ ifSumSimple 2 4 l t = do print $ length $ show $ take 100 t l $ drop 100 t haskell 131648 kB 6716 kB