Continuations

2,039 views

Published on

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,039
On SlideShare
0
From Embeds
0
Number of Embeds
40
Actions
Shares
0
Downloads
27
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Continuations

  1. 1. Continuations & Web Applications -Balaji Damodaran, ThoughtWorks
  2. 2. Contiuation ● Continuation is Time Travel ● Continuation is saving the control flow of a program's execution
  3. 3. class ControlCentre def exploreTerrain marsPlateau = Plateau.new(5, 5) alpha = Rover.new("alpha") source = Position.new(1, 2, "N") alpha.land(marsPlateau, source) destination = alpha.explore("LMLMLMLMM") print destination end end
  4. 4. class ControlCentre def exploreTerrain marsPlateau = Plateau.new(5, 5) alpha = Rover.new("alpha") source = Position.new(1, 2, "N") alpha.land(marsPlateau, source) destination = alpha.explore("LMLMLMLMM") print destination end end
  5. 5. class ControlCentre def exploreTerrain marsPlateau = Plateau.new(5, 5) alpha = Rover.new("alpha") source = Position.new(1, 2, "N") alpha.land(marsPlateau, source) destination = alpha.explore("LMLMLMLMM") print destination end end Control Scope Execution Context marsPlateau alpha
  6. 6. class ControlCentre def exploreTerrain marsPlateau = Plateau.new(5, 5) alpha = Rover.new("alpha") source = Position.new(1, 2, "N") alpha.land(marsPlateau, source) destination = alpha.explore("LMLMLMLMM") print destination end end Control Scope Current Continuation Execution Context source = Position.new(1, 2, "N") marsPlateau alpha.land(marsPlateau, source) destination = alpha.explore("LMLMLMLMM") alpha print destination
  7. 7. class ControlCentre def exploreTerrain marsPlateau = Plateau.new(5, 5) alpha = Rover.new("alpha") callcc{|@cc|} source = Position.new(1, 2, "N") alpha.land(marsPlateau, source) destination = alpha.explore("LMLMLMLMM") print destination return @cc end end
  8. 8. class ControlCentre def exploreTerrain marsPlateau = Plateau.new(5, 5) alpha = Rover.new("alpha") callcc{|@cc|} source = Position.new(1, 2, "N") alpha.land(marsPlateau, source) destination = alpha.explore("LMLMLMLMM") print destination return @cc end end > c = exploreTerrain “1 3 N” => #<Continuation:0xb744a8c4> > c.call “1 3 N” => #<Continuation:0xb744a8c4>
  9. 9. Normal Control Flow with Continuation invoked Control Flow Continuations continuation continuation
  10. 10. Isn't that just a glorified GOTO?
  11. 11. class ControlCentre def exploreTerrain marsPlateau = Plateau.new(5, 5) alpha = Rover.new("alpha") c = nil source = callcc do |cc| c = cc Position.new(1, 2, "N") end alpha.land(marsPlateau, source) destination = alpha.explore("LMLMLMLMM") print destination return c end end > c = exploreTerrain “1 3 N” => #<Continuation:0xb7466240> > c.call(Position.new(2, 3, “E”)) “2 4 E” => #<Continuation:0xb7466240>
  12. 12. Normal Control Flow with Continuation invoked Control Flow Continuations with different parameters continuation continuation With different parameters
  13. 13. def continuation puts "i do some computation " + "& save the state of execution." m = callcc { |cc| return cc } puts "then i restart the execution from " + "the saved state & pass custom " + "values such as "#{m[0]}" and "#{m[1]}"" end > c = continuation i do some computation & save the state of execution. > c.call("so..", "then..") then i restart the execution from the saved state & pass custom values such as "so.." and "then.."
  14. 14. Normal Control Flow with Continuation reinvoked Control Flow Continuations paused with parameters continuation With parameters continuation
  15. 15. Continuation? ● A continuation reifies the control flow of a program as just another data value ● Reify – To consider an abstract concept to be real. To make control flow as first class functions/objects.
  16. 16. Continuation ● Continuation is an object that takes a snapshot copy of the running process. ● The current process is copied and saved. ● Current process – execution context and all local variables
  17. 17. Normal Control Flow marked with Control Flow continuation Memory Local variables # continuation
  18. 18. A new process that invokes a continuation Memory # The current execution is abandoned Note: Global data does not get stored in a continuation
  19. 19. Continuations ● A Continuation stores the execution context, its references and pointers. ● However, it does not store the heap data or data that is outside the scope of local references and pointers. ● So any change made to them will stay changed even after invoking the continuation.
  20. 20. Continuations Sandwich Analogy
  21. 21. call-with-current-continuation ● call-with-current-continuation, in short called as “call/cc” is a procedure first introduced in Scheme. ● Now exists in several other programming languages such as Ruby, known as “callcc”
  22. 22. call-with-current-continuation ● call/cc takes in only one argument, which is a function f. ● It takes the current continuation as an object and applies f to it. – continuation = new Continuation() – function(continuation) ● When, callcc gets invoked, the program flow will continue from the point it was captured and the argument to the continuation will become its return value
  23. 23. call-with-current-continuation Method definition: function: call/cc(function: f) { c = new: Continuation f(c) } JavaScript (Rhino): function callcc(f) { var c = new Continuation(); return f(c); } Ruby: callcc {|cont|} cont => Continuation object cont.call(*args)
  24. 24. call-with-current-continuation function callcc(fun) { var continuation = new Continuation() return fun(continuation) } var cc print(3 * (8 + callcc(function(c) { cc = c return 4 }))) js> 36
  25. 25. call-with-current-continuation function callcc(fun) { var continuation = new Continuation() return fun(continuation) } var cc print(3 * (8 + callcc(function(c) { cc = c return 4 }))) js> 36 js> cc(6) 42
  26. 26. def continue_example i = 0 print "Before callcc #{i}n" callcc do |cc| for i in 1..10 do print "In callcc #{i}n" return cc if i > 5 end end print "After callcc #{i}n" end
  27. 27. def continue_example i = 0 print "Before callcc #{i}n" callcc do |cc| for i in 1..10 do print "In callcc #{i}n" return cc if i > 5 end end print "After callcc #{i}n" end puts "begin control flow." c = continue_example() puts "after invoking the method" if c c.call puts "this will not get executed" end
  28. 28. def continue_example i = 0 print "Before callcc #{i}n" callcc do |cc| begin control flow. for i in 1..10 do Before callcc 0 print "In callcc #{i}n" In callcc 1 return cc if i > 5 In callcc 2 end In callcc 3 end In callcc 4 print "After callcc #{i}n" In callcc 5 end In callcc 6 after invoking the method After callcc 6 after invoking the method puts "begin control flow." c = continue_example() puts "after invoking the method" if c c.call puts "this will not get executed" end
  29. 29. call-with-current-continuation ● Continuations are sort of goto labels. But more powerful. ● We can store the continuation in a variable or object field, unlike a goto label. ● Goto labels are restricted within a functional scope, continuations are not limited by that.
  30. 30. The following code is strictly for session purposes only. Implementing this in usable code may cause harm to life and limb.
  31. 31. Continuation as a GOTO def goto_in_ruby_1 i = 0 callcc {|@label|} i = i + 1 print "#{i}t" @label.call if i < 10 end
  32. 32. Continuation as a GOTO def goto_in_ruby_1 i = 0 callcc {|@label|} i = i + 1 print "#{i}t" @label.call if i < 10 end output: 1 2 3 4 5 6 7 8 9 10
  33. 33. Continuation as a GOTO def goto_in_ruby_1 def goto_in_ruby_2 i = 0 i = 0 callcc {|@label|} callcc do |label| i = i + 1 label.call print "#{i}t" i = 99 @label.call if i < 10 end end print i end output: 1 2 3 4 5 6 7 8 9 10
  34. 34. Continuation as a GOTO def goto_in_ruby_1 def goto_in_ruby_2 i = 0 i = 0 callcc {|@label|} callcc do |label| i = i + 1 label.call print "#{i}t" i = 99 @label.call if i < 10 end end print i end output: output: 1 2 3 4 5 6 7 8 9 10 0
  35. 35. Summary ● Continuation is a procedure that represents the remaining steps in a computation. ● It is a "snapshot" of the current control context or control state of the program ● The continuation can be later invoked (repeatedly) with custom arguments
  36. 36. Continuations ● Languages that support first class continuations ● Scheme (call/cc) ● Ruby (callcc) ● Smalltalk (Continuation currentDo:) ● Rhino [JavaScript] (new Continuation()) ● Scala (Responder & shift, reset) ● Perl (Coro) ● Haskell (Control.Monad.Cont)
  37. 37. Continuations Types ● First class continuations ● Continuation Passing Style (CPS) ● Delimited Continuations
  38. 38. Continuation Passing Style ● A function, instead of returning an explict value, it takes an explict 'continuation' argument – another function which is meant to receive the result of the computation
  39. 39. Continuation Passing Style function (arg) { function (arg, k) { //computation //computation return result; k(result); } }
  40. 40. CPS - Example function add(x, y) { return x + y } function square(x) { return x * x } function calculate(x, y) { return add(square(x), square(y)) } js> print(calculate(3, 4)) => 25
  41. 41. CPS - Example function add_cps(x, y, c) { c(x + y) } function square_cps(x, c) { c(x * x) }
  42. 42. CPS - Example function add_cps(x, y, c) { c(x + y) } function square_cps(x, c) { c(x * x) } function calculate_cps(x, y, c) { square_cps(x, function(v) { square_cps(y, function(r){ add_cps(v,r,c) }) }) }
  43. 43. CPS - Example function add_cps(x, y, c) { c(x + y) } function square_cps(x, c) { c(x * x) } function calculate_cps(x, y, c) { square_cps(x, function(v) { square_cps(y, function(r){ add_cps(v,r,c) }) }) } js> calculate_cps(3, 4, print) => 25 js> calculate_cps(3, 4, function(v) {print(sqrt(v))}); => 5
  44. 44. CPS ● CPS is used in programming languages that do not have first – class continuations, but have first – class functions ● Every call is a tail call and if used without Tail Call Optimization (TCO), the continuation would grow during recursion ● Using CPS and TCO, compilers and interperters of some programming languages managed to eliminate the need for a runtime stack.
  45. 45. Delimited Continuations ● Delimited (or partial, or composable) continuations are more like regular functions and less like GOTOs. They do not embody the entire rest of the computation, but just a partial rest, up to a programmer-defined outer bound. ● delimited continuations will return control to the caller after they are invoked, and they may also return values – Tiark Rompf, Ingo Maier, Martin Odersky
  46. 46. Normal Control Flow with Control Flow Delimited Continuations Continuation invoked Continuation - start Delimited continuation Continuation - end
  47. 47. Delimited Continuations ● Delimited Continuations are manipulated by means of two primitives, shift and reset. ● Calling shift captures the current continuation, and reset defines the boundary up to which the continuation reaches.
  48. 48. Delimited Continuations reset { shift { k: (Int=>Int) => k(7) } + 1 } * 2 scala> 16 CPS transformed 2 * (1 + 7)
  49. 49. Delimited Continuations reset { shift { k: (Int=>Int) => k(7) } + 1 } * 2 scala> 16 __________________________________________________________ reset { def foo() { foo() + 1 shift { k: (Int=>Int) => } * 2 k(7) } } CPS transformed 2 * (1 + 7)
  50. 50. Delimited Continuations reset{ 1 + shift{ k: (Int=>Int) => k(k(7)) } } * 3 scala> 27 reset{ 1 + shift{ k: (Int=>Int) => k(k(7)) } * 3 } scala> 67
  51. 51. Delimited Continuations reset{ 1 + shift{ k: (Int=>Int) => k(k(7)) } } * 3 scala> 27 CPS Transform: (1 + (1 + 7)) * 3 = 27 reset{ 1 + shift{ k: (Int=>Int) => k(k(7)) } * 3 } scala> 67 CPS Transform: (1 + (1 + 7 * 3) * 3) = 67
  52. 52. So... ummm.. Whats the real world use of this thing?
  53. 53. Applications of Continuations ● Pause and Play e.g. User Interface design ● Backtracking ● Coroutines ● Exception Handling ● Web Frameworks ● Compiler & Interpreter implementation
  54. 54. Problems ● Page centric ● HTTP Stateless-ness causes heavy use of session, cookies ● 'Back' button in user interaction pages ● Browser cloning in user interaction pages ● Inversion of control
  55. 55. def add_two_numbers n1 = callcc { |cc| return ask("1st number:", cc) } n2 = callcc { |cc| return ask("2nd number:", cc) } print "sum of two numbers is #{n1 + n2}n" end
  56. 56. def add_two_numbers n1 = callcc { |cc| return ask("1st number:", cc) } n2 = callcc { |cc| return ask("2nd number:", cc) } print "sum of two numbers is #{n1 + n2}n" end irb> add_two_numbers 1st number: respond with: submit(25, ...): => #<Continuation:0xb76e0e58> irb> submit(25, 30) 2nd number: respond with: submit(37, ...): => #<Continuation:0xb76ddde8> irb> submit(37, 12) sum of two numbers is 42 => nil
  57. 57. def add_two_numbers n1 = callcc { |cc| return ask("1st number:", cc) } n2 = callcc { |cc| return ask("2nd number:", cc) } print "sum of two numbers is #{n1 + n2}n" end @session = Hash.new def ask(str, cc) r = rand(100).to_i print "#{str}nrespond with: submit(#{r}, ...): " @session[r] = cc cc end def submit(id, number) @session[id].call(number) End
  58. 58. Continuations lookup table (session) Server renders the page and saves the The continuation continuation in the object is looked up session with a uuid based on the uuid The page is 1 4 in the url and rendered with the executed uuid given in the url server 2 call: page a call: page b client call: page c 3 Client makes a server response with required information
  59. 59. Web Frameworks ● Seaside in Smalltalk (v 3.1) ● Wee in Ruby (v 2.1) ● Nagare in Python (v 0.3) ● Apache Cocoon in Java (v 2.2) ● RIFE in Java (v 1.6) ● Ocsigen in OCaml (v 1.3) ● Weblocks in Common Lisp
  60. 60. Web Servers with Continuations support ● Continuity (Perl) ● Jetty 6 (Java) ● Plt-Scheme web server (Scheme)
  61. 61. Seaside ● Written in Smalltalk ● Often called the 'heretic' framework because it doesn't follow the 'conventional' web wisdom – Clean urls – Templates to separate model and view – Share as little state as possible – Urls contain session identifiers – There is no 'view' or html templates. Views are part of smalltalk objects – Seaside continuations & callbacks give a stateful behavior
  62. 62. Seaside - Installation One – click install experience
  63. 63. Seaside - Workspace ● Smalltalk deals with image snapshots for saving the workspace. ● There is no concept of 'files' and 'editors' ● Class objects are created through 'object browser' and code is executed through a 'workspace'
  64. 64. Seaside - Components ● Components represent the whole of a page or portion of pages ● The inherit from 'WAComponent' class ● Components maintain state ● Component's response loop – Renders the component – Waits for user's input – Executes a block of code when a link or button is pressed – Re-renders itself or another component in place
  65. 65. Image from - Seaside – A Multiple Control Flow Web Application Framework, Stéphane Ducasse
  66. 66. Seaside - callbacks ● Every user interaction on the web page triggers a callback. ● A callback can be on a link, button or any other form elements ● The callback will execute a block of code whose result will end in re-rendering the component or a new component
  67. 67. SimpleCounter>>initialize super initialize. counter := 0. SimpleCounter>>renderContentOn: html html heading: 'the counter is ', counter asString. html anchor callback: [ counter := counter + 1 ]; with: 'increase'.
  68. 68. Seaside - Continuations ● Call / Answer ● call: takes a component as a parameter and it swaps the current component for the new component ● The new component will be rendered and user action will cause a callback to run that'll send an answer: ● The value passed to answer: will be returned to call: and the program will continue from there.
  69. 69. Image from - Seaside – A Multiple Control Flow Web Application Framework, Stéphane Ducasse
  70. 70. Problem with full continuation Response 1 Response 2 Continuation saved Continuation invoked Request 1 Request 2
  71. 71. Solved with delimited continuation Response 1 Response 2 Delimited Continuation saved Delimited Continuation invoked Request 1 Request 2
  72. 72. Challenges ● Understanding continuations as a concept ● Debugging ● Buying into the 'heretic' idea
  73. 73. Seaside – Demo
  74. 74. References ● http://en.wikipedia.org/wiki/Continuation ● http://idea-log.blogspot.com/2005/10/why-are-continuations-so-confusing- and.html ● http://www.iam.unibe.ch/~scg/Archive/Papers/Duca04eSeaside.pdf ● http://vimeo.com/13304075 ● http://www.intertwingly.net/blog/2005/04/13/Continuations-for-Curmudgeons ● http://www.cs.indiana.edu/~dfried/appcont.pdf ● http://lambda-the-ultimate.org/node/86 ● http://en.wikipedia.org/wiki/Continuation-passing_style ● http://lamp.epfl.ch/~rompf/continuations-icfp09.pdf ● http://book.seaside.st/book ● http://en.wikipedia.org/wiki/Call-with-current-continuation ● http://www.ibm.com/developerworks/java/library/j-contin.html ● http://www.cs.brown.edu/~sk/Publications/Papers/Published/khmgpf-impl-use- plt-web-server-journal/ ● http://double.co.nz/pdf/continuations.pdf

×