Merge pull request #456 from maxsnew/trampoline

Trampoline
This commit is contained in:
Evan Czaplicki 2014-01-24 08:31:58 -08:00
commit 5d5b01cb2d
2 changed files with 67 additions and 0 deletions

View file

@ -0,0 +1,25 @@
Elm.Native.Trampoline = {};
Elm.Native.Trampoline.make = function(elm) {
elm.Native = elm.Native || {};
elm.Native.Trampoline = elm.Native.Trampoline || {};
if (elm.Native.Trampoline.values) return elm.Native.Trampoline.values;
var _E = Elm.Native.Error.make(elm),
// trampoline : Trampoline a -> a
trampoline = function(t) {
var tramp = t;
while(true) {
switch(tramp.ctor) {
case "Done":
return tramp._0;
case "Continue":
tramp = tramp._0({ctor: "_Tuple0"});
continue;
}
_E.Case("Trampoline", "in Native.Trampoline.trampoline");
}
}
return elm.Native.Trampoline.values = { trampoline: trampoline };
};

42
libraries/Trampoline.elm Normal file
View file

@ -0,0 +1,42 @@
module Trampoline where
{-| Trampolining loops for unbounded recursion.
Since most javascript implementations lack tail-call elimination, deeply tail-recursive functions will result in a stack overflow.
```haskell
fac' : Int -> Int -> Int
fac' n acc = if n <= 0
then acc
else fac' (n - 1) (n * acc)
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
-}
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)
{-| Run a trampolining loop in constant space. -}
trampoline : Trampoline a -> a
trampoline = Native.Trampoline.trampoline