This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-03-30
Channels
- # announcements (8)
- # babashka (102)
- # beginners (312)
- # calva (9)
- # clj-kondo (9)
- # cljfx (7)
- # clojure (128)
- # clojure-europe (52)
- # clojure-nl (2)
- # clojure-norway (2)
- # clojure-spec (5)
- # clojure-uk (4)
- # clojurescript (13)
- # conjure (5)
- # cursive (5)
- # datalog (18)
- # datomic (8)
- # emacs (1)
- # events (3)
- # fulcro (16)
- # graphql (2)
- # gratitude (1)
- # helix (16)
- # inf-clojure (17)
- # introduce-yourself (9)
- # java (11)
- # lambdaisland (3)
- # leiningen (3)
- # lsp (8)
- # malli (3)
- # membrane (7)
- # missionary (26)
- # nextjournal (1)
- # off-topic (19)
- # pathom (3)
- # polylith (13)
- # portal (16)
- # reagent (39)
- # reitit (2)
- # releases (23)
- # remote-jobs (1)
- # shadow-cljs (40)
- # specter (3)
- # sql (12)
- # tools-deps (8)
- # tree-sitter (1)
- # vim (3)
- # web-security (6)
- # xtdb (16)
Hello! Is there any stdlib fn or macro, which works like (defn t [pred val default] (if (pred val) val default))
?
exept of its first argument, whih is need to be a boolean value instead of predicate itself
no core functions or macros. Small enough to write your own one liner
Thaths why I'm asking - it's not a problem to write custom fn or macro, but I try to find existed ones first
Can’t think of any.
`fnil` comes close but doesn't work exactly like that (edit: nevermind, you want to replace the output)
fnil is good for checks on nil? but not on custom predicate. I just thought, that there shoul be a common pattern for such type of code in dynamic types world...
There are other ways to do type checking if that’s what you want.
clojure.spec
for one
And other spec
related tools
such as malli
or schema
What exactly are you trying to do, if I may ask?
I'm trying to find an usable way for checking & setting defaults to values, which are not of proposed types or nils
For a specific instance or as a pattern in general?
f.e. I can coerce val to string as (str val)
and it makes nil as "" and 3 as "3" but it will keep [1 2 3] as "[1 2 3]" what can be undesireable
Can’t you simply have a map of undesirables mapping to their default values?
(def defaults {nil 42})
(defn make-default [x] (get defaults x x))
(make-default 42) ;; returns 42
(make-default nil) ;; returns 42
Let talk about this case:
{:a nil} => 0
{} => 0
{:a 3} => 3
{:a "3"} => 3
{:a ....} => 0
It's a more complex one, I know, we should parse a string to int, but it's just an example of one case when I want to use my check helper
You can use custom predicates but that will quickly become unmanageable because you're not simply "removing undesirable values" nor parsing. You're describing a conversion process that (potentially) involves a significant amount of logic. Like I said in the other thread I really believe that you should use a library like https://github.com/noprompt/meander to unnest your data. For the coercions you can use something like https://github.com/exoscale/coax.
And another one, which works like (defn v [val default] (if (nil? val) default val))
? or
fails on booleans
This is basically if-not
😄
exept of its first argument, whih is need to be a boolean value instead of predicate itself
Right. Might as well wrap it into your own fn. Can’t think of anything in core that does this
You can hack it
Is that better/more readable than (if (nil? val) default val)
?
Are you looking for a way to not have to repeat val or is there more to it?
1. I'd go one step back: Do you control what goes into the map? If so, try not to have nils before you build the map and then you'll be able to just (merge default-map m)
. No or/ifs anywhere.
2. If not, I'd just write (or (:active {:id 1 :active nil}) 42)
- oh, or
will replace false too though, right that's what you said
3. if you're absolutely sure that you don't need any of the nil vals you could remove those keys (this is risky though) and then do a merge with a default map
This is on of the cases, but I have to write stable backend code having input map from json, and frontend can either send nil values or does not send them as well. I can sanitize and delete all the nils (on all the nested levels!) before, but looks like it is overkill. I'm looking for simple & usable solution, standart one first
Right, I don't think there's much you can do in that case. You could write your own wrapper function and use it everywhere to protect your data from unwanted nils but I've actually been there and it's not pretty. However: > nested levels Have you considered transforming your data with something like https://github.com/noprompt/meander of https://github.com/healthsamurai/ironhide? As your project grows I suspect you'll have bigger problems if you have nils and nested data to handle.
I just entered new team & project, and don't know about input data transformation process yet, but I already see the hacks & tricks in the code and my first idea was to cleanup it as possible
For 1.11, the passing map to keyword argument function (https://clojure.org/news/2021/03/18/apis-serving-people-and-programs) what actual pain point does it solve?
the main problem is that callers must list trailing args (good for people) but calling functions (programs) often have stuff in a map. this lets those functions pass the data directly without needing to apply/spread the kwargs
you commonly run into this when trying to layer one kwarg function over another
yeah, if you've ever worked with a kwarg-only API and needed to programmatically choose which elements to add, you'll probably have made your own custom apply that first flattens an input map into a sequence before passing it to the function. Now that wrapper function need not exist except in codebases looking to support multiple clojure versions.
@i For one thing, you can pass a regular map to a named argument function instead of having to do stuff with apply
https://twitter.com/FakeUnicode/status/1490262540030713856?s=20&t=5KnaGhc0j-FelgLlDCWHrw I'm so frustrated I can't make a Clojure version of this that fits in a single tweet 😄
(let [s (vec " ▁▂▃▄▅▆▇█")
walk (fn [n]
(let [n (+ n (rand-nth [-1 1]))]
(cond
(> 0 n) (+ n 2)
(<= (count s) n) (- n 2)
:else n)))]
(->> (iterate walk 0)
(map #(nth s %))
(take 5000)
(clojure.string/join))
here's what I have so far.(require '[clojure.string :as s])
(let [s " ▁▂▃▄▅▆▇█"
w (fn [n]
(let [n (+ n (rand-nth [-1 1]))]
(cond
(> 0 n) (+ n 2)
(<= (count s) n) (- n 2)
:else n)))]
(->> (iterate w 0)
(map #(nth s %))
(take 5000)
(s/join))
A bit smaller, don't need to use vecYou can make w
a #(...)
function.
Not sure if you've tried removing all the unnecessary whitespace. :)
maybe apply str instead of join
(let [s " ▁▂▃▄▅▆▇█"]
(clojure.string/join
(take
5000
(map
#(.charAt s %)
(iterate
(fn [n]
(let [n (+ n (rand-nth [-1 1]))]
(if (> 0 n) (+ n 2) (if (<= (count s) n) (- n 2) n))))
0)))))
(let [s (vec " ▁▂▃▄▅▆▇█")]
(clojure.string/join
(take
5000
(map
#(s %)
(iterate
(fn [n]
(let [n (+ n (rand-nth [-1 1]))]
(if (> 0 n) (+ n 2) (if (<= (count s) n) (- n 2) n))))
0)))))
235 chars(let [s (vec " ▁▂▃▄▅▆▇█")]
(clojure.string/join
(take
5000
(map
#(s %)
(iterate
#(let [n (+ % (rand-nth [-1 1]))]
(if (> 0 n) (+ n 2) (if (<= (count s) n) (- n 2) n)))
0)))))
218(apply str (take 5000 (map #(nth (vec " ▁▂▃▄▅▆▇█") %) (iterate #(let [n (+ % (rand-nth [-1 1]))] (cond (> 0 n) (+ n 2) (<= 9 n) (- n 2) :else n)) 0))))
(apply str (take 5000 (map #((vec " ▁▂▃▄▅▆▇█") %) (iterate #(let [n (+ % (rand-nth [-1 1]))] (if (> 0 n) (+ n 2) (if (<= 9 n) (- n 2) n))) 0))))
144(apply str (take 5000 (map #((vec " ▁▂▃▄▅▆▇█") %) (iterate #(let [n (+ % (rand-nth [-1 1]))] (cond (> 0 n) (+ n 2) (<= 9 n) (- n 2) 0 n)) 0))))
143142!
(apply str (take 5000 (map #((vec " ▁▂▃▄▅▆▇█") %) (iterate #(let [n (+ % (rand-nth [-1 1]))] (+ n (if (> 0 n) 2 (if (<= 9 n) (- 2) 0)))) 0))))
@UK0810AQ2 Replace (- 2)
with just -2
. :)
(> 0 n) is neg? isn't it?
I guess that's bigger, nvm
(apply str(take 5000(map #((vec " ▁▂▃▄▅▆▇█")%)(iterate #(let[n(+ % (rand-nth[-1 1]))](+ n(if(> 0 n)2(if(<= 9 n)(- 2)0))))0))))
124!
(apply str(take 5000(map #((vec " ▁▂▃▄▅▆▇█")%)(iterate #(let[n(+ % (rand-nth[-1 1]))](+ n(if(> 0 n)2(if(<= 9 n)-2 0))))0))))
121 chars
(apply str(take 5000(map #(nth" ▁▂▃▄▅▆▇█"%)(iterate #(let[n(+ % (rand-nth[-1 1]))](+ n(if(> 0 n)2(if(<= 9 n)-2 0))))0))))
(apply str (take 5000 (map #(nth " ▁▂▃▄▅▆▇█" %) (iterate #(let [n (+ % (rand-nth [-1 1]))] (cond (< n 0) 1 (> n 8) 7 0 n)) 0))))
128 with spaces@U1EP3BZ3Q Not equivalent since in your code the new value of n
does not depend on the old value of n
, except for one branch. In the original solution, all three branches depend on n
.
(apply str (take 5e3 (map #(nth " ▁▂▃▄▅▆▇█" %) (iterate #(let [n (+ % (rand-nth [-1 1]))] (cond (< n 0) 1 (> n 8) 7 0 n)) 0))))
127 with spacesHere is bigger collection: https://www.ioccc.org/
we've been reducing the size of the current algorithm but what if we did something different, like using reduce to build up the string
(apply str (take 5e3 (map #(nth " ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁" (mod % 16)) (iterate #(+ % (rand-nth [-1 1])) 0))))
brilliant!!
I was staring at the 8 characters trying to figure out how to make mod 8 not reset to 1
and of course the solution is to make it 16
There is another way of removing the if mathematically
(defn foo [s z]
(let [z (+ z (rand-nth [-1 1]))
z (+ z (* -2 (Math/floor (/ z (dec (count s))))))]
(int z)))
Yes, your solution is significantly more elegant.
I was just making the point that there is a mathematical solution to it 🙂
Clamping is always annoying. Of all the ifs that get your goat, clamping is probably one of the worst ones
What I like the most about your last solution is how by modifying the static input you got a more elegant expression
@U1EP3BZ3Q mind if I post a (slightly modified version) of this on Twitter and mention you?
@U7PBP4UVA sure!!! don't forget about mentioning the rest of people from this thread, a lot of contribution to the final result
https://twitter.com/orestis/status/1509553038268243976?s=20&t=7dRpv3LCfTpwItn6liaWaw
We were so preoccupied with if we could, we didn't stop to consider if we should.
Fantastic thread and go @U1EP3BZ3Q and clojure for getting this down to 102 chars! :punch:⛳Somewhat unintuitively I think code colfing actually tends to teach you things about both the language and the problem domain.
I think we can squeeze a little more out - a vector is a function, so (vec " ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁")
is equivalent to #(nth " ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁" %)
and 3 characters shorter. We just need to push the mod
onto the iterate
thus: (apply str (take 5e3 (map (vec " ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁") (iterate #(mod (+ % (rand-nth [-1 1])) 16) 0))))
comes in at 99 characters.
Hey, when working with the clojure cli, it looks like our polylith project is outputting no deps besides clojure and its dependencies when doing clj -A:dev -X:deps tree
, where the :dev
alias has all the actual dependencies of the project.
Is this a known behavior and I'm just missing something?
Or is that a bug?
It’s a misunderstanding of how this works
You're running the deps tree tool program and adding aliases to that program (which has no effect on the calculated classpath)
But you can do that too …
-Stree is run in your project classspath so the aliases are in effect
-Stree may eventually fade in prominence, the :deps tree continues to add more features
Thanks so much!
You'll need a pretty recent release of clj for that to work