Fork me on GitHub
Neil Barrett01:02:39

Since into requires the input channel to be closed before it produces a result, and to-chan does indeed close the channel that it creates, the result is as expected.

(<!! (into [] (to-chan (range 10))))
;; => [0 1 2 3 4 5 6 7 8 9]
On the other hand, closing c explicitly produces a result that I didn't expect:
(def c (chan))
(onto-chan c (range 10) false)
(close! c)
(<!! (into [] c))
;; => [0]
If c has a buffer of length at least 10, then the result is the same as that above. What am I misunderstanding here?

Neil Barrett01:02:43

I guess that to-chan creates a buffer of the length required by the collection, whereas the pending puts onto c are discarded. I would then expect the second variant to produce [].


(chan) acts as a rendezvous point so one adding a value (`0`) onto it parks, then you close it, then you read from it, which picks up the parked 0, and then it's a closed channel.


If you use (chan 1), you actually get two values out of it:

user=> (def c (chan 1))
  #_=> (onto-chan c (range 10) false)
  #_=> (close! c)
  #_=> (<!! (into [] c))
[0 1]


(for the same reason)

Neil Barrett02:02:47

Got you - subtle stuff!


core.async is tricky.

Neil Barrett02:02:27

I'm still a hobbyist and haven't used it in any project yet, but I'm really excited by its potential.


onto-chan pours some values into an existing channel. Your call to onto-chan returns immediately and the pouring happens in the background (subject to the flow of the channel that you're pouring into) the close! call closes the destination channel of that background pouring process.


since you used a rendezvous chan (an unbuffered channel), the pouring process is going to be driven by the takers on the destination channel the 3 calls to 1) launch the background pouring (onto-chan), 2) close the channel, and 3) launch the async/into process - those call proceed rapidly in succession


This question was asked in the wrong channel and removed: > in rich4clojure. I press the atl+enter key and the tests fun return nil. how can i know its pass or fail Reposting it here to be able to provide an answer. 😃 I'm assuming this is a problem when running Rich4Clojure locally (as opposed to the GitPod option). The solution is to first load dev/repl.cljc, to initialize the testing facility. It's mentioned here:

👍 1

Note to self: I should probably add some note about that to the first problem(s).

quan xing09:02:53

thanks. I got it:smile:

quan xing09:02:31

I found studying Clojure is so hard. 😭


We (I think I can speak for the community here) really want to make it easier! We have a channel for it: #improve-getting-started Please don't hesitate to post there about what makes it hard for you and if you have ideas what would make it easier.

💯 1

Have you found my attempt to help with this, btw?

quan xing00:02:37

thank you very much


Is there a core fn to change from [{:name "Foo" :value 1}, {:name "Bar" :value 2}] to {"Foo": 1, "Bar": 2}?


On my phone so haven't tested it but something like this should work: (into {} (map (juxt :name :value) coll))


awesome, that worked 🙂 TIL about juxt

🎉 1

juxt is amazing! It's one of my favorite core functions

👋 1
Thomas Segura14:02:27

Hi fellow Clojurists, I’m struggling to understand how to compose predicates with the every-pred, especially how to explain why an execution error in thrown here:

user=>((every-pred even? integer?) 4.99)
; Execution error (IllegalArgumentException) at ghostly.core/eval7861 (form-init12829955687297635352.clj:100).
; Argument must be an integer: 4.99


you are doing it correctly. even? is just a little picky. (even? 3.45) throws an error that its argument must be an integer


but you’l want to switch the order here


((every-pred integer? even?) 4.99) returns false.

David Pham15:02:21

In CojureScript, is it safe to use the namespace clojure.browser.dom or should it be considered as implementation?

👀 1
oxalorg (Mitesh)08:02:18

It's safe but I've rarely seen it use anywhere. It's a part of history now and no updates have been made to it. I think it might be better to just use goog.dom directly, but I would go a step further and say if you don't really care about compat with IE11 and stuff just directly use js/... APIs.

Michael Stokley20:02:53

I would like to add a docstring to my multimethod. Are there conventions around this?


A multimethod has a single doc string, you can set with the defmulti that creates the multimethod


There is no place to hang a docstring for individual implementations

Michael Stokley20:02:28

thank you, that answers my question


Can specs have a docstring?


No, but it is one of the most-requested features.

👍 3

ah cool. I will use comments for now 🙂


you can also make your own table of {spec-kw-or-sym -> metadata} and store whatever metadata you want


docstring, related specs, author, hyperlinks


it just won't be directly integrated with clojure.spec's registry

Neil Barrett23:02:37

