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

JSExperience 7masters - Recursion & Trampolines

JSExperience 7masters - Recursion & Trampolines

Ana Luiza Portello

July 05, 2018
Tweet

More Decks by Ana Luiza Portello

Other Decks in Programming

Transcript

  1. ANA LUIZA BASTOS
    github.com/anabastos
    @naluhh
    @anapbastos
    Fullstack Developer na Quanto e
    cientista da computação na
    PUC-SP
    anabastos.me

    View Slide

  2. JSLADIES
    fb.com/jsladiesbr
    twitter.com/jsladiessp
    meetup.com/JsLadies-BR/
    LAMBDA.IO
    t.me/lambdastudygroup
    github.com/lambda-study-group/
    meetup.com/Lambda-I-O-Sampa-
    Meetup/

    View Slide

  3. VISÃO GERAL SOBRE
    RECURSÃO &
    TRAMPOLINES

    View Slide

  4. VAMOS FALAR SOBRE
    RECURSÃO

    View Slide

  5. Recursão é quando uma função
    chama a si mesma até uma condição parar o
    loop.

    View Slide

  6. λ Programação Funcional

    View Slide

  7. Fatorial
    1! = 1
    3! = 1 * 2 * 3 = 6

    View Slide

  8. const iterativeFactorial = (n) => {
    let i
    let contador = 0
    for (i = 1; i <= n; i++)
    {
    contador *= i
    }
    return contador
    }

    View Slide

  9. 1. Qual parte do código é
    recursiva
    2. Condição de saída

    View Slide

  10. const fac = (n) => {
    if (n == 0) {
    return 1
    }
    return n * fac(n - 1)
    }

    View Slide

  11. ● EXPRESSIVO
    ● PURO / EVITANDO MUDANÇA DE
    ESTADO(CONTADOR)
    ● IMUTABILIDADE DE DADOS
    ● DECLARATIVO
    ● IDEMPOTENCIA

    View Slide

  12. JS é single threaded
    e orientado a stack

    View Slide

  13. View Slide

  14. GC
    fac(3)
    GC
    fac(2)
    fac(3)
    GC
    fac(1)
    fac(2)
    fac(3)
    GC
    fac(0)
    fac(1)
    fac(2)
    fac(3)
    GC
    call
    call
    call
    call

    View Slide

  15. GC
    fac(3)
    GC
    fac(2)
    fac(3)
    GC
    fac(1)
    fac(2)
    fac(3)
    GC
    fac(0)
    fac(1)
    fac(2)
    fac(3)
    GC
    1
    1* 1 = 1
    1 * 2 = 2
    2 * 3 = 6

    View Slide

  16. GC
    fac(9999)
    GC
    fac(9998)
    fac(9999)
    GC
    fac(9997)
    fac(9998)
    fac(9999)
    GC
    oh no
    ...
    fac(9998)
    fac(9999)
    GC
    StackOverFlow :(

    View Slide

  17. Cruza os dedos?
    Senta e chora?

    View Slide

  18. TAIL CALL OPTIMIZATION
    (TCO)

    View Slide

  19. Truque antigo

    View Slide

  20. GC
    fac(3)
    GC
    fac(2)
    fac(3)
    GC
    fac(1)
    fac(2)
    fac(3)
    GC
    fac(0)
    fac(1)
    fac(2)
    fac(3)
    GC
    call
    call
    call
    call

    View Slide

  21. TCO faz com que a gente evite
    explodir o stack quando
    fazemos chamadas recursivas

    View Slide

  22. PROPER TAIL CALLS
    (PTC)

    View Slide

  23. Possibilita que sua função
    recursiva seja otimizada pela
    engine.

    View Slide

  24. RECURSÃO EM CAUDA
    (TAIL CALL)

    View Slide

  25. //Não é tail call :(
    const fac = (n) => n == 0
    ? 1
    : n * fac(n - 1)

    View Slide

  26. A última coisa a ser feita na função
    é o retorno da própria função.

    View Slide

  27. Acumulador

    View Slide

  28. const tailRecursiveFac = (n, acc = 1) => {
    return n == 0
    ? acc
    : tailRecursiveFac(n - 1, acc * n)
    }

    View Slide

  29. ES6
    http://www.ecma-international.org/ecma-262/6.0/#sec-tail-position-
    calls

    View Slide

  30. View Slide

  31. Além disso existem casos de
    algoritmos que precisam de mais
    de duas chamadas
    recursivas(multiple recursion) e
    não tem como colocar tudo no final

    View Slide

  32. COMO LIDAR COM ISSO?

    View Slide

  33. CONTINUATION PASSING
    STYLE (CPS)

    View Slide

  34. Um estilo de programação em que
    o controle é passado
    explicitamente em forma de
    continuação

    View Slide

  35. Continuação é uma parte de
    código que ainda vai ser executada
    em algum ponto do programa
    Callbacks por exemplo são continuations

    View Slide

  36. Continuação não chama a si mesma, ela só expressa
    um fluxo de computação onde os resultados fluem
    em uma direção.
    Aplicar continuações não é chamar funções é passar
    o controle do resultado.

    View Slide

  37. LAZY EVALUATION

    View Slide

  38. CALL-BY-NEED

    View Slide

  39. > (1 + 3) * 2
    8
    > const expression = () => (1 + 3) * 2
    > expression()
    8

    View Slide

  40. Ou seja, o programa espera receber os
    dados antes de continuar.

    View Slide

  41. E daí?

    View Slide

  42. CPS elimina a necessidade de um
    call stack pois os valores estarão
    dentro da continuation sendo
    executada .

    View Slide

  43. Acumulador para uma
    continuação

    View Slide

  44. IDENTITY FUNCTION

    View Slide

  45. const id = x => x

    View Slide

  46. ● O último parâmetro da função é sempre a
    continuation.
    ● Todas as funções precisam acabar chamando
    sua continuação com o resultado da execução
    da função.

    View Slide

  47. const cpsFac = (n, con) => {
    return n == 0
    ? con(1)
    : cpsFac(n - 1, y => con(n + y))
    }
    cpsFac(3, id) //6

    View Slide

  48. TRAMPOLINES

    View Slide

  49. Técnica stack safe para fazer
    chamadas tail-recursive em
    linguagens orientadas a stack

    View Slide

  50. Um trampoline é um loop
    que iterativamente invoca
    funções que retornam thunks
    (continuation-passing style)

    View Slide

  51. THUNKS

    View Slide

  52. Função que encapsula outra
    função com os parâmetros que
    para quando a execução dessa
    função for necessária.

    View Slide

  53. function thunk(fn, args) {
    return fn(...args)
    }

    View Slide

  54. Ao invés de chamar a tail call
    diretamente, cada método retorna
    a chamada para um thunk para o
    trampolim chamar.

    View Slide

  55. const trampoline = (thunk) => {
    while(thunk instanceof Function){
    thunk = thunk()
    }
    return thunk
    }

    View Slide

  56. ● É um loop que chama funções repetidamente
    ● Cada função é chamada de thunk.
    ● O trampolim nunca chama mais de um thunk
    ● É como se quebrasse o programa em pequenos
    thunks que saltam pra fora do trampolim, assim o
    stack não cresce.

    View Slide

  57. const trampolineFac = (n) {
    const fac = (n, ac = 1) => {
    return n == 0
    ? ac
    : thunk(fac, n - 1, ac * n)
    }
    return trampoline(thunk(fac, n, 1))
    }

    View Slide

  58. GC
    fac(3)
    GC
    call
    GC
    fac(2)
    GC GC
    bounce
    bounce

    View Slide

  59. :(

    View Slide

  60. Trade off por stack safety
    Trocamos o trabalho de criar stack frames com
    o de criar binding de funções.

    View Slide

  61. Em muitos casos o trade-off de
    overhead por expressividade vale a
    pena

    View Slide

  62. Trampolines são mais apropriadas
    para funções complexas em que não
    existem soluções iterativas e não
    conflitam com outras técnicas de
    mediar controle de fluxo(Promises).

    View Slide

  63. ● Kyle Simpson. Functional Light Programming. Cap
    8. - github.com/getify/Functional-Light-JS
    ● Functional Programming Jargon -
    github.com/hemanth/functional-programming-jarg
    on
    ● Structure and Interpretation of Computer
    Programs - Javascript Adaptation

    View Slide

  64. ● Compatibilidade TCO -
    kangax.github.io/compat-table/es6/#test-proper_tail_c
    alls_
    ● Yoyojs - npmjs.com/package/yoyojs
    ● Ramda Memoisation -
    ramdajs.com/docs/#memoize

    View Slide

  65. t.me/lambdastudygroup
    github.com/lambda-study-group

    View Slide

  66. OBRIGADA :)
    https://speakerdeck.com/anabastos

    View Slide