A flatter cond

utilities — cgrand, 17 June 2011 @ 14 h 44 min

Long time, no post. I’ve had two hiatus (one of this kind and one of that kind) and I’m still going through the pile of accumulated work (including the bird book — it’s a painted snipe).

To warm up, a little macro I find quite handy:

(ns flatter.cond
  (:refer-clojure :exclude [cond]))

(defmacro cond 
  "A variation on cond which sports let bindings:
     (cond 
       (odd? a) 1
       :let [a (quot a 2)]
       (odd? a) 2
       :else 3)" 
  [& clauses]
  (when-let [[test expr & clauses] (seq clauses)]
    (if (= :let test)
      `(let ~expr (cond ~@clauses))
      `(if ~test ~expr (cond ~@clauses)))))

Linear Interpolation and sorted-map

utilities — cgrand, 8 June 2009 @ 19 h 07 min

Sorted collections (with subseq and rsubseq) can help when working with a partition of disjoint intervals, eg when you need to interpolate.

(defn interpolator 
 "Takes a coll of 2D points (vectors) and returns 
  their linear interpolation function."
 [points]
  (let [m (into (sorted-map) points)]
    (fn [x]
      (let [[[x1 y1]] (rsubseq m <= x)
            [[x2 y2]] (subseq m > x)]
        (if x2 
          (+ y1 (* (- x x1) (/ (- y2 y1) (- x2 x1))))
          y1)))))

;; => (map (interpolator [[0 0] [1 1] [3 2] [4 3]]) (range 0 9/2 1/2))
;; (0 1/2 1 5/4 3/2 7/4 2 5/2 3)

Functionally growing a tree (2): insertion points and zippers

utilities — cgrand, 1 May 2009 @ 11 h 10 min

