attempt to make the documentation easier
This commit is contained in:
parent
4ef397c3dc
commit
3fec0f94ee
1 changed files with 39 additions and 32 deletions
|
@ -1,42 +1,49 @@
|
|||
module Trampoline where
|
||||
{-| A [trampoline](http://en.wikipedia.org/wiki/Tail-recursive_function#Through_trampolining)
|
||||
makes it possible to recursively call a function without growing the stack.
|
||||
|
||||
{-| Trampolining loops for unbounded recursion.
|
||||
Since most javascript implementations lack tail-call elimination, deeply tail-recursive functions will result in a stack overflow.
|
||||
Popular JavaScript implementations do not perform any tail-call elimination, so
|
||||
recursive functions can cause a stack overflow if they go to deep. Trampolines
|
||||
permit unbounded recursion despite limitations in JavaScript.
|
||||
|
||||
```haskell
|
||||
fac' : Int -> Int -> Int
|
||||
fac' n acc = if n <= 0
|
||||
then acc
|
||||
else fac' (n - 1) (n * acc)
|
||||
This strategy may create many intermediate closures, which is very expensive in
|
||||
JavaScript, so use this library only when it is essential that you recurse deeply.
|
||||
|
||||
fac : Int -> Int
|
||||
fac n = fac' n 1
|
||||
|
||||
-- Stack overflow
|
||||
main = asText <| fac 1000000000000
|
||||
```
|
||||
|
||||
Trampolining allows for long-running tail-recursive loops to be run without pushing calls onto the stack:
|
||||
```haskell
|
||||
facT : Int -> Int -> Trampoline Int
|
||||
facT n acc = if n <= 0
|
||||
then Done acc
|
||||
else Continue <| \() -> facT (n - 1) (n * acc)
|
||||
fac : Int -> Int
|
||||
fac n = trampoline <| facT n 0
|
||||
|
||||
-- Doesn't stack overflow
|
||||
main = asText <| fac 1000000000000
|
||||
```
|
||||
# Trampoline
|
||||
@docs Trampoline, trampoline
|
||||
# Trampolines
|
||||
@docs trampoline, Trampoline
|
||||
-}
|
||||
|
||||
import Native.Trampoline
|
||||
|
||||
{-| A computation that might loop. A trampoline is either the resulting value or a thunk that needs to be run more. -}
|
||||
data Trampoline a = Done a
|
||||
| Continue (() -> Trampoline a)
|
||||
{-| A way to build computations that may be deeply recursive. We will take an
|
||||
example of a tail-recursive function and rewrite it in a way that lets us use
|
||||
a trampoline:
|
||||
|
||||
{-| Run a trampolining loop in constant space. -}
|
||||
length : [a] -> Int
|
||||
length list = length' 0 list
|
||||
|
||||
length' : Int -> [a] -> Int
|
||||
length' accum list =
|
||||
case list of
|
||||
[] -> accum
|
||||
hd::tl -> length' (accum+1) tl
|
||||
|
||||
This finds the length of a list, but if the list is too long, it may cause a
|
||||
stack overflow. We can rewrite it as follows:
|
||||
|
||||
length : [a] -> Int
|
||||
length list = trampoline (length' 0 list)
|
||||
|
||||
length' : Int -> [a] -> Trampoline Int
|
||||
length' accum list =
|
||||
case list of
|
||||
[] -> Done accum
|
||||
hd::tl -> Continue (\() -> length' (accum+1) tl)
|
||||
|
||||
Now it uses a trampoline and can recurse without growing the stack!
|
||||
-}
|
||||
data Trampoline a = Done a | Continue (() -> Trampoline a)
|
||||
|
||||
{-| Evaluate a trampolined value in constant space. -}
|
||||
trampoline : Trampoline a -> a
|
||||
trampoline = Native.Trampoline.trampoline
|
||||
|
|
Loading…
Reference in a new issue