Implement transient thoughts

This commit is contained in:
2025-12-17 12:43:11 +01:00
parent 4514f9c8e8
commit 187ba48dcf
5 changed files with 66 additions and 16 deletions

View File

@@ -17,11 +17,7 @@
(def/define! [:emptyhead :core :return] (def/define! [:emptyhead :core :return]
(fn [thought parent] (fn [thought parent]
[parent (thought/data thought)]) [parent (thought/data thought)]))
:constr-fn
(fn [thought parent]
(let [[_ data] (thought/pop-stack parent)]
{:data data})))
(def/define! [:emptyhead :core :nop] (def/define! [:emptyhead :core :nop]
(fn [thought parent] (fn [thought parent]

View File

@@ -3,30 +3,55 @@
Since thoughts are ideas, 'missing' operations here are implemented in [[emptyhead.idea.crud]]." Since thoughts are ideas, 'missing' operations here are implemented in [[emptyhead.idea.crud]]."
(:require [emptyhead.idea.protocol :as prtc] (:require [emptyhead.idea.protocol :as prtc]
[emptyhead.idea.crud :as idea] [emptyhead.idea.crud :as idea]
[emptyhead.util.magic :as magic])) [emptyhead.util.magic :as magic]
[emptyhead.idea.property :as prop]))
(defn make-thought (defn make-thought
"Helper function to make thought object. "Helper function to make thought object.
You may want `register-thought!` instead." You may want `register-thought!` instead."
[operator & {:keys [data ext-stages return] [operator & {:keys [data ext-stages return transient]
:or {data {} :or {data {}
ext-stages [[:PRE-EXECUTE] [:EXECUTE] [:POST-EXECUTE]] ext-stages [[:PRE-EXECUTE] [:EXECUTE] [:POST-EXECUTE]]
transient true
return []}}] return []}}]
(hash-map :operator operator (hash-map :operator operator
:data data :data data
:ext-stages ext-stages :ext-stages ext-stages
:transient transient
:return return)) :return return))
(defn register-thought! (defn register-thought!
"Create a thought and register it in the state. "Create a thought and register it in the state.
Returns a reference to the created thought." Returns a reference to the created thought."
[operator & {:keys [data ext-stages] [operator & {:keys [data ext-stages return transient]
:as args}] :as args}]
(idea/have-idea! (idea/have-idea!
:prefix (str "emptyhead.thought#" (magic/symbolize-ns operator)) :prefix (str "emptyhead.thought#" (magic/symbolize-ns operator))
:properties [magic/thought-ns] :properties [magic/thought-ns
(magic/operator-property [operator])]
:data (make-thought operator args))) :data (make-thought operator args)))
(defn deref-primitive_
[operator]
(prop/with-property (magic/operator-property [operator])))
(defn deref-primitive
[operator]
(let [existing (deref-primitive_ operator)
n (count existing)]
(when (> n 1)
(throw (ex-info (str "ERROR: Primitive " operator " has " n " implementations.")
{:n n :operator operator})))
(first existing)))
(defn register-singleton!
"Register a thought of which only one is meant to exist."
[operator & {:keys [data ext-stages]
:as args}]
(let [existing (deref-primitive_ operator)]
(run! idea/forget-idea! existing)
(register-thought! operator args)))
(defn stages (defn stages
"Get the extension stages of a `thought`. "Get the extension stages of a `thought`.
Returns the list of stages." Returns the list of stages."
@@ -52,6 +77,20 @@
[thought] [thought]
[(assoc thought :return (-> thought prtc/copy stack butlast vec)) (-> thought prtc/copy stack peek)]) [(assoc thought :return (-> thought prtc/copy stack butlast vec)) (-> thought prtc/copy stack peek)])
(defn empty-stack
[thought]
[(assoc thought :return []) (:return thought)])
(defn pop-args
[thought dest]
(let [sentinel (into [:_FOR] (prtc/val-fn :operator dest))
stack (prtc/val-fn :return thought)
idx (.lastIndexOf stack sentinel)
before (subvec stack 0 idx)
after (subvec stack (+ 1 idx))]
[(assoc thought :return before)
after]))
(defn add-ext-stage! (defn add-ext-stage!
[thought stage] [thought stage]
(idea/mutate-idea! #(update % :ext-stages conj stage) thought)) (idea/mutate-idea! #(update % :ext-stages conj stage) thought))

View File

@@ -6,6 +6,7 @@
[emptyhead.util.logging :as logging] [emptyhead.util.logging :as logging]
[emptyhead.thought.return :as return] [emptyhead.thought.return :as return]
[emptyhead.idea.property :as prop] [emptyhead.idea.property :as prop]
[emptyhead.idea.crud :as idea]
[emptyhead.util.magic :as magic])) [emptyhead.util.magic :as magic]))
(defn- impl! [thought & [parent]] (defn- impl! [thought & [parent]]
@@ -16,14 +17,12 @@
{:thought thought :parent parent :type :unimplemented-thought}) {:thought thought :parent parent :type :unimplemented-thought})
((prtc/val-fn :implementation impl-idea) thought parent)))) ((prtc/val-fn :implementation impl-idea) thought parent))))
;; FIXME I don't think omitting the parent here is actually valid?
;; might need to use thought.crud/root-thought, but better making parent mandatory tabun
(defn execute! (defn execute!
"Execute `thought` with `parent`, applying aspects to `thought` according to its :extension-stages. "Execute `thought` with `parent`, applying aspects to `thought` according to its :extension-stages.
Returns (potentially modified) `parent`." Returns (potentially modified) `parent`."
[thought & [parent]] [thought & [parent]]
(loop [th (prtc/val-fn #(assoc % :_parent (prtc/value parent)) thought) (loop [parent (or parent (thought/make-thought [:EH :NOP]))
parent parent] th (prtc/val-fn #(assoc % :_parent (prtc/value parent)) thought)]
(let [[extensions th cur] (extend/pop-stage th) (let [[extensions th cur] (extend/pop-stage th)
;; Execute extensions, potentially modifying th ;; Execute extensions, potentially modifying th
@@ -42,4 +41,7 @@
;; Recur if there's remaining aspects, otherwise return `parent`. ;; Recur if there's remaining aspects, otherwise return `parent`.
(if (not-empty (thought/stages th)) (if (not-empty (thought/stages th))
(recur th parent) (recur th parent)
parent)))) (do
(when (prtc/val-fn :transient thought)
(prtc/ref-fn idea/forget-idea! thought))
parent)))))

View File

@@ -11,6 +11,10 @@
#(update % :return (fnil into []) data) thought) #(update % :return (fnil into []) data) thought)
thought)) thought))
(defn update-return
[thought fn]
(prtc/val-fn #(update-in % [:return] fn) thought))
(defn return-vals [thought namespace] (defn return-vals [thought namespace]
(prtc/val-fn #(get-in % [:return namespace]) thought)) (prtc/val-fn #(get-in % [:return namespace]) thought))

View File

@@ -2,7 +2,11 @@
"Magic values for EmptyHead." "Magic values for EmptyHead."
(:require [clojure.string :as str])) (:require [clojure.string :as str]))
(def thought-ns [:emptyhead :thought]) (def thought-ns [:EH :THOUGHT])
(defn operator-property
[op]
(into [:EH :OPERATOR] op))
(def thought-impl-ns (conj thought-ns :implementation)) (def thought-impl-ns (conj thought-ns :implementation))
@@ -15,4 +19,9 @@
(conj extension-ns stage)) (conj extension-ns stage))
(defn symbolize-ns [ns] (defn symbolize-ns [ns]
(str/join "." (map name ns))) (str/join
"." (map
#(if (sequential? %)
(symbolize-ns (concat [:<] % [:>]))
(name %))
ns)))