Skip to content

Instantly share code, notes, and snippets.

@shesek
Created March 5, 2012 08:29
Show Gist options
  • Save shesek/1977471 to your computer and use it in GitHub Desktop.
Save shesek/1977471 to your computer and use it in GitHub Desktop.
CoffeeScript generator function decorator
# Very simple implementation for generators in CoffeeScript. Obviously not as powerful as real generators,
# and only useful for iterating over values (pulling values via `.next()` is quite impossible to implement
# with a natural `yield` syntax in the generator), but still quite useful and provides an elegant syntax.
# The `generator` function is used as a decorator for functions. The function passed to `generator` gets
# called with the `this` context having a `yield` property that should be used to yield values to consumers.
# The function returned by calling `generator` should than be called with a function to consume the values.
generator = do ->
StopIteration = {}
stopCtx = stop: -> throw StopIteration
(gen) -> (fn) ->
try gen.call yield: (args...) -> fn.apply stopCtx, args
catch e then throw e unless e is StopIteration
# Usage:
range = (min, max) -> generator -> @yield i for i in [min..max]; return
(range 5, 15) (num) -> console.log num
# Infinite generators can be stopped by calling `@stop` in the function consuming the values:
fib = generator ->
[prev, curr] = [0, 1]
loop
[prev, curr] = [curr, prev+curr]
@yield curr
return
fib (n) ->
console.log n
do @stop if n > 50
## Or, if `this` needs to be preserved, `yield` and `stop` can be passed as arguments instead
# (`yield` is reserved in strict mode [and about to be used in harmony], so a different name should probably be used if its passed as an argument)
generator = do ->
StopIteration = {}
stop = -> throw StopIteration
(gen) -> (fn) ->
try gen.call this, (args...) -> fn.apply this, [stop, args...]
catch e then throw e unless e is StopIteration
range = (min, max) -> generator (yield) -> yield i for i in [min..max]; return
(range 5, 15) (stop, num) -> console.log num
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment