Named freeze scopes for serializable reactive state
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
Replace raw CEK state serialization with named freeze scopes.
A freeze scope collects signals registered within it. On freeze,
signal values are serialized to SX. On thaw, values are restored.
- freeze-scope: scoped effect delimiter for signal collection
- freeze-signal: register a signal with a name in the current scope
- cek-freeze-scope / cek-thaw-scope: freeze/thaw by scope name
- freeze-to-sx / thaw-from-sx: full SX text round-trip
- cek-freeze-all / cek-thaw-all: batch operations
Also: register boolean?, symbol?, keyword? predicates in both
Python and JS platforms with proper var aliases.
Demo: counter + name input with Freeze/Thaw buttons.
Frozen SX: {:name "demo" :signals {:count 5 :name "world"}}
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -542,79 +542,45 @@
|
||||
|
||||
|
||||
(defisland ~geography/cek/freeze-demo ()
|
||||
(let ((source (signal "(+ 1 (* 2 3))"))
|
||||
(state-sig (signal nil))
|
||||
(step-count (signal 0))
|
||||
(frozen-sx (signal ""))
|
||||
(thaw-result (signal "")))
|
||||
(letrec
|
||||
((do-parse (fn ()
|
||||
(reset! frozen-sx "")
|
||||
(reset! thaw-result "")
|
||||
(reset! step-count 0)
|
||||
(let ((parsed (sx-parse (deref source))))
|
||||
(when (not (empty? parsed))
|
||||
(reset! state-sig (make-cek-state (first parsed) (make-env) (list)))))))
|
||||
(do-step (fn ()
|
||||
(when (and (deref state-sig) (not (cek-terminal? (deref state-sig))))
|
||||
(reset! state-sig (cek-step (deref state-sig)))
|
||||
(swap! step-count inc))))
|
||||
(do-freeze (fn ()
|
||||
(when (deref state-sig)
|
||||
(let ((frozen (cek-freeze (deref state-sig))))
|
||||
(reset! frozen-sx (sx-serialize frozen))))))
|
||||
(do-thaw (fn ()
|
||||
(when (not (empty? (deref frozen-sx)))
|
||||
(let ((parsed (sx-parse (deref frozen-sx))))
|
||||
(when (not (empty? parsed))
|
||||
(let ((thawed (cek-thaw (first parsed))))
|
||||
(reset! thaw-result
|
||||
(str "Resumed from step " (deref step-count) ": "
|
||||
(cek-run thawed)))))))))
|
||||
(do-run (fn ()
|
||||
(when (deref state-sig)
|
||||
(let run-loop ()
|
||||
(when (not (cek-terminal? (deref state-sig)))
|
||||
(do-step)
|
||||
(run-loop)))))))
|
||||
;; Auto-parse
|
||||
(effect (fn () (do-parse)))
|
||||
(div :class "space-y-4"
|
||||
;; Input
|
||||
(div :class "flex gap-2 items-end"
|
||||
(div :class "flex-1"
|
||||
(label :class "text-xs text-stone-400 block mb-1" "Expression")
|
||||
(input :type "text" :bind source
|
||||
:class "w-full px-3 py-1.5 rounded border border-stone-300 font-mono text-sm focus:outline-none focus:border-violet-400"
|
||||
:on-change (fn (e) (do-parse))))
|
||||
(div :class "flex gap-1"
|
||||
(button :on-click (fn (e) (do-step))
|
||||
:class "px-3 py-1.5 rounded bg-violet-500 text-white text-sm hover:bg-violet-600"
|
||||
"Step")
|
||||
(button :on-click (fn (e) (do-run))
|
||||
:class "px-3 py-1.5 rounded bg-violet-700 text-white text-sm hover:bg-violet-800"
|
||||
"Run")))
|
||||
;; Step count + freeze button
|
||||
(div :class "flex items-center gap-3"
|
||||
(span :class "text-sm text-stone-500 font-mono"
|
||||
"Step " (deref step-count))
|
||||
(when (deref state-sig)
|
||||
(button :on-click (fn (e) (do-freeze))
|
||||
:class "px-3 py-1.5 rounded bg-amber-500 text-white text-sm hover:bg-amber-600"
|
||||
"Freeze")))
|
||||
;; Frozen SX output
|
||||
(when (not (empty? (deref frozen-sx)))
|
||||
(div :class "space-y-2"
|
||||
(label :class "text-xs text-stone-400 block" "Frozen CEK state")
|
||||
(pre :class "text-xs font-mono bg-stone-50 rounded p-3 overflow-x-auto whitespace-pre-wrap text-stone-700"
|
||||
(deref frozen-sx))
|
||||
(button :on-click (fn (e) (do-thaw))
|
||||
:class "px-3 py-1.5 rounded bg-emerald-600 text-white text-sm hover:bg-emerald-700"
|
||||
"Thaw \u2192 Resume")))
|
||||
;; Thaw result
|
||||
(when (not (empty? (deref thaw-result)))
|
||||
(div :class "rounded bg-emerald-50 border border-emerald-200 p-3 text-emerald-800 font-mono text-sm"
|
||||
(deref thaw-result)))))))
|
||||
(let ((count (signal 0))
|
||||
(name (signal "world"))
|
||||
(frozen-text (signal "")))
|
||||
;; Register signals in a freeze scope (runs once at hydration)
|
||||
(freeze-scope "demo" (fn ()
|
||||
(freeze-signal "count" count)
|
||||
(freeze-signal "name" name)))
|
||||
(div :class "space-y-4"
|
||||
;; Interactive controls
|
||||
(div :class "flex gap-4 items-center"
|
||||
(div :class "flex items-center gap-2"
|
||||
(button :on-click (fn (e) (swap! count dec))
|
||||
:class "px-2 py-1 rounded bg-stone-200 text-stone-700 hover:bg-stone-300" "-")
|
||||
(span :class "font-mono text-lg font-bold w-8 text-center" (deref count))
|
||||
(button :on-click (fn (e) (swap! count inc))
|
||||
:class "px-2 py-1 rounded bg-stone-200 text-stone-700 hover:bg-stone-300" "+"))
|
||||
(input :type "text" :bind name
|
||||
:class "px-3 py-1 rounded border border-stone-300 font-mono text-sm"))
|
||||
;; Live output
|
||||
(div :class "rounded bg-violet-50 border border-violet-200 p-3 text-violet-800"
|
||||
(str "Hello, " (deref name) "! Count = " (deref count)))
|
||||
;; Freeze / Thaw controls
|
||||
(div :class "flex gap-2"
|
||||
(button :on-click (fn (e)
|
||||
(reset! frozen-text (freeze-to-sx "demo")))
|
||||
:class "px-3 py-1.5 rounded bg-amber-500 text-white text-sm hover:bg-amber-600"
|
||||
"Freeze")
|
||||
(button :on-click (fn (e)
|
||||
(when (not (empty? (deref frozen-text)))
|
||||
(thaw-from-sx (deref frozen-text))))
|
||||
:class (str "px-3 py-1.5 rounded text-sm "
|
||||
(if (not (empty? (deref frozen-text)))
|
||||
"bg-emerald-600 text-white hover:bg-emerald-700"
|
||||
"bg-stone-100 text-stone-300 cursor-not-allowed"))
|
||||
"Thaw"))
|
||||
;; Frozen SX display
|
||||
(when (not (empty? (deref frozen-text)))
|
||||
(pre :class "text-xs font-mono bg-stone-50 rounded p-3 overflow-x-auto text-stone-600"
|
||||
(deref frozen-text))))))
|
||||
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user