This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # 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)
@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
Then you abstract away the first/rest functions.
(defn chn [c h n l] (if (seq l) (c (h (first l)) (chn c h n (rest l))) n))
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.
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)
reduced letting you short-circuit execution, you can do a lot of interesting
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?
(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
(fn [avg value] (+ avg (* 0.05 (- value avg)))) will often spit out something close to the average
(using the golden ratio)
user=> (reduce (fn [avg value] (+ avg (* (/ 1.61803 100) (- value avg)))) 0 (range 100)) 50.290307530750695 user=>
transduce can do it:
(transduce identity (fn ( [0 0]) ;;initiaize [ct sum] ([[ct sum]] (/ sum ct)) ;;calculate average on completion ([acc x] ;;update ct and sum on each step (-> acc (update 0 inc) (update 1 + x)))) [1 2 3 4 5])