Fork me on GitHub
#beginners
<
2018-12-02
>
potetm01:12:41

@kwcharllie379 I think the proper answer here is a/merge

potetm01:12:07

Ah, but you say you don’t care about the res

potetm01:12:28

for that I’ve written my own wait-for-finish

potetm01:12:41

based on a/merge

Daouda01:12:30

i need to send back the result

Daouda01:12:41

and look like that is not being done

Daouda01:12:55

i am struggling here to make it work no success

Daouda01:12:59

hehehehehe

potetm01:12:30

@kwcharllie379

(defn wait-for-close!
  "Returns a chan that will close after all supplied chs
  close.

  Any values returned by chs are dropped."
  ([chs] (merge chs nil))
  ([chs]
   (let [out (chan)]
     (go-loop [cs (vec chs)]
              (if (pos? (count cs))
                (let [[v c] (alts! cs)]
                  (if (nil? v)
                    (recur (filterv #(not= c %) cs))
                    ;; drop returned values
                    (recur cs)))
                (close! out)))
     out)))

😮 4
❤️ 4
potetm01:12:48

it’s basically the same as a/merge except it doesn’t produce any values on out

potetm01:12:18

@quieterkali You’ve been at it a while. My first suggestion is a little sleep 😉

Daouda01:12:34

kkkkkkkkkkkkk

potetm01:12:44

If you just wanna make it work, I would do (doall (map get-users user-ids))

Daouda01:12:51

i took 1h break

potetm01:12:57

that will force evaluation

Daouda01:12:30

check my code please

Daouda01:12:59

can this return an array or vector?

Daouda01:12:10

collections?

potetm01:12:34

it returns nil

potetm01:12:43

because doseq always returns nil

Daouda01:12:45

hahahahahahahahaha

potetm01:12:08

so yeah I was thinking smth like this:

(defn get-profile-connection-suggestion
  [id]
  "Take an id and return list of the connection suggestion"
  (let [suggestions (frequencies (get-connections-not-connected-to-profile id))]
    (doall (map (fn [[user-id count]]
                  (get-profile user-id))
                (sort-by val > suggestions)))))

👏 4
Daouda01:12:12

don't know if i should laugh or cry

potetm01:12:20

I know this feel

potetm01:12:40

sorry I led you a bit astray 😕

Daouda01:12:54

not your fault

Daouda01:12:05

i need to learn more about clojure

Daouda01:12:56

i am newbie

Daouda01:12:44

but it's really pleasant to play around with clojure

potetm01:12:13

hopefully it starts to sink in soon

potetm01:12:25

there’s definitely a bit of a learning curve to clear early on

Daouda01:12:12

@potetm that did the trick 😄

Daouda01:12:21

working fiiiiiiiiiiiiiiiiiiiiiiiiiiiiiinnnnnnnnnnnnnnnneeee

bananadance 4
Daouda01:12:31

thank youuuu

potetm01:12:40

my pleasure 🙂

Daouda01:12:38

some day i will be do great clojure like you guys hahahaha

jumpnbrownweasel02:12:53

I really liked http://www.4clojure.com/ for learning clojure, especially the aspect of functional programming with immutable data structures which was something I'd never done before. I started with the easy exercises and just kept trying different approaches. This motivated me to think differently and I gradually got the hang of it. It's nice because you can go as slowly as you want and look at other people's approaches for comparison.

✔️ 4
potetm02:12:40

yeah it’s pretty great to get an encyclopedic knowledge of clojure

potetm02:12:04

I personally don’t like the constraints they give — makes it difficult to develop familiarity w/ idiomatic clojure

potetm02:12:18

but I did it after years of using clojure professionally so…

potetm02:12:23

not an average case I suppose 😛

jumpnbrownweasel02:12:07

I think I know what you mean. Learning to solve problems functionally is only one aspect. I have also started picking up the best practices, but you're right that 4clojure didn't help with that. I'm not sure what the best resource would be for that.

potetm02:12:39

Advent of Code is pretty great

Daouda02:12:48

take the best from all of them hahaha

potetm02:12:53

(you can also look at other people’s solutions)

jumpnbrownweasel02:12:46

Sounds worth trying.

ckiehl03:12:39

Could anyone point towards a few open source Clojurescript + Reagent projects that make for good studying? I'm trying to wrap my head around the patterns / common structures that I should be using with core.async

Daouda03:12:52

can anyone help me with function testing? i am a bit lost 😞

Daouda03:12:22

actually completely lost. first time i am trying to do

ckiehl03:12:50

What've you tried so far? ^_^

Daouda03:12:34

looking for how to use in my compojure-api project

Daouda03:12:43

clojure version: 1.8

Daouda03:12:18

what i get online is configuration setting for clojure 1.9

ckiehl03:12:11

Did you setup your project with leiningen?

ckiehl03:12:22

It should have made a test dir for you with an example test

ckiehl03:12:32

You can run the tests with lein test

Daouda03:12:29

yeah, it run

sova-soars-the-sora04:12:10

Hi, when i post a new comment I want to update the "child comments" entry for the selected parent post...

sova-soars-the-sora04:12:10

(swap! posts update-in pid [:comments] conj this-comment-map) .... makes sens?

sova-soars-the-sora04:12:01

@quieterkali slow and steady wins the race

👍 4
Daouda04:12:55

@sova hehehehehe, you right

sova-soars-the-sora04:12:12

do some every day and mastery will be yours

sova-soars-the-sora04:12:32

(whether that is clojure or basketball or metta/lovingkindness, that's up to you)

Martin07:12:36

I’m not quite understanding when-let binding and test. I’ve got:

(def dif (compare val arr))
    (when (nil? dif)
      ...)

Martin07:12:07

which I’d like to convert to something like:

(when-let [dif (compare val arr)]
  dif)

Martin07:12:46

does the binding have to be truthy for the binding?

Martin07:12:08

is it possible to seperate the test from the binding?

orestis07:12:33

Yes, the binding has to be truthy.

orestis07:12:44

What should the top-level expression return?

orestis07:12:31

In your first block, if dif is nil, then presumably you don’t need it bound to any name, right? You know it’s going to be nil.

orestis07:12:58

The second block says, if the result of (compare val arr) is truthy, bind it to dif and execute the following code, i.e., return dif. Meaning your second block can be replaced entirely with (compare val arr) but I guess this is not the whole picture 🙂

Martin08:12:31

thanks @orendon, I’ve ended up with this:

(loop [val (first arr) values arr]
    (if-let [dif (compare val arr)]
      dif
      (recur (first (rest values)) (rest values))))

Martin08:12:16

I want to compare every value to every other value in an array, stopping when I find some diff.

Martin08:12:50

compare will return nil until the correct dif is found

jaihindhreddy13:12:00

How do I go about implementing a circular mutable linked list in portable Clojure(script)?

jaihindhreddy13:12:20

This doesn't work:

user=> (deftype Node [^:volatile-mutable next value])
user.Node
user=> (def a (Node. nil 1))
#'user/a
user=> (def b (Node. a 2))
#'user/b
user=> (set! (.-next a) b)
Execution error (IllegalArgumentException) at user/eval7232 (REPL:1).
No matching field found: next for class user.Node

alexmiller14:12:04

When deftype makes mutable fields, they are private, to avoid making mutable objects

alexmiller14:12:56

this also follows from the “opinionated” design of defrecord/deftype: default to immutability, program only to interfaces

alexmiller14:12:37

if you want to build a mutable type object with deftype, also create an interface or protocol that exposes methods that a user would call to manipulate a mutable field

Logan Powell14:12:21

👋 Hi Everyone! I have a problem and I'm not quite sure what the root of it is. I have a function like this that works in development (i.e., the cache is kept alive across function calls), but when I compile it to javascript, the function never hits the cache (it calls callAPI even when the input is exactly the same). Is there something obvious that I'm missing here?

orestis14:12:12

Oh wow that’s not beginners material 🙂 If you don’t get a good answer here perhaps try also #clojurescript

Logan Powell14:12:52

Thank you for making me feel better. I feel like a beginner 😄

orestis14:12:27

Are you storing the output of spooler anywhere?

orestis14:12:00

I mean, you call it with the three channels but then throw the result away.

orestis14:12:44

Also, spooler supposedly takes one argument, but you are calling it with the three channels?

jaihindhreddy14:12:14

Yeah, I was wondering how it works in development.

jaihindhreddy14:12:32

spooler seems to take an argument and return a function that takes the three channels

Logan Powell14:12:35

Whoops, I'm still new at creating example snippets... corrected

👍 4
orestis14:12:22

Still not quite there:slightly_smiling_face: Shouldn’t it be ((spooler "API call") =I= =O= =E=)

orestis14:12:13

So the purpose of the spooler-returned function is just to kick-off the go block, right? I wonder if the entire thing just gets GC’ed for some reason, since you never hold a reference to the result of the function anywhere. I don’t know much about core.async, sorry.

Logan Powell14:12:30

Hmm... but wouldn't I get the same behavior in development and release?

Logan Powell14:12:53

It never gets garbage collected in development

orestis14:12:19

Yeah, development is a different beast on CLJS.

orestis14:12:27

I’m also a beginner there

Logan Powell14:12:45

It may be some javascript stuff, which I'm even more a beginner at

Logan Powell14:12:07

I'm confused why it work until it's in JS land

Logan Powell18:12:48

Got it working!

orestis20:12:17

Cool, what was the issue in the end?

nikola14:12:53

How is

(contains? [0 3 6 10 8] 4)
equal to
true
?

orestis14:12:06

I had literally the same question when I started 🙂

☑️ 4
nikola14:12:52

I choose the data structure poorly, instead of a vector, I can use a set

orestis14:12:39

Yeah, sets are immensely useful.

peter-kehl14:12:14

What do we call the stack-like scope of (binding [dyn-var value...] body)? It's more than stack, because it applies to lazy sequiences, too. Would you call it a "dynamic scope," or do we have a better term?

Chris14:12:03

@peter.kehl pretty sure that’s dynamic scope (as opposed to lexical scope, which is the norm)

nikola14:12:09

how can I measure the time it takes for a function to execute in REPL?

nikola14:12:34

or compare different implementations

Chris15:12:06

Off the top of my head I think it’s just (time (my-function))

nikola15:12:31

awesome, will check

sova-soars-the-sora15:12:49

Hi, I'm trying to work on my nested comment render-er. so far so good. i can now post a comment and have the atom get updated and re-rendered right away with rum/react but I am curious now, how can I update the atom to tell the parent element that the new comment is a child? My data looks like

(atom {77 
                      {:id 77, 
                       :contents "Seventy seven is the nicest number below one hundred", 
                       :author "", 
                       :comments [33 53]},
and I'd like to inject a new value into :comments... say :comments [33 53 78] now. What's the right way to do that with swap! ?

jumpnbrownweasel15:12:33

Have you tried update-in with conj?

sova-soars-the-sora15:12:05

i'm confused because i want to use a new way to index each map in the atom (with the ID hanging outside as the key)...

sova-soars-the-sora15:12:41

How can I use reduce-kv to get the index of a particular element (:key val) match in my atom? I'm trying to do indexOf to then use assoc-in.

mfikes15:12:21

Can you give a small example of what your data looks like?

mfikes15:12:41

Oh, I see it is above.

sova-soars-the-sora15:12:41

Yeah actually I just had a vector of maps called posts [ {:id X :comments Y :author Z} {:id, :com, :aut} {} {} {} ...]

sova-soars-the-sora15:12:45

but under the recommendation of potetm, i'm moving toward making it posts [ 77 { :id 77 .. } 33 {:id 33 ... } 5 {} 9 {} ...] so that the indexing is fast, but then i'm not sure how to assoc-in ... there's no conj-in is there?

sova-soars-the-sora15:12:22

like i'd like to assoc-in posts [post-id :comments] comment-id but not assoc because that will overwrite, non?

sova-soars-the-sora15:12:59

maybe I can use update-in + conj?

mfikes16:12:14

Maybe give a very tiny actual data structure and what you want it to become. (It is difficult to piece together from above.) That way anyone can see exactly what you are saying.

mfikes16:12:27

I mean, I probably could figure this out, but after looking at the above for 30 seconds, I gave up.

sova-soars-the-sora16:12:32

right now i have two atoms and things are getting messy

sova-soars-the-sora16:12:56

the basic data structure is a collection of post-map s

sova-soars-the-sora16:12:10

But when I want to render a post, I was using filter on the :id ... now I am transitioning it to a map indexed by :id, but updating nested values in the atom is like huh.

mfikes16:12:22

Is this a valid minimal example of your data?

[{:id 1, :x "a"} {:id 2, :y "b"}]

mfikes16:12:41

Actually, I'm guessing this might be a better structure to talk about

[{:id 1, :x [3]} {:id 2, :x [5 7]}]

mfikes16:12:38

If so, is the question, given an id 2 and value 11, how do I turn this into the following?

[{:id 1, :x [3]} {:id 2, :x [5 7 11]}]

valerauko16:12:49

@sova wouldn't this work?

(let [posts [{:id 1 :contents "hoge"}
             {:id 4 :contents "fuga"}
             {:id 12 :contents "piyo"}]]
  (->> posts
       (filter #(= (:id %) 4))
       first))
; {:id 4, :contents "fuga"}

valerauko16:12:58

oh you want to update a post?

valerauko16:12:43

having id-indexed would definitely make things easier

valerauko16:12:46

you can then use update-in

valerauko16:12:12

(update-in posts [id :comments] conj new-comment)

valerauko16:12:34

without id-indexing you can use keep-indexed

valerauko16:12:43

(let [posts [{:id 1 :contents "hoge" :comments []}
             {:id 4 :contents "fuga" :comments [1 2]}
             {:id 12 :contents "piyo" :comments [4 5 6]}]
      first-hit (->> posts
                     (keep-indexed #(when (= (:id %2) 4) %1))
                     first)]
  (update-in posts [first-hit :comments] conj 42))

sova-soars-the-sora16:12:48

Thank you! tell me more about keep-indexed. I'm tempted to use 2 atoms to hold the state and that's bad.

valerauko16:12:30

i just learned about it myself as i was googling about your question so the docs are probably a better guide

sova-soars-the-sora16:12:41

cool. awesome. thanks for your help ^_^

👍 4
sova-soars-the-sora17:12:17

so... i can use keep-indexed to get a subset of results...

sova-soars-the-sora17:12:24

but why prefer this over filter? /newb

noisesmith17:12:42

filter has no way to provide the positional index of an item

sova-soars-the-sora17:12:21

oh. it gives positional index? nice! so i don't have to use reduce-kv & update-in... i can just use update and the index from keep-indexed?

valerauko17:12:31

think about it like this: filter gives you the value, keep-indexed (also) gives you the key

noisesmith17:12:49

keep-indexed also gives you the value

valerauko17:12:52

that's exacttly what the code i pasted above does

sova-soars-the-sora17:12:51

os loading music plays

sova-soars-the-sora17:12:14

tell me more about %2 and %1

mfikes17:12:29

It is a shorthand.

#(when (= (:id %2) 4) %1)
could have been written
(fn [idx id] (when (= (:id id) 4) idx))

jaihindhreddy17:12:49

@sova #() syntax is a reader macro, and it understands %1, %2 and so on as the first, second and so on args.

jaihindhreddy17:12:05

%& is for variadic args

sova-soars-the-sora17:12:37

seeing examples side-by-side really nails it in

sova-soars-the-sora17:12:58

Rock on! This is very goo

sova-soars-the-sora17:12:14

(keep-indexed ...) very nice for updating my parent comments' vectors

noisesmith17:12:30

for even more flexibility there's also (mapcat f (range) coll) - with keep you get to accept or reject each item, with mapcat you can accept, reject, or insert new items as needed

sova-soars-the-sora17:12:57

uh you can insert with mapcat?

sova-soars-the-sora17:12:18

let's get delirious with maps and keywords!

sova-soars-the-sora17:12:42

could i trouble you for an exmpl gratia?

noisesmith17:12:56

+user=> (mapcat (fn [idx el]                                                              
          (cond (zero? (mod idx 4))                                               
                [el el]                                                           
                (zero? (mod idx 3))                                               
                nil                                                               
                :else [el]))                                                      
        (range)                                                                   
        [:a :b :c :d :e :f :g :h :i])
(:a :a :b :c :e :e :f :h :i :i)

noisesmith18:12:08

for every input, mapcat can produce 0 or more outputs

sova-soars-the-sora18:12:13

return a vector of elements

sova-soars-the-sora18:12:06

i thought i was adding comment-ids to the parent's :comments field but apparently i'm adding them to the parents' parent... so comments are being rendered as the same level (not indented) as the parent

sova-soars-the-sora18:12:16

so i've got a little insect hanging out somewheres...

sova-soars-the-sora18:12:20

nevermind. the code is correct. the rendering is not.

nikola19:12:05

how can I convert a string like "ababaa" into a map like {:a 4 :b 2}?

nikola19:12:16

I can implement a very naive function that recurs over the string, but is there a smarter way?

mfikes19:12:08

@nikola.kasev (frequencies "ababaa") is very close

noisesmith19:12:13

frequencies plus the function that turns \a into :a

noisesmith19:12:25

(comp keyword str)

noisesmith19:12:51

user=> (frequencies (map (comp keyword str) "ababaa"))
{:a 4, :b 2}

mfikes19:12:21

cljs compatible ^ as well

nikola19:12:21

'frequencies` - I get, but (comp keyword str) - I still need to wrap my head around it. I know the str function, but what's the purpose of comp?

mfikes19:12:15

Compare with (frequencies (map (fn [ch] (keyword (str ch))) "ababaa"))

noisesmith19:12:18

comp takes functions and returns a function that chains them to an input in reverse order

noisesmith19:12:38

((comp f g h) x) is the same as (f (g (h x))

noisesmith19:12:49

notice f, g, h don't move, the parens do

dpsutton19:12:49

if you check (frequencies "ababaa") you will probably see the problem he is avoiding

rmprescott19:12:54

Do you really need a keyword here? The character itself might be just fine as the keys of the map.

nikola19:12:28

@rmprescott yeah, I can live with that

nikola19:12:46

@noisesmith so keyword is turning a character into a key how exactly?

noisesmith19:12:29

there's no such thing as a key - keyword is a function that takes a string and returns a keyword

noisesmith19:12:07

or, maybe we could say "in clojure anything is a key" - in (frequencies "ababaa") the chars are keys

noisesmith19:12:57

the useful things about keywords are that they evaluate to themselves, not some other value, and act as a key lookup when called as a function

nikola19:12:32

I was referring as a key in a map with key/values, so keywords are like atoms in other languages like Erlang, right?

noisesmith19:12:04

keywords are strings that can be called like functions, and you can't do string operations on them

noisesmith19:12:05

in most lisps (not clojure) atom means anything that isn't a collection

noisesmith19:12:17

I'm not sure what an atom is in Erlang

lilactown19:12:46

atom (Erlang/Elixir) is essentially what a keyword is (in Clojure)

4
noisesmith19:12:04

OK - question was edited after I answered so I'm deleting my answer

nikola19:12:46

your example is magic

nikola19:12:56

@mfikes your example is more understandable for a rookie like me, thank you both

noisesmith19:12:37

@nikola.kasev a search you can use to learn more about comp and how / why it is used is "point free programming"

noisesmith19:12:28

it's more common in eg. Haskell but Clojure has some facilities for it, and often a point free solution is clearer (once you understand the constructs and how they are used)

mfikes19:12:10

You may have seen it in math class as well. (fg)(x) = (f (g (x))

4
nikola19:12:31

I recognize it from Elm where your example would be h x |> g |> f if I'm not mistaken

noisesmith19:12:32

right, comp is a prefix version of ∘

noisesmith19:12:48

@nikola.kasev we have -> which is remarkably similar to that (-> (h x) g f) is a macro that expands to (f (g (h x)))

noisesmith19:12:24

reversing the order comp uses, and it's not as refactorable / first class as comp

noisesmith19:12:36

but also helps to make code much clearer

mfikes19:12:04

comp is important, because it is at the core of what this is really all about You want to use composable abstractions, and that's one really good aspect of FP. 🙂

lilactown19:12:50

I totally thought ∘ was a smudge on my screen

😂 4
mfikes19:12:03

Yeah, that comp symbol could use some love

Tim19:12:04

quick question, I have many vectors of vectors (rows) and want to turn them into a vector of columns, how can I easily do that? I tried (apply map into rows) but it fails as into only accepts 2 arguments.. :thinking_face:

noisesmith19:12:58

you want vec

noisesmith19:12:15

or (partial into []) which does the same thing less efficiently

noisesmith19:12:19

oh - reading the problem description, you actually want vector not vec or into

noisesmith19:12:51

user=> (apply map vector [[:a :b :c] [:d :e :f]])
([:a :d] [:b :e] [:c :f])

noisesmith19:12:34

or (def row->col (partial apply map vector))

Tim19:12:52

that works brilliantly, thanks so much!

Allan Araujo22:12:16

plumatic/schema users: how to define a schema that can contain any map?

enforser23:12:28

maybe something like {s/Any s/Any}

Allan Araujo23:12:10

i was looking for something like s/Map, but it looks like it doesnt'have one

Allan Araujo23:12:29

s/Any is good enough, anyway