Fork me on GitHub
#beginners
<
2019-04-11
>
johnj03:04:12

don't know how I missed you could write a name spaced keyword like this :addr/addr šŸ˜‰

johnj03:04:11

local name and ns are the same (duh)

tabidots03:04:02

Iā€™m using Paredit for Atom. Is there a name for this operation? Take a sexp to the next higher level, outside of the current sexp. Canā€™t seem to do it with barf or slurp. Before (when (and (= 2 (degree pnml) (prime? p))) After (when (and (= 2 (degree pnml)) (prime? p))

seancorfield03:04:07

That's barf @tabidots -- you have lisp-paredit installed in Atom?

tabidots03:04:36

Yes, Iā€™m using lisp-paredit. Trying to figure out what the keyboard shortcut symbols mean is a nightmare though

tabidots03:04:35

Oh, I see. The cursor has to be in the sexp you want to barf from, not the sexp you want to move

emilaasa05:04:58

The sexp editing sentences read pretty funny even after a week of not doing Lisp šŸ˜ƒ

šŸ˜† 4
sooheon07:04:21

I want to read a bunch of rows from DB, do operations and insert results to another table. Some other cron job is inserting into first table so Iā€™ll have an endless amount of stuff to work on. Code looks something like:

(doseq [x (get-things-from-db)]
  (do-work-on x))
I want to make this start/stop with Mount along with the rest of my application. To make it stoppable, I thought about putting it in a future and calling future-cancel on :stop key. Is this the right way to approach this problem?

evocatus09:04:12

I feel sooo stupid - can't solve ProjectEuler exercize #3 (find some number prime factors) in Clojure for weeks. Could you give me some hints? I decided to create a lazy sequence of all prime numbers and then find the biggest prime factor of a given number (there is another way, I know - to divide the given number until it's 1)

evocatus09:04:47

The second function (primes) doesn't work

markx09:04:11

Hi folks, I have a question about how to orchestrate some core.async go blocks/threads. For example I want to build a simple telnet client like app. It has a connection, and a loop that constantly tries to read from the connection in a go block, and another loop which constantly reads input from stdin and then writes the input to the connection. The problem is, how do I cancel one loop from the other loop, like when I type ā€œctrl + cā€ I want to terminate the loop that reads from the connection, and terminate the loop that reads from stdin when the connection is closed.

Alex Miller (Clojure team)09:04:19

Well first, go blocks shouldnā€™t block on io, so use a loop in a thread instead

Alex Miller (Clojure team)09:04:23

To communicate between threads of control, you need a means of signaling, so make a control channel

markx09:04:03

Thanks for the quick reply. Is there some code example of this pattern you could point me to?

Alex Miller (Clojure team)09:04:30

Also note that Clojure has a built in socket server that does a lot of what you describe already

tabidots09:04:52

@gr.evocatus Rather than a sieve or lazy sequence, I found it easier to implement prime? as a primality tester, and use that as a filtering function. For example, (filter prime? (range 1 (inc 100))) gives me the primes from 1 to 100.

šŸ‘ 4
evocatus09:04:47

In order to check for primeness you need to try to divide this number by all prime numbers below it. Do you use some caching (explicit or implicit)?

tabidots10:04:40

I did not bother trying to divide by all prime numbers below n. I have a cond that tests whether n is <= 1, = 2 or even?, then loops through all odd numbers from 3 to sqrt(n) to test divisibility. Thatā€™s the naive fn. Then I memoized it.

tabidots10:04:14

I did also implement isqrt (integer sqrt) function with an algorithm I donā€™t understand (found on SO) to speed things up for very large n (like > 1E24)

tabidots09:04:38

You can get decently fast results even with this simple approach. Sieves and lazy-seq approaches to prime generation are certainly doable in Clojure, but are incredibly complex and nearly unreadable

markx09:04:03

Thanks for the quick reply. Is there some code example of this pattern you could point me to?

tabidots10:04:05

@gr.evocatus I couldnā€™t post a code snippet in the thread, but this is my implementation. If your n is smaller than 1E24-ish then tower/sqrt +1 or Math/sqrt +1 should work fine for the upper bound. btw, I tried refactoring the loop-recur with some, but itā€™s slightly slower

porksausages12:04:49

is there a standard function that drops non-unique values from a collection? like `=> (the-thing-i-want [1 2 3 3 4]) [1 2 4]`

porksausages12:04:50

I can't quite work out what to search in google to find what I want lol

manutter5112:04:07

(remove #(= 3 %) [1 2 3 3 4 5])
=> (1 2 4 5)

manutter5112:04:45

or you want to filter anything that appears more than once?

porksausages12:04:14

yeah i want to filter out anything that appears more than once while still keeping the same order of values if possible

porksausages12:04:35

looks like your snippet does that

porksausages12:04:52

oh wait no i see

manutter5112:04:55

Not quite, it only removes 3's

manutter5112:04:11

but itā€™s not too hard to write a fn that does what youā€™re saying.

yuhan12:04:13

do you want to remove non-consecutive repetitions?

yuhan12:04:34

so [1 2 3 2 4] => [1 3 4]

jthibaudeau12:04:55

you can use a set

yuhan12:04:25

my first thought would be to use frequencies

porksausages12:04:45

yeah me too but then how do i get the original order back

yuhan12:04:51

and then use the keys that are >1 to filter the original list

porksausages12:04:07

you're right that'll do it

dpsutton12:04:19

do you need to remove duplicates or consecutive duplicates.

dpsutton12:04:56

oh sorry. already discussed. there is distinct

porksausages12:04:54

dedupe doesn't remove the non-uniques entirely

porksausages12:04:08

it just makes everything appear once

dpsutton12:04:25

i think we got confused if consecutive was a part of this. i've never used dedupe. Love this channel'

porksausages12:04:29

sorry i'm probably explaining what i'm looking for badly lol

mloughlin13:04:07

(map key 
     (filter #(= 1 (val %)) 
       (frequencies data)))

yuhan13:04:23

huh, is that guaranteed to preserve the order?

mloughlin13:04:41

idk about a guarantee, but it does in my small tests

mloughlin13:04:45

what would you do to ensure it?

yuhan13:04:53

I tried it on a few small samples and was surprised that it did

mloughlin13:04:13

it doesn't work with a list as input

yuhan13:04:40

I couldn't find anything in the documentation that said frequencies would preserve order - it's probably an implementation detail that I wouldn't rely on

mloughlin13:04:54

my bad, it breaks when I increase the size of the input

mloughlin13:04:04

it treats list and vector the same way

yuhan13:04:31

I was thinking something along the lines of

(defn drop-repeated [xs]
  (let [to-drop (->> xs
                  (frequencies)
                  (filter #(> (val %) 1))
                  (keys)
                  (into #{}))]
    (remove to-drop xs)))

āž• 4
Alex Miller (Clojure team)13:04:26

just as an aside, (frequencies), (keys) here don't need parens around them - ->> will do that for you

Alex Miller (Clojure team)13:04:42

but some people like the way it reads better, so no big deal either way

Alex Miller (Clojure team)13:04:52

and (into #{}) could just be set

yuhan16:04:06

yup, I prefer the consistency of having everything wrapped in parens :)

yuhan16:04:40

Also come to think of it, I often use (into ***) instead of the plain constructor as a sort of idiom signalling that the collection type is being changed, not sure if there's any practical difference there

Alex Miller (Clojure team)16:04:20

isn't using set the same signal? (even better, it's basically a no-op, so faster, if it isn't a change)

Alex Miller (Clojure team)16:04:59

I view it as a statement assuring final type (and set / vec) are optimized for more special cases than into around this

šŸ‘ 4
yuhan17:04:55

Thanks! I didn't realise there would be a performance difference there - time to change some of those habits šŸ™‚

mloughlin13:04:02

that makes more sense

dpsutton13:04:06

frequencies returns a map which has no concept of order. as an implementation detail, it is ordered up to 8 i think and then switches to an unordered version. don't rely on this though

Alex Miller (Clojure team)13:04:13

you should consider it unordered and subject to change

porksausages15:04:55

is there a simple way to subtract a collection from another collection?

porksausages15:04:31

something like (remove '(2 3) '(1 2 3)) => (1) except actually works

manutter5115:04:34

(remove #{2 3} [1 2 3 4])
=> (1 4)

manutter5115:04:01

Just make the collection you want to remove into a set.

tolitius15:04:18

or

=> (require '[clojure.set :as s])
=> (s/difference #{1 2 3} #{2 3})
#{1}

porksausages15:04:10

oh jesus thats easy

yuhan17:04:52

another set-related question, does anyone know the name of this operation which takes a collection of overlapping sets and merges them into mutually non-overlapping sets?

yuhan17:04:30

I've been trying to google this for a while, can't seem to find a standard name or algorithm for it

hiredman17:04:44

because it sounds terrible

hiredman17:04:54

some kind of cross join

noisesmith17:04:14

sounds almost like clojure.data/diff or I might misunderstand completely

yuhan17:04:18

I'm thinking of it as unifying of equivalence classes

noisesmith17:04:50

user=> (clojure.data/diff #{:a :b :c} #{:c :d :e})
[#{:b :a} #{:e :d} #{:c}]

yuhan17:04:10

eg. [[a b] [c d] [a c] [e f]] => [[a b c d] [e f]]

yuhan17:04:30

(imagine hashset notation there, brackets are easier to type)

hiredman17:04:43

to do that you are going to have to iterate over all the sets multiple times, slowly merging them, and you will only know you are done when the output stops changing

yuhan17:04:34

yeah, I came up with an ugly pass at a solution that I'm pretty sure is O(n^2)

yuhan17:04:00

but it seems like there should be cleverer ways of doing it

hiredman17:04:42

the clever way is likely to not generate sets that you need to merge that way in the first place

hiredman17:04:01

maybe make a map of elements to sets of ids

noisesmith17:04:50

it's the subgraph algorithm in disguise, right?

noisesmith17:04:54

graph partitioning

noisesmith17:04:14

where two sets having an element in common is an edge

noisesmith17:04:52

that's where I'd look for a fast implementation, if any existed

yuhan17:04:22

oh nice, I didn't see it that way

hiredman17:04:29

{a #{0 2} b #{0} c #{1 2} d #{1} e #{3} f #{3}} has the same information as the sets in your example

yuhan17:04:00

@hiredman yup, but how do you extract the information of #{a b c d} out of that?

yuhan17:04:22

that's basically my problem- looks like graph partitioning is the direction to explore, thanks!

yuhan18:04:28

hmm, now learning that the graph partitioning problem is NP-complete, I'm very suspicious about my polynomial-time solution that I had before, even if it was quadratic.

dpsutton18:04:01

You can look into union find algorithm

dpsutton18:04:34

ah, but that will union the overlapping rather than separate them

noisesmith18:04:24

@qythium I worry that "partitioning" was imprecise here, because most graph partitioning is about finding edges to remove in order to create a subgraph, not detecting already distinct subgraphs

noisesmith18:04:37

the latter, what you need, is a much less complex task

noisesmith18:04:50

what you want, I think is "find all mutually vertex disjoint subgraphs" - the hard part is wading through the interesting and harder algorithms to find that simpler one I think

šŸ¤Æ 4
yuhan18:04:12

That's good to know - I'm unfamiliar with most of this graph theory stuff

yuhan18:04:27

here's my current implementation if anyone's interested to take a look:

(defn merge-sets [sets]
  (loop [reacted         #{}
         [s & unreacted] sets]
    (if-not s
      reacted
      ;; react the first unreacted set with the already reacted ones
      (let [reacted*
            (loop [acc      #{}
                   reacting s
                   [r & rs] reacted]
              (if-not r
                (conj acc reacting)
                ;; if r shares an element with the set being reacted
                (if (seq (set/intersection reacting r))
                  ;; merge them
                  (recur acc (set/union reacting r) rs)
                  ;; ignore it
                  (recur (conj acc r) reacting rs))))]
        (recur reacted* unreacted)))))

(merge-sets '#{ #{a b} #{c d} #{a c} #{e g f} })
;; => #{#{e g f} #{a c b d}}

noisesmith18:04:21

what would it do for #{{a b} #{b c} #{d e} #{e f} #{g h} #{h i}}

noisesmith18:04:08

I don't think that code could generate #{#{a b c} #{d e f} #{g h i}} which I think is the answer?

yuhan18:04:28

yup, it does:

(merge-sets '#{#{a b} #{b c} #{d e} #{e f} #{g h} #{h i}})
;; => #{#{e d f} #{i g h} #{a c b}}

noisesmith18:04:41

oh! I misread the code, nice

yuhan18:04:08

the idea is that the "reacted" sets are always guaranteed to be disjoint