Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use the clojure 'for' macro to reverse a string?

Tags:

clojure

This is a follow up to my question "Recursively reverse a sequence in Clojure".

Is it possible to reverse a sequence using the Clojure "for" macro? I'm trying to better understand the limitations and use-cases of this macro.

Here is the code I'm starting from:

((defn reverse-with-for [s] 
    (for [c s] c))

Possible?

If so, I assume the solution may require wrapping the for macro in some expression that defines a mutable var, or that the body-expr of the for macro will somehow pass a sequence to the next iteration (similar to map).

like image 353
noahlz Avatar asked Dec 06 '22 17:12

noahlz


1 Answers

Clojure for macro is being used with arbitrary Clojure sequences.

These sequences may or may not expose random access like vectors do. So, in general case, you do not have access to the last element of a Clojure sequence without traversing all the way to it, which would make making a pass through it in reverse order not possible.

I'm assumming you had something like this in mind (Java-like pseudocode):

for(int i = n-1; i--; i<=0){
   doSomething(array[i]);
}

In this example we know array size n in advance and we can access elements by its index. With Clojure sequences we don't know that. In Java it makes sense to do that with arrays and ArrayLists. Clojure sequences are however much more like linked lists - you have an element, and a reference to next one.

Btw, even if there were a (probably non-idiomatic)* way to do that, its time complexity would be something like O(n^2) which is just not worth the effort compared to much easier solution in the linked post which is O(n^2) for lists and a much better O(n) for vectors (and it is quite elegant and idiomatic. In fact, the official reverse has that implementation).

EDIT:

A general advice: Don't try to do imperative programming in Clojure, it wasn't designed for it. Although many things may seem strange or counter-intuitive (as opposed to well known idioms from imperative programming) once you get used to the functional way of doing things it is a lot, and I mean a lot easier.

Specifically for this question, despite the same name Java (and other C-like) for and Clojure for are not the same thing! First is an actual loop - it defines a flow control. The second one is a comprehension - look at it conceptually as a higher function of a sequence and a function f to be done for each of its element, which returns another sequence of f(element) s. Java for is a statement, it doesn't evaluate to anything, Clojure for (as well as anything else in Clojure) is an expression - it evaluates to the sequence of f(element) s.

Probably the easiest way to get the idea is to play with sequence functions library: http://clojure.org/sequences. Also, you can solve some problems on http://www.4clojure.com/. The first problems are very easy but they gradually get harder as you progress through them.

*As shown in Alexandre's answer the solution to the problem in fact is idiomatic and quite clever. Kudos for that! :)

like image 142
Goran Jovic Avatar answered Jan 17 '23 12:01

Goran Jovic