Fork me on GitHub
Redbeardy McGee01:09:22

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?

Duane Bester01:09:08

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)))))

Duane Bester01:09:42

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?


The correct solution is very obviously a fold

Redbeardy McGee01:09:42

That's an interesting direction to go in. Thanks for the neat idea.


(reduce min ...) Is almost perfect


But min is operating with the default ordering of numbers

Redbeardy McGee01:09:53

I'm trying to "think functionally" for the solution which is why I arrived at the reduce, but I got stuck after that.


(reduce my-min identity-value ...)


Is what you want


Where my-min and identity value are monoid over your values

Redbeardy McGee01:09:16

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


A monoid is not a monad to be clear

Redbeardy McGee01:09:00

It's okay, I don't understand either yet 🙂


A monoid is a function that is really useful with reduce


+ has an identity 0 (x+0=x)


So you can write (reduce + 0 [1 2 3]) and it will work

Redbeardy McGee01:09:03

I remember reading a bit about that.


For min, the identity value is something like positive infinity, I often use Long/MAX_VALUE


The min of x and Long/MAX_VALUE is in practice often x

Redbeardy McGee01:09:08

Right, of course

Duane Bester01:09:23

cljs version

(if (empty? temps) 0 (last (first (sort (zipmap (map #(.abs js/Math %) temps) temps)))))


With a complexity of n^4 or something


Where a fold will do it in n


(sorting is n^2, zipmap is n, last is n)

Duane Bester02:09:55

yeah the java sort is O(n log n). agreed there is a more efficient approach

Redbeardy McGee05:09:55

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.

Redbeardy McGee01:09:57

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


sort, sorted-set, etc as mentioned in that link


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

Redbeardy McGee06:09:06

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)

😄 4
Redbeardy McGee06:09:17

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?


ensure-email ?

👍 1

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.

Johan Thorén09:09:47

@UEQPKG7HQ, I used to think that user would be a better name, but the way I interpret, 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))

👍 3

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


(ns zugnush.rtf2html
   [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 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");


Thanks. My java's not good.


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


Ah I didn't know that. Thank you very much both of you :)


(let [f (fn give-it-a-name
          ([] (give-it-a-name :foo))
          ([arg] arg))]


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?

      (let [thing (a/<! c)]
and c at some point just doesn't deliver anything anymore


if you know that input is done, that channel's producer should close it


I 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?


generally yes - you can look at pipeline-async


but it's not tying up a thread while waiting

Noah Bogart19:09:34

in the clojure core function select-keys , what does (. clojure.lang.RT (find map (first keys))) do?

Noah Bogart19:09:56

or more specifically, what does the (. clojure.lang.RT part do? the rest looks like a normal function call


java interop


runtime probably


(. 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.

Noah Bogart19:09:30

right, that’s part of what’s confused me. i’m not sure what it’s doing in the algorithm


source code is there if you want to look it up the algo.

Noah Bogart19:09:24

same with the find definition, why the call to clojure.lang.RT?


find was probably added later.

Noah Bogart19:09:43

ah, excellent. thanks for finding that


also the idiomatic interop syntax would usually be:

(clojure.lang.RT/find map (first keys))

👍 1

(that expands to the (. class static-method ...) version used here)

Alex Miller (Clojure team)19:09:03

It is just a function call to the RT class, which is the internal Clojure runtime

👍 1
Noah Bogart19:09:55

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

George Silva20:09:18

Hello dear friends! I have been doing 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]

(defn second-card
  "Returns the second card from deck."
  (let [[top sec] deck]

(defn swap-top-two-cards
  "Returns the deck with first two items reversed."
  (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."
  (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."
  (let [[a & others] deck]
    (filter some? (into [a] (concat face-cards others)))))


you'll need the filter to lose the nils 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)

George Silva14:09:48

Thank you both for the suggestions! 🙂


Is the a the only thing that's actually going to put a nil in the results of insert-face-cards? If so you might also be able to write that as (concat (when a [a]) face-cards others)