This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-09-09
Channels
- # announcements (1)
- # aws-lambda (3)
- # babashka (6)
- # beginners (91)
- # bristol-clojurians (5)
- # calva (25)
- # chlorine-clover (8)
- # cider (6)
- # clj-kondo (13)
- # cljdoc (10)
- # cljsrn (1)
- # clojure (80)
- # clojure-berlin (6)
- # clojure-europe (29)
- # clojure-nl (4)
- # clojure-spec (18)
- # clojure-uk (51)
- # clojurescript (41)
- # conjure (55)
- # cursive (3)
- # datomic (58)
- # emacs (9)
- # events (1)
- # figwheel-main (2)
- # fulcro (29)
- # graphql (12)
- # helix (4)
- # jobs (4)
- # klipse (8)
- # london-clojurians (1)
- # malli (5)
- # off-topic (13)
- # portal (9)
- # re-frame (30)
- # shadow-cljs (44)
- # spacemacs (7)
- # specter (3)
- # sql (11)
- # tools-deps (71)
- # windows (1)
- # xtdb (10)
is it an anti-pattern to do something like the following?
(let [x (atom [])]
(for [y some-collection]
(some-async-modification-with-callback y #(swap! x conj %)))
as opposed to building a purely functional structure and using chans and e.g. async/map
?for
being lazy the body may not be evaluated (beware of the repl forcing realization). Use doseq
.
How do you plan to wait for termination?
You mean if one of the async modification functions never returns or errors out? What I am really wondering is if using an atom like this as a temporary mutatey variable, which is basically like using a let
in Javascript, is frowned upon.
I think he means like, how do you know the thing that will later read the value of x will do the read after all async operations have added their result to it?
Using mutation is always "preferred to be avoided", but atoms are also there for a reason, so it's kind of up to you to decide if this is some ugly hack in the context of what you are doing, or a necessary way that ends up making things simpler
Ah yes I see what you mean about receiving all values and knowing when it's done. In that case creating chans and pulling from them in an async/map would be better.
I'm just thinking, agent kind of do what you're expecting and allow you to wait on them being done processing. But they also implement asynchronous behavior, so if the function is already async by other means it won't work
Otherwise in your case, you could use promise, like pass a callback that delivers the promise.
i think the use case where i ran into this wasn't actually async. it was a javascript function which returned intermediate values via a callback.
(for [y some-collection]
(let [p (promise)]
(some-async-fn-with-clbk y #(deliver p %)))
ah yes sorry
but i guess the question applies in Java too
finding the original use case
var map = new ROT.Map.Arena(3, 3);
var userCallback = function(x, y, value) {
// do something with x, y, value e.g. store them
}
map.create(userCallback);
you could have a simliar situation in java/clojureBut what you do is fine as well, if you don't care to know that everything is done conjing before you read
i guess the reason i got confused is because map.create()
is not actually asynchronous. it blocks until all the values have been called with userCallback
.
so it seems strange to set up chans and use core.async
yeah that temporary atom
is what my friend suggested and i didn't like it but i think you and he are right that it's actually a good use of atom here.
Cause basically that API wants you to use it in an imperative way. Since it doesn't return results, but instead provides them to your callback
thanks
Given a nested vector like [[0 1 "X"] [3 4 5 ] ["O" 7 8] ], how could I write a function so that everything gets printed with a breakline for every new vector?. Should return 0 1 "X" 3 4 5 "O" 7 8
Thank you. I wasn't sure how. Ill give that a shot.
hey all, curious if anyone had some advice on how to structure namespaces in a numerical library. I'm implementing a number of minimization routines, all of which have sort-of-similar interfaces
and what I'm rebelling against a bit is, say, Scipy's organization style, where function after function are stacked into the 1000s of lines of code
one idea is to use a single namespace for every implementation of "minimize"; say, sicmutils.numerical.minimize.brent
, sicmutils.numerical.minimize.golden-section
etc, and then to alias all the implementations (or provide a dispatching fn) in sicmutils.numerical.minimize
the con is that we end up with many namespaces with nested names. but the pro is that the various methods are MUCH easier to learn and describe if they're split up. Curious to hear what folks think
A relevant SO question: https://stackoverflow.com/questions/15580807/sharing-functions-between-namespaces-in-clojure Check out the email thread linked in the accepted answer.
There's also quite a few relevant discussions if you search for "potemkin": https://groups.google.com/g/clojure/search?q=potemkin
nice, this is great
good grist for the mind
@U017QJZ9M7W have you seen how neanderthal does protocol based dispatching for different types per op? https://github.com/uncomplicate/neanderthal/blob/master/src/clojure/uncomplicate/neanderthal/internal/api.clj
interesting, I have not
@U0CJ19XAM I don't quite see here how resolution is handled for different types...
https://github.com/littleredcomputer/sicmutils/blob/master/src/sicmutils/numbers.cljc#L155
vs this, say
https://github.com/uncomplicate/neanderthal/blob/81e943f86875ec595bdde9c3053de264c6606235/src/clojure/uncomplicate/neanderthal/core.clj#L155 That ^^^ is used across different data types as well as engines. It may be more involved than what you're looking for but it's stupid fast. I'm sorry I can't speak more to the neanderthal approach right now, but I highly recommend studying what was done in this library and how it interacts with cpus / gpus X cuda / opencl / blas. it's an incredible testament to clojure.
yes, this is a fantastic recommendation
to the extent that I can I want to simply extend the ability to use Neanderthan's data types into the sicmutils system
(insert-after [1 2 3] 3 "a")
=> [1 2 3 "a"]
(insert-after [1 2 3] 2 "a")
=> [1 2 "a" 3]
(insert-after [1 2 3] 1 "a")
=> [1 "a" 2 3]
(insert-after [1 2 3] 444 "a")
=> [1 2 3]
(defn insert-after [items after item]
(let [idx (.indexOf items after)]
(if (< idx 0)
items
(vec (concat (subvec items 0 (inc idx))
[item]
(subvec items (inc idx)))))))
(defn insert-after [coll idx item]
(let [[begin after] (split-at idx coll)]
(concat begin (cons item after))))
here's a lazy version, for all sequences
(defn insert-after [items after item]
(into [] (mapcat #(cond-> [%] (= % after) (conj item)) items)))
Purposely not using xform
here or just a misplacement of parens? I ask because I’m curious if there’s something I’m not aware of re: xforms.
(mapcat f)
returns a transducer.
Oh, gotcha.
You were asking why @U3E46Q1DG didn't use the xform version!
(I misread the parens)
user=> (defn insert-after [items after item]
(into [] (mapcat #(cond-> [%] (= % after) (conj item))) items))
#'user/insert-after
user=> (insert-after (range 10) 3 :x)
[0 1 2 3 :x 4 5 6 7 8 9]
user=>
I think a lot of us "old 'uns" are so used to the non-transducer versions of core functions that we instinctively dash off quick snippets of code that way...
And to be honest I don’t like creating a vector just to concatenate it immediatly after.
So maybe
(defn insert-after [items after item]
(into [] (fn [rf] (fn ([acc] (rf acc)) ([acc x] (cond-> (rf acc x) (= x after) (rf item))))) items))
(not checking for reduced
on purpose: there’s only into
below us)