Skip to content

Instantly share code, notes, and snippets.

@tcr
Created June 17, 2012 08:53
Show Gist options
  • Save tcr/2943937 to your computer and use it in GitHub Desktop.
Save tcr/2943937 to your computer and use it in GitHub Desktop.
Generators using IcedCoffeeScript
# Generators and "yield" in IcedCoffee
# See: https://developer.mozilla.org/en/JavaScript/Guide/Iterators_and_Generators
# Try it: http://maxtaco.github.com/coffee-script/
# We can mimick much of the Generator functionality of JavaScript 1.7
# using IcedCoffeeScript's Deferrals.
#
# We define a "generator" function that can be given a function and return a generator.
# To mimick yield, we use a passed argument, "cc", and await/defer on it. This holds on
# to the deferral callback until the next time the function is invoked.
# Like JS1.7 Generators, return early at any time (or don't yield) to throw StopIteration.
if not StopIteration?
StopIteration = {}
generator = (next) ->
ret = null; send = `void 0`
cc = (_next, _ret) ->
ret = _ret; next = _next
args = [cc]
return gen =
next: ->
fn = next; next = null
fn args...
if not next then throw StopIteration
args = []
return ret
send: (_send) ->
args = [_send]
return gen.next()
# That's it! Examples:
# Create a generator to count up.
counter = (from, to) ->
return generator (cc) ->
i = from
while i < to
await cc defer(), i # "yield i"
i++
return # Stop iterating
# Prints 0, 1, 2, ... 9
count = counter(0, 10)
try
loop
console.log 'Iterator returned:', count.next()
catch e
console.log 'Thrown StopIteration:', e == StopIteration
# We can emulate .send() by requiring an argument back from defer()
fibonacci = ->
return generator (cc) ->
fn1 = 1
fn2 = 1
loop
current = fn2
fn2 = fn1
fn1 = fn1 + current
await cc defer(reset), current # reset = yield current
if reset
fn1 = 1
fn2 = 1
sequence = fibonacci()
console.log sequence.next() # 1
console.log sequence.next() # 1
console.log sequence.next() # 2
console.log sequence.next() # 3
console.log sequence.next() # 5
console.log sequence.next() # 8
console.log sequence.next() # 13
console.log sequence.send(true) # 1
console.log sequence.next() # 1
console.log sequence.next() # 2
console.log sequence.next() # 3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment