Skip to content

Instantly share code, notes, and snippets.

@kohyama
Created June 8, 2012 06:41
Show Gist options
  • Save kohyama/2893987 to your computer and use it in GitHub Desktop.
Save kohyama/2893987 to your computer and use it in GitHub Desktop.
fold-right and reduce-right in Clojure
(use 'clojure.test)
(defn fold-right [f s coll]
((reduce (fn [acc x] (comp acc #(f x %))) identity coll) s))
(deftest test-fold-right
(are [result expected] (= result expected)
(fold-right - 5 '(3 1 4 1)) 10
(fold-right #(concat %2 (list %)) '() '(:a :b :c :d)) '(:d :c :b :a)))
; previous version
(defn old-fold-right [f s coll]
((reduce (fn [acc x] #(acc (f x %))) identity coll) s))
@kohyama
Copy link
Author

kohyama commented Jun 10, 2012

A definition of fold-right in the revision https://gist.github.com/2893987/568bda07ad16860695e3a52b3cd5b7ae559b7081
seems to consume a large stack.
(fold-right - 0 (range 10000)) ; -> -5000
(fold-right - 0 (range 100000)) ; -> StackOverflowError java.lang.Number. (Number.java:32)
What is a better implementation of fold-right?
If a implementation using reverse don't consume a large stack, how can reverse do reversing without consuming a large stack?

@kohyama
Copy link
Author

kohyama commented Jun 12, 2012

Updated not to eat large stack but heap.

user=> (fold-right - 0 (range 1000000))
-500000
user=> (fold-right - 0 (range 2000000))
OutOfMemoryError Java heap space clojure.lang.ArrayChunk.dropFirst (ArrayChunk.java:54)

@kohyama
Copy link
Author

kohyama commented Jun 12, 2012

How stupid have I been!
'f' doesn't vary in the accumulated list.
We only have to keep 1st operands of 'f' in reversed order in a list.

user=> (fold-right - 0 (range 2000000))
-1000000

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment