For a project I have written a stateful map and stateful filter using transducers. Perhaps it can be useful to others as well? https://gist.github.com/holyjak/578571a134ce90526e6907436e91014a
Can it be generalized to a reducing function?
I think there's some common ground with https://github.com/cgrand/xforms/blob/master/src/net/cgrand/xforms.cljc#L491
With something like
(defn with-state
[txf trf f init]
(let [state (volatile! init)
tf (txf trf)]
(fn [in]
(let [old @state]
(vswap! state tf in)
(f old in)))))
You can generalize. the t
stands for transitionWith some more hand waving:
(defn with-state
([trf f]
(with-state trf f nil))
([trf f init]
(with-state identity trf f init))
([txf trf f init]
(let [state (volatile! init)
tf (txf trf)]
(fn [in]
(let [old @state]
(vswap! state tf in)
(f old in))))))
(defn right [x y] y)
(sequence (stateful-filter not= right) [1 2 2 2 3 4 4 5])
(sequence (filter (with-state right not=)) [1 2 2 2 3 4 4 5])
Great comments, Ben, thanks a lot!
Cheers 🙂
If you don't want to use a volatile for performance reasons, since it won't be thread safe anyway, you can use a box type. Probably overkill 🙂
(definterface IBox
(_put [x])
(_look []))
(deftype Box [^:unsynchronized-mutable v]
IBox
(_put [this x] (set! v x))
(_look [this] v))
(defn with-state2
([trf f]
(with-state2 trf f nil))
([trf f init]
(with-state2 identity trf f init))
([txf trf f init]
(let [^Box state (->Box init)
tf (txf trf)]
(fn [in]
(let [old (._look state)]
(._put state (tf old in))
(f old in))))))
I used an interface because I couldn't get rid of reflection warnings otherwise
Probably didn't try hard enough
Good morning Clojurians, I read the https://unixsheikh.com/articles/sqlite-the-only-database-you-will-ever-need-in-most-cases.html article this morning and wanted to know if it makes sense for a small Clojure website with the DB on the the same machine, with the goal to minimize the complexity. Also, if SQLite is used, does it make sense to use HekaryCP?
@vemv, Yes, this is an interesting comment, I do feel the same way. That article made me waver but every developers dream is for their website to go viral. If that happens, and multiple machines need to be spun up, scaling postgres is quick, so it is probably a better choice.
Good morning! I've been building some automation at work with Clojure/SQLite recently, and it's been great. Would be fantastic for a small website. Regarding connection pooling, it might make sense to use it. The JDBC driver for SQLite will serialize when using the same connection across multiple threads: https://github.com/xerial/sqlite-jdbc/issues/369
Did you know that https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Box.java
There are also pure Java alternatives like H2, Derby and HSQLDB
TBH I have only used SQLite though. It has been pretty good although the column types are kind of crappy compared to e.g. Postgres.
I do wonder if the SQLite is quicker than Postgres when both run on the same machine.
That'll depend on the workload. For something read-heavy like a website, SQLite will probably be as fast or faster than PostgreSQL. For anything write-heavy, PostgreSQL will perform better.
not applicable, since we need something mutable
"small website" is really ambiguous wording tbh. apps can be small but also represent a lot of work and hopes (e.g. your MVP startup) any startup that intends to satisfy actual customers should have make a minimally reasonable HA setup. That practically rules out sqlite and friends I don't want to come off as dogmatic but honestly "cattle not pets" is pretty hard to argue against in 2021. You can get a HA psql for 100 bucks or whatever on aws/heroku/...
Shameless plug: if you are not wedded to SQL, you may consider Datalevin, a SQLite like Datalog database for Clojure, it will be much simpler to use in Clojure, no drivers to worry about and native EDN input/output
Ya, I feel for a small use case like you describe, it will be even better to go with a Java native solution like H2 or Datalevin. Then you don't even need to install anything else, its all embedded in your app.
is this an idiomatic way to schedule a function to be called every second or so? I need it in two places and don't want a whole dependency (like chime) to handle it.
(defn tick
"Call f every ms. First call will be after ms"
[active? callback ms]
(future
(while @active?
(Thread/sleep ms)
(callback))))
Maybe you need some error handling in case callback
fails?
good point
you might want something more robust than Thread/sleep alone if the timing precision matters, but it probably doesn't
it does not. This is to clean up empty lobbies in a game sever
also, I like to use a delay or promise for turn-off-switch args, because unlike an atom they are simple, limited purpose, and one way
I like to use the weak / specific construct when possible, it helps clarify intent
I don't know much about those objects. do you have an example of how I would use it here?
example coming up
(ins)user=> (defn tick [done? callback ms] (future (while (not (realized? done?)) (callback) (Thread/sleep ms))))
#'user/tick
(cmd)user=> (def signal (delay :done))
#'user/signal
(cmd)user=> (tick signal #(println "still going") 10000)
#object[clojure.core$future_call$reify__8454 0x1dab9dd6 {:status :pending, :val nil}]
still going
user=> still going
(force signal)
:done
also I changed the order of callback
and Thread/sleep
because calling callback again after cancelled seems oddalso the code becomes clearer if you have a helper (def pending? (complement realized?))
or see https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html
or the older https://docs.oracle.com/javase/8/docs/api/java/util/Timer.html
Java, mutable by default
(.val ^Box b)
1
user=> (set! (. ^Box b val) 2)
2
I did not know we had this object lying around 🙂
Thank you! I’ll read this over
The oddest thing. I have two projects. Both use malli 0.2.1 (according to lein deps :tree
). But one of them accepts the syntax [:map [:a string?] [:b string?]]
just fine, while the other throws an error on (restart)
:
data-spec collection [] should be homogeneous, 3 values found
Any idea what could be the cause?@lkorogodski Perhaps a question for #malli
Thanks.
If that error might be caused by a difference in malli
versions, then perhaps you have an uberjar on your classpath that contains a different version of malli
.