loki
loki

Reputation: 2311

concatenating sequences in 4clojure function

I just finished 4clojure Problem 60, here's the code for my first program with the problem description:

;;Write a function which behaves like reduce, but returns each intermediate
;;value of the reduction. Your function must accept either two or three arguments,
;;and the return sequence must be lazy.
(fn red
  ([fun sq]
     (red fun (first sq) (rest sq)))
  ([fun acum sq]
   (if (empty? sq) acum
     (cons acum (lazy-seq (red fun (fun acum (first sq)) (rest sq)))))))

The core of the function occurs one line bellow the if, I just return the initial value followed by applying it to the next element in the sequence. But it fails for the second test case involving vectors:

user=> (red conj [1] [2 3 4])
([1] [1 2] [1 2 3] 1 2 3 4);; it should be ([1] [1 2] [1 2 3] [1 2 3 4])

It took me some time to realize that the problem was the cons which just adds the vector [1 2 3 4] as it were the rest of the list instead as a single element.

What I did is to convert cons to concat and acum to [acum] and it worked:

(fn red
  ([fun sq]
     (red fun (first sq) (rest sq)))
  ([fun acum sq]
   (if (empty? sq) [acum]
     (concat [acum] (lazy-seq
                     (red fun (fun acum (first sq)) (rest sq)))))))

Don't ask me why but it seems to me kind of inelegant, the other solutions didn't use concat neither.

The question is, considering the first function as it is, what function/macro does the work without modifying the code too much.

Upvotes: 0

Views: 136

Answers (2)

tomsky
tomsky

Reputation: 1

You can avoid the use of concat if you take cons instead. Cons is lazy (see the discussion of cons vs. conj on Stack Overflow):

(defn my-reductions
  ([f sq] (my-reductions f (first sq) (rest sq)))
  ([f init sq]
    (if (empty? sq)
      (list init) 
      (cons init (lazy-seq (my-reductions f (f init (first sq)) (rest sq))))
    )
  )
)

Btw: This code passes the 4Clojure tests, but doesn't quite behave like reductions in all cases:

(my-reductions + [])  
(nil)  
(reductions + [])  
(0)

Upvotes: 0

Ankur
Ankur

Reputation: 33637

In the if true case return [acum] instead of acum

Upvotes: 3

Related Questions