It might be a stupid question. And it might me formulated incorrectly.
But how do I run a channel in endless loop in my main function? I can do that in repl with (async/go-loop ...)
but not with lein run
Ok. I just figured out. It was not a problem of my channels misunderstaning, but wrong config.
Now another question. A file being read in my code. How do I say it not to look for the same file to read after compilation, but rather have it "remembered"?
I think you could read the file inside a macro, and substitute the reading with actual values you read at compile time. Another approach would be to put the file youβre reading as a resource which is compiles as a part of the final JAR β so itβs always with you the way you compiled it.
If I can somwhow pack it inside of jar?
Yes. With leiningen you do it by putting in resource/ folder in your project, and open the file with this function https://clojuredocs.org/clojure.java.io/resource
yep. The provlem is I am doing exactly same thing by now with
(defmacro compile-time-read-file
[resource-path]
(slurp (io/resource resource-path)))
w8 a second
ok. I got it.
Ok. I just get this. The problem is still with the first question.
Having this function:
(defn start [x y]
(async/go-loop []
...))
I want go make it work being into main
:
(defn -main [& args]
(start))
But it's not working as an endless loop.In your example above, youβre not calling the start function, youβre returning the function object from -main. Wrap it in parentheses like that (start)
Yes. I've meant. Sorry. I actually call it with parenthesis.
Ok. In this case, looks like what you need to do is to βwaitβ for the go-loop
thread to finish from the main thread. You can do that by doing this:
(async/<!! (start))
@altjsus
1 min. I'll try
Yep. This seems like the right approach.
go-loop
returns a channel from which you can read the result of async code execution when itβs ready (when the loop finishes). By reading for the value in a blocking way, we ensure that the main thread waits for the async loop to finish.
thnx!
I'm using next.jdbc to connect to postgres which is running as a docker container. I am able to connect to it using intellij and psql, but not via the repl. I have the following in my project.clj
[org.postgresql/postgresql "42.2.5"]
[seancorfield/next.jdbc "1.1.613"]
This is the code I executed to test
(comment
(require '[next.jdbc :as jdbc])
(def db {:dbtype "postgresql"
:classname "org.postgresql.Driver"
:dbname "foo-dev"
:username "foo"
:password "foo"
:host "localhost"
:port 7432})
(def ds (jdbc/get-datasource db))
(jdbc/execute! ds ["select * from some-table"]))
I am able to connect to it via psql (entering the password on prompt)
psql -h localhost -p 7432 --username foo -d foo-dev
The error I get when I run (jdbc/execute! ds ["select * from some_table"])
is this
Execution error (ConnectException) at java.net.PlainSocketImpl/socketConnect (PlainSocketImpl.java:-2).
Connection refused (Connection refused)
This is the docker-compose.yml
part for the postgres container
db:
image: postgis/postgis:13-master
volumes:
- db_data:/var/lib/postgresql/data
ports:
- 7432:5432
environment:
POSTGRES_USER: foo
POSTGRES_PASSWORD: foo
POSTGRES_DB: foo-dev
Change username
to user
user=> (def db {:dbtype "postgres" :classname "org.postgresql.Driver" :dbname "foo-dev" :user "foo" :password "foo" :host "localhost" :port 7432})
#'user/db
user=> (jdbc/execute! (jdbc/get-datasource db) ["select now()"])
[{:now #inst "2020-12-26T11:25:58"}]
β― docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
04d4199d1cd8 postgis/postgis:13-master "docker-entrypoint.sβ¦" 4 minutes ago Up 4 minutes 0.0.0.0:7432->5432/tcp david_db_1
Is clojure.lang.PersistentQueue
still the appropriate data structure to use if you want a FIFO queue? i.e. conj to the back, pop off the front?
still the same error π
Interesting. Works for me, and I basically copy and pasted your code to my terminal
AFAIK that is its primary purpose
Tried it in the older clojure.jdbc and it works, guessing it's a problem with next.jdbc and my system
(def idb {:classname "org.postgresql.Driver"
:subprotocol "postgresql"
:subname "//localhost:7432/foo-dev"
:user "foo"
:password "foo"})
Glad you got it sorted! π
Hey, everyone. I'm coming in from the Java/Kotlin world, and I'd like to try building a REST API using Clojure. In Java, you download Spring Boot and get to work, but I'm reading that in the Clojure world you tend to put together the pieces that you want, with everyone using Ring. Is there a de facto standard for building APIs nowadays? I I've seen samples with Reitit and Compojure; where is the industry heading?
compojure and reitit are routers, ring provides an http server (which can be combined with the router of your choice). none of these are REST specific
@abyala for "batteries included" opinionated setups, the biggest player is luminus, they have a project template generator which accepts args reflecting the setup you are looking for (eg. cljs webapp support, database backend...) https://luminusweb.com/ - the excellent book "web development with clojure" uses a luminus template, walks through building a full app, and is worth the price https://pragprog.com/titles/dswdcloj3/web-development-with-clojure-third-edition/
but depending on what kind of REST API you are trying to make, there are tools that simplify that as well (and those can be combined with the big pile of code that luminus hands you)
NB - don't ever use first / rest / etc. seq operations on a queue, it can quietly turn your fifo into a lifo
only use into, peek, conj, and pop
(and other tools built on those)
Awesome, I'll check that out. Thanks!
Hello , When can we use apply and when can we use reduce? what is the difference between them? I searched in internet before posting here, But did not get good understanding!
Thanks team for the reply, What I understood is apply and reduce both give same result, but acts different for different functions , and the way it handle functions are different
@popeyepwr for many functions that take variable argument counts, adding an arg to the function is equivalent to another call - in that case apply and reduce do the same thing
so "can" - for many vararg functions that treat their arguments homogenously, you can use either
in practice reduce has some optimizations that the function might not, so it's often preferable
concretely: (+ 1 2 3)
will always be the same as (+ (+ 1 2) 3)
, so apply and reduce will do the same thing with +
and [1 2 3]
also conj
(ins)user=> (apply conj [] [1 2 3])
[1 2 3]
(ins)user=> (reduce conj [] [1 2 3])
[1 2 3]
but with apply, it can be smarter about building the result, with reduce it needs to do more allocations (it builds a bunch of immutable vectors it only needs once)
for correctness they both work, it is case by case which is more efficient
To add to @noisesmithβs answer, I'll try and illustrate the difference: (apply f coll)
will call f
once with all elements of given collection supplied to it as arguments; (reduce f val coll)
will call the function once for each element in the collection. Consider this:
(vector 1 2) ;; => [1 2]
(vector 1 2 3 4 5) ;; => [1 2 3 4 5]
(apply vector [1 2 3 4 5]) ;; => [1 2 3 4 5]
(reduce vector 1 [2 3 4 5]) ;; => [[[[1 2] 3] 4] 5]
The short form (reduce f coll)
is convenient when val
is already in your collection:
(reduce vector [1 2 3 4 5]) ;; => [[[[1 2] 3] 4] 5]
So when your function yields the same results for (f (f x y) z) and (f x y z) the results of apply and reduce will be the same (as with e.g. addition), but generally they do different things.
Last, consider this example of how reduce can be used with result and collection elements of somewhat different types:
(reduce #(apply update %1 %2) {:left 0 :right 0} [[:left dec]
[:right inc]
[:right inc]])
;; => {:left -1, :right 2}
Can we say reduce is equivalent to apply if f is associative?
that's the word I almost used earlier, yes
Associativity is somewhat different, it is only defined for binary functions (but see below).
And yes, reduce
in its basic form [1] repeatedly applies a binary function to a sequence. If the function is associative, then the result will be the same for reversed sequence.
But apply
works with functions of different arities for which associativity makes no sense, e.g. (apply update [{:a 0} :a inc])
.
[1] https://en.wikipedia.org/wiki/Fold_(higher-order_function)
right, and a foolish person could make a vararg function that is associative for two args, but does something non-associative for a higher arg count
Well, for higher arg count, the function cannot be associative or non-associative -- e.g. above
Edit: I think we can translate associativity to variadic functions if we consider them as functions of one argument which operate on finite sequences, i.e. associative then meaning (using common mathematical notation) f((x1, f((x_2, ..., x_n)))) = f((f((x_1, ..., x_{n-1})), x_n)) for all such sequences. For (update :a inc)
would make no senseapply
and reduce
to be equivalent on the other hand would mean that f((f((x_1, f(( ... )), x_{n-1})), x_n)) = f((x_1, x_2, ... x_n))._
a version of plus that took three args would still be "associative" in the loose sense that you could start simplifying anywhere in the expression and get the same answer
sorry, no, that's incoherent, clojure functions based on known associative functions are often varargs, and if so they usually do the same thing under reduce / apply, that's all
I think the reason apply and reduce seem similar is that clojure provides many functions with their reduce'd extensions to higher arities.
Consider addition as commonly defined in mathematics: it is a binary operation which can be extended to sequences via formal equivalent of reduce
. Since it's associative, it can even be extended to sets. And in many programming languages addition remains just a binary operation, and to get a sum of more than two numbers one has to reduce
or fold
it. It's just that clojure conveniently provides this already -- if we look at the source of +
, we'll see
(defn +
;; snip
([x y] (. clojure.lang.Numbers (add x y)))
([x y & more]
(reduce1 + (+ x y) more)))
where reduce1
is specialized implementation of reduce
afaics.I think it's because it's commutative that you can do that on sets
(ins)user=> (apply / [1 2 3 4])
1/24
(ins)user=> (reduce / [1 2 3 4])
1/24
I think I mixed up associative and commutative above myself
@max.deineko reduce1 is a less efficient and less flexible version of reduce used before the clojure compiler has implemented reduce
You're right, for the reduction to be well defined on at least some interesting sets, the operation has to both be associative and commutative. But I shouldn't have mentioned it -- we don't want to drift too far I reckon π
@popeyepwr I found this very useful https://stackoverflow.com/questions/3153396/clojure-reduce-vs-apply