/collects/redex/examples/delim-cont/reduce.rkt

http://github.com/gmarceau/PLT · Racket · 212 lines · 123 code · 20 blank · 69 comment · 2 complexity · 446b65caeca820da9313b6cd9a3c88b4 MD5 · raw file

  1. #lang racket
  2. (require redex/reduction-semantics
  3. "grammar.rkt"
  4. "meta.rkt")
  5. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  6. ;; Reductions:
  7. (define :->
  8. (reduction-relation
  9. grammar
  10. ;; beta
  11. (~~> ((λ (x_1 ..._1) e_1) v_1 ..._1)
  12. (subst* (x_1 ...) (v_1 ...) e_1)
  13. "beta")
  14. ;; arithmetic
  15. (~~> (+ n_1 n_2)
  16. ,(+ (term n_1) (term n_2))
  17. "+")
  18. (~~> (zero? 0)
  19. #t
  20. "zero?")
  21. (~~> (zero? v_1)
  22. #f
  23. (side-condition (not (equal? 0 (term v_1))))
  24. "non-zero")
  25. ;; lists
  26. (~~> (cons v_1 (list v_2 ...))
  27. (list v_1 v_2 ...)
  28. "cons")
  29. (~~> (first (list v_1 v_2 ...))
  30. v_1
  31. "first")
  32. (~~> (rest (list v_1 v_2 ...))
  33. (list v_2 ...)
  34. "rest")
  35. ;; printing
  36. (--> (<> s_1 [o_1 ...] (in-hole E_1 (print o_2)))
  37. (<> s_1 [o_1 ... o_2] (in-hole E_1 #f))
  38. "print")
  39. ;; if
  40. (~~> (if #t e_1 e_2)
  41. e_1
  42. "ift")
  43. (~~> (if #f e_1 e_2)
  44. e_2
  45. "iff")
  46. ;; begin
  47. (~~> (begin v e_1)
  48. e_1
  49. "begin-v")
  50. ;; set! and lookup
  51. (--> (<> ([x_1 v_1] ... [x_2 v_2] [x_3 v_3] ...) [o_1 ...] (in-hole E_1 (set! x_2 v_4)))
  52. (<> ([x_1 v_1] ... [x_2 v_4] [x_3 v_3] ...) [o_1 ...] (in-hole E_1 #f))
  53. "assign")
  54. (--> (<> ([x_1 v_1] ... [x_2 v_2] [x_3 v_3] ...) [o_1 ...] (in-hole E_1 x_2))
  55. (<> ([x_1 v_1] ... [x_2 v_2] [x_3 v_3] ...) [o_1 ...] (in-hole E_1 v_2))
  56. "lookup")
  57. ;; prompt
  58. ;; When we get a value, drop the prompt.
  59. (~~> (% v_1 v_2 v_3)
  60. v_2
  61. "prompt-v")
  62. ;; call/cc
  63. ;; Capture; the context E_2 must not include a prompt with the same tag,
  64. ;; and we don't want immediate marks.
  65. (~~> (% v_2 (in-hole E_2 (wcm w_1 (call/cc v_1 v_2))) v_3)
  66. (% v_2 (in-hole E_2 (wcm w_1 (v_1 (cont v_2 E_2)))) v_3)
  67. (side-condition (term (noMatch E_2 E (% v_2 E v))))
  68. "call/cc")
  69. ;; Invoke a continuation when there are no dw pre or post thunks to run (i.e.,
  70. ;; no dw thunks in the unshared parts of the current and target continuations).
  71. ;; D_2/D_6 is shared between the captured and current continuations; we make sure
  72. ;; that W_3 and E_4 don't share.
  73. (~~> (% v_1 (in-hole D_2 (in-hole W_3 ((cont v_1 (in-hole D_6 (in-hole W_4 hole))) v_2))) v_3)
  74. (% v_1 (in-hole D_6 (in-hole W_4 v_2)) v_3)
  75. (side-condition (term (noMatch (in-hole D_2 W_3) E (% v_1 E v))))
  76. (side-condition (term (sameDWs D_2 D_6)))
  77. (side-condition (term (noShared W_3 W_4)))
  78. "cont")
  79. ;; Invoke a continuation where there is a dw post thunk to run:
  80. ;; - D_2/D_6 is the shared prefix of the current and captured continuation.
  81. ;; (We make sure that E_3[(dw x_1 e_1 W_5 e_2)] and E_4 don't share.)
  82. ;; - Keep D_2[E_3], replacing the relevant `dw' to run the post thunk
  83. ;; and then resume the continuation jump.
  84. ;; The second step means replacing (dw x e_1 W_5[((cont ...) v)] e_2)
  85. ;; with (begin e_2 ((cont ...) v))).
  86. (~~> (% v_2 (in-hole D_2 (in-hole E_3 (dw x_1 e_1 (in-hole W_5 ((cont v_2 (in-hole D_6 (hide-hole E_4))) v_1)) e_2))) v_3)
  87. (% v_2 (in-hole D_2 (in-hole E_3 (begin e_2 ((cont v_2 (in-hole D_6 E_4)) v_1)))) v_3)
  88. (side-condition (term (noMatch (in-hole D_2 E_3) E (% v_2 E v))))
  89. (side-condition (term (sameDWs D_2 D_6)))
  90. (side-condition (term (noMatch W_5 E (% v_2 E v))))
  91. (side-condition (term (noShared (in-hole E_3 (dw x_1 e_1 W_5 e_2)) E_4)))
  92. "cont-post")
  93. ;; Invoke a continuation when there are only dw pre thunks to run (i.e.,
  94. ;; no dw thunks in the unshared part of the current continuation).
  95. ;; D_2/D_6 is shared between the captured and current continuations; we
  96. ;; make sure that W_3 and W_4[(dw ...)] don't share.
  97. ;; We do one pre thunk at a time, just in case the pre thunk arranges for
  98. ;; the relevant prompt to disappear. To do just one pre thunk, we
  99. ;; create `(begin e_1 (dw x_1 e_1 ((cont ...) v) e_2))', which runs the pre
  100. ;; thunk and then tries again to invoke the continuation --- but inside a
  101. ;; `dw' for the already-run pre-thunk, so that it's treated as shared and not
  102. ;; run again.
  103. (~~> (% v_1 (in-hole D_2 (in-hole W_3 ((cont v_1 (name k_1 (in-hole D_6 (in-hole W_4 (dw x_1 e_1 (hide-hole E_5) e_2))))) v_2))) v_3)
  104. (% v_1 (in-hole D_6 (in-hole W_4 (begin e_1 (dw x_1 e_1 ((cont v_1 k_1) v_2) e_2)))) v_3)
  105. (side-condition (term (noMatch (in-hole D_2 W_3) E (% v_1 E v))))
  106. (side-condition (term (sameDWs D_2 D_6)))
  107. (side-condition (term (noShared W_3 (in-hole W_4 (dw x_1 e_1 E_5 e_2)))))
  108. "cont-pre")
  109. ;; abort
  110. ;; Like continuation invocation, the case without dw post thunks:
  111. (~~> (% v_1 (in-hole W_2 (abort v_1 v_2)) v_3)
  112. (v_3 v_2)
  113. (side-condition (term (noMatch W_2 E (% v_1 E v))))
  114. "abort")
  115. ;; And the case with a dw post thunk --- simpler than invoking a
  116. ;; continuation, because we don't have to compute shared parts:
  117. (~~> (dw x_1 e_1 (in-hole W_2 (abort v_1 v_2)) e_2)
  118. (begin e_2 (abort v_1 v_2))
  119. (side-condition (term (noMatch W_2 E (% v_1 E v))))
  120. "abort-post")
  121. ;; composable continuation
  122. ;; Capture up to the relevant prompt, not including immediate marks:
  123. (~~> (% v_2 (in-hole E_2 (wcm w_1 (call/comp v_1 v_2))) v_3)
  124. (% v_2 (in-hole E_2 (wcm w_1 (v_1 (comp E_2)))) v_3)
  125. (side-condition (term (noMatch E_2 E (% v_2 E v))))
  126. "call/comp")
  127. ;; On invocation, we want to splice leading `wcm's with any marks
  128. ;; at the invocation context. We do that by convertings the leading
  129. ;; `wcm's back to `call/cm', so they get spliced as usual
  130. ;; for evaluating `call/cm' (see below). Meanwhile, we need to
  131. ;; handle the case that there are dw pre thunks to run on the way in
  132. ;; (which is a little simpler than for non-composable continuations,
  133. ;; since we don't have to worry about sharing w.r.t. a prompt).
  134. (~~> ((comp (in-hole W_1 hole)) v_1)
  135. (expose-wcm (in-hole W_1 v_1))
  136. "comp")
  137. (~~> ((comp (in-hole W_1 (dw x_1 e_1 (hide-hole E_2) e_2))) v_1)
  138. (expose-wcm (in-hole W_1 (begin e_1 (dw x_1 e_1 ((comp E_2) v_1) e_2))))
  139. "comp-pre")
  140. ;; continuation marks
  141. ;; Introduce a `wcm' when needed for certain primitives:
  142. (-+> (in-hole E_1 (u_1 v_1 ...))
  143. (in-hole E_1 (wcm () (u_1 v_1 ...)))
  144. (side-condition (term (noMatch E_1 E (wcm w hole))))
  145. "wcm-intro")
  146. ;; When we get a value, discard marks:
  147. (~~> (wcm w v_1)
  148. v_1
  149. "wcm-v")
  150. ;; When `call/cm' uses the same key as a wrapping
  151. ;; mark, then replace the old value.
  152. (~~> (wcm ((v_1 v_2) ... (v_3 v_4) (v_5 v_6) ...)
  153. (call/cm v_3 v_7 (λ () e_1)))
  154. (wcm ((v_1 v_2) ... (v_3 v_7) (v_5 v_6) ...) e_1)
  155. "wcm-set")
  156. ;; When `call/cm' uses a different key than any wrapping
  157. ;; mark, then add a new mark.
  158. (~~> (wcm ((v_1 v_2) ...) (call/cm v_3 v_4 (λ () e_1)))
  159. (wcm ((v_1 v_2) ... (v_3 v_4)) e_1)
  160. (side-condition (term (notIn v_3 (v_1 ...))))
  161. "wcm-add")
  162. ;; To get the current mark value for mark key, search
  163. ;; the current context (using `get-marks'), using only
  164. ;; the part of the continuation up to a prompt with the
  165. ;; given tag.
  166. (~~> (% v_2 (in-hole E_2 (current-marks v_1 v_2)) v_3)
  167. (% v_2 (in-hole E_2 (get-marks E_2 v_1 (list))) v_3)
  168. (side-condition (term (noMatch E_2 E (% v_2 E v))))
  169. "marks")
  170. ;; dynamic-wind
  171. ;; Evaluate a `dynamic-wind' function by generating a new `dw'
  172. ;; wrapper. The wrapper uses a newly allocated (globally unique)
  173. ;; tag variable. Also, introduce a `begin' with the pre-thunk
  174. ;; body --- which, crucially, is put *outside* the generated `dw'.
  175. (~~> (dynamic-wind (λ () e_1) (λ () e_2) (λ () e_3))
  176. (begin e_1 (dw x_1 e_1 e_2 e_3))
  177. (fresh x_1)
  178. "dw")
  179. ;; When we get a result from the dw, evaluate the post thnk
  180. ;; (outside the `dw') and then continue returning the result.
  181. (~~> (dw x e_1 v_1 e_3)
  182. (begin e_3 v_1)
  183. "dw-v")
  184. with
  185. ;; -+> is evaluation independent of the store and output:
  186. [(--> (<> s_1 [o_1 ...] from) (<> s_1 [o_1 ...] to)) (-+> from to)]
  187. ;; ~~> is evaluation in any E:
  188. [(-+> (in-hole E_1 from)
  189. (in-hole E_1 to))
  190. (~~> from to)]))
  191. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  192. (provide :->)