Structure of parser in Clojure I'm working on my first Clojure project, which is a parser. Since it's my first project I'm unsure of many aspects, from my general approach to solving this problem to the small implementation details. I also don't know anyone proficient in Clojure so any guidance is welcome.

In higher terms, my implementation will take a string (which is one message to be parsed) and break it into fields. Each field it will apply some function to (often a dictionary lookup), and finally return a dictionary of results.

(use 'clojure.string)

;; This defines the breakdown of each line in the file. The line contains an entry and start with something
;; like "1AXYZ ". In this case the first two characters ("1A") are the "Record Type" and the next four
;; ("XYZ ") are the "Entering Firm". This data structure holds that information.
(def parser
  {:shared '(  ; These are the entries shared amongst all types of message

          ;; Field-Name  num-chars
             Record-Type 2   
             Entering-Firm 4
             Clearing-Number 4
             Symbol 11
             Lot-Indicator 1
             ;;...
             )

   :1A     '(      ; this is one type of message, indicated with record-type=1A

          ;; Field-Name  num-chars
             Filler 9
             Poss-Dupe 1
             Booth-Booked-Indicator
             Order-Time 6
             Order-Date 8
             ;; ...
             )
   }
)


;; if no implementation is found for a field, just return a map to its contents.
(defn default [header x]
  {(str header) (trim (join x))})


;; most of the fields that dont use the default function will just be a dictionary lookup    
(defn Poss-Dupe [[x]] (default 'Poss-Dupe ({\1 "Odd Lot" \D "Rule 902" \E "Poss Dupe Rule 902" 
                                            \F "Auto Execution" \G "Poss Dupe of Auto-Execution" 
                                            \H "Non-auto Execution" \I "Poss Dupe of Non-auto Execution"
                                            \0 "" \space ""}
                                               x (str "ERROR: " x))))

(defn Booth-Booked-Indicator [[x]] (default 'Booth-Booked-Indicator ({\0 "Post" \1 "Booth" \2 "Booked"} x (str "ERROR: " x))))

(defn Order-Time [x] (default 'Order-Time (-&gt;&gt; x (partition 2) (map join) (join ":")  ))) ; "HHMMSS" -&gt; "HH:MM:SS"

(defn Order-Date [x] (default 'Order-Date 
                       (join "-" (map join (list (take 4 x) (take 2 (drop 4 x)) (drop 6 x)))))) ; "YYYYMMDD"-&gt;"YYYY-MM-DD"

(defn Filler [x] nil)


(defn try-call [f subseq]
  (try
    ((eval f) subseq)
    (catch Exception e  ; f not defined -&gt; call default
      (default f subseq))))


;; Where the recursion happens
(defn grab-call [[f n &amp; rest-instructions] line] 
  (let [[field rest-line] (split-at n line)]
    (if (or (empty? line) (not f)) 
      nil
      (merge (try-call f field) (grab-call rest-instructions rest-line)))))


;;; Entry point
(defn parse-line [line]
  (grab-call (concat (:shared parser) 
                     ((keyword (subs line 0 2)) parser)) 
    line ))


If you care to know the particulars of what is being parsed, that can be found at NYSE MRO specs.
There is a lot of weird stuff here.


It's strange to have no ns form for defining your namespace and requiring the libraries you need. Putting a bare use at the top is gross.
Don't use an entire namespace. Either require with an alias, like (:require [clojure.string :as s]) ... (s/join ...), or else require and refer the specific stuff you use: `(:require [clojure.string :refer [join trim]]).
The uppercase function names should be lowercase: poss-dupe, or even possible-duplicate, not Poss-Dupe
There should be a newline after the parameter definitions for most functions: (defn foo [x] \newline (...))
The eval is very suspicious, but I don't want to read your whole program and figure out what you should be doing instead. Probably ns-resolve or something.
(if (or (empty? x) f) nil y) is a bad way to write (when (and (seq x) f) y)
Usually calling keyword to look stuff up in a map suggests that you shouldn't be using keywords as keys, but in your case it looks fine-ish. However, instead of ((keyword whatever) m), it would be more readable to write (get m (keyword whatever)).