Il threading è probabilmente la soluzione più semplice, ma non è molto difficile gestirlo da solo su un singolo thread. Gli ambienti di "simulazione" che ti danno solo 100ms spesso non consentono nuovi thread, quindi questa è un'alternativa.
L'idea di base è creare una chiusura che rappresenti il lavoro da eseguire per completare l'attività e restituire tale risultato invece di un risultato se non si ha tempo per terminare. Ecco uno schizzo: aggiunge una sequenza di numeri e viene interrotto ogni dieci operazioni anziché ogni 100ms.
(let [timer (atom 9)]
(defn keep-going? []
(not= 0 (swap! timer #(mod (inc %) 10)))))
(defn saving-addition [sum xs]
(if-let [[x & more] (seq xs)]
(let [next-thunk (fn [] (saving-addition (+ x sum) more))]
(if (keep-going?)
(next-thunk)
next-thunk))
sum))
(defn monitor [xs]
(loop [thunk (saving-addition 0 xs)]
(if (fn? thunk)
(do
(println "Saving execution state")
(recur (thunk)))
thunk)))
user> (monitor (range 25))
Saving execution state
Saving execution state
Saving execution state
300
Edit: Perché Clojure non ha ottimizzazione coda-call, la creazione di un tonfo e quindi chiamando utilizza fino stack. Se, come è probabile, sei in grado di eseguire più di qualche migliaio di passaggi prima di dover essere interrotto, otterrai uno stack overflow. L'unica soluzione realistica è quella di duplicare il corpo del thunk sia in un recur
e nella continuazione, come
(defn saving-addition [sum xs]
(if-let [[x & more] (seq xs)]
(let [sum (+ x sum)]
(if (keep-going?)
(recur sum more)
#(saving-addition sum more)))
sum))
si potrebbe probabilmente astratto questo fuori con una macro se si doveva scrivere più tali funzioni "sospendibili".
L'albero non è ordinato? Hai solo bisogno di trovare qualche elemento e restituire true se lo ottieni, o hai bisogno anche del percorso? – toto2