This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-02-24
Channels
- # announcements (5)
- # aws (24)
- # babashka (41)
- # beginners (130)
- # bristol-clojurians (2)
- # calva (39)
- # chlorine-clover (64)
- # cider (30)
- # clojure (202)
- # clojure-belgium (1)
- # clojure-dev (99)
- # clojure-europe (5)
- # clojure-hungary (4)
- # clojure-italy (10)
- # clojure-losangeles (8)
- # clojure-nl (11)
- # clojure-norway (6)
- # clojure-spec (7)
- # clojure-uk (12)
- # clojurescript (52)
- # core-typed (26)
- # cursive (19)
- # data-science (19)
- # datomic (19)
- # duct (10)
- # emacs (17)
- # fulcro (22)
- # graalvm (11)
- # jobs (3)
- # kaocha (28)
- # leiningen (6)
- # lumo (2)
- # malli (10)
- # nrepl (2)
- # off-topic (23)
- # pathom (2)
- # pedestal (7)
- # re-frame (3)
- # reagent (30)
- # reitit (2)
- # remote-jobs (2)
- # shadow-cljs (77)
- # sql (10)
- # test-check (22)
- # tools-deps (37)
- # vscode (1)
- # yada (3)
why is this happening?
(def one 1)
=> #'user/one
(case 1 one :one :not-one)
=> :not-one
The clue is in docs: http://clojuredocs.org/clojure.core/case > The test-constants are not evaluated. They must be compile-time literals
In your case, it would actually reeturn :one
if you would pass the quoted 'one
(def one 1)
(case 'one
one :one
:not-one)
;;=> :one
Interesting, I wonder why they made that choice. I can see situations where writing an expression to match might be helpful tho one can use cond with = I guess.
case
is designed for efficiency's sake, where a multi-way branch of comparing against compile-time constants is being done. If you want to compare against run-time values, case
would not be helpful.
because of the implementation techniques it can take advantage of because it knows its comparison values are compile-time constants.
As you say cond
is there, and all the rest of Clojure.
thank you all — actually i feel more dumb 🙂 can you think any other core macros behaving surprisingly (for a noob) like this?
Just about anything can be surprising, depending upon your background knowledge and/or assumptions.
Sorry, I know that is a very general and unhelpful statement, but your question was pretty broad 🙂
I would recommend reading the doc strings of core macros you want to use, and ask questions about any parts of them that are unclear.
In this case, for example, the doc string for case says: "The test-constants are not evaluated. They must be compile-time literals, and need not be quoted."
I am not here claiming that all of those terms, and their consequences, should be obvious to someone new to Clojure from reading that, but that is why I suggested asking questions about any parts of them that are unclear.
http://ClojureDocs.org contains useful examples for at least many Clojure macros and functions. It is not "official" documentation, so treat it with just a tiny bit of suspicion if something seems wrong there, as the examples there are contributed by anyone in the world with the time and interest, and are not vetted for correctness except by other similar people.
thank you for taking the time for explaining. the doc seems reasonable enough actually — seems i have a tendency for ignoring pieces i dont understand
i suppose condp
is my best bet for this
(condp contains? (.getType eat)
#{EventAttributeType/TYPE_DATE}
:date
#{EventAttributeType/TYPE_FLOAT}
:float
#{EventAttributeType/TYPE_STRING}
:string
#{EventAttributeType/TYPE_TREE_ACC_BOOK
EventAttributeType/TYPE_TREE_ANY
EventAttributeType/TYPE_TREE_LEAF_ONLY}
:discrete)
(trying to work with this legacy java api — this is were i had hard time with case
. wanted to use this as dispatch fn for defmulti
)It is pretty common to skim over things that do not make sense, I think -- often you can get what you need to know by focusing on the parts you do understand. Maybe when new to something is a good time to ask on some of the things that do not make sense. I know it can be time consuming, but on occasion might really help in the long term.
In this case, where it looks like you want to dispatch on Java Enum
values, you might be able to use this case-enum
macro:
(defmacro case-enum
"Like Clojure's built-in `case`, but can explicitly dispatch on Java
enum ordinals."
{:style/indent 1}
[e & clauses]
(letfn [(enum-ordinal [e] `(let [^Enum e# ~e] (.ordinal e#)))]
`(case ~(enum-ordinal e)
~@(concat
(mapcat (fn [[test result]]
[(eval (enum-ordinal test)) result])
(partition 2 clauses))
(when (odd? (count clauses))
(list (last clauses)))))))
Does anybody know if core.logic is still being developed? The 'development' page was last updated 9 years ago https://github.com/clojure/core.logic/wiki/Development
No one is actively working on it, but would be happy to have someone do so!
It sounded promising. Why doesn't it take off, in your opinion?
people do use it for things, can't say I know why people do or do not use it
Is there a slack channel for it, or some other kind of forum?
there's #core-logic
Thanks!
Projects in Clojure tend to get to a stage where they work well, and are just left alone. To people more familiar with other worlds, where there is more churn, they can seem dead. But sometimes they are just where they need to be.
Judging by CHANGES.md and release history, it's been mostly bugfixes and porting to cljs for the last 7 years
Maybe not the best way, but quite elegant solution is to use ByteArrayOutputStream
But if you want extreme performance, sum the counts to find final size, then create new byte array of said size. Use Java System/arraycopy to fill.
hello
is there a way to make https://github.com/clojure/java.jdbc
take care of _
and -
transformation of names for me without me having to specify identifiers or entries?
If you are making an app (like some sort of server) and not a library, should your main function be in a namespace like <stuff>.core
or <stuff>.main
or something else? I ask because core
doesn't seem to make sense outside of the library case, but I see a lot of that out there. Looking for an opinion
whatever makes sense to you :)
I know what makes sense to me (`main` or the like) but if there is a predominant trend I'm not going to buck it...but if there ain't there ain't I suppose.
main is fine (in Clojure itself, the repl/launcher is clojure.main for example)
Hello,
How can I swap!
an atom with nested maps? If I have a vector of questions (def questions ["q1" "q2" "q3"])
and I have an id
which is a long int, and I want the result to be something like :
{id1 {"q1" "q2" "q3"}
id2 {"q1" "q2" "q3"}}
Then I would like to get q1 for the first id1 and drop q1, or get q2 for the id2 and drop it. To control the questions I’m asking each user until there are now questions left
{id1 {"q2" "q3"}
id2 {"q3"}}
Thanks for your help!@orlandomr27 I manage to write this solution to your problem:
(def db (atom {1 #{"q1" "q2" "q3"}
2 #{"q1" "q2" "q3"}}))
(defn remove-question-from-user [id q]
(let [qrs (get @db id)]
(swap! db assoc id (disj qrs q))))
(remove-question-from-user 1 "q1")
However, the "nested-map" does not exist. The map {"q1" "q2" "q3"} is invalid, it must obey a [key value] pair structure. So, I imagined you choose this data structure to avoid repetition of questions to each user, right? So I change it to a set
There’s a race condition here though because the value of qrs
is obtained outside of the swap!
call, so if another thread changes db
in between when @
(`deref`) is called, and when swap!
is called, data will be lost. Both operations should be performed inside the swap!
call.
Here is the thread-safe way to write it:
(defn remove-question-from-user
[id q]
(swap! db (fn [old-val]
(let [qrs (get old-val id)]
(assoc old-val id (disj qrs q))))))
However, there is an even more concise and idiomatic way to write it by using the update-in
function:
(defn remove-question-from-user
[id q]
(swap! db update-in [id] disj q))
Thank you @iagwanderson It is really a set. I’m going to try your solution. 🙂
could someone help me understand what’s going on here?
user=> (defn aux-fn [] (prn "returning") "test")
#'user/aux-fn
user=> (defn fn1 [] (prn "orig fn") (aux-fn))
#'user/fn1
user=> (fn1)
"orig fn"
"returning"
"test"
user=> (def store (atom {:fn fn1}))
#'user/store
user=> ((:fn @store))
"orig fn"
"returning"
"test"
user=> (defn aux-fn [] (prn "returning something else") "bananas")
#'user/aux-fn
user=> ((:fn @store))
"orig fn"
"returning something else"
"bananas"
user=> (defn fn1 [] (prn "orig fn but changed") (aux-fn))
#'user/fn1
user=> ((:fn @store))
"orig fn"
"returning something else"
"bananas"
tldr, define a function A that calls some other function B, store fn A in an atom. i cannot redefine A, but i can redefine B
when you store the function like that it looks at the function stored at that var at that time and stores that specific function
it doesn't look in the var every time
there's a shorthand to store the var rather than the function
I'm not sure what it is off the top of my head... I think it might be #'fn1
this is also something that can happen when you use things like partial
and juxt
to create functions out of other functions
they take the function out of the var at the time of the call to partial/juxt, so when you update that var with a new function, the old one will stick around
Using emacs and the accompanying tools (cider etc) , having started a web server (Iike Yada’s) how does one modify a ring handler and have it reload without closing their repl and starting a new one. I have to quit my repl session and open a new repl every thirty seconds and might as well not be using a repl at all.
Nvm. :reload
It seems I only actually find what I’m looking for, after I make up my mind to ask about it here. Sorry to bother
I doubt anyone will mind, unless you do it 10 times per hour 🙂
@acgollapalli A helpful trick is to refer to the handler function with #'
so that a Var is passed, instead of the function "value" -- that allows you to modify the function via the REPL and have it take effect immediately without any sort of reload needed.
Example of handler passed as a Var: https://github.com/seancorfield/usermanager-example/blob/master/src/usermanager/main.clj#L202
Is it good practice to use the built in memoize function for a function that will be called with a really huge map as an argument?
Or rather, does the caching that makes memoizing work have significant costs for a large set or large args?
The caching overhead is: memory to store the arguments that you want the function to be memoized for and the comparison overhead of equality testing the arguments.
Will it ever dump old cached args?
memoizing will remember a reference to arguments, including large ones, so those values cannot be GC'ed if they are no longer used by your application, unless the memoize option you use times out old entries, too.
The default memoize
implementation never times out old entries, but you could create one using Clojure's core.cache library that did.
If you call the function with lots of different arguments, that could potentially be both a large space overhead and perhaps even a noticeable comparison overhead. The built-in memoize
keeps data "forever". org.clojure/core.memoize
lets you memoize with different caches, such as TTL, LRU, etc.
core.memoize
(you don't need to build it from core.cache
directly).
What Sean said 🙂
Ok, cool. So just because I keep all my global state in a single atom and could call this function pure if I pass in the global atom doesn't mean I should. 😁 thanks.
I'll figure out some sort of caching, the state changes in a predictable way so I know exactly how long the cache needs to exist for
If you mean passing in an immutable value that is the current value stored inside of an atom, into a function that is pure, then I have no arguments against that terminology. If you meant passing the atom itself, i.e. the mutable "container" that stores a reference to an immutable value, that is a mutable object, and I wouldn't think any function you pass that to could be considered pure in any traditional sense, nor take advantage of memoization.
I would be passing in an immutable value, but it's a value that takes 30+ KB of text to represent and it is replaced with a new state 25 times a second, with a relatively low chance of ever being exactly the same twice. This function gets called a few hundred thousands times a "frame" so it's worth the effort to cache it properly, I just saw a fancy functional concept and wanted it to apply to my weird situation 😁
You could also argue that maybe I shouldn't call it hundreds of thousands of times but we will see where caching gets me
if you break it up into smaller pieces the individual pieces are more likely to be cachable
but the nature of caching is any change breaks the cache
You may not want to rely upon this in your use case, but note that if two immutable values are the same object in memory, then in most if not all cases of that, Clojure =
is just a pointer comparison and return true
if the pointers are equal. i.e. no deep comparison is done if they are the same object. How often two big collections are the same object in memory depends entirely on how your application is written.
@doby162 one pattern is to have the messy "state" blob, and a function of that that derives a "key", where you know that any two states that should derive the same answer would have the same key (even if they are not equal), then cache based on the key
it could be that you could break your function into smaller calculations that each have their own way of deriving a key
I thought about that, I could cache based on the tic-number in my simulation. But without the ability to dump cashed data that is more than N seconds old, that will still reach infinity in theory. I should be able to precalculate for a frame instead of calling the function to recalculate every time I need the answer
TTL is one of the classic cache variants, clojure/core.memoize makes different memoization functions out of various cache types
or you don't even need TTL - a LRU for a fixed N frames is cheaper CPU wise and would do exactly what you want as far as discarding older data
another pattern, if you need on-demand calculation but to reuse those calculations if they come up again in the same scope, is to use a let block with recursive delays
Thanks, I will look into that!
% clj
Clojure 1.10.1
(ins)user=> (load-file "/tmp/delays.clj")
"Elapsed time: 2005.193238 msecs"
74088
(ins)user=> (println (slurp "/tmp/delays.clj"))
(let [x (delay (Thread/sleep 1000) 31)
y (delay (Thread/sleep 1000) (+ @x 11))]
(time (* @y @y @y)))
nil
I’m thinking about saving a future in an atom with the intent of running something in parallel (fetching data from an API) that I’ll need further down the line my data pipeline. Is that a bad idea and how do I deref both without blowing things up? I haven’t tried it, but it sounds weird
Hi folks - I’m wanting a list of just 5 letter words. I’ve got a list of all the words from my local dictionary with:
(def words
(set (map str/trim (str/split-lines (slurp "/usr/share/dict/words")))) )
[Using the excellent Clojure tutorial at https://www.bernhardwenzel.com/articles/clojure-spellchecker/ .]
How can I process that to just keep the 5 letter words? I’m somewhat new to Clojure and sure I’m overthinking this.sweet - sweet - sweet!
(def scores {"Fred" 1400, "Bob" 1240, "Angela" 1024}) (get scores "Fred") => #function[clojure.core/get] ??? Why dont repl display 1400 here instead of that above??? 🙂
my guess is you are hitting the key combination to "evaluate form under cursor" rather than the key combination for "evaluate this whole line / surrounding expression"
If you try your code on a fresh repl (I used http://clojurescript.io) it works as you expect.
Many times in the past I have foolishly defined values under the symbol count
and then been confused as to why the count function is throwing. My first thought was something along those lines.
@bfabry - Thanks… I’m just using the wrong (newbie) terminology. I meant “lazy sequence”.
I just improved my code using a thread. (First time I’ve tried this.)
(def words
(->> (slurp "/usr/share/dict/words")
(str/split-lines)
(map str/trim)
(set)
(filter #(= 5 (.length %)))
(filter #(Character/isLowerCase (first %)))
)
)
I also added another filter to take out the proper names. (Ensuring first character is lower case.)Cool - Yeah, ok - that makes sense.
also use count
instead of .length
- if it's a perf question then at least provide a hint to the length call, but that's not likely to be a perf bottleneck
any takes on a more elaborate version of this tweet? https://twitter.com/stuarthalloway/status/1229856488560234497
@lockdown- if you look at the rest of the thread, it's about using someone else's org name for your stuff