on master help sign in
attempt to make the documentation easier
3fec0f9Evan Czaplicki
libraries/Trampoline.elm+42−35
@@ -1,42 +1,49 @@
1module Trampoline where
1module Trampoline where
2+{-| A [trampoline](http://en.wikipedia.org/wiki/Tail-recursive_function#Through_trampolining)
3+makes it possible to recursively call a function without growing the stack.
4+
5+Popular JavaScript implementations do not perform any tail-call elimination, so
6+recursive functions can cause a stack overflow if they go to deep. Trampolines
7+permit unbounded recursion despite limitations in JavaScript.
8+
9+This strategy may create many intermediate closures, which is very expensive in
10+JavaScript, so use this library only when it is essential that you recurse deeply.
11+
12+# Trampolines
13+@docs trampoline, Trampoline
14+-}
2
15
3−{-| Trampolining loops for unbounded recursion.
4−Since most javascript implementations lack tail-call elimination, deeply tail-recursive functions will result in a stack overflow.
5−
6−```haskell
7−fac' : Int -> Int -> Int
8−fac' n acc = if n <= 0
9− then acc
10− else fac' (n - 1) (n * acc)
11−
12−fac : Int -> Int
13−fac n = fac' n 1
14−
15−-- Stack overflow
16−main = asText <| fac 1000000000000
17−```
18−
19−Trampolining allows for long-running tail-recursive loops to be run without pushing calls onto the stack:
20−```haskell
21−facT : Int -> Int -> Trampoline Int
22−facT n acc = if n <= 0
23− then Done acc
24− else Continue <| \() -> facT (n - 1) (n * acc)
25−fac : Int -> Int
26−fac n = trampoline <| facT n 0
27−
28−-- Doesn't stack overflow
29−main = asText <| fac 1000000000000
30−```
31−# Trampoline
32−@docs Trampoline, trampoline
33− -}
34import Native.Trampoline
16import Native.Trampoline
35
17
36−{-| A computation that might loop. A trampoline is either the resulting value or a thunk that needs to be run more. -}
18+{-| A way to build computations that may be deeply recursive. We will take an
19+example of a tail-recursive function and rewrite it in a way that lets us use
20+a trampoline:
21+
22+ length : [a] -> Int
23+ length list = length' 0 list
24+
25+ length' : Int -> [a] -> Int
26+ length' accum list =
27+ case list of
28+ [] -> accum
29+ hd::tl -> length' (accum+1) tl
30+
31+This finds the length of a list, but if the list is too long, it may cause a
32+stack overflow. We can rewrite it as follows:
33+
34+ length : [a] -> Int
35+ length list = trampoline (length' 0 list)
36+
37+ length' : Int -> [a] -> Trampoline Int
38+ length' accum list =
39+ case list of
40+ [] -> Done accum
41+ hd::tl -> Continue (\() -> length' (accum+1) tl)
42+
43+Now it uses a trampoline and can recurse without growing the stack!
44+-}
37−data Trampoline a = Done a
45+data Trampoline a = Done a | Continue (() -> Trampoline a)
38− | Continue (() -> Trampoline a)
39
46
40−{-| Run a trampolining loop in constant space. -}
47+{-| Evaluate a trampolined value in constant space. -}
41trampoline : Trampoline a -> a
48trampoline : Trampoline a -> a
42trampoline = Native.Trampoline.trampoline
49trampoline = Native.Trampoline.trampoline