免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 38066 | 回复: 8
打印 上一主题 下一主题

什么是continuation? [复制链接]

论坛徽章:
8
2015年迎新春徽章
日期:2015-03-04 09:58:112015元宵节徽章
日期:2015-03-06 15:51:33数据库技术版块每日发帖之星
日期:2016-06-09 06:20:00数据库技术版块每日发帖之星
日期:2016-06-10 06:20:00数据库技术版块每日发帖之星
日期:2016-07-20 06:20:0015-16赛季CBA联赛之同曦
日期:2016-07-21 21:26:51数据库技术版块每日发帖之星
日期:2016-07-23 06:20:00数据库技术版块每日发帖之星
日期:2016-07-26 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-07-26 16:29 |只看该作者 |倒序浏览
continuation概念及意义

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
2 [报告]
发表于 2016-07-26 20:32 |只看该作者

continuation的概念

粗略地说, continuation就是“接下来要做什么”。。。

  1. void f(int x, int y, int root)
  2. {
  3.   printf("%s x+y = %d\n", root? "#": "$", x+y);
  4.   printf("%s x-y = %d\n", root? "#": "$", x-y);
  5. }
复制代码
“printf("%s x+y = %d\n", root? "#": "$", x+y)” 的continuation就是:
1. 继续执行下面一条printf
2. f返回它的调用者
3. 在返回处继续执行知道这个线程中止(continuation是有界限的)


“x+y”的continuation说明起来就更复杂一些。 假设 v 是 “x+y”的结果, “x+y”的continuation可能是:
1. “printf("%s x+y = %d\n", root? "#": "$", v)” 接着是这整个表达式的continuation, 就是上面说的直到这个线程中止的剩余部分。
2. “printf("%s x+y = %d\n", "$" , v)” 以及后续continuation
3. “printf("%s x+y = %d\n", "#" , v)” 以及后续continuation
...
C语言规定了两个printf的顺序, 必须先执行第1个, 再执行第2个。 所以前一个printf的continuation说明起来更容易一些。
C语言并没有规定printf的参数的求值顺序, 所以就此处就不像前面那样容易说明。。。
如果 root? "#": "$" 比 “x+y”后求值, 那就是1的情况。
如果 root? "#": "$" 比 “x+y”先求值, 那2就是root非0的情况, 3就是root为0的情况。

实际上还可以继续细分, 比如 “root” “"%s x+y = %d\n"”这些子表达式。
总之, continuation 是等待这一个的。
“printf("%s x+y = %d\n", root? "#": "$", x+y)” 也等待这printf的返回值, 只是立即丢弃了, 不容易看出来。
而“x+y”的continuation就需要“x+y”的求值结果。


因此, 哪怕是C语言,也存在continuation。 但这些continuation不能拿给程序员继进行操作, 所以没啥卵用。。。
C语言也有可以让程序员使用的continuation, 就是jmp_buf。

  1. jmp_buf k;
  2. int x = setjmp(k);
  3. ...
复制代码
“setjmp(k)”的continuation就是“int x = v; ...”, 即对x赋值, 以及后续表达式, 直到线程中止。 其中v是setjmp(k)的值。
这个continuation就是程序员可以操作的了。 可以通过“longjmp(k, val)” 调用该continuation, 即是回到“setjmp(k)”处, 为x提供一个值, 并继续执行。

不过C语言规定longjmp只能从调用链的“深处”往“浅处”跳, 不能反过来。 于是限制了它的用处。。。
并且用的时候还要各种小心。。。 C++的析构函数。。。 volatile。。。 sign mask。。。。 于是肯定就会出现“setjmp/longjmp  Considered Harmful”这样的论点。。。

除了C语言标准外, windows下有fiber, posix里有ucontext。 它们都让程序员可以操作continuation。


continuation最出名的应该是Scheme里的call-with-current-continuation(一般简称为call/cc, 但前者才是r5rs里有的, call/cc不是)。
call/cc 是一种 undelimited continuation , 其实不如 delimited continuation 好用。。。
delimited continuation好像正是源自ML系列的语言。。。  你可以去搜一下, reset/shift或者prompt/control之类的, 它们都是delimited continuation。


还有一种与continuation有关的概念叫continuation passing style。 俗称callback或callback hell。。。

论坛徽章:
8
2015年迎新春徽章
日期:2015-03-04 09:58:112015元宵节徽章
日期:2015-03-06 15:51:33数据库技术版块每日发帖之星
日期:2016-06-09 06:20:00数据库技术版块每日发帖之星
日期:2016-06-10 06:20:00数据库技术版块每日发帖之星
日期:2016-07-20 06:20:0015-16赛季CBA联赛之同曦
日期:2016-07-21 21:26:51数据库技术版块每日发帖之星
日期:2016-07-23 06:20:00数据库技术版块每日发帖之星
日期:2016-07-26 06:20:00
3 [报告]
发表于 2016-07-26 20:44 |只看该作者
回复 2# OwnWaterloo


    谢谢,那么call/cc和delimited continutation是什么?

论坛徽章:
8
2015年迎新春徽章
日期:2015-03-04 09:58:112015元宵节徽章
日期:2015-03-06 15:51:33数据库技术版块每日发帖之星
日期:2016-06-09 06:20:00数据库技术版块每日发帖之星
日期:2016-06-10 06:20:00数据库技术版块每日发帖之星
日期:2016-07-20 06:20:0015-16赛季CBA联赛之同曦
日期:2016-07-21 21:26:51数据库技术版块每日发帖之星
日期:2016-07-23 06:20:00数据库技术版块每日发帖之星
日期:2016-07-26 06:20:00
4 [报告]
发表于 2016-07-26 20:46 |只看该作者
continutation passing style又是什么?

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
5 [报告]
发表于 2016-07-26 20:50 |只看该作者

