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

PureScript Lunch-n-Learn Lesson 5

PureScript Lunch-n-Learn Lesson 5

Slides for the fifth lesson in my PureScript lunch-n-learn series. This lesson concludes "Recursion, Maps, & Folds," chapter 4 of "PureScript by Example," covering folds.

Jim Fitzpatrick

July 28, 2016
Tweet

More Decks by Jim Fitzpatrick

Other Decks in Programming

Transcript

  1. PureScript Lunch & Learn 5: Recursion, Maps & Folds (pt.

    3) github.com/jimf/purescript-lunchnlearn
  2. Last lesson’s “homework” A pythagorean triple is an array of

    numbers [a, b, c] such that a² + b² = c². Write a function triples that takes an Integer and uses the guard function to calculate and return all Pythagorean triples whose components are less than n.
  3. Last lesson’s “homework” triples :: Int -> Array (Array Int)

    triples n = do a <- 1 .. (n - 1) b <- 1 .. (n - 1) c <- 1 .. (n - 1) guard $ ( a*a + b*b == c*c && a < b && b < c ) pure [a, b, c]
  4. • Look at folds • Solve related problems in an

    interactive, “dojo” style Goals
  5. This lesson is built upon Ch. 4 of PureScript by

    Example. Be sure to check it out: https://leanpub.com/purescript/read#leanpub-auto-recursion-maps-and-folds Note
  6. • Provides functions foldl and foldr ◦ foldl “folds from

    the left”. :type ▪ forall a b f. (Foldable f) => (b -> a -> b) -> b -> f a -> b ◦ foldr “folds from the right”. :type ▪ forall a b f. (Foldable f) => (a -> b -> b) -> b -> f a -> b Data.Foldable
  7. foldl vs foldr > import Prelude > import Data.Foldable >

    foldl (+) 0 [1, 2, 3, 4, 5] 15 > foldr (+) 0 [1, 2, 3, 4, 5] 15 > foldl (\acc n -> acc <> show n) "" [1, 2, 3, 4, 5] "12345" > foldr (\n acc -> acc <> show n) "" [1, 2, 3, 4, 5] "54321"
  8. • Recursion, while powerful, can lead to stack overflow •

    Few JS engines perform proper “tail call optimization” • The PureScript compiler will compile recursive functions in “tail call” position to simple while loops • More complete solutions can be found in the purescript- free and purescript-tailrec packages Tail Recursion
  9. • Recursion, while powerful, can lead to stack overflow •

    Few JS engines perform proper “tail call optimization” • The PureScript compiler will compile recursive functions in “tail call” position to simple while loops • More complete solutions can be found in the purescript- free and purescript-tailrec packages Tail Recursion
  10. • Recursion, while powerful, can lead to stack overflow •

    Few JS engines perform proper “tail call optimization” • The PureScript compiler will compile recursive functions in “tail call” position to simple while loops • More complete solutions can be found in the purescript- free and purescript-tailrec packages Tail Recursion
  11. • Recursion, while powerful, can lead to stack overflow •

    Few JS engines perform proper “tail call optimization” • The PureScript compiler will compile recursive functions in “tail call” position to simple while loops • More complete solutions can be found in the purescript- free and purescript-tailrec packages Tail Recursion
  12. Tail Recursion fact :: Int -> Int -> Int fact

    0 acc = acc fact n acc = fact (n - 1) (acc * n)
  13. Tail Recursion fact :: Int -> Int -> Int fact

    0 acc = acc fact n acc = fact (n - 1) (acc * n) Only recursive call is the very last action in this function—it’s in tail position.
  14. • Add an extra param to a recursive function •

    Extra param is used to accumulate the result • Used to turn a non-tail-recursive function into a tail- recursive form Accumulators
  15. • Add an extra param to a recursive function •

    Extra param is used to accumulate the result • Used to turn a non-tail-recursive function into a tail- recursive form Accumulators
  16. • Add an extra param to a recursive function •

    Extra param is used to accumulate the result • Used to turn a non-tail-recursive function into a tail- recursive form Accumulators
  17. Accumulators -- Recursively reverse an array by appending elements at

    -- the head of the input array to the end of the result. -- NOT tail-recursive! reverse :: forall a. Array a -> Array a reverse [] = [] reverse xs = snoc (reverse (unsafePartial tail xs)) (unsafePartial head xs)
  18. Accumulators -- Tail-recursive reverse that uses an accumulator. reverse ::

    forall a. Array a -> Array a reverse = reverse' [] where reverse' acc [] = acc reverse' acc xs = reverse' (unsafePartial head xs : acc) (unsafePartial tail xs)
  19. Prefer folds over recursion -- reverse implemented as a fold.

    reverse'' :: forall a. Array a -> Array a reverse'' = foldr (\x xs -> xs <> [x]) []