This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-07-31
Channels
- # announcements (4)
- # aws-lambda (1)
- # babashka (25)
- # beginners (60)
- # calva (33)
- # cider (15)
- # cljdoc (1)
- # clojure (28)
- # clojure-dev (1)
- # clojure-europe (4)
- # clojurescript (29)
- # clojureverse-ops (4)
- # conjure (10)
- # datomic (4)
- # graalvm (4)
- # holy-lambda (4)
- # honeysql (13)
- # introduce-yourself (1)
- # lambdaisland (1)
- # missionary (11)
- # music (2)
- # off-topic (35)
- # pathom (17)
- # pedestal (20)
- # reagent (3)
- # sci (10)
- # shadow-cljs (39)
- # sql (6)
- # tools-deps (6)
- # vim (1)
You can write map
and filter
in terms of reduce
.
into
is written in terms of reduce
as I recall?
into
= reduce conj
@max.r.rothman I think you can write sort
as a double-`reduce` implementation of insertion sort?
Hm, maybe you’re right. I vaguely remember from my haskell days that there’s an isomorphism between folds and recursion or something
Back when I was doing my PhD work on FP language implementation and design, one of the exercises was looking at "primitive" FP operations and as I recall there was a five(?) argument function from which you could build map, filter, reduce, etc...
That's kind of taking it to mathematical extremes but, yeah, it's all somewhat related.
I can't remember the name I used in my thesis for the 5-argument HOF I outlined. I think I called it R
. But part of the work was to show that if you implemented that as a primitive in the engine, you could build all the rest using pretty much any FP style syntax, and that was really where I was working: looking at a variety of syntax to see what was more expressive and what was a worthwhile set of primitives for a language.
My other work was focused primarily on GC strategies to support FP languages. Back then, it was all single-threaded and so it was about figuring out how to interleave GC work with actual VM operations and still have a responsive interactive system.
Speaking of GC, you might find this interesting https://clojurians.slack.com/archives/C03RZGPG3/p1627244431292500
Part of the way there is
(defn chn [c h n l] (if (seq l) (c (h (first l)) (chn c h n (rest l))) n))
Then you abstract away the first/rest functions.In general, I think you can probably write any function that takes and returns a coll in terms of reduce. There may be special cases in which you can write certain functions in terms of reduce as long as they take a coll (even if they don’t return one)
I’m rereading SICP in prep for Software Design for flexibility and it’s more useful to revisit fundamentals than I thought.
@deleted-user we sure are!
I was slightly off with chn
above (I've corrected it) but here's map in terms of it:
user=> (defn chn [c h n l] (if (seq l) (c (h (first l)) (chn c h n (rest l))) n))
#'user/chn
user=> (defn map1 [f l] (chn cons f () l))
#'user/map1
user=> (map1 inc [1 2 3 4])
(2 3 4 5)
With reduced
letting you short-circuit execution, you can do a lot of interesting reduce
ops.
I think the canonical examples are aggregate functions like sum, average etc. if it doesn’t feel like them, maybe it’s the wrong function?
Using https://github.com/cgrand/xforms
(require '[net.cgrand.xforms :as x])
(sequence
(x/partition 3 x/avg)
(range 9))
;=> (1.0 4.0 7.0)
You can also use a streaming average estimator if you don't need to be completely accurate
something like (fn [avg value] (+ avg (* 0.05 (- value avg))))
will often spit out something close to the average
user=> (reduce (fn [avg value] (+ avg (* (/ 1.61803 100) (- value avg)))) 0 (range 100))
50.290307530750695
user=>
(using the golden ratio)