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
|
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.
|
Popular JavaScript implementations do not perform any tail-call elimination, so
|
||||||
Since most javascript implementations lack tail-call elimination, deeply tail-recursive functions will result in a stack overflow.
|
recursive functions can cause a stack overflow if they go to deep. Trampolines
|
||||||
|
permit unbounded recursion despite limitations in JavaScript.
|
||||||
|
|
||||||
```haskell
|
This strategy may create many intermediate closures, which is very expensive in
|
||||||
fac' : Int -> Int -> Int
|
JavaScript, so use this library only when it is essential that you recurse deeply.
|
||||||
fac' n acc = if n <= 0
|
|
||||||
then acc
|
|
||||||
else fac' (n - 1) (n * acc)
|
|
||||||
|
|
||||||
fac : Int -> Int
|
# Trampolines
|
||||||
fac n = fac' n 1
|
@docs trampoline, Trampoline
|
||||||
|
-}
|
||||||
|
|
||||||
-- 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
|
|
||||||
-}
|
|
||||||
import Native.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. -}
|
{-| A way to build computations that may be deeply recursive. We will take an
|
||||||
data Trampoline a = Done a
|
example of a tail-recursive function and rewrite it in a way that lets us use
|
||||||
| Continue (() -> Trampoline a)
|
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 : Trampoline a -> a
|
||||||
trampoline = Native.Trampoline.trampoline
|
trampoline = Native.Trampoline.trampoline
|
||||||
|
|
Loading…
Reference in a new issue