Generator自动执行器 
今天也是炫技的一天呢~原意是设法将异步回调变成瀑布执行,然后写出了一个比较奇怪的模式。
Js版本 
Promise、async和await不过是Generator的语法糖。
js
const autoRun = (gen) => {
  const g = gen();
  const run = () => {
    const result = g.next();
    if (result.done) return;
    result.value(run);
  };
  run();
};
autoRun(function* () {
  yield (next) => setTimeout(() => { // await new Promise((next) => setTimeout(next, 1000))
    console.log(2);
    next();
  }, 1000);
  yield (next) => setTimeout(() => {
    console.log(3);
    next();
  }, 1000);
});Lua版本: 
lua
local co = coroutine 
function setTimeout(callback, timeout)
  local start = os.clock()
  while os.clock() - start <= timeout do end
  callback()
end
local autoRun = function(gen)
  local g = co.create(gen)
  function run() 
    local _,result = co.resume(g)
    if result == nil then return end
    result(run)
  end
  run()
end
autoRun(function() 
  co.yield(function(next) 
    setTimeout(function() 
      print(2)
      next()
    end, 1)
  end)
  co.yield(function(next)
    setTimeout(function() 
      print(3)
      next()
    end, 1)
  end)
end)Python版本 
python
import time
def setTimeout(callback, timeout):
    time.sleep(timeout)
    callback()
def autoRun(gen):
    g = gen()
    def run():
        result = next(g)
        if result != None:
            result(run)
    run()
autoRun(lambda: [
    (yield (lambda n: setTimeout(lambda: [print(2), n()], 1))),
    (yield (lambda n: setTimeout(lambda: [print(3), n()], 1))),
    (yield None)])Racket版本 
用continuation实现。
scheme
#lang racket
(define (setTimeout callback timeout)
  (sleep timeout)
  (callback))
     
(define (autoRun g)
  (let [(next (call/cc (lambda (yield) (g yield))))]
    (if (eq? #f next)
      (void)
      (next))))
(autoRun (lambda (yield)
           (setTimeout (lambda () (println 2) (call/cc (lambda (next) (yield next)))) 1)
           (setTimeout (lambda () (println 3) (call/cc (lambda (next) (yield next)))) 1)
           (yield #f)))Go版本 
用channel模拟yield。这种模拟给了我们一种很微妙的感觉,如果站在整个程序执行流的视角,写入channel和读取channel的两个线程没有任何同时执行的契机,名为多线程,其实还是单线程模型。
go
package main
import (
	"fmt"
	"time"
)
type Yield chan func(func())
func setTimeout(callback func(), timeout time.Duration) {
	time.Sleep(timeout * time.Millisecond)
	callback()
}
func autoRun(gen func(Yield)) {
	yield := make(Yield)
	
	var run func()
	run = func() {
		result := <- yield
		if result != nil {
			result(run)
		}
	}
	go gen(yield)
	run()
}
func main() {
	autoRun(func (yield Yield) {
		yield <- func(next func ()) {
			setTimeout(func () {
				fmt.Println(2)
				next()
			}, 1000)
		}
		yield <- func(next func ()) {
			setTimeout(func () {
				fmt.Println(3)
				next()
			}, 1000)
		}
		yield <- nil
	})
}Rust版本 
也基于channel。对Rust的lifetime还不够了解,见注释。
rust
#![allow(non_snake_case)]
use std::{
    sync::mpsc::{sync_channel, SyncSender},
    thread,
    time::Duration,
};
fn setTimeout(callback: &dyn Fn(), timeout: u64) {
    std::thread::sleep(Duration::from_millis(timeout));
    callback();
}
type Lambda<Param> = Box<dyn Fn(Param) + Send + Sync>;
// Rust does not support recursive lambda function
struct Closure<'a> {
    lambda: &'a dyn Fn(&Closure),
}
// How to convert to SyncSender<Lambda<&Closure>> with appropriate lifetime?
type Yield = SyncSender<Box<dyn Fn(&Closure) + Send + Sync>>;
fn autoRun(gen: Lambda<Yield>) {
    let (tx, rx): (Yield, _) = sync_channel(1);
    let run = Closure {
        lambda: &|this| {
            if let Ok(result) = rx.recv() {
                result(this);
            }
        },
    };
    thread::spawn(move || gen(tx));
    (run.lambda)(&run);
}
pub fn test_yield() {
    autoRun(Box::new(|tx| {
        tx.send(Box::new(|next| {
            setTimeout(
                &|| {
                    println!("2");
                    (next.lambda)(next);
                },
                1000,
            );
        }))
        .unwrap();
        tx.send(Box::new(|next| {
            setTimeout(
                &|| {
                    println!("3");
                    (next.lambda)(next);
                },
                1000,
            );
        }))
        .unwrap();
    }));
}C++版本 
channel不过是信号量的语法糖。
cpp
#include <future>
#include <thread>
#include "example/semaphore.h"
void setTimeout(std::function<void()> const& callback, std::chrono::milliseconds const& timeout) {
  std::this_thread::sleep_for(timeout);
  callback();
}
using Yield = std::function<void(std::function<void()>)>;
// simulate one size channel
class Channel {
 public:
  // write to channel
  friend void operator<<(Channel& chan, Yield const& data) {
    chan.slot.P();
    chan.data = data;
    chan.item.V();
  }
  // read from channel
  friend Yield const& operator>>(Channel& chan, void*) {
    chan.item.P();
    auto data = new Yield(chan.data);
    chan.slot.V();
    return *data;
  }
 private:
  Yield     data;
  Semaphore slot{1};
  Semaphore item{0};
};
void autoRun(std::function<void(Channel&)> const& gen) {
  Channel yield;
  std::function<void()> run = [&]() {
    auto result = yield >> 0;
    if (result == nullptr) return;
    result(run);
  };
  auto p = std::async([&]() { gen(yield); });
  run();
  p.wait();
}
int main() {
  using namespace std;
  using namespace std::chrono_literals;
  autoRun([](Channel& yield) {
    yield << [](std::function<void()> const& next) {
      setTimeout(
          [&next]() {
            cout << 2 << endl;
            next();
          },
          1000ms);
    };
    yield << [](std::function<void()> const& next) {
      setTimeout(
          [&next]() {
            cout << 3 << endl;
            next();
          },
          1000ms);
    };
    yield << nullptr;
  });
  return 0;
}