This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-06-09
Channels
- # beginners (47)
- # boot (5)
- # cider (25)
- # cljs-dev (2)
- # clojars (2)
- # clojure (33)
- # clojure-dev (25)
- # clojure-italy (2)
- # clojure-uk (35)
- # clojurescript (27)
- # core-async (2)
- # datomic (5)
- # graphql (2)
- # immutant (3)
- # off-topic (3)
- # onyx (2)
- # pedestal (4)
- # portkey (52)
- # reagent (2)
- # shadow-cljs (55)
- # spacemacs (21)
- # sql (8)
- # tools-deps (22)
Morning
Anyone have anything planned for the weekend?
rye is a small south-coast seaside town, not far from hastings and romney marsh... think pleasant seaside walks, rustic pub lunches, beaches... a long time ago it was an important port iirc, but it's quite out of the way now
i often forget about reduce-kv
and destructure instead: (reduce (fn [m [k v]] (assoc m k (do-stuff-to v)) {} m)
or since it's map-in map-out then maybe (into {} (for [[k v] m] [k (do-stuff-to v)]))
Rye sounds lovely. And badminton too. Haven't played it in years. We've taken the hounds for walks and now we're heading out to go strawberry picking 🍓
@mccraigmccraig yeah - it seems reduce-kv
is functionally the same as destructuring - the implementation might be a lot simpler though as it probably doesn’t need to turn a map into a sequence of KV pairs? Not that that matters too much really. (and the into
example is pretty well what I usually do, though I use map
not for
because for
seems to encourage me to overly-procedural thinking 🙂 )
Re: Rye - yeah, it’s near Hastings and Camber Sands for beaches if it’s nice. We have Australian relatives to visit, and they wanted to see some of the coast - Beachy Head and the like - and Rye looked nice. (They obviously are sarcastic about English beaches though!)
(defprotocol IKVReduce
"Protocol for concrete associative types that can reduce themselves
via a function of key and val faster than first/next recursion over map
entries. Called by clojure.core/reduce-kv, and has same
semantics (just different arg order)."
(kv-reduce [amap f init]))
@korny i often do pipelines like (->> m (map (fn [[k v]] [k (do-stuff-to v)])) (map (fn [[k v]] [k (do-other-stuff-to v)])) (into {}))
too... but i find for
clearer for single-step transformations
what dyu mean about "procedural thinking" though ?
Somehow when I type for
I start writing code like I was in Java or C-ish languages. Purely psychological.
I tend to be the same as @korny. If I start using functions that I'm more used to in non-functional languages (e.g. for
loops instead of map
/`reduce`) I find I drop into that mindset and start producing code that is more 'OO-like'. So I avoid using them
It's why I found Clojure so useful as a functional language. It's so different from anything else I write, being Lisp-y, that it's easy to make my brain go "Clojure = functional", whereas when I'm writing for e.g. Python even if I'm trying to do it in a functional style I find myself dropping into OO habits, and when I've (briefly) poked stuff like Scala I find the same
<heresy> I’d kind-of like to try Scala again, now, after quite a bit of clojure - I hated it when I used it last, but that was 8 years ago when my FP was largely theoretical. Maybe scala-as-if-it-were-clojure might be viable… </heresy>
So, clojure laziness question… I have some code that is sort-of like this:
(-> (reduce (fn [memo thing]
(let [new-data (something done with thing)]
{:log (conj (:log memo) new-data) :metadata (something irrelevant}
{:log [] :metadata nil}
iterator-over-stuff-from-elsewhere)
:log)
So the :metadata
is used for internal state while the iterator-over-stuff-from-elsewhere
is processed into the :log
bit of the memo.
I throw away the :metadata
and just use the :log
- which I want to stream to a JSON output. But it doesn’t seem to do this lazily - I guess because I’m not returning anything from the reduce
until it’s complete. Or something - I have no brain right now to think this through, which is why I’m asking you folks 🙂
Is there a simple way to make this into something streaming? I’m reducing over hundreds of thousands of rows, I’d prefer to send the output directly to an output stream, rather than accumulate it all in memory!
(of course it isn’t lazy because reduce
has no way of knowing what the final :log
element will be until it has finished reducing)
… or maybe I should rework this using loop
/`recur` - I just like the way reduce
operates 🙂
reduce
and loop
/`recur` are all eager not lazy, so it won’t matter whether iterator-over-stuff-from-elsewhere
is a lazy-seq
or not
also :log
is initalised as a vector, which is again an eager data structure - and conj
is polymorphic on that type
so whilst (take 20 (conj (range) 10))
will work lazily, conj
on a vector will return a vector too