Skip to content

Instantly share code, notes, and snippets.

@joinr joinr/forfold.clj
Created Aug 25, 2018

Embed
What would you like to do?
for/fold from racket interpreted to clojure
(ns forfold)
;;From racket example
;;https://docs.racket-lang.org/reference/for.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for%2Ffold%29%29
;; (for/fold ([acc '()]
;; [seen (hash)]
;; #:result (reverse acc))
;; ([x (in-list '(0 1 1 2 3 4 4 4))])
;; (cond
;; [(hash-ref seen x #f)
;; (values acc seen)]
;; [else (values (cons x acc)
;; (hash-set seen x #t))]))
;; '(0 1 2 3 4)
;;we can opt in using macros...
(defmacro for-fold [bindings for-clause & body]
(let [binds (partition 2 bindings)
[pairs [[_ result]]]
(partition-by (fn [[l _]]
(= l :result)) binds)
result-expr (second result)
vars (mapv first pairs)
inits (mapv second pairs)
iter (first for-clause)
res (gensym "res")]
`(let [[~@vars :as ~res]
(reduce (fn [[~@vars] ~iter]
~@body)
~inits (for ~for-clause
~iter))]
~(or result
res))))
;; (for-fold [acc '()
;; seen #{}
;; :result (reverse acc)]
;; [x '(0 1 1 2 3 4 4 4)]
;; (cond (seen x) [acc seen]
;; :else [(cons x acc) (conj seen x)]))
;; (0 1 2 3 4)
;;or use reduce...
(->> '(0 1 1 2 3 4 4 4)
(reduce (fn [[acc seen :as res] x]
(if (seen x) res
[(cons x acc) (conj seen x)]))
['() #{}])
first
reverse)
;;or use a vector...no need to reverse.
(->> '(0 1 1 2 3 4 4 4)
(reduce (fn [[acc seen :as res] x]
(if (seen x) res
[(conj acc x) (conj seen x)]))
[[] #{}])
first)
;;or use state + filter
(let [seen (atom #{})]
(->> '(0 1 1 2 3 4 4 4)
(filter (fn [x] (when-not (@seen x)
(do (swap! seen conj x)
x))))))
;;or define our own stateful filter
(defn filter-once
([pred]
(let [f (atom #{})]
(fn [x] (when-not (@f x)
(do (swap! f conj x)
(pred x))))))
([] (filter-once identity)))
;;and use transducers via into
(into [] (filter (filter-once)) '(0 1 1 2 3 4 4 4))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.