Another core.async misunderstanding! map is core.async/map and the example is a modification of the documentation.

(defn inc-async
  (let [ret (promise-chan)]
      (<! (timeout (rand-int 2000))) ;; Randomly sleep up to 2 seconds
      (put! ret (inc num)))

(def a (atom nil))

  (let [v1 (inc-async 1)
        v2 (inc-async 10)
        v3 (inc-async 100)]
    (reset! a (take! (map vector [v1 v2 v3]))))

Neil Barrett23:02:02

Why does @a return nil?


Look at the docstring of take!


(I’m not shouting)

Neil Barrett23:02:33

What about using <!?


Yeah that would change the result


put!/take! are asynchronous, intended for integrating with non-chan aware things


<! and friends are sync

Neil Barrett23:02:37

Using <! still returns nil


I'm getting

user=> @a
[2 11 101]


(using <!)


btw, take! takes two arguments

Neil Barrett23:02:10

That's weird - I'm using Clojupyter, but it also failed in Calva.

Neil Barrett23:02:37

I'll try a lein repl


failed or incorrect? did you deref after 2 seconds?


it will take potentially 2 seconds for the inc-async's to finish

Neil Barrett23:02:36

Surely map should block until all results are available?


map will block, but you might be dereffing the atom before the <! takes place


go blocks happen in a background thread

Neil Barrett23:02:36

Incorrect - still get nil - trying lein repl now

Neil Barrett23:02:04

Got you! Sounds good.


it's clearer for understanding to have the last statement of the go block be (<! (map ...)) then take from the go block (remember go blocks return a channel that yields their last expression)


rather than banging into an atom

Neil Barrett23:02:14

That's great - thanks so much


(def my-process (go (<! (map ....))) (<!! my-process)


fyi #core-async exists

Neil Barrett23:02:38

Works perfectly with that suggestion

Neil Barrett23:02:58

oh - didn't know


firing up a repl


I'm making slides in revealjs, and I want to do line-by-line animations. What's an idiomatic way to turn this:

[[:h2 "title"] [:p "some info"] [:li "an item"] [:li "another item"]]
into this?
 [:section {:data-auto-animate ""} [:h2 "title"]]
 [:section {:data-auto-animate ""} [:h2 "title"]
  [:p "some info"]]
 [:section {:data-auto-animate ""} [:h2 "title"]
  [:p "some info"]
  [:li "an item"]]
 [:section {:data-auto-animate ""} [:h2 "title"]
  [:p "some info"]
  [:li "an item"]
  [:li "another item"]]]
It's the "take 0, then take 1, then take 2" over and over that I am having trouble thinking of a function for


Thinking through it: The signature of the fn could be [title & items]


there's the boilerplate bit with the section and data-animate


and then uh...


(for [index (range (count items)] ...)


(defn animate [title & items]
    (for [index (range (count items))]
      (concat [:section title] (take index items))))


this might be getting there


REPL-driven development vs. Slack-rubber-ducking development


but I'm not sure this is going to splice(?) right into hiccup


(animate [:h2 "title"] [:p "2018"] [:li "23 employees"])
;; => ((:section {:data-auto-animate ""} [:h2 "title"]) (:section {:data-auto-animate ""} [:h2 "title"] [:p "2018"]))
those aren't vectors


and i'm off by one


(defn animate [title & items]
   (for [index (range (count items))]
     (vec (concat [:section {:data-auto-animate ""} title] (take index items))))])

(animate [:h2 "title"] [:p "quote"] [:li "item"] [:li "another"])
;; => [:section ([:section {:data-auto-animate ""} [:h2 "title"]] [:section {:data-auto-animate ""} [:h2 "title"] [:p "quote"]] [:section {:data-auto-animate ""} [:h2 "title"] [:p "quote"] [:li "item"]])]


Those dang parentheses wrapping the good bits



(defn animate [title & items]
    (vec (concat [:section]
                 (for [index (range (count items))]
                   (vec (concat [:section {:data-auto-animate ""} title] (take index items)))))))

Gavin Ray23:02:18

Curious how Clojure developers deal with lack of types? I am Curious about Clojure and have played with it, but not being able to get type-checking really crippled me Since I was blindly writing code without knowing if it was correct or not until I tried to run it Are there any tools/options for this?


While @U04V70XH6 is quite correct about running code (even just snippets of it) as you go, personally, I find types are useful, even if it’s just for documentation. Many people like spec, though I haven’t been comfortable with it (for multiple reasons). I suggest looking at Malli


It’s not the same as a type system, but it gets you a long way. More importantly, it documents what you structures should look like, and what the arguments and return types of your functions should be