Fork me on GitHub
Yehonathan Sharvit08:09:05

A question related to def. Could you explain in simple words why calling defining twice the same variable is not prevented by Clojure?


@viebel isn’t that the idea behind reloadable code?

Yehonathan Sharvit09:09:37

@borkdude Yes. But it confuses beginners when we say that Clojure on one hand encourages immutability and on the other hand allows you to redefine what is already defined


it has to do with the REPL workflow. this is the first thing a beginner should learn.


if you don’t want reloading of defs, you should use defonce

Yehonathan Sharvit09:09:43

Do you have good material about: 1. the importance of REPL workflow 2. The details of REPL workflow


@viebel using def isnt exactly an assignment like other languages. its like a binding that gives a name to a memory location.

(def value 5)
(def value (+ value 1))
this case doesnt really mutate value. a completely new memory location with the value of 6 is allocated and is now called value again. so yes clojure is still immutable even with multiple defs on the same name.


that’s also a way to look at it, but fundamentally vars are mutable, e.g. you can call alter-var-root on them


correct. but i guess that is not advisable?


depends 🙂

Yehonathan Sharvit10:09:14

@rahul080327 @borkdude What is the fundamental difference between def and alter-var-root beside the fact that the latter is atomic and apply to its current value?


@viebel I think as lispyclouds pointed out, when you re-def something with the same name, the old var isn’t re-used

Yehonathan Sharvit10:09:34

But what is the difference between not reusing the old var and creating a new var with the exact same name?

Yehonathan Sharvit10:09:00

In both cases, the value is not modified


compare to defining a new atom or mutating the contents of an atom

Yehonathan Sharvit10:09:08

I think that both def and alter-var-root don’t modify the content


by defining a var you mutate the state of the runtime


I don’t know the exact implementation of def, it could be that it reuses the old object


seems to be the case, no?