continuation的意义

比较理论地说, 可以将各种所谓的control structure看作对continuation的使用。
不过还是整点实际的吧。。。

比如, 进行一个文件读写操作(可以是regular file, pipe, socket, ...)。
可以选择使用blocking read/write。
这样的好处是代码依然是“正常”的, 坏处就是一个线程被阻塞了。

也可以不选择blocking read/write, 而是等待它可以读写的时候再进行read/write或者等待read/write完成后处理数据。

从continuation的角度来分析, 这个所谓的等待, 其实就是传递continuation。。。
区别在于是语言帮程序员提取一个continuation, 还是程序员自己人肉提取。。。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
6 [报告]
发表于 2016-07-26 20:55 |只看该作者

RE: 什么是continuation?

回复 3# love_wisdom

  1. (call/cc
  2.   (lambda (k)
  3.     ...))
复制代码
k就是整个call/cc表达式的continuation。
它的界限标准里似乎并没有说。

  1. (shift k ...)
复制代码
k就是整个shift表达式的continuation。
它的界限是到最近的一个reset为止。
reset/shift是delimited continuation的一种。

论坛徽章:
8
2015年迎新春徽章
日期:2015-03-04 09:58:112015元宵节徽章
日期:2015-03-06 15:51:33数据库技术版块每日发帖之星
日期:2016-06-09 06:20:00数据库技术版块每日发帖之星
日期:2016-06-10 06:20:00数据库技术版块每日发帖之星
日期:2016-07-20 06:20:0015-16赛季CBA联赛之同曦
日期:2016-07-21 21:26:51数据库技术版块每日发帖之星
日期:2016-07-23 06:20:00数据库技术版块每日发帖之星
日期:2016-07-26 06:20:00
7 [报告]
发表于 2016-07-26 21:12 |只看该作者
OwnWaterloo 发表于 2016-07-26 20:55
回复 3# love_wisdom k就是整个call/cc表达式的continuation。
它的界限标准里似乎并没有说。k就是整个shi ...

说了等于没说

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
8 [报告]
发表于 2016-07-26 21:27 |只看该作者
回复 4# love_wisdom

  1. (define (ls dir)
  2.   (let*((files (readdir dir))
  3.         (files (cons "." (cons ".." files)))
  4.         (files (map (lambda (file) (string-append dir file)) files)))
  5.     (map lstat files)))
复制代码
这个就是direct style的样子。 其中readdir返回一个list, 里面是string, 元素是dir里的所有文件但不包含"."和".."。
lstat就是。。。 就是lstat(2)的绑定。。。 它返回文件的stat。。。

其他函数也都是传递参数/返回。。。


然而。。。  有个叫nodejs的平台。。。  它的readdir和lstat是这样的。。。

  1. (define (readdir& dir k)
  2.   (let ((files ...))
  3.     (k files)))

  4. (define (lstat& file k)
  5.   (let ((stat ...))
  6.     (k stat)))
复制代码
它接受一个continuation k, 当readdir(2)或lstat(2)完成后调用k。

这个就是 continutation passing style。 函数不再是直接的返回, 而是要求调用者传递自己的continutation(俗称callback)。
在direct style里, 通过返回给调用者提供值的时候, continutation passing style通过调用continutation 给调用者提供值。


如果语言没有提取continutation的机制, 那么continutation passing style是传染性的, 一旦有一处是这个样子, 就会让其他地方也变成这个样子, 比如:

  1. (define (ls& k dir)
  2.   (readdir& dir
  3.     (lambda (files)
  4.       (let loop
  5.           ((files (map (lambda (file) (string-append dir file)) (cons "." (cons ".." files))))
  6.            (stats '()))
  7.         (if (not (null? files))
  8.           (lstat& files
  9.             (lambda (stat) (set! stats (cons stat stats))))
  10.           (k stats))))))
复制代码
如果要调用 readdir& 和 lstat& , ls也不能直接返回了, 而是要继续写成continutation passing style。
ls& 要求调用者传递一个k给它, 它在搜集完stats的时候调用这个k。


而如果语言可以帮助程序员提取continutation, 就可以恢复成direct style:

  1. (define (readdir dir)
  2.   (shift k (readdir& dir k)))

  3. (define (lstat file)
  4.   (shift k (lstat& file k)))
复制代码
此处用readdir&和lstat&实现一个direct style的readdir和lstat。

它们内部依然是continutation passing style。 readdir和lstat要将一个continuation传递给readdir&和lstat&。 只是这个continutation是语言帮忙提取的。

对readdir和lstat的调用者来说, 它们会返回, 是direct style的。

论坛徽章:
8
2015年迎新春徽章
日期:2015-03-04 09:58:112015元宵节徽章
日期:2015-03-06 15:51:33数据库技术版块每日发帖之星
日期:2016-06-09 06:20:00数据库技术版块每日发帖之星
日期:2016-06-10 06:20:00数据库技术版块每日发帖之星
日期:2016-07-20 06:20:0015-16赛季CBA联赛之同曦
日期:2016-07-21 21:26:51数据库技术版块每日发帖之星
日期:2016-07-23 06:20:00数据库技术版块每日发帖之星
日期:2016-07-26 06:20:00
9 [报告]
发表于 2016-07-26 22:14 |只看该作者
回复 8# OwnWaterloo


    delimited continuation 是什么?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP