This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-06-05
Channels
- # babashka (14)
- # beginners (62)
- # calva (1)
- # cider (54)
- # clj-kondo (3)
- # cljdoc (15)
- # cljs-dev (2)
- # clojure (180)
- # clojure-europe (5)
- # clojure-italy (4)
- # clojure-losangeles (1)
- # clojure-nl (2)
- # clojure-spec (10)
- # clojure-uk (39)
- # clojurescript (85)
- # core-async (9)
- # core-logic (1)
- # core-typed (5)
- # data-science (27)
- # datomic (2)
- # emacs (15)
- # figwheel-main (98)
- # fulcro (26)
- # graphql (15)
- # helix (1)
- # jobs-discuss (26)
- # kaocha (1)
- # off-topic (54)
- # other-lisps (1)
- # re-frame (21)
- # reagent (1)
- # reitit (3)
- # shadow-cljs (49)
- # spacemacs (12)
- # specter (5)
- # xtdb (2)
What is a better way to "chain" / "pipeline" go channels together?
e.g. an extremely dumbed down version using cljs-http
(defn f1 [url] (cljs-http.client/get url))
(defn f2 [url] (cljs-http.client/post url))
What's the best way to chain/pipeline those functions together while adding some e.g. logging behaviours?
basically I'm doing something like below, my code is very manual and redundant, so I thought there must be a more idiomatic / better way of doing the chaining/pipe lining.
(log input) -> (fn1 input) -> (log output) -> (fn2 output) -> (use-output output) -> (log rssult)
With go channel, it seems that I need to do something like this for almost every single function
(let [out (chan)]
(go
(let [result (<! (fn-returns-go))]
(>! out result)))
out)
i’m not sure I understand the question. what about something like:
(defn my-process [input]
(go
(let [_ (log input)
output (<! (fn1 input))
_ (log output)
output (<! (fn2 output))
result (use-output output)
_ (log result)]
result)))
I guess I'm trying to somehow be able to make my-process a partial function so that I can easily chain / re-group differnt part without having to do
(let [out (chan)] (go (blah)) out)
everywherego
expressions return channels
so I would write the above as (go (blah))
(let [out (chan)]
(go
(let [result (<! (fn-returns-chan))]
(>! out result)))
out)
would become
(fn-returns-chan)
are you saying (go (blah))
would return the go channel from (blah)?
I think I tested it, but wasn't getting the said behavior, I will test again. That's why I was doing (let [out (chan)] (go (>! out (blah)))) out)
where (blah) returns a channel
will, test and report back
thanks very much
if blah returns a channel then you don’t need to do anything, you can just do (blah)
a go
expression will return a channel that will receive whatever the value of the last expression is
for example:
(go
(<! (timeout 5000))
42)
this go
expression will return a channel that will receive the value 42 after 5 secondsit might be easier to illustrate if you have some sample code
(defn f1 [a]
(go
(timeout 2000)
(prn "after f1 timeout")
a))
(defn f2 [a]
(go
(timeout 3000)
(prn "after f2 timeout")
a))
(defn f3 []
(go
(let [a (<! (f1 "hello"))
b (<! (f2 "world"))
c (str a " " b)]
c)))
(prn (go (<! (f3))))
Any reason the last prn
doesn't work?
Looks like the go block must be outside of prn
like so
(go (prn (<! (f3))))
the go
expression returns a channel, so if prn
is on the outside, it will just print out the channel itself. in clojure, you can do a blocking take with <!!
if you want prn on the outside:
(prn (<!! (go (f3)))
there’s no blocking take in clojurescript
(timeout 2000)
returns a channel, so it’s not going to wait unless you take from it:
(defn f1 [a]
(go
;; park here until timeout chan times out
(<! (timeout 2000))
(prn "after f1 timeout")
a))
an alternate way to write f3 that shows the flexibility of core/async:
(defn f1 [a]
(go
(prn "starting f1")
(<! (timeout 2000))
(prn "after f1 timeout")
a))
(defn f2 [a]
(go
(prn "starting f2")
(<! (timeout 3000))
(prn "after f2 timeout")
a))
(defn f4 []
(go
(let [achan (f1 "hello")
bchan (f2 "world")
a (<! achan)
b (<! bchan)
c (str a " " b)]
c)))
the difference between f3 and f4 is that f4 will start running f1 and f2 at the same time instead of waiting for f1 to finish.
Does clojurescript properly support data_readers.cljc
? and evaling custom reader tags?
e.g. I have
{g/uri my.namespace/->uri}
But evaling:
#g/uri ""
At a REPL gives:
Failed to read input: clojure.lang.ExceptionInfo: Attempting to call unbound fn: #'my.namespace/->uri {:type :reader-exception, :line 1, :column 19, :file "repl-input.cljs"}
That’s not why I want it… 🙂 I want to round trip printed values for otherwise unprintable objects back into my REPL.
i.e. for REPL debugging large values
without having to manually convert them all
so the problem with reader literals in code is that in CLJS reading happens on the CLJ side
and the way they are implemented requires the compiler to able to turn whatever was read into JS code which will then be evaluated by the client
@thheller: ah of course! Makes total sense, though a little frustrating.
If your REPL is on CLJ and you really need to just send printed values from CLJS to CLJ, then you don't really need data readers on the CLJS side, right?
Why then does #inst work?
Thanks!
@rickmoynihan it should work, we have tests for the compile case
as pointed out - you need to handle both sides - the Clojure reading side and the runtime side - that can be done w/ .cljc
of course
records are more or less free - but if your type is JavaScript stuff then you're going to have some challenges.
https://github.com/clojure/clojurescript/blob/master/src/test/cljs/data_readers_test/records.cljc
@dnolen: Thanks… I was using a cljc file… but yeah I almost certainly haven’t loaded the ns as it’s in a shadow-cljs “compile process”… though I’m not sure how I can do that with shadow-cljs :thinking_face:
would you accept a feature request? 🙂
just the REPL would be 👌
supported in 2.10.2
if you add :compiler-options {:data-readers true}
in your build config.
Wow thanks!!!
Hello 🙂 I have an atom that is a set (the value is the check boxes of the columns to be displayed)
(reagent/atom #{:campaign-name
:strategy-name
:total-spend
:average-spend-per-day})
Here I am adding a column if it is not present at the set and removing it if it is on the set.
toggle-column-selection (fn [column-name] (if (contains? @selected-columns column-name)
(swap! selected-columns disj column-name)
(swap! selected-columns conj column-name)))
Here is where selected-columns atom is dereferenced. This is where I need to put some order to display the column how i prefer them.
(case (:variant @strategies)
:not-loaded [:div.alert.alert-light {:role :alert} "File not loaded"]
:error [error @strategies]
:correct [loaded-strategies {:strategies (:data @strategies)
:selected-columns @selected-columns}])
Set offers membership check but also do not have guaranteed ordering.
I want to custom order the columns displayed on the screen ( the screenshot below). How do I go about it?
I want to reorder the columns like this:
1. campaign name
2. Age in days
3. uniques
4. post-click c.
Thank you!@fana I usually keep multiple options in a separate collection, eg. (def my-options [{:value :campaign-name :label "Campaign"} ...])
which is in order. the set you can get from (set (map :value my-options))
. this lets you couple a label and other additional things you may need with the keyword itself. whereever you are displaying the value just use my-options
directly and have that check if :value
is in the set.
I use a vector of maps like [{:option-a {:checked true}} {:option-b {:checked false}]
, serves me well, even if its a bit verbose
I haven't looked at modern build tools in a long time. Does anyone have any resources or blog posts that compare the value proposition something like shadow-cljs (or others I haven't heard of) has over traditional lein/figwheel?
@naomarik this blog post isn’t a direct comparison but explains the motivation behind shadow-cljs: https://code.thheller.com/blog/shadow-cljs/2019/03/01/what-shadow-cljs-is-and-isnt.html
The main thing I like is the build report... only thing that's stopping me from building my project with shadow-cljs are my required foreign-libs.
@naomarik things are changing in figwheel.main for npm support because of underlying changes in clojurescript
@naomarik shadow-cljs does support foreign libraries, it is slightly different than standard CLJS
@lilactown I saw several references that it was removed, also just spent a bit of time setting up a shadow-cljs.edn and that was the only thing stopping me from building my project with it. https://code.thheller.com/blog/shadow-cljs/2017/09/15/js-dependencies-going-forward.html
shadow doesn’t support `:foreign-libs` the CLJS feature, but it does support foreign code
when I converted our project at work to shadow-cljs, it was pretty simple to add a proxy namespace for the foreign libs we were using at the time
My current project is kind of a mishmash of buildtools right now but it's working for me, mainly using lein fighweel for development and the cljs build tool API directly (within boot) for advanced compilation. Have a few js files that I depend on that I'm able to consume with :foreign-libs
option. Plan on cleaning it up later but it's not causing me any pain whatsoever right now, would really like the build report though.
yeah. one of the thing that isn’t made clear in that blog post you linked above is you can just require JS files in your CLJS namespaces
e.g.:
(ns my-app.feature
(:require ["../js/some-lib.js" :as some-lib])
with externs inference on, we successfully migrated off of many of our internal foreign libs using that method and doing a simple mechanical translation to ESM in the JS fileshi there, i wonder if anyone might be abelt to help me figure out what im doing wrong wrt: shaddow cljs & emacs & repls etc
im using spacemacs and i can seem to get a REPL running with either :app or :test but not both ?
there's nothing wrong with your project you're just asking about CIDER? if so come chat in #cider
mmmm actually i think ive got it now….
i can add a sibling session ??
if i do it directly
however if i try to start a session and then take the promopt to add a sibling instead then it seems to go weird
looks like im a few version behind latest shaddow-cljs as well, mgiht try and upgrade now before i get too far behind ! :d
newbie sort of question, but is watching the REPL the “normal” way to run tests?