               (do (vreset! fst input) (rf results input))) ;; fst is nil. reset fst and return the results.
             (rf results (impl/cast-row cast-fns input :only only :exception-handler exception-handler)))))))))
 
-;; TODO: properly implement except first as transducer.  need to take n functions and apply then in order as in ->>.
-;; (defn except-first
-;;   []
-;;   (fn [rf]
-;;     (let [fst (volatile! nil)]
-;;       (fn
-;;         ([] (rf))
-;;         ([results] (rf results))
-;;         ([results input]
-;;          (if @fst
-;;            (rf results)))))))
+;; Let's try casting a numeric column using this function:
+;;
+;;     => (with-open [in-file (io/reader "test/test.csv")]
+;;          (transduce
+;;            (comp
+;;              (remove-comments)
+;;              (mappify)
+;;              (cast-with {:this #(Integer/parseInt %)}))
+;;            conj
+;;            []
+;;            (csv/parse-csv in-file)))
+;;
+;;     ({:this 1, :that "2", :more "stuff"}
+;;      {:this 2, :that "3", :more "other yeah"})
+;;
+;; Alternatively, if we want to cast multiple columns using a single function, we can do so
+;; by passing a single casting function as the first argument.
+;;
+;;     => (with-open [in-file (io/reader "test/test.csv")]
+;;          (transduce
+;;            (comp
+;;              (remove-comments)
+;;              (mappify)
+;;              (cast-with #(Integer/parseInt %) {:only [:this :that]}))
+;;            conj
+;;            []
+;;            (csv/parse-csv in-file)))
+;;
+;;     ({:this 1, :that 2, :more "stuff"}
+;;      {:this 2, :that 3, :more "other yeah"})
+;;
+;; Note that this function handles either map or vector rows.
+;; In particular, if you’ve imported data without consuming a header (by either not using mappify or
+;; by passing `:header false` to `process` or `slurp-csv` below), then the columns can be keyed by their
+;; zero-based index.
+;; For instance, `(cast-with {0 #(Integer/parseInt %) 1 #(Double/parseDouble %)} rows)`
+;; will parse the first column as integers and the second as doubles.
+;;
+;; <br/>
+;; It's worth pointing out this function isn't strictly an _input_ processing function, but could be
+;; used for intermediate or output preparation processing.
+
+
+;; <br/>
+;; ## process
 
 (defn process
   "This function wraps together the most frequently used input processing capabilities,

    (transduce (process rest-options) conj []
     (impl/apply-kwargs csv/parse-csv csv-readable parser-opts))))

(defn slurp-csv
  "This convenience function let's you `parse-and-process` csv data given a csv filename. Note that it is _not_
  lazy, and must read in all data so the file handle can be closed."

;; # Core functionality as Transducers
;;

(ns semantic-csv.transducers
  "# Transducers API namespace"
  (:require [clojure.java.io :as io]
            [clojure-csv.core :as csv]
            [semantic-csv.impl.core :as impl :refer [?>>]]))

;; # Input processing functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Note that all of these processing functions return a transducer unless otherwise stated.
;; This allows for single passes accross collections.
;;


;; <br/>
;; ## mappify

(defn mappify
  "Takes a sequence of row vectors, as commonly produced by csv parsing libraries, and returns a sequence of
