|
|
1.1 ! root 1: A set of new primitives has been added to ML to give access to continuations: ! 2: ! 3: type 'a cont ! 4: val callcc : ('a cont -> 'a) -> 'a ! 5: val throw : 'a cont -> 'a -> 'b ! 6: ! 7: The continuation of an expression is an abstraction of what the system ! 8: will do with the value of the expression. For example in the ! 9: expression: ! 10: ! 11: if a orelse b then foo() else goo() ! 12: ! 13: the continuation of the expression "a orelse b" can be described in ! 14: words as "if the value is true then compute foo() otherwise compute ! 15: goo()" and then continue in the context of the if-expression. Usually ! 16: the continuation of an expression is implicit, however, the primitive ! 17: callcc allows the programmer to capture and use these continuations. ! 18: ! 19: The primitive callcc takes a function as an argument and applies it to ! 20: the current continuation. The continuation of an expression of type 'a ! 21: has type 'a cont and is a first-class object. To capture the ! 22: continuation described above one would write: ! 23: ! 24: if callcc(fn k => a orelse b) then foo() else goo ! 25: ! 26: Here the continuation of the callcc-application is captured by being ! 27: bound to k, but it is not used. Because the continuation is not used ! 28: the result is simply the result of the expression "a orelse b". To ! 29: use the continuation a value must be supplied, and the computation ! 30: continues as if that value where the result of the callcc-application. ! 31: This is called throwing the continuation a value; it is performed by ! 32: applying "throw" to the continuation and the value. ! 33: ! 34: if callcc(fn k => (throw k false) orelse b) then foo() else goo() ! 35: ! 36: Here, when the continuation k is thrown the value false, "orelse b" is simply ! 37: ignored, the callcc-application returns false, and goo() is then evaluated. ! 38: ! 39: The type returned by a throw-expression is unconstrained like that of ! 40: a raise-expression and for the same reason: neither of these ! 41: expressions ever return. ! 42: ! 43: One of the less interesting uses of callcc is as an alternative to ! 44: exception handlers. For example: ! 45: ! 46: exception Prod ! 47: ! 48: fun prod l = let fun loop [] = 1 ! 49: | loop(0::r) = raise Prod ! 50: | loop(a::r) = a * loop r ! 51: in loop l handle Prod => 0 ! 52: end ! 53: ! 54: can be written with callcc as follows: ! 55: ! 56: fun prod l = callcc(fn exit => ! 57: let fun loop [] = 1 ! 58: | loop(0::r) = throw exit 0 ! 59: | loop(a::r) = a * loop r ! 60: in loop l ! 61: end) ! 62: ! 63: But continuations are more general than exception handlers and can be ! 64: used to implement sophisticated control structures. These more complex ! 65: uses often involve subtle interactions with the type system. For just ! 66: a taste of the techniques involved consider the following example ! 67: implementing an infinite loop. ! 68: ! 69: datatype State = S of State cont ! 70: fun state_throw (S k) = throw k ! 71: ! 72: let val s = callcc S ! 73: in state_throw s s ! 74: end ! 75:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.