This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # aws (1)
- # bangalore-clj (1)
- # beginners (73)
- # boot (13)
- # cider (3)
- # clara (19)
- # cljs-dev (33)
- # cljsrn (37)
- # clojure (177)
- # clojure-dev (13)
- # clojure-gamedev (1)
- # clojure-italy (10)
- # clojure-nlp (1)
- # clojure-russia (1)
- # clojure-spec (64)
- # clojure-uk (128)
- # clojurescript (177)
- # core-async (23)
- # cursive (5)
- # datascript (13)
- # datomic (20)
- # devops (49)
- # emacs (13)
- # graphql (5)
- # hoplon (13)
- # keechma (1)
- # leiningen (3)
- # liberator (4)
- # lumo (2)
- # off-topic (11)
- # om (19)
- # om-next (3)
- # onyx (6)
- # re-frame (13)
- # reagent (14)
- # ring-swagger (7)
- # rum (2)
- # spacemacs (7)
- # unrepl (1)
- # untangled (23)
- # vim (8)
- # yada (1)
i'm wondering what the colon prefix on :when, :let and :while do in the first two examples
:something is a keyword.
for recognizes a number of keywords to specify qualifiers on the iteration
wherever you have
(filter pred (map f coll)) you can do
(for [x coll :when (pred x)] (f x)) -- think I got that right...
user=> (for [x (range 10) y (range 10) :while (< y x)] y) (0 0 1 0 1 2 0 1 2 3 0 1 2 3 4 0 1 2 3 4 5 0 1 2 3 4 5 6 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 8)
user=> (macroexpand '(for [x (range 10) y (range 10) :while (< y x)] y)) (let* [iter__7307__auto__ (clojure.core/fn iter__916 [s__917] (clojure.core/lazy-seq (clojure.core/loop [s__917 s__917] (clojure.core/when-first [x s__917] (clojure.core/let [iterys__7303__auto__ (clojure.core/fn iter__918 [s__919] (clojure.core/lazy-seq (clojure.core/loop [s__919 s__919] (clojure.core/when-let [s__919 (clojure.core/seq s__919)] (if (clojure.core/chunked-seq? s__919) (clojure.core/let [c__7305__auto__ (clojure.core/chunk-first s__919) size__7306__auto__ (clojure.core/int (clojure.core/count c__7305__auto__)) b__921 (clojure.core/chunk-buffer size__7306__auto__)] (if (clojure.core/loop [i__920 (clojure.core/int 0)] (if (clojure.core/< i__920 size__7306__auto__) (clojure.core/let [y (.nth c__7305__auto__ i__920)] (clojure.core/when (< y x) (do (clojure.core/chunk-append b__921 y) (recur (clojure.core/unchecked-inc i__920))))) true)) (clojure.core/chunk-cons (clojure.core/chunk b__921) (iter__918 (clojure.core/chunk-rest s__919))) (clojure.core/chunk-cons (clojure.core/chunk b__921) nil))) (clojure.core/let [y (clojure.core/first s__919)] (clojure.core/when (< y x) (clojure.core/cons y (iter__918 (clojure.core/rest s__919)))))))))) fs__7304__auto__ (clojure.core/seq (iterys__7303__auto__ (range 10)))] (if fs__7304__auto__ (clojure.core/concat fs__7304__auto__ (iter__916 (clojure.core/rest s__917))) (recur (clojure.core/rest s__917))))))))] (iter__7307__auto__ (range 10)))
and this is why people get "method too large" errors when they try to use core.async, for, doseq, and core.match together in the same code
if the Java virtual machine code for a method is exactly 65535 bytes long and ends with an instruction that is 1 byte long, then that instruction cannot be protected by an exception handler
So, I use clojure A LOT, and I've really been sponging up material from talks, but I still don't know how to use transducers really tbh, it feels like Monads when I was first learning Haskell, but I've seen Rich's talk on them. Does anyone else have some really nice info on using transducers practically and what they are?
And I think the answers here are pretty good: https://stackoverflow.com/questions/26317325/can-someone-explain-clojure-transducers-to-me-in-simple-terms
@alice If I recall correctly, in very succinct terms they can be described as a means to compose operations on data collections, whereby the operations you describe through your transducers, aren't applied each on the entire input collection as in normal plain clojure code, but rather every element in the collection gets acted upon by a composition of what you specify in your transducers. Meaning, the input collection gets walked only once!
So, it is an alternative way to act on data collections, which requires of you to stray from the plain clojure API you'd normally would, but brings along some benefits like lazy evaluation and/or different performance trade-offs.
In addition, some advantages in terms of affording greater modularity in applying transformations on data, are mentioned in the linked SO question above ― although not really well elucidated in code examples there.
@alice http://eli.thegreenplace.net/2017/reducers-transducers-and-coreasync-in-clojure/ walks through a little bit of the basics
@matan - I'd agree except the part where you mention "collections" - items coming from a collection are a common case with transducers, but a big motivation for making transducers was the ability to apply transformation directly to the source of data, without forcing it into a collection first (eg. a core.async channel or a network stream etc.)
the fact that you can chain transducing functions without intermediate collections comes from this - the context of another transducer is one of the data sources you can apply a transducer to
@noisesmith good point, which I was oblivious to until now, and thanks for the feedback!
you can use (map f), as one example of a transducing function, directly on a channel
it's an optional arg when you create the channel, and causes that transform to be applied to all data that goes through the channel
ah, really this makes transducers and core.async channels a match made in heaven or something like that
channels are part of why they were invented - the clojure team discovered they were re-implementing filter, map, partition, etc. etc. on core.async and realized it would be better to have an abstraction for the transforms independent of the source and destination of data
mmmm thanks for this key perspective @noisesmith . so transducers are the only abstraction that can "equally" apply to "plain" collections as well as abstractions like async channels
java.jdbc 0.7.0-beta1, you can also apply transducers to “reducible queries” (and reducible result sets).