I just uploaded a library that builds on zippers but shifts emphasis from nodes to insertion-points (interstitial positions before, between and after nodes).
It eases growing trees from an empty root.

  ; show-ip represents the currently edited structure with * denoting the insertion-point
  (defn show-ip [ip] (-> ip (insert-left '*) first z/root))
  (def e (-> [] z/vector-zip (insertion-point :append)))
  (-> e show-ip) ; [*]
  (-> e (insert-left 1) show-ip) ; [1 *]
  (-> e (insert-left 1) (insert-right 2) show-ip) ; [1 * 2]
  (-> e (insert-left 1) (insert-right 2) left show-ip) ; [* 1 2]
  (-> e (insert-left [1 2]) show-ip) ; [[1 2] *]
  (-> e (insert-left [1 2]) left show-ip) ; [* [1 2]]
  (-> e (insert-left [1 2]) left right show-ip) ; [[1 2] *]
  (-> e (insert-left [1 2]) left next show-ip) ; [[* 1 2]]
  (-> e (insert-left [1 2]) left next next show-ip) ; [[1 * 2]]
  (-> e (insert-left [1 2]) left next next next show-ip) ; [[1 2 *]]
  (-> e (insert-left [1 2]) left next next next next show-ip) ; [[1 2] *]
  (-> e (insert-left [1 2]) left next next next next prev show-ip) ; [[1 2 *]]

.toUpperCase

utilities — cgrand, 29 April 2009 @ 20 h 37 min

I recently learnt that when you want to convert the case of a technical identifier (a tagname, a HTTP header etc.) you must not use plain .toUpperCase or .toLowerCase but specify Locale/ENGLISH.

Mapping every second item

utilities — cgrand, 17 April 2009 @ 10 h 58 min

I wanted to apply a function to every second item in a coll. I was considering writing something using interleave, take-nth and map or a combination of mapcat and partition when I thought of this:

(map #(%1 %2) (cycle [f identity]) coll)

I really love clojure’s map parallel processing. (I should ask if every? and some could be allowed to take several colls.)

mapsplice

utilities — cgrand, 25 March 2009 @ 22 h 11 min

I needed to update a seq as follows: apply a given function to items at specified indices and insert the result (a seq) in place.
My first laborious attempt involved extracting subseqs of untouched items, mapping the function on the remaining items then joining everything back. Bleh! (Really, I don’t like indices but this time I haven’t found a way to work around.)
I was sad when, suddenly, I found this shortest solution:

(defn mapsplice [f coll indices]
  (let [need-splice (map (set indices) (iterate inc 0))]
    (mapcat #(if %2 (f %1) [%1]) coll need-splice)))
;; (mapsplice #(repeat % %) (range 10) [7 3])
;; (0 1 2 3 3 3 4 5 6 7 7 7 7 7 7 7 8 9)

Living on the bleeding edge

utilities — cgrand, 27 January 2009 @ 19 h 34 min

You can try clojure libs straight from the cloud:

(add-classpath "http://clojure-contrib.svn.sourceforge.net/viewvc/clojure-contrib/trunk/src/") ; sourceforge
(add-classpath "http://github.com/Lau-of-DK/clojureql/raw/master/src/"); github
(require '[clojure.contrib.duck-streams :as duck]) 
(require '[dk.bestinclass.clojureql :as ql])

Disclaimer:

  • add-classpath is not meant to be used anywhere but at the repl,
  • you’d better trust what you download,
  • if you are unlucky you can get an inconsistent snapshot,
  • use at your own risk!

Bindings and send

utilities — cgrand, 20 January 2009 @ 19 h 50 min

This morning on #clojure erohtar asked:

what is the best way to bind vars to a value when sending to an agent?

I don’t know if it’s the best way but it’s mine:

(defmacro capture-and-send
 "Capture the current value of the specified vars and rebind 
  them on the agent thread before executing the action."
 [vars agent action & args]
  (let [locals (map #(gensym (name %)) vars)]
    `(let [~@(interleave locals vars)
           action# (fn [& args#]
                     (binding [~@(interleave vars locals)]
                       (apply ~action args#)))]
       (send ~agent action# ~@args))))
;; usage:
(capture-and-send [*out*] a f b c)

I post it here because erohtar needed it, I needed it once so others may need it.

try-or, or-try, try-else or else-try?

utilities — cgrand, 8 January 2009 @ 18 h 26 min

I can’t decide which name is best for this macro:

(defmacro try-or
 "Evaluates exprs one at a time, from left to right. If a form returns a 
  value, this value is returned. If a form throws an exception, the next 
  form is evaluated. 
  If the last form throws an exception, the exception isn't caught." 
 ([] nil)
 ([form] form)
 ([form & forms]
   `(try 
      ~form
      (catch Exception e#
        (try-or ~@forms)))))

Recursive seqs

utilities — cgrand, 5 January 2009 @ 16 h 11 min

Recursively defined sequences are pretty but difficult to get right when you don’t want to assign the sequence to a var. Here is a couple of macros to ease recursive definitions.

(defmacro rec-cat 
 "Similar to lazy-cat but binds the resulting sequence using the supplied 
  binding-form, allowing recursive expressions. The first collection 
  expression must not be recursive and must return a non-nil seq."
 [binding-form expr & rec-exprs]
  `(let [rec-rest# (atom nil)
         result# (lazy-cat ~expr (force @rec-rest#))
         ~binding-form result#]
     (swap! rec-rest# (constantly (delay (lazy-cat ~@rec-exprs))))
     result#))
         
(defmacro rec-cons 
 "Similar to lazy-cons but binds the resulting sequence using the supplied 
  binding-form, allowing recursive expressions. The first expression must 
  not be recursive and must return a non-nil seq."
 [binding-form expr & rec-exprs]
  `(let [rec-rest# (atom nil)
         result# (lazy-cons ~expr (force @rec-rest#))
         ~binding-form result#]
     (swap! rec-rest# (constantly (delay (lazy-cat ~@rec-exprs))))
     result#))

Examples:

Natural numbers (just like (iterate inc 0)):

(rec-cons naturals 0 (map inc naturals))

fibonnaci sequence:

(rec-cat fibs [0 1] (map + fibs (rest fibs)))

Chouser’s cute reduction:

(defn reduction
  "Returns a lazy seq of the intermediate values of the reduction (as
  per reduce) of coll by f, starting with init."
  ([f coll]
   (if (seq coll)
     (rec-cons reductions (first coll) (map f reductions (rest coll)))
     (cons (f) nil)))
  ([f init coll]
   (rec-cons reductions init (map f reductions coll))))
Next Page »
(c) 2024 Clojure and me | powered by WordPress with Barecity