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

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

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

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

Avatar for Smolensk Computer Science Club

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