PasteRack.org
Paste # 24401
2026-07-23 06:24:15

Fork as a new paste.

Paste viewed 121 times.


Embed:

effects

  1. #lang racket
  2. (require racket/control)
  3.  
  4. (struct Done (x))
  5. (struct Eff (op k))
  6. (define (perform op) (shift k (Eff op k)))
  7.  
  8. (define-syntax (handler stx)
  9.   (define (handle-cases cases value-cases eff-cases finally-cases)
  10.     (syntax-case cases (effect -> finally)
  11.       [() (values (reverse value-cases)
  12.                   (reverse eff-cases)
  13.                   (reverse finally-cases))]
  14.       [((p -> e1 e2 ...) . cases)
  15.        (handle-cases #'cases
  16.                      (cons #'(p e1 e2 ...) value-cases)
  17.                      eff-cases
  18.                      finally-cases)]
  19.       [((effect p k -> e1 e2 ...) . cases)
  20.        (handle-cases #'cases
  21.                      value-cases
  22.                      (cons #'((p k) e1 e2 ...) eff-cases)
  23.                      finally-cases)]
  24.       [((finally p -> e1 e2 ...) . cases)
  25.        (handle-cases #'cases
  26.                      value-cases
  27.                      eff-cases
  28.                      (cons #'(p e1 e2 ...) finally-cases))]))
  29.   (syntax-case stx (finally)
  30.     [(_ h1 h2 ...)
  31.      (let-values ([(value-cases eff-cases finally-cases)
  32.                    (handle-cases #'(h1 h2 ...) '() '() '())])
  33.        #`(lambda (body)
  34.            (define (handle req)
  35.              (match req
  36.                [(Done x)
  37.                 (match x
  38.                   #,@value-cases
  39.                   [x x])]
  40.                [(Eff op k)
  41.                 (match* (op (lambda (x) (handle (k x))))
  42.                   #,@eff-cases
  43.                   [(op _) (handle (k (perform op)))])]))
  44.            (match (handle (reset (Done (body))))
  45.              #,@finally-cases
  46.              [x x])))]))
  47.  
  48. (define-syntax with-handler
  49.   (syntax-rules ()
  50.     [(_ handler e1 e2 ...)
  51.      (handler (lambda () e1 e2 ...))]))
  52.  
  53. (define (run-state init)
  54.   (handler
  55.     [x -> (lambda (s) (cons x s))]
  56.     [effect (State:Get) k -> (lambda (s) ((k s) s))]
  57.     [effect (State:Set s) k -> (lambda (_) ((k '()) s))]
  58.     [finally f -> (f init)]))
  59.  
  60. (struct State:Get ())
  61. (struct State:Set (s))
  62. (define (set s) (perform (State:Set s)))
  63. (define (get) (perform (State:Get)))
  64.  
  65. (with-handler (run-state 1)
  66.   (set (+ 1 (get)))
  67.   (+ (get) (get)))
  68. ;; '(4 . 2)
  69.  
  70. (struct Amb (choices))
  71. (define (amb . xs) (perform (Amb xs)))
  72. (define run-amb
  73.   (handler
  74.     [x -> (list x)]
  75.     [effect (Amb xs) k -> (append-map k xs)]))
  76.  
  77. (with-handler run-amb
  78.   (with-handler (run-state 1)
  79.     (let ([s1 (get)])
  80.       (set (+ s1 (amb 1 2 3)))
  81.       (cons (amb 1 2 3) (get)))))
  82. ;; '(((1 . 2) . 2)
  83. ;;   ((2 . 2) . 2)
  84. ;;   ((3 . 2) . 2)
  85. ;;   ((1 . 3) . 3)
  86. ;;   ((2 . 3) . 3)
  87. ;;   ((3 . 3) . 3)
  88. ;;   ((1 . 4) . 4)
  89. ;;   ((2 . 4) . 4)
  90. ;;   ((3 . 4) . 4))
  91.  
  92. ;; or alternative you can define them manually like this
  93. ;; ...
  94.  
  95. (define (state-lowlevel th init)
  96.   (let handle ([r (reset (Done (th)))]
  97.                [s init]) ;; can more efficiently thread resources
  98.     (match r
  99.       [(Done x) (cons x s)]
  100.       [(Eff (State:Get) k) (handle (k s) s)]
  101.       [(Eff (State:Set s) k) (handle (k) s)]
  102.       [(Eff u k) (handle (k (perform u)) s)])))
  103.  
  104.  
  105. (define (amb-lowlevel th)
  106.   (let handle ([r (reset (Done (th)))])
  107.     (match r
  108.       [(Done x) (list x)]
  109.       [(Eff (Amb xs) k) (append-map (lambda (x) (handle (k x))) xs)]
  110.       [(Eff u k) (handle (k (perform u)))])))
  111.  
  112. (define (test)
  113.   (let ([s1 (get)])
  114.     (set (+ s1 (amb 1 2 3)))
  115.     (cons (amb 1 2 3) (get))))
  116.  
  117. (amb-lowlevel
  118.  (lambda ()
  119.    (state-lowlevel test 1)))
  120. ;; '(((1 . 2) . 2)
  121. ;;   ((2 . 2) . 2)
  122. ;;   ((3 . 2) . 2)
  123. ;;   ((1 . 3) . 3)
  124. ;;   ((2 . 3) . 3)
  125. ;;   ((3 . 3) . 3)
  126. ;;   ((1 . 4) . 4)
  127. ;;   ((2 . 4) . 4)
  128. ;;   ((3 . 4) . 4))

=>

eval:5:0: match: syntax error in pattern

  in: (State:Get)

run-state: undefined;

 cannot reference an identifier before its definition

  in module: 'm

run-state: undefined;

 cannot reference an identifier before its definition

  in module: 'm

'(((1 . 2) . 2)

  ((2 . 2) . 2)

  ((3 . 2) . 2)

  ((1 . 3) . 3)

  ((2 . 3) . 3)

  ((3 . 3) . 3)

  ((1 . 4) . 4)

  ((2 . 4) . 4)

  ((3 . 4) . 4))