This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-01-30
Channels
- # babashka (19)
- # beginners (87)
- # calva (11)
- # cider (6)
- # cljdoc (30)
- # clojure (84)
- # clojure-china (1)
- # clojure-dev (13)
- # clojure-europe (4)
- # clojure-france (1)
- # clojure-gamedev (1)
- # clojurescript (12)
- # core-async (1)
- # cursive (12)
- # data-oriented-programming (1)
- # defnpodcast (1)
- # emacs (9)
- # events (1)
- # fulcro (8)
- # graalvm (1)
- # introduce-yourself (1)
- # missionary (6)
- # music (1)
- # nextjournal (14)
- # off-topic (26)
- # portal (2)
- # re-frame (1)
- # releases (2)
- # shadow-cljs (13)
I feel like there's things in clojure.set (https://clojure.github.io/clojure/clojure.set-api.html) that I don't understand. I'm using union, intersection and difference, but not the rest of the namespace. I want to understand what functions like index and join are meant to do. What's a rel? What's an xrel?
Once somebody commented that clojure.set implements the api for an "in-memory database" and I think that at least explains functions like join
and select
rel
and xrel
are relations, as in the mathemtical notion of a relation that relational databases are named for, but do not always precisely implement the mathematical notion of
Sounds reasonable. How can I make use of that? Can I just improvise a relational database on top of clojure.set?
There is nothing built into Clojure that implements SQL, for example, so don't expect to find that.
There are functions in clojure.set for doing join, project, and clojure.core/filter can be used to implement a select operation. If you want to implement relational operations using those operators, they are there for you.
If you want a different API, or you want persistence of data on disk or other storage, then I'd recommend instead using some other project that provides those features, of which there are many.
@U0NCTKEV8 thanks! Your example made it way more tangible.
I have the data in the below format
(def input-data {"data" {
"days" {
"Jan" 346,
"Feb" 143,
"March" 416,
},
"date" {
"Jan" "2023-02-21",
"Feb" "2023-09-12",
"March" "2023-11-21"
}
}})
what is the best way to get as
{"Jan" {
"days" 346
"date" "2023-02-21"
}
"Feb" {
"days" 143
"date" "2023-09-12"
}}
Roughly something like:
(into
{}
(let [{:strs [days date]} (get input-data "data")]
(for [[mon days] days]
[mon {"days" days "date" (get date mon)}])))
An alternate way, using map
:
(into {}
(let [{:strs [days date]} (data "data")]
(map (fn [[mon day] [mon timestamp]]
{mon {"days" day "date" timestamp}})
days date)))
@U030TQP563U you can't make an assumption regarding the order of days and date being the same, unfortunately
Sorry, my bad. Maps are unordered. This should fix the bug in my version:
(into {}
(let [{:strs [days date]} (get data "data")]
(map (fn [[month day]]
{month {"days" day "date" (get date month)}})
days)))
By explicitly looking up date
inside the map function, we can avoid the ordering problem.Thanks @UK0810AQ2 and @U030TQP563U for your time 🙂 I wrote below code which reduced any hard coded values, Let me know if any thoughts
(defn test-fn [input-data]
(reduce (fn [a b]
(assoc a (first b) (second b)))
{}
(second input-data)))
(println (apply merge-with vector (map test-fn (get data "data"))))
@popeyepwr Indeed your code works . Here is a live https://klipse-embed.herokuapp.com/?src=KGRlZiUyMGRhdGElMjAlN0IlMjJkYXRhJTIyJTIwJTdCJTIyZGF5cyUyMiUyMCU3QiUyMkphbiUyMiUyMCUyMCUyMDM0NiUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMkZlYiUyMiUyMCUyMCUyMDE0MyUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMk1hcmNoJTIyJTIwNDE2JTdEJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIyZGF0ZSUyMiUyMCU3QiUyMkphbiUyMiUyMCUyMCUyMCUyMjIwMjMtMDItMjElMjIlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjJGZWIlMjIlMjAlMjAlMjAlMjIyMDIzLTA5LTEyJTIyJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIyTWFyY2glMjIlMjAlMjIyMDIzLTExLTIxJTIyJTdEJTdEJTdEKSUwQSUwQShkZWZuJTIwdGVzdC1mbiUyMCU1QmlucHV0LWRhdGElNUQlMEElMjAlMjAocmVkdWNlJTIwKGZuJTIwJTVCYSUyMGIlNUQlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAoYXNzb2MlMjBhJTIwKGZpcnN0JTIwYiklMjAoc2Vjb25kJTIwYikpKSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCU3QiU3RCUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMChzZWNvbmQlMjBpbnB1dC1kYXRhKSkpJTBBJTBBKGFwcGx5JTIwbWVyZ2Utd2l0aCUyMHZlY3RvciUyMChtYXAlMjB0ZXN0LWZuJTIwKGdldCUyMGRhdGElMjAlMjJkYXRhJTIyKSkp&lang=clojure.
How to apply merge-with into
function for which is inside list
({:Jan 346, :Feb 143 :March 416} {:Jan "2023-02-21", :Feb "2023-09-12", :March "2023-11-21"}
I think you want (apply merge-with into ...)
- so literally what you had there :D
no, that doesn't work because there's no data structure for the into
then (apply merge-with vector ...)
works - unless you have more than two maps
another option:
(cmd)user=> (defn group-keys [& maps]
(into {}
(map (juxt identity (apply juxt maps)))
(->> maps
(mapcat keys)
(distinct))))
#'user/group-keys
(cmd)user=> (apply group-keys '({:Jan 346, :Feb 143 :March 416} {:Jan "2023-02-21", :Feb "2023-09-12", :March "2023-11-21"}))
{:Jan [346 "2023-02-21"], :Feb [143 "2023-09-12"], :March [416 "2023-11-21"]}
juxt creates a vector by calling each function arg, and a map acts as a lookup function
can you help me to understand this https://clojurians.slack.com/archives/C053AK3F9/p1643544286294269?thread_ts=1643533982.741629&cid=C053AK3F9
when you call map on a hash-map, it calls seq
on the hash-map, and seq for a hash-map returns two element vectors, key and value. technically a subtype of vector called map entry.
my function above does the opposite, and feeds into
with a two element vector, which becomes the key and value
(ins)user=> (->> {:a 0} seq)
([:a 0])
(ins)user=> (->> {:a 0} seq first)
[:a 0]
(ins)user=> (->> {:a 0} seq first type)
clojure.lang.MapEntry
(ins)user=> (->> {:a 0} seq first vector?)
true
when trying to understand a data structure, I find it useful to go into the repl and use ->
or ->>
, and use the arrow keys to retry and add stuff at the end
Thanks @U051SS2EU, That helped 🙂
Sounds reasonable. How can I make use of that? Can I just improvise a relational database on top of clojure.set?
I wrote below function which is working as expected ,
(defn test-fn [args]
(fn [a]
(do-some-thing-else (map reduc-fn args) a)))
(println ((test-fn (get data "data") ) rename-keys-sample))
But is there any wau we can improve calling function ((test-fn (get data "data") )
rather than using ((......))

@popeyepwr can you tell me more about the function raname-keys-sample
? i notice you are invoking test-fn
with arguments (get data "data")
but i don't understand the motivation behind rks
(def rename-keys-sample {"Jan" " montly jan"
"Feb" "Yearly Feb"
"March" "Montly Match"})
i have writtern just test data herethe implicit pass will require ((
explicit pass can do (
you could, for example, accept a
in the test-fn
arguments, rather than as an implicit pass. (defn test-fn [a args] ...
and keep variadicity with allowing the function to be passed in at the top level (test-fn rename-sample-keys (get data "data")
Another approach is to pass in a map and use destructuring on the map coming in
How can I test with a function that uses `*in*` for example:
(def input
"Receive the stdin input lines at once"
(str (slurp *in*)))
This code is blocking me from running tests since its waiting for a input, even using with-in-str
isn't possible.thanks @U3JH98J4R, was able to solve it by defining defn instead of def for all things related to the in input, so it stopped blocking the stdin on tests
@U031GTMB8QG was the issue that you used def instead of defn?
(ins)user=> (defn input []
"Receive the stdin input lines at once"
(str (slurp *in*)))
#'user/input
(ins)user=> (with-in-str "hello" (input))
"hello"
@U3JH98J4R that's what with-in-str
does
the problem @U051SS2EU was that it stuck in the require waiting for the stdin while try to run the lein test command
right, because all code in def
runs to completion before require returns
anything with any sort of state or side effect (including io) should be in defn and not def
yep @U051SS2EU, first time working with clojure haha, thank you!
Hmm, is declare
inherently side-effecting?
I have this puzzling case where this is happening:
(if (debug?) ;; <-- evaluates to true
(do
(require '[nrepl.cmdline :refer [-main] :rename {-main -nrepl-main}])
(resolve 'nrepl.cmdline))
(declare -nrepl-main))
#_#_=> Syntax error (IllegalStateException) compiling def at (src/example/core.clj:37:7).
-nrepl-main already refers to: #'nrepl.cmdline/-main in namespace: example.core
I was expecting the if
to prevent declare
from evaluating.
Even this evaluates declare
with the same syntax error...
(when false
(declare -nrepl-main))
declare
is just as side-effecting as def
and defn
are, and all of those are often strongly recommended not to be done inside of a function, but only at the top level of your code.
I see you are doing something where you explicitly want conditional requiring of namespaces, etc. so that is sometimes done for things like a user.clj
file.
I do not know why the error is occurring for declare
here.
I've mostly used requiring-resolve for conditional requires, happy with the result. You pass it a symbol, and returns a var or throws. https://clojuredocs.org/clojure.core/requiring-resolve
I'll check out requiring-resolves
@U3X7174KS 😃...
Yes, I'm trying to create dev / prod conditions and normally those work fine, but this was something I was just expecting to work @U0CMVHBL2. How is it normally done?
Notice that the same error occurs even if there is an empty part of the if
with no declare
. The error is not because declare
is there.
I just pasted this into another namespace to check and if I delete the second if branch, it doesn't happen.
This appears to work if loaded and re-evaluated:
(if true ;; <-- evaluates to true
(do
(require '[nrepl.cmdline :refer [-main] :rename {-main -nrepl-main}])
(resolve 'nrepl.cmdline)
nil) #_(declare -nrepl-main))
What am I missing @U0CMVHBL2? 😃
I am probably missing something, in that I tried it with no nrepl.cmdline in my classpath, so my bad there, sorry.
The error message was at least similar, but perhaps it wasn't identical. Let me check.
Neither of these expressions give an error with Clojure 1.10.1:
$ clj
Clojure 1.10.1
user=> (if true (do nil) (declare -nrepl-main))
nil
user=> (if false (do nil) (declare -nrepl-main))
#'user/-nrepl-main
That suggests to me that it isn't the declare
that is causing your error, unless our environments differ substantially in a way I'm not guessing.
Perhaps you'll forgive me for guessing, but I guess it may be due to the compiler doing things with certain forms before other things i.e. testing the requires and declares before the runtime runs the ifs.
declare and def both have compile time effects (the same compile time effect, interning a var)
What is happening is the declares effect (interning nrepl-main in *ns*
) is happening when the code is compiled, then when the code is run, it is trying to do all the requiring and rename stuff. And that throws an error because a var with that name already exists because of the compile time effect of the declare
Thank you, so other than using requiring-resolves
is there another way to do this sort of conditional require?
What is a simple (hopefully free) way i can get a Ring server up and running on a domain I own?
To run a ring server, you need a computer connected to the internet somewhere to run it. Not exactly sure what you're trying to host, but here some options: • aws has a https://aws.amazon.com/premiumsupport/knowledge-center/what-is-free-tier/. As they explain, there's 1) services that have free trials, 2) 12 months free, and 3) always free. If you're looking at always free, then your best bet is https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free%20Tier%20Types=tier%23always-free&awsf.Free%20Tier%20Categories=categories%23compute. I'm not sure it's ring compatible, but there is a clojure library targeting aws lambda called https://github.com/FieryCod/holy-lambda. You'll still be limited by usage, but it should work for personal usage. • Both digital ocean and AWS have servers that run around $5/mo. I've used both, but tend to prefer digital ocean for hobby projects • You can run a website using static hosting very cheaply, on the order of a few cents a month or less. The catch is that if your app requires persistent storage (eg. database), then you'll need find a cheap storage solution. There are cheap/free-ish storage solutions, but it depends on your use case. • https://pages.github.com/ can be a good option for free hosting, but this is closer to a static option rather than a ring server • If you have an extra computer or raspberry pi, then you can just run the server there. There's some setup to make it available on the public internet, but it's very doable. I'd be happy to expand on any of the options above if they sound interesting.
Thanks! I tried using aws in the past but I found it to be a bit confusing to navigate and manage; would digital ocean be any easier? I might choose the last option but there’s a router in the way and I’ve never figured out how to make if public
> would digital ocean be any easier It kind of depends on how familiar you are with linux. Digital Ocean has fewer services and options, so it might be a little easier to manage > there’s a router in the way and I’ve never figured out how to make if public Just about every router has port forwarding. As long as you have admin access to the router, then you should be able to find "port forwarding" somewhere in the options.
I'm using Digtal Ocean to run a hobby web server, with NGINX as a proxy in front, if you message me I can try help walk you through it :)
Thanks! My app will need a database though, and I'm not too sure how that affects my options...
I don't know exactly what kind of setup you need, but if you're able to run it locally on your machine, it will very likely run just fine on a rented server
You can run a Clojure project on Heroku for free, even including a postgresql database The free version puts apps to sleep after an hour of inactivity, automatically waking them up again on activity. https://devcenter.heroku.com/articles/getting-started-with-clojure
This is an example using Circle CI and Heroku to deploy a Clojure CLI (deps.edn) project https://practical.li/clojure-web-services/projects/banking-on-clojure/deployment-via-ci.html