This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-09-29
Channels
- # aws (8)
- # babashka (45)
- # beginners (83)
- # cider (23)
- # clj-on-windows (4)
- # cljdoc (23)
- # clojars (6)
- # clojure (68)
- # clojure-dev (33)
- # clojure-europe (75)
- # clojure-nl (1)
- # clojure-uk (4)
- # clojurescript (14)
- # conjure (6)
- # data-science (15)
- # datascript (7)
- # datomic (47)
- # docker (15)
- # events (1)
- # fulcro (4)
- # graphql (3)
- # jobs (4)
- # lsp (14)
- # nginx (2)
- # nrepl (2)
- # off-topic (41)
- # pathom (18)
- # pedestal (1)
- # polylith (72)
- # reitit (8)
- # reveal (1)
- # shadow-cljs (48)
- # tools-build (11)
- # tools-deps (24)
- # xtdb (8)
I'm learning clojure, and found a couple of sites with exercises supporting clojure. I feel like an idiot for spending a day digging through clj docs trying to find the most applicable core language features for the very first exercise, but I am definitely missing something.
The problem statement: Write a program that prints the temperature closest to 0 among input data. If two numbers are equally close to zero, positive integer has to be considered closest to zero (for instance, if the temperatures are -5 and 5, then display 5). Display 0 (zero) if no temperatures are provided.
I can get the value closest to zero this way: (reduce min (map #(Math/abs %) temperatures))
I can probably use (if (seq temperatures) (min ...) 0)
to guard against an empty seq.
However, this approach loses all negative values, which results in returning a positive integer even when all inputs are below zero. Does this mean I've tried to approach the problem incorrectly, or am I missing a functional idiom that could preserve the negative sign?
just messing around:
(def temps [-7 5 4 -8 9 -3 2])
(if (empty? temps) 0
(last (first (sort (zipmap (map (partial Math/abs) temps) temps)))))
made the abs vals the keys of a map & the values the temps, then sort the map, then grab first key,val pair, then the val
Math/abs being a java method is not something you can call partial on, you must using clojurescript?
That's an interesting direction to go in. Thanks for the neat idea.
I'm trying to "think functionally" for the solution which is why I arrived at the reduce, but I got stuck after that.
I haven't grokked monoid yet
The link about comparators should be good fodder for writing my-min if not exactly how to do that
It's okay, I don't understand either yet 🙂
I remember reading a bit about that.
For min, the identity value is something like positive infinity, I often use Long/MAX_VALUE
Right, of course
cljs version
(if (empty? temps) 0 (last (first (sort (zipmap (map #(.abs js/Math %) temps) temps)))))
yeah the java sort is O(n log n). agreed there is a more efficient approach
finally sat down to finish this and find out that this platform has broken boilerplate code throwing a NumberFormatException by trying to call Integer/parseInt
on the empty string.
Sorry, I don't understand what the implication of this link is meant to be.
You are comparing numbers with certain rules, the tool for comparing things are comparators, which is what that link is about. If you have a comparator that uses the order defined by your rules, then you can use it lots of other things
comparators ... i feel like that's a deeper java thing, maybe a few clear examples of wtf reduce is doing would be better for a beginner sure, you'll eventually want to make your own comparator but what am reduce? reduce is a magic fairy with 2 hands that starts with an initial value, does some operation on initial value and first value, and then stores the result as the new initial value, and "collapses" a collection two elements at a time until it's reduced to one value
Thanks, I get what reduce does, though I struggle to know when it's appropriate to apply
reduce
is appropriate whenever you need to “visit” every element of a collection in order to obtain a result. In practice, I don’t usually use it very often. Depends on the type of problems you’re solving. Often, there can be a simpler way to solve a problem via map
and/or filter
if you’re processing items one by one. But if you really need to check every item, reduce
is your friend.
If you need to go through every item of a collection in order to produce a side effect (send items to analytics, save to a database, etc), there’s run!
Which is basically reduce
🙂
(defn run!
"Runs the supplied procedure (via reduce), for purposes of side
effects, on successive items in the collection. Returns nil"
[proc coll]
(reduce #(proc %2) nil coll)
nil)
seemed perfect for this case
(defn assoc-email [m]
(assoc m :email (fetch-email (:user-id m))))
what would be an unsurprising name for this aasoc-email
function?My 2 cents: I probably wouldn't put it in a function on its own.
Assuming that there are other keys with trivial logic like this that you want to assoc to m
, I'd rather gather them all into an enrich-m
function.
Also what does m
represent? Something more specific, like user
would communicate intent better.
@UEQPKG7HQ, I used to think that user
would be a better name, but the way I interpret https://guide.clojure.style/#idiomatic-names, it seems m
would be preferred?
@U02DW53HCSE I don't think that the style guide suggests that it's idiomatic to name every map m
.
m
implies an arbitrary map. If you're writing a function that operates on generic data structures, it's idiomatic, sure. But in this particular example, m
represents an entity that has an email (from the context it seems like it's a user but I can't be sure).
And yes, you can't tell if user
is supposed to be a map or a collection or something else but that's what spec is for.
You should try to write your code in a pure fashion. Do this instead:
(defn assoc-email [m email]
(assoc m :email email))
Now the name you have makes sense. And in a higher level function you'd now coordinate the two:
(->> (:user-id user)
(fetch-email db)
(assoc-email user))
Argument order anyone? Could also use {:keys [m email]}
I'm really struggling with a java interop problem. I think because there are multiple implementations of an interface. I'm trying to use https://github.com/bbottema/rtf-to-html.
(ns zugnush.rtf2html
(:gen-class)
(:import
[org.bbottema.rtftohtml.impl RTF2HTMLConverterJEditorPane]
[org.bbottema.rtftohtml RTF2HTMLConverter]))
(.rtf2html (RTF2HTMLConverterJEditorPane.) "xx")
(.rtf2html (RTF2HTMLConverter.) "xx")
;; both no matching ctor
(RTF2HTMLConverter/rtf2html "xx")
(RTF2HTMLConverterJEditorPane/rtf2html "xx")
;; both no matching method
there are no public constructors, just a public static instance for you to use https://github.com/bbottema/rtf-to-html/blob/master/src/main/java/org/bbottema/rtftohtml/impl/RTF2HTMLConverterJEditorPane.java#L20-L22. It should be something like (.rtf2html RTF2HTMLConverterJEditorPane/INSTANCE "the rich text")
as in the readme:
RTF2HTMLConverter converter = RTF2HTMLConverterJEditorPane.INSTANCE;
RTF2HTMLConverter converter = RTF2HTMLConverterClassic.INSTANCE;
RTF2HTMLConverter converter = RTF2HTMLConverterRFCCompliant.INSTANCE;
String html = converter.rtf2html("RTF text");
I am coming from the same place - nearly no Java experience. I recommend you to find some really basic Java tutorial and try to do it in Clojure. It will help you to get basic Clojure / java interop really quick.
Is there a way for an anonymous function to reference itself to make multiarity nicer? (I'm trying to have an overloaded re-frame event that allows optional arguments. I'm currently doing this with a rest argument and just fishing out the relevant information from a map I supply there, but if possible I'd like to make it less janky.)
e.g. what would ? be here?
(fn ([some opts] (? some opts default-parameter))
([some opts optional-argument] (…)))
anonymouse functions can have a name (fn foo [] …)
and this name resolvable within functions’s body
(fn foo
([] (foo nil))
([arg] ...))
anonymous functions by definition do not have names 🙂 . but you can name a function expression
is it fine to create a core.async go
routine that ends up being blocked by a parking take forever? Or should these be closed?
(a/go-loop
[]
(let [thing (a/<! c)]
...)
(recur))
and c
at some point just doesn't deliver anything anymoreI see. I guess it is a common pattern to have a coll, (say a list of users) and fetching for each element something, in parallel. So I get a list of say emails or sth. Is this what pipeline
is for?
in the clojure core function select-keys
, what does (. clojure.lang.RT (find map (first keys)))
do?
or more specifically, what does the (. clojure.lang.RT
part do? the rest looks like a normal function call
(. clojure.lang.RT (find map (first keys)))
can be just
(find map (first keys))
cause i see in source code that find
is now defined as a clj func.right, that’s part of what’s confused me. i’m not sure what it’s doing in the algorithm
same with the find definition, why the call to clojure.lang.RT
?
ah, excellent. thanks for finding that
also the idiomatic interop syntax would usually be:
(clojure.lang.RT/find map (first keys))
(that expands to the (. class static-method ...)
version used here)
It is just a function call to the RT class, which is the internal Clojure runtime
if I’m implementing my own version of select-keys
that will skip nil values, do I need it? i would have written the line without that part
Hello dear friends! I have been doing https://exercism.org/tracks/clojure/exercises/elyses-destructured-enchantments exercise on exercism. The last exercise on destructuring made me sweat a bit. It is passing, but I was wondering if there is a way to be less verbose on insert-face-cards
.
The tricky part is a test that checked if we were return nil as the first element, when passed an empty vector to insert-face-cards
. I came up with the filter, but still a bit puzzled.
(ns elyses-destructured-enchantments)
(defn first-card [deck]
(let [[top-card] deck]
top-card))
(defn second-card
"Returns the second card from deck."
[deck]
(let [[top sec] deck]
sec))
(defn swap-top-two-cards
"Returns the deck with first two items reversed."
[deck]
(let [[a b & rest] deck]
(concat [b a] rest)))
(defn discard-top-card
"Returns a vector containing the first card and
a vector of the remaining cards in the deck."
[deck]
(let [[a & rest] deck]
(vector a rest)))
(def face-cards
["jack" "queen" "king"])
(defn insert-face-cards
"Returns the deck with face cards between its head and tail."
[deck]
(let [[a & others] deck]
(filter some? (into [a] (concat face-cards others)))))
you'll need the filter
to lose the nil
s but you don't need into
since you're already using concat
user=> (concat [1] ["a" "b" "c"] [2 3 4])
(1 "a" "b" "c" 2 3 4)
user=> (concat '(1) '("a" "b" "c") '(2 3 4))
(1 "a" "b" "c" 2 3 4)
Thank you both for the suggestions! 🙂