Implementing yield
First, let's see what yield is by looking at some usage examples.
foo = with-yield(λ(yield){
  yield(1);
  yield(2);
  yield(3);
  "DONE";
});
println(foo());  # prints 1
println(foo());  # prints 2
println(foo());  # prints 3
println(foo());  # prints DONE
  When called, yield stops execution of the function and
  returns a value.  Pretty much like return so far.  But when you
  call the function again, it resumes from where the
  last yield left off, as you can see in the above example.  It
  prints 1, 2, 3, DONE.
A more real-world usage:
fib = with-yield(λ(yield){
  let loop (a = 1, b = 1) {
    yield(b);
    loop(b, a + b);
  };
});
## print the first 50 fibonacci numbers
let loop (i = 0) {
  if i < 50 {
    println(fib());
    loop(i + 1);
  };
};
  The fib function contains an infinite loop.  There is no
  termination condition.  But yield interrupts that loop and
  returns the current number.  Calling the function again resumes from where
  it left off, so to print the first 50 numbers then we just need to call
  the function 50 times.
This program will also run much faster than the duble-recursive version of fib, because it keeps track of the previous two values internally and just returns the next one.
A failed implementation attempt
I wouldn't waste your time with a failed attempt unless there were valuable lessons to learn from it, so please bear with me.
  To implement yield it seems we need to save the initial
  continuation of the function.  We need that so we can exit early, like we
  do for return.  However, before actually returning from
  a yield we also have to save yield's own continuation, in
  order to be able to return later to that point inside the
  function.  That's what it seems, at least.  We can attempt an
  implementation like this:
with-yield = λ(func) {
  ## with-yield returns a function of no arguments
  λ() {
    CallCC(λ(kret){        # kret is the "return" continuation
      let (yield) {
        ## define yield
        yield = λ(value) { # yield takes a value to return
          CallCC(λ(kyld){  # kyld is yield's own continuation…
            func = kyld;   # …save it for later
            kret(value);   # and return.
          });
        };
        ## finally, call the current func, passing it the yield.
        func(yield);
      };
    });
  };
};
  This was my first stab at implementing yield and it all
  seemed to make sense.  But if we try to run the first sample above for
  this definition of with-yield, it will be an endless loop.
  Try it below if you wish, but be prepared to refresh the page (I actually
  modified Execute in this page to use setTimeout
  instead of exceptions for clearing the stack, so it won't freeze your
  browser).  If you click Run you'll briefly notice in the output that it
  prints 1, 2, 3, followed by an endless stream of "DONE".
The reason why it loops is subtle. But first, if you want to see something even more bizarre, edit the code above and change the last 4 println lines to this:
println(foo());
foo();
The output will be exactly the same. Again: if you ran this example you should refresh your page, otherwise it will run endlessly, draining the battery and eventually all your computer's RAM.
Problem 1: yield never changes
  One problem to notice is that the continuation we save for the
  first yield (kyld, which becomes the
  next func to call, if you follow the implementation
  of with-yield) embeds this computation:
  yield(2);
  yield(3);
  "DONE";
  But who is yield in this continuation?
  It's the same as the first yield, which actually returns to
  the first kret continuation ever saved, which is to print the
  result and continue from there, resulting in a loop.  Fortunately there's
  an easy fix for that.  Clearly enough, we should create
  the yield closure only once, since we cannot change it in the
  function after the first call; in order to return to the proper exit point
  we maintain a new return variable:
with-yield = λ(func) {
  let (return, yield) {
    yield = λ(value) {
      CallCC(λ(kyld){
        func = kyld;
        return(value);       # return is set below, on each call to the function
      });                    # it's always the next return point.
    };                       #
    λ(val) {                 #
      CallCC(λ(kret){        #
        return = kret;       # <- here
        func(val || yield);
      });
    };
  };
};
  Additionally, recognizing that it doesn't make sense to
  pass yield each time to the function, but only the first
  time, this new version allows passing another value on each invocation
  (except for the first).  That will be yield's own return
  value.
  The following code still uses the “foo” example, but it has
  println(foo()) only three times:
  It appears to work properly.  It's a clear improvement over the first
  version, which looped on code like print(foo()); foo().  But what
  happens if you add another println(foo())?  LOOP!