(def a 1)
(def b #'a)
(identical? (var a) @(var b))
(def a 2)
(identical? (var a) @(var b))


yes, it’s even in the docstring:


> Creates and interns a global var with the name of symbol in the current namespace (ns) or locates such a var if it already exists.


but to come back to mutation: the value that is referred to by the var isn’t mutated, like the value in an atom is not mutated, but replaced. but you could say the var itself is mutated

Yehonathan Sharvit10:09:57

@borkdude did you mean (identical? @(var a) @@(var b))?


yes, i'd like to think of it as changing the value associated by the name. def for me is an explicit naming of a value where as using atoms or alter-var-root gives us a feel of in place mutation regardless of their actual implementations


@viebel no, I was comparing the var objects, not the thing inside the var objects


but to make it simple: Clojure has a couple of mutable cell references: vars, atoms, refs and agents. vars are designed to be mutable.

Yehonathan Sharvit11:09:08

Both the vars are identical and the values. The same happen if we do (alter-var-root #'a inc)


yes, it seems alter-var-root has the same effect as re-deffing

Denis G11:09:42

I have a vector of numbers, like [2,3,5] Need to create a sorted sequence of (distinct, nice to have) it's multiplies (dunno how to express it better) But the result I want is → [2,3,4,5,6,8,9,10,12,14,15, ...] Would like an infinite sequence



(sort (distinct [1 4 2 3 4 2 5 5]))

=> (1 2 3 4 5)

Denis G11:09:15

but I want the multples, like multiplying iterate with this sequence, take the distinct and sort them

Denis G11:09:56

meaning [2,3,5, 2*2, 2*3, 4*2, 3*3, 2*5, ...]


I’m not sure I understand, what do you mean by multiples?


Do you mean, you want to take [2 3 5] and get all possible multiplications of those numbers?

Denis G11:09:55

@borkdude for me for sure 😄 actually solving this problem:;playlist_slugs%5B%5D=interview-preparation-kit&amp;playlist_slugs%5B%5D=search And was thinking of doing something like this, since this would make solving the problem easier

Denis G11:09:11

> Do you mean, you want to take [2 3 5] and get all possible multiplications of those numbers? exactly. in sorted order, distinct only


so it’s an x-y problem

Denis G11:09:46

what does this mean? 😄


but it’s an interesting subpuzzle 😉

Denis G11:09:31

@borkdude but still interested in this, even if this is a wrong approach exactly 😄

Denis G11:09:15

@borkdude so iterate/range and then filter


I’m not sure what the formal problem is. Each number in this range is the product of either, 2, 3 or 5?

Denis G11:09:55

sounds much more simpler than multiplying then sorting then distinct 😄


so 7 is not one of those

Denis G11:09:54

all modulos should be zero


and 8 is, because 2^3. 9 is because 3^3, 10 is because 2*5, etc.


^ means power


good luck 😉

Denis G11:09:13

thanks 🙂


… machines that take [2, 3, 2] days to produce an item. I.e., they produce [1/2 1/3 1/2] items per day. So they produce 1 1/3 items per day. Number of items modulo that, right?

Denis G11:09:07

number of items modulo speed what about this e.g. [5 and 10], target is 2, won't your answer be 7.5/8 days or smth since at 8 the first machine will do 0.6 and machine 2 will do 0.8 amount of work


Yep, you’re right. Only whole items count, so that’s a no-go.


(def speed 2)

(def prod (let [xf (comp (map inc)
                         (map #(mod % speed))
                         (map-indexed vector)
                         (filter #(-> % second zero?))
                         (map first))]
            (sequence xf (range))))

(take 10 prod)
=> (1 3 5 7 9 11 13 15 17 19)


Day 1, 3, 5 and so on for speed 2?

Denis G11:09:08

I guess range and filter doesn't sound so good, since machines can be up to 10^9 to go through all of them for every i in range

Denis G11:09:30

what does speed mean?


2 days to produce 1 item.


But seqs are lazy, so drop + take should let you iterate through an arbitrarily long sequence without blowing a giant hole in your memory.


Nah, I’m not sure.

Denis G11:09:52

A guess I can use a priority_queue or smth. Popping the day and multiplier of that day. Then looking at day-machines-map subtracting items to do by the day-machines-map[day] length and then insert the day with new multiplier priority-queue should work on day * multiplier or smth dunno

Denis G11:09:37

This is not really a clojure problem, sorry for spamming. Normally I try to solve problem in Python, then do a Clojure version


@denisgrebennicov I notice there is also a #puzzles channel. And if you would like, there will probably more activity around puzzles in #adventofcode around December.

metal 1

Drop map first and filter and you get a sequence of vectors where the first item is the day, and the next is number of items produced that day.

(def speed 2)

(def prod (let [xf (comp (map inc)
                         (map #(mod % speed))
                         (map-indexed vector))]
            (sequence xf (range))))

(take 10 prod)
=> ([0 1] [1 0] [2 1] [3 0] [4 1] [5 0] [6 1] [7 0] [8 1] [9 0])
Make three of these for speeds 2, 2, and 3, and you could easily loop over all three, adding the number produced that day until the desired number of items are reached. I think.

Denis G12:09:12

Thanks. But if speed is dynamic array coming at runtime


For lazy sequences, you’re never holding the entire thing in memory at any one time. They are only computed when they are realized. (range) is infinite. But by doing (take 10) I’m only considering 10 of those.

Denis G12:09:08

The problem is about speed being constant in this case and not dynamically set as an array/vector/seq

Yehonathan Sharvit12:09:53

A philosophical question: Is it expected that (= [1 2] '(1 2)) ?


Probably because it simplifies a lot of code

Yehonathan Sharvit12:09:16

You mean code inside Clojure itself or inside apps written in Clojure?


Definitely, code written using Clojure


would be a good one to add to the faq:


Likewise, hash intentionally produces the same value


Is there a better way to achieve (assoc response :headers (merge (:headers response) {:a 1 :b 2}) )?

Yehonathan Sharvit12:09:41

@mfikes Indeed it makes sense to consider that (= (map inc [1 2 3]) '[2 3 4]) although (map inc [1 2 3]) is a lazy sequence


(update response :headers merge {:a 1 :b 2})

👍 1
Denis G12:09:58

@viebel there is identical? when you need the pointer/object reference comparison. But = operator does make sense, since content inside is the same

Yehonathan Sharvit12:09:03

@denisgrebennicov identical? is very dangerous/tricky. For instance (identical? [1] [1]) is false


that's because they're two different vectors in memory. it's expected


it works as equality for a small number of lists though 😛

(let [a '()
        b '()]
    (identical? a b))


The abstract nature of = also applies to numbers

Yehonathan Sharvit12:09:40

What do you mean @mfikes by the abstract nature of =?


For collections, there are “equality partitions” - sequentials, sets, and maps.


All sequential collections compare = (vectors, lists, sequences)


This is essential when working with a mix of collections and sequences


After years of reflection on it, I think that equality working over all sequential collections was a brilliant and non-obvious design choice

👍 2

I have an article on the main ideas, and a few subtleties, of Clojure's = and hash implementations, here:

Yehonathan Sharvit07:09:51

@U064X3EF3 can you share some examples of the advantages of this non-obvious design choice? When I teach Clojure to beginners, and show them that (= [1 2] '(1 2)) is true, they find it very surprising. And indeed, when you put it out of any application context, it is surprising. But when you think about in the context of an application, it starts to make sense: you don’t want to find yourself in a situation when [1 2 3] is not equal to (map inc [0 1 2]) just because map returns a lazy sequence. Do you see it the same way?

Yehonathan Sharvit12:09:54

How does it apply to numbers?


Digging up my copy of Clojure Programming, which has a great section on the subject

Yehonathan Sharvit13:09:22

even == present some surprises:

(not (== (+ 0.1 0.2) 0.3))
(== (+ 0.2 0.3) 0.5)


Yeah, that’s IEEE 754


Related to that

(+ 0.1 0.2 0.3)
needs to associate from the left 🙂 It would be incorrect for Clojure or ClojureScript to effectively do
(+ 0.1 (+ 0.2 0.3))


Oh, right, you need to use ==. Perhaps the docstring for = is incorrect.


how do i express dependent relationships between components of a tuple spec? say I need a tuple of two strings such that the first one has the same characters as the second one


(let [[a b] ["foo" "bar"] (= a b)) ?


@borkdude I want to express this in spec parlance for tuples


(s/tuple (s/coll-of ::public-key) (s/coll-of ::private-key) ???such that each private key corresponds to a public key??? )


You can s/and any arbitrary predicate onto that coll-of spec

👍 1

yes but how do i capture the public-keys in a symbol?


(s/valid? (s/and (s/tuple string? string?) (fn [[a b]] (= a b))) ["a" "a"])

✔️ 1

sorry, didn’t read the thing about public key yet


but should work similarly


huh! I see, thx


@denisgrebennicov This is fun to tinker with! Thanks for the puzzle. It certainly takes time to calculate the production day for a billion items on my poor laptop, but it doesn’t use much memory at all.


okay, great, I'll take a look!


@U250T6MFA table/column or class/method is a good starting point, you'll figure the paterns soon enough, and Datomic gives you enough flexibility to recover from your mistakes


@U250T6MFA +1 for table/column. You will be able to figure this out as you go. Just get started.


In addition to table/column, I like to think about the schema as an attribute catalogue that I can use to create entities. So don´t worry about having ALL possible attributes upfront. Just add the minimal attributes your domain needs and follow the best practices

Denis G15:09:24

@henrik you are welcome hahahah 😄 Obviously time is also very crucial here. (For this kind of hackerrank challenges) But a solution is better than no solution 😉


@denisgrebennicov Yeah, the final reduction can be easily done in parallel I think. I wonder if something like Neanderthal could take care of it.

Denis G17:09:24

@henrik actually the solution to their problem was really "cheap". I didn't expect somethign like this They just do binary search, since they know the input constraints Then for every mid point they compute, they sum all the products that can be done for every machine and check for the goal/items to produce if it is more or less than the given val 😞

👍 1
Denis G17:09:44

but obviously your solution is cool. much more complex though 🙂

Denis G17:09:11

Sample solution:

def minTime(machines, goal):


    low_rate = machines[0]
    lower_bound = (goal // (len(machines) / low_rate))
    high_rate = machines[-1]
    upper_bound = (goal // (len(machines) / high_rate)) + 1

    while lower_bound < upper_bound:

        num_days = (lower_bound + upper_bound) // 2
        total = getNumItems(machines, goal, num_days)
        if total >= goal:
            upper_bound = num_days
            lower_bound = num_days + 1

    return int(lower_bound)

def getNumItems(machines, goal, num_days):

    total = 0

    for machine in machines:
        total += (num_days // machine)

    return total


reduction in parallel, that reminds me of


Hi. I am trying to "flatten" an xml tree while adding a depth count to some nodes. I've considered prewalk or xml-sec but it seems they won't help as they use one element at a time. My plan now is to use something like loop [z zipper result []] over an xml-zip to copy nodes out and use (count zip/path) where needed. Is there a more idiomatic approach?

Eccentric J16:09:55

Hello so a coworker has expressed interest in learning programming. I would love to introduce them to Clojure but I’m concerned it might not have a lot of educational content aimed at absolute beginners like Python currently has. Is there any resources that come to mind that would introduce absolute beginners to Clojure?


ClojureBridge curriculum maybe?


Kyle Kingsbury wrote a fine introduction that doesn’t assume any background knowledge a few years back:

Eccentric J17:09:29

Thanks, I’ll look into those!


is it possible to start a clojurescript repl in cursive using boot?


(defn- generate-lein-project-file! [& {:keys [keep-project] :or {keep-project true}}]
  (require ')
  (let [pfile ((resolve ') "project.clj")
        ; Only works when pom options are set using task-options!
        {:keys [project version]} (:task-options (meta #'boot.task.built-in/pom))
        prop #(when-let [x (get-env %2)] [%1 x])
        head (list* 'defproject (or project 'boot-project) (or version "0.0.0-SNAPSHOT")
                 (prop :url :url)
                 (prop :license :license)
                 (prop :description :description)
                 [:dependencies (conj (get-env :dependencies)
                                      ['boot/core "2.6.0" :scope "compile"])
                  :repositories (get-env :repositories)
                  :source-paths (vec (concat (get-env :source-paths)
                                             (get-env :resource-paths)))]))
        proj (pp-str head)]
      (if-not keep-project (.deleteOnExit pfile))
      (spit pfile proj)))

(deftask lein-generate
  "Generate a leiningen `project.clj` file.
   This task generates a leiningen `project.clj` file based on the boot
   environment configuration, including project name and version (generated
   if not present), dependencies, and source paths. Additional keys may be added
   to the generated `project.clj` file by specifying a `:lein` key in the boot
   environment whose value is a map of keys-value pairs to add to `project.clj`."
 (with-pass-thru fs (generate-lein-project-file! :keep-project true)))
I added this snippet from the For Cursive Users section of the boot docs


It seems successful for generating a clojure repl. But I can’t figure out how to get it create a clojurescript repl


that really depends on the kind of repl you want. Usually it's going to be a piggybacked REPL, where a clojure repl is started, and some function starts a cljs repl on top of that connected to a browser via websocket (this is how figwheel does things for example - the java side code recompiles, and sends to the browser, and the cljs repl operates via a websocket on top of that process)


Guys Sente is insanely nice.


Anyone tried to run it at a big scale? Thousands of clients


what I ended up needing was a "bounce channel" that propagated async results so that the client could still get them if they reconnected and load balanced to a different server


I didn't have thousands of clients, but a heavy enough app with enough clients to require multiple servers with load balancing


the tl;dr of the design is that for any delayed result, you need a way to get that result to the server that that client is currently talking to (or accept that that flow of data breaks if they find a new server)


Thank you for the insight @U051SS2EU 👍


Is hara.event the conditional restart library no longer supported?


I cannot even find the documentation for the library.


the github appears to have been taken down


the author got fed up with clojure at some point (wrote a big blog post about it) and may still feel that way?