Saturday, June 18, 2011

List processing functions continued

I am going to implement all of the array methods from the JavaScript prelude. First of all here is the mutator methods:

(swap! coll rest)                 ; shift
(swap! coll butlast)              ; pop
(swap! coll concat [1])           ; push
(swap! coll (partial concat [1])) ; unshift

(swap! coll reverse) 
(swap! coll (partial sort <))
The only one that really requires special attention is splice.
(defn splice
  [coll start-index how-many & insertions]

  (let [start-coll (map coll (range 0 start-index))
        end-coll (map coll (range (+ start-index how-many) (count coll)))]
    (concat start-coll insertions end-coll)))
The accessor method concat is already implemented in Clojure, and here is the rest of the methods:
(defn join
  [coll separator]

  (cond
   (empty? coll) ""
   (= (count coll) 1) (str (first coll))
   :else (str (first coll) separator (join (rest coll) separator))))

(defn to-string
  [coll]

  (join coll ","))

(defn to-source
  [coll]
  
  (str "[" (join coll ", ") "]"))

(defn slice
  [coll start end]

  (map coll (range start end)))

(defn index-of
  [coll elt]

  (cond
   (nil? ((set coll) elt)) -1
   (= (first coll) elt) 0
   :else (inc (index-of (rest coll) elt))))

(defn last-index-of
  [coll elt]

  (- (dec (count coll)) (index-of (reverse coll) elt)))

The methods, filter, map, some, every?, and reduce are already implemented in clojure. The only thing we don't really have already is for-each. This can be implemented as a macro that uses the loop primitive.
(defmacro for-each
  [coll func]

  (let [i (gensym)]
    `(loop [~i 0]
       (when-not (= ~i (count ~coll))
         (do
           (~func (nth ~coll ~i))
           (recur (inc ~i)))))))
This function is actually quite useful, for example we can use it print out elements of a list:
(for-each [1 2 3 4 5] prn)

No comments:

Post a Comment