Reputation: 97
In DrRacket to return the list without changing by using foldr done this way:
(foldr cons '() '(1 2 3))
However in Clojure reduce is fold left so how can I do this?
First I tried this:
(reduce cons '() '(1 2 3))
=> IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:542)
Afterward I tried this:
(reduce conj '() '(1 2 3))
=> (3 2 1)
"=>" is the output in REPL
No I don't want to read how Clojure implements reduce. I already know that. This is a more specific question. I found the answer myself, I will post it.
Upvotes: 0
Views: 612
Reputation: 97
Here is my solution. I don't know how efficient it. We used this kind of solutions in University during Racket lessons.
(reduce #(concat %1 (list %2)) '() '(1 2 3))
=> (1 2 3)
Upvotes: 0
Reputation: 5766
I'm not that familiar with Racket, but Clojure's reduce
appears to differ from Racket's foldr
in two major ways:
reduce
processes the list from head to tail (vs. tail to head for foldr
). In this respect, reduce
is similar to foldl
.reduce
passes the accumulated value as the first argument to the reducing function (vs. the last argument for foldr
/foldl
).The second difference is the reason for the error when using cons
-- (cons '() 1)
is the first call made, and 1
obviously isn't a list.
If we consider that (conj xs x)
is equivalent to (cons x xs)
when xs
is a list, then (reduce conj '() '(1 2 3))
is equivalent to (cons 3 (cons 2 (cons 1 '())))
which might be more apparent when written as
(->> '()
(cons 1)
(cons 2)
(cons 3))
Now, if you don't mind the result being a vector instead of a list, you could do:
(reduce conj [] '(1 2 3))
Or, if you prefer, you could convert the result into a seq
so that it essentially behaves like a list:
(seq (reduce conj [] '(1 2 3)))
Alternatively, you could reverse
the input list:
(reduce conj () (reverse '(1 2 3)))
Upvotes: 0
Reputation: 4746
In your second attempt you had to "flip" the arguments passed to cons for things to work:
(reduce #(cons %2 %1) '() '(1 2 3))
=> (3 2 1)
However, as you noticed, reduce is actually a fold-left, so the first item in the original list, becomes the inner-most (or last) item in the result list. This could be handled with reverse
:
(reduce (fn[a b](cons b a)) '() (reverse '(1 2 3)))
=> (1 2 3)
You can read more about why clojure 'lacks' foldr in here
Upvotes: 3