Problem 2: WTF?
  The reason for looping this time is a little more profound.  It has to do
  with the unlimited nature of our continuations: they encode the whole
  future of the computation and that happens to
  include returning from the first call
  to foo().  What happens when we return from it? — we start
  all over:
println(foo()); ## yield 1 <----------------- HERE -------------------+
println(foo()); ## yield 2                                            |
println(foo()); ## yield 3                                            |
println(foo()); ## we reached "DONE", so the first foo() RETURNS -->--+
  Let's look at this line from with-yield:
        func(val || yield);
        #...
  When func exits via an invocation of yield, it
  calls a continuation, so the execution doesn't reach the #...
  line.  But by the time it finishes, for reaching the end of the function
  (the "DONE" line), func will have been effectively
  reduced to a function which returns "DONE" to the original
  continuation, which is to call the first print.
  The foo() on the second line just loops over, but all those
  "DONE" lines are printed by the first print line.  You can verify
  this by running the following code:
println(foo());
println("bar");
println(foo());
println(foo());
foo();
  The output will be: 1, bar, 2, 3, DONE, bar, DONE, bar, ....
  So for a possible fix, we simply must set func to something
  else when it returns “naturally” (that is to say simply, “finishes”).
  We'll make it a do-nothing function which just returns "no more
  continuations".
        val = func(val || yield);
        func = λ() "NO MORE CONTINUATIONS";
        kret(val);
It no longer loops now, but be prepared to be confused when running the code below:

  We would have hoped for 1, 2, 3, DONE, but we also get "NO
  MORE CONTINUATIONS" three times.  To figure out what happens we can
  interleave some prints, like this:
print("A. "); println(foo());
print("B. "); println(foo());
print("C. "); println(foo());
print("D. "); println(foo());
## and the output is:
A. 1
B. 2
C. 3
D. DONE
B. NO MORE CONTINUATIONS
C. NO MORE CONTINUATIONS
D. NO MORE CONTINUATIONS
***Result: false
  Which shows that the problem remained: a natural exit from the function
  still goes back to the first continuation; but because the function is now
  a no-op, the "B." line won't trigger a loop.
  Our implementation is still useful, provided that the function never
  finishes and only exits via yield.  Here's for the Fibonacci
  example:
But if we want a solid implementation (so, one that doesn't return to the first call site when the function finishes), we need another concept called “delimited continuations”.
Delimited continuations: reset and shift
  We're going to implement yield in terms of two other
  operators, reset and shift.  They provide
  “delimited continuations” — these are continuations that return, like an
  ordinary function.  reset creates a frame
  and shift intercepts the continuation only upto that frame,
  instead of “the whole future of the program” like CallCC
  does.
  Both reset and shift take a single function
  argument.  During the execution of the reset function, a call
  to shift will allow us to return a value to the place
  where reset was called.
  First, let's see how with-yield will look:
with-yield = λ(func) {
  let (yield) {
    ## yield uses shift to return a value to the innermost
    ## reset call.  before doing that, it saves its own
    ## continuation in `func` — so calling func() again will
    ## resume from where it left off.
    yield = λ(val) {
      shift(λ(k){
        func = k;  # save the next continuation
        val;       # return the currently yielded value
      });
    };
    ## from with-yield we return a function with no arguments
    ## which uses reset to call the original function, passing
    ## to it the yield (initially) or any other value
    ## on subsequent calls
    λ(val) {
      reset( λ() func(val || yield) );
    };
  }
};
  Note that each call to the function is now embedded in
  a reset.  This ensures that we don't enclose the whole
  continuation of the program, but only the part up to this reset.  By
  definition it is now impossible to loop.  When the function finishes
  naturally, the program will just continue execution instead of going back
  to the place of the first call.
You can run our troublesome program below and you'll see that it finally behaves as expected. It prints nothing more nor less than it should, and it doesn't loop.
Implementation of reset / shift
These operators are quite tricky to implement, although the code is short. Prepare for some headaches. I'll give you two solutions. I am not the author of this method and I can tell you I stared at the code for a long time before it clicked. I found it in this Scheme program by Oleg Kiselyov. I recommend these articles to understand more about this mind-blowing concept.
As primitives
  In this page they are implemented as primitive functions.  In primitives,
  the current continuation is explicit (we don't need CallCC),
  and this makes it somewhat easier to understand what's going on under the
  covers.  Here's the complete implementation (left):
| 
var pstack = [];
function _goto(f) {
    f(function KGOTO(r){
        var h = pstack.pop();
        h(r);
    });
}
globalEnv.def("reset", function(KRESET, th){
    pstack.push(KRESET);
    _goto(th);
});
globalEnv.def("shift", function(KSHIFT, f){
    _goto(function(KGOTO){
        f(KGOTO, function SK(k1, v){
            pstack.push(k1);
            KSHIFT(v);
        });
    });
});
 | 
  It can be useful to have  
with-yield = λ(func) {
  let (yield) {
    yield = λ(val) {
      shift(λ(SK){
        func = SK;
        val;         ## return val
      });
    };
    λ(val) {
      reset( λ() func(val || yield) );
    };
  }
};
 | 
  The key is that both reset and shift
  use _goto, which isn't a “normal” function.  It has no
  continuation of its own.  _goto receives a normal function
  and invokes it with a continuation (KGOTO).  Any continuations
  caught during the execution of f (even
  by CallCC) can only capture “the future of the computation”
  upto this KGOTO, since there's nothing above it.  Therefore, no
  matter if f exits normally, or by calling a continuation, it
  will eventually get to run KGOTO — which takes the next
  continuation from the stack and applies it on the result.
  reset pushes its own continuation (KRESET) to the
  stack before _goto(th).  If it didn't do that, the program
  would stop when the function exits, because nothing else happens
  after _goto.  So when the function exits, in any way,
  KGOTO will resume to this KRESET.
  Finally, shift calls the function with the KGOTO
  continuation, so if it exits normally then KGOTO will resume from
  the top of pstack, and it passes to it a SK function
  which is able to return to the point where shift itself was
  called (by using shift's own continuation, KSHIFT).  SK
  is a delimited continuation — it has the ability to return a value, like a
  function — hence we need to push its k1 continuation to the
  stack as well.  To illustrate the difference I included in this page
  a shift2 primitive which is just like the shift
  above but without this line: pstack.push(k1);.  Try this sample:
  shift gives us a continuation (k) which is the
  delimited continuation upto the enclosing reset.  In this
  case the continuation is to add 1 to whatever the result of shift was:
1 + [?]
  When we're calling k, we're replacing the ? above
  with a value.  We call it twice k(k(2)).  We supply 2 and continue
  the program, hence the inner k(2) will return 3.  Therefore what
  follows is k(3) which supplies a 3, also in place of the question
  mark, yielding 4 as the final result.
  shift2 is incorrect: the inner k(2) never returns.
CallCC-based
  As stated, if we had no means to define primitive functions
  and CallCC was all we had, it'd still be possible to
  implement delimited continuations.  The code below does pretty much the
  same as the primitives version, but since we don't have JS arrays it uses
  lists to maintain the stack (as we saw some time back, we can implement lists directly in λanguage,
  although here they are provided as primitives).  The code is a bit longer
  because we need those CallCC-s in order to fetch the current
  continuation (which we get as an explicit argument in primitives).
  The trickiest part in the code below is how it
  implements goto, and why it has to do it like this,
  but I'll leave to you the pleasure of figuring it out.
pstack = NIL;
goto = false;
reset = λ(th) {
  CallCC(λ(k){
    pstack = cons(k, pstack);
    goto(th);
  });
};
shift = λ(f) {
  CallCC(λ(k){
    goto(λ(){
      f(λ(v){
        CallCC(λ(k1){
          pstack = cons(k1, pstack);
          k(v);
        });
      });
    });
  });
};
let (v = CallCC( λ(k){ goto = k; k(false) } )) {
  if v then let (r = v(), h = car(pstack)) {
    pstack = cdr(pstack);
    h(r);
  }
};