Hacker News new | past | comments | ask | show | jobs | submit login

You know how in Python the "yield" statement is actually an expression and can be sent values using "next"? Imagine there is a special "yield" called "call-with-current-continuation" that can be used anywhere (not just in generators) which bundles everything up and makes a generator-like thing called a "continuation." This continuation object can be called later on, like using "next" in Python. Unlike generators, though, continuations can usually be resumed repeatedly, always resuming at the same point where the call-with-current-continuation expression was.

A weird thing is that call-with-current-continuation doesn't yield back to something; it yields to the function given to call-with-current-continuation.

Would that be like having a yield statement AND passing a context (e.g. binding a this that represents "current-continuation")?

Here are two examples in Python syntax, assuming "yield" is no longer a keyword.

  def f():
    def receiver(yield):
      # yield jumps out of the 'receiver' function and never returns
      print("This never prints")
    x = callcc(receiver)
    return x+1
  # f returns 2+1
  # backtracks stores (continuation,[values]) pairs.  Whenever a computation fails, we pull out another
  # value from the list and feed it to the continuation.  The idea is to perform a depth-first search.
  backtracks = []
  def fail():
    """Aborts the current continuation and backtracks to another alternative stored in backtracks."""
    if not backtracks: raise Exception('amb ran out of alternatives')
    yield, alternatives = backtracks.pop()
    alt = alternatives.pop()
    if alternatives: # this continuation still has alternatives, so put them back on the list in case of a future 'fail'
      backtracks.push((yield, alternatives))
  def amb(*alternatives):
    """The "ambivalent operator."  The arguments to amb are alternatives, and the return value of amb
    is an alternative which makes the future computation not fail."""
    if not alternatives: fail()
    def receiver(yield):
      backtracks.append((yield, alternatives))
    return callcc(receiver)
  def expect(b):
    if not b: fail()
  def test_amb():
    """Let's find a Pythagorean triple."""
    x = amb(*range(1,100))
    y = amb(*range(1,100))
    z = amb(*range(1,100))
    expect(x**2 + y**2 == z**2)
    return (x,y,z)
  # We can print out all the Pythagorean triples.
  trip = test_amb()
  print("(x,y,z)=(%s,%s,%s)" % trip)
  fail() # fail every time so it keeps backtracking, but the side effect of printing out remains

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact