I'm trying to make a sleep function in ClojureScript (w/ Reagent):
(ns cljweb.webpage
(:require [reagent.core :as reagent]))
(def temp-atom (reagent/atom 0))
(defn sleep [msec]
(js/setTimeout (fn []) msec))
(defn page []
[:div
[:p #temp-atom]
[:button
{:on-click
(fn []
(sleep 3000)
(swap! temp-atom inc))}
"Click me!"]])
For some reason, this doesn't sleep properly - when I click the "Click me!" button, temp-atom increments instantly - when I time it, by putting this after in page:
[:p (time (sleep 3000))]
I get this in the console:
"Elapsed time: 0.015000 msecs"
What did I do wrong in the code?
Javascript's setTimeout function accepts two arguments: function and timeout in milliseconds. Its contract is to run the received function after the timeout passes.
Your code doesn't pass the function you would like to execute after 3 seconds but instead passes a no-op function ((fn [])).
Your sleep function should look like this (and it would be better named timeout or you could just call js/setTimeout directly in your on-click handler):
(defn sleep [f ms]
(js/setTimeout f ms))
You also need to change how you call this function:
(sleep #(swap! temp-atom inc) 3000)
Or with calling js/setTimeout directly:
(js/setTimeout #(swap! temp-atom inc) 3000)
With ClojureScript, the best way to write asynchronous code is with the CoreAsync library. In your case, take a look at the timeout function:
(ns cljweb.webpage
(:use-macros [cljs.core.async.macros :only [go]]
(:require [reagent.core :as reagent]
[cljs.core.async :refer [<! timeout]]))
(def temp-atom (reagent/atom 0))
(defn page []
[:div
[:p #temp-atom]
[:button
{:on-click
(fn []
(go
(<! (timeout 3000))
(swap! temp-atom inc)))}
"Click me!"]])
There is a way to implement such functionality using goog.async.Debouncer
Here is an example:
(ns example.utils
(:require [goog.async.Debouncer]))
(defn debounce [f interval]
(let [dbnc (goog.async.Debouncer. f interval)]
(fn [& args] (.apply (.-fire dbnc) dbnc (to-array args)))))
(defn save-input! [input]
(js/console.log "Saving input" input))
(def save-input-debounced!
(debounce save-input! 3000))
(save-input-debounced! "hi")
Related
Here's a simple re-frame app that I tried to create based on the existing example project in re-frame's github repo. But it is only displaying things from the html file. Seems like no event is being dispatched. Can anyone point out what am I doing wrong? Thanks.
(ns simple.core
(:require [reagent.core :as reagent]
[re-frame.core :as rf]
[clojure.string :as str]))
(rf/reg-event-db
:rand
(fn [db [_ _]]
(assoc db :winner ( + 2 (rand-int 3)))))
(rf/reg-sub
:winner
(fn [db _]
(:winner db)))
(def participants ["Alice" "Bob" "Ellie"])
(defn winners-name
[idx]
(get participants idx))
(defn show-winner
[]
[:h1
(winners-name
(#(rf/subscribe [:winner])))])
(defn ui
[]
[:div
[:h1 "Lottery"]
[show-winner]])
(defn ^:export run
[]
(rf/dispatch-sync [:rand])
(reagent/render [ui]
(js/document.getElementById "app")))
The :rand handler will produce nil most times since you are adding 2 to the generated value and the participants vector only has 3 entries.
The issue is caused because of a pair of extra parenthesis around the deref thing. So the function winners-name is treating it as a list instead of an integer.
(winners-name
(#(rf/subscribe [:winner]))
How to evaluate a function correctly every minute using at-at and chime?
Here are my tests:
(require '[overtone.at-at :refer :all]
'[chime :refer [chime-at]]
'[clj-time.periodic :refer [periodic-seq]]
'[clj-time.core :as t])
;; 1. Use of future
(defonce data1 (atom {:num 1}))
(defonce updater
(future
(while true
(swap! data1 update-in [:num] inc)
(Thread/sleep 60000))))
;; 2. Using at-at
(defonce data2 (atom {:num 1}))
(def my-pool (mk-pool))
(every 60000 #(swap! data2 update-in [:num] inc) my-pool)
;; 3. Using chime
(defonce data3 (atom {:num 1}))
(chime-at (periodic-seq (t/now) (-> 60 t/seconds))
(fn [] (swap! data3 update-in [:num] inc))
{:error-handler (fn [e] (str e))})
After 5 minutes:
#data1
;;=> {:num 5}
#data2
;;=> {:num 8}
#data3
;;=> {:num 1}
Why is at-at counting to fast?
Why is chimenot counting at all?
Thank you!
Not sure what's up with at-at.
As for Chime, chime-at calls the callback function with the time of the current chime, so you'll need to amend your callback to something like
(fn [time] (swap! data3 update-in [:num] inc))
With (fn [] …) you'll get an ArityException at each chime and your :error-handler swallows those. (Chime's default handler prints a stack trace; NB. depending on your setup that stack trace may or may not be visible in your REPL window – for example with a fairly typical Emacs/CIDER setup you might have to switch to an *nrepl-server* buffer to see it.)
(Incidentally, in 1.7 alphas you can use update :num instead of update-in [:num].)
I'd like to use memoize for a function that uses core.async and <! e.g
(defn foo [x]
(go
(<! (timeout 2000))
(* 2 x)))
(In the real-life, it could be useful in order to cache the results of server calls)
I was able to achieve that by writing a core.async version of memoize (almost the same code as memoize):
(defn memoize-async [f]
(let [mem (atom {})]
(fn [& args]
(go
(if-let [e (find #mem args)]
(val e)
(let [ret (<! (apply f args))]; this line differs from memoize [ret (apply f args)]
(swap! mem assoc args ret)
ret))))))
Example of usage:
(def foo-memo (memoize-async foo))
(go (println (<! (foo-memo 3)))); delay because of (<! (timeout 2000))
(go (println (<! (foo-memo 3)))); subsequent calls are memoized => no delay
I am wondering if there are simpler ways to achieve the same result.
**Remark: I need a solution that works with <!. For <!!, see this question: How to memoize a function that uses core.async and blocking channel read? **
You can use the built in memoize function for this. Start by defining a method that reads from a channel and returns the value:
(defn wait-for [ch]
(<!! ch))
Note that we'll use <!! and not <! because we want this function block until there is data on the channel in all cases. <! only exhibits this behavior when used in a form inside of a go block.
You can then construct your memoized function by composing this function with foo, like such:
(def foo-memo (memoize (comp wait-for foo)))
foo returns a channel, so wait-for will block until that channel has a value (i.e. until the operation inside foo finished).
foo-memo can be used similar to your example above, except you do not need the call to <! because wait-for will block for you:
(go (println (foo-memo 3))
You can also call this outside of a go block, and it will behave like you expect (i.e. block the calling thread until foo returns).
This was a little trickier than I expected. Your solution isn't correct, because when you call your memoized function again with the same arguments, sooner than the first run finishes running its go block, you will trigger it again and get a miss. This is often the case when you process lists with core.async.
The one below uses core.async's pub/sub to solve this (tested in CLJS only):
(def lookup-sentinel #?(:clj ::not-found :cljs (js-obj))
(def pending-sentinel #?(:clj ::pending :cljs (js-obj))
(defn memoize-async
[f]
(let [>in (chan)
pending (pub >in :args)
mem (atom {})]
(letfn
[(memoized [& args]
(go
(let [v (get #mem args lookup-sentinel)]
(condp identical? v
lookup-sentinel
(do
(swap! mem assoc args pending-sentinel)
(go
(let [ret (<! (apply f args))]
(swap! mem assoc args ret)
(put! >in {:args args :ret ret})))
(<! (apply memoized args)))
pending-sentinel
(let [<out (chan 1)]
(sub pending args <out)
(:ret (<! <out)))
v))))]
memoized)))
NOTE: it probably leaks memory, subscriptions and <out channels are not closed
I have used this function in one of my projects to cache HTTP calls. The function caches results for a given amount of time and uses a barrier to prevent executing the function multiple times when the cache is "cold" (due to the context switch inside the go block).
(defn memoize-af-until
[af ms clock]
(let [barrier (async/chan 1)
last-return (volatile! nil)
last-return-ms (volatile! nil)]
(fn [& args]
(async/go
(>! barrier :token)
(let [now-ms (.now clock)]
(when (or (not #last-return-ms) (< #last-return-ms (- now-ms ms)))
(vreset! last-return (<! (apply af args)))
(vreset! last-return-ms now-ms))
(<! barrier)
#last-return)))))
You can test that it works properly by setting the cache time to 0 and observe that the two function calls take approximately 10 seconds. Without the barrier the two calls would finish at the same time:
(def memo (memoize-af-until #(async/timeout 5000) 0 js/Date))
(async/take! (memo) #(println "[:a] Finished"))
(async/take! (memo) #(println "[:b] Finished"))
I'm looking for a very simple way to call a function periodically in Clojure.
JavaScript's setInterval has the kind of API I'd like. If I reimagined it in Clojure, it'd look something like this:
(def job (set-interval my-callback 1000))
; some time later...
(clear-interval job)
For my purposes I don't mind if this creates a new thread, runs in a thread pool or something else. It's not critical that the timing is exact either. In fact, the period provided (in milliseconds) can just be a delay between the end of one call completing and the commencement of the next.
If you want very simple
(defn set-interval [callback ms]
(future (while true (do (Thread/sleep ms) (callback)))))
(def job (set-interval #(println "hello") 1000))
=>hello
hello
...
(future-cancel job)
=>true
Good-bye.
There's also quite a few scheduling libraries for Clojure:
(from simple to very advanced)
at-at
chime (core.async integration)
monotony
quartzite
Straight from the examples of the github homepage of at-at:
(use 'overtone.at-at)
(def my-pool (mk-pool))
(let [schedule (every 1000 #(println "I am cool!") my-pool)]
(do stuff while schedule runs)
(stop schedule))
Use (every 1000 #(println "I am cool!") my-pool :fixed-delay true) if you want a delay of a second between end of task and start of next, instead of between two starts.
This is how I would do the core.async version with stop channel.
(defn set-interval
[f time-in-ms]
(let [stop (chan)]
(go-loop []
(alt!
(timeout time-in-ms) (do (<! (thread (f)))
(recur))
stop :stop))
stop))
And the usage
(def job (set-interval #(println "Howdy") 2000))
; Howdy
; Howdy
(close! job)
The simplest approach would be to just have a loop in a separate thread.
(defn periodically
[f interval]
(doto (Thread.
#(try
(while (not (.isInterrupted (Thread/currentThread)))
(Thread/sleep interval)
(f))
(catch InterruptedException _)))
(.start)))
You can cancel execution using Thread.interrupt():
(def t (periodically #(println "Hello!") 1000))
;; prints "Hello!" every second
(.interrupt t)
You could even just use future to wrap the loop and future-cancel to stop it.
I took a stab at coding this up, with a slightly modified interface than specified in the original question. Here's what I came up with.
(defn periodically [fn millis]
"Calls fn every millis. Returns a function that stops the loop."
(let [p (promise)]
(future
(while
(= (deref p millis "timeout") "timeout")
(fn)))
#(deliver p "cancel")))
Feedback welcomed.
Another option would be to use java.util.Timer's scheduleAtFixedRate method
edit - multiplex tasks on a single timer, and stop a single task rather than the entire timer
(defn ->timer [] (java.util.Timer.))
(defn fixed-rate
([f per] (fixed-rate f (->timer) 0 per))
([f timer per] (fixed-rate f timer 0 per))
([f timer dlay per]
(let [tt (proxy [java.util.TimerTask] [] (run [] (f)))]
(.scheduleAtFixedRate timer tt dlay per)
#(.cancel tt))))
;; Example
(let [t (->timer)
job1 (fixed-rate #(println "A") t 1000)
job2 (fixed-rate #(println "B") t 2000)
job3 (fixed-rate #(println "C") t 3000)]
(Thread/sleep 10000)
(job3) ;; stop printing C
(Thread/sleep 10000)
(job2) ;; stop printing B
(Thread/sleep 10000)
(job1))
Using core.async
(ns your-namespace
(:require [clojure.core.async :as async :refer [<! timeout chan go]])
)
(def milisecs-to-wait 1000)
(defn what-you-want-to-do []
(println "working"))
(def the-condition (atom true))
(defn evaluate-condition []
#the-condition)
(defn stop-periodic-function []
(reset! the-condition false )
)
(go
(while (evaluate-condition)
(<! (timeout milisecs-to-wait))
(what-you-want-to-do)))
I have a situation where I am creating and destroying objects in one clojure namespace, and want another namespace to co-ordinate. However I do not want the first namespace to have to call the second explicitly on object destruction.
In Java, I could use a listener. Unfortunately the underlying java libraries do not signal events on object destruction. If I were in Emacs-Lisp, then I'd use hooks which do the trick.
Now, in clojure I am not so sure. I have found the Robert Hooke library https://github.com/technomancy/robert-hooke. But this is more like defadvice in elisp terms -- I am composing functions. More over the documentation says:
"Hooks are meant to extend functions you don't control; if you own the target function there are obviously better ways to change its behaviour."
Sadly, I am not finding it so obvious.
Another possibility would be to use add-watch, but this is marked as alpha.
Am I missing another obvious solution?
Example Added:
So First namespace....
(ns scratch-clj.first
(:require [scratch-clj.another]))
(def listf (ref ()))
(defn add-object []
(dosync
(ref-set listf (conj
#listf (Object.))))
(println listf))
(defn remove-object []
(scratch-clj.another/do-something-useful (first #listf))
(dosync
(ref-set listf (rest #listf)))
(println listf))
(add-object)
(remove-object)
Second namespace
(ns scratch-clj.another)
(defn do-something-useful [object]
(println "object removed is:" object))
The problem here is that scratch-clj.first has to require another and explicitly push removal events across. This is a bit clunky, but also doesn't work if I had "yet-another" namespace, which also wanted to listen.
Hence I thought of hooking the first function.
Is this solution suitable to your requirements?
scratch-clj.first:
(ns scratch-clj.first)
(def listf (atom []))
(def destroy-listeners (atom []))
(def add-listeners (atom []))
(defn add-destroy-listener [f]
(swap! destroy-listeners conj f))
(defn add-add-listener [f]
(swap! add-listeners conj f))
(defn add-object []
(let [o (Object.)]
(doseq [f #add-listeners] (f o))
(swap! listf conj o)
(println #listf)))
(defn remove-object []
(doseq [f #destroy-listeners] (f (first #listf)))
(swap! listf rest)
(println #listf))
Some listeners:
(ns scratch-clj.another
(:require [scratch-clj.first :as fst]))
(defn do-something-useful-on-remove [object]
(println "object removed is:" object))
(defn do-something-useful-on-add [object]
(println "object added is:" object))
Init binds:
(ns scratch-clj.testit
(require [scratch-clj.another :as another]
[scratch-clj.first :as fst]))
(defn add-listeners []
(fst/add-destroy-listener another/do-something-useful-on-remove)
(fst/add-add-listener another/do-something-useful-on-add))
(defn test-it []
(add-listeners)
(fst/add-object)
(fst/remove-object))
test:
(test-it)
=> object added is: #<Object java.lang.Object#c7aaef>
[#<Object java.lang.Object#c7aaef>]
object removed is: #<Object java.lang.Object#c7aaef>
()
It sounds a lot like what you're describing is callbacks.
Something like:
(defn make-object
[destructor-fn]
{:destructor destructor-fn :other-data "data"})
(defn destroy-object
[obj]
((:destructor obj) obj))
; somewhere at the calling code...
user> (defn my-callback [o] (pr [:destroying o]))
#'user/my-callback
user> (destroy-object (make-object my-callback))
[:destroying {:destructor #<user$my_callback user$my_callback#73b8cdd5>, :other-data "data"}]
nil
user>
So, here is my final solution following mobytes suggestion. A bit more work, but
I suspect that I will want this in future.
Thanks for all the help
;; hook system
(defn make-hook []
(atom []))
(defn add-hook [hook func]
(do
(when-not
(some #{func} #hook)
(swap! hook conj func))
#hook))
(defn remove-hook [hook func]
(swap! hook
(partial
remove #{func})))
(defn clear-hook [hook]
(reset! hook []))
(defn run-hook
([hook]
(doseq [func #hook] (func)))
([hook & rest]
(doseq [func #hook] (apply func rest))))
(defn phils-hook []
(println "Phils hook"))
(defn phils-hook2 []
(println "Phils hook2"))
(def test-hook (make-hook))
(add-hook test-hook phils-hook)
(add-hook test-hook phils-hook2)
(run-hook test-hook)
(remove-hook test-hook phils-hook)
(run-hook test-hook)