        io/reader
        line-seq
        tag-lines
+       var-lines
        check-length
        (s/join "\n")
        (spit fout-path)))

  "Return the name of a hashtag, if any. Otherwise return nil."
  [line]
  (last (first (re-seq #"#(\S+)" line))))

(defn attag
  "Return the name of an @tag, if any. Otherwise return nil."

                     (into {}))]
    (map (partial replace-attag tag-map) source)))

(defn replace-vars
  "Given a string (line) and a map of tags to line numbers, replace any instance
  of @tag with the corresponding number. Otherwise return the line."
  [var-lst line]
  (reduce (fn [l var]
            (let [idx (.indexOf var-lst var)]
              (-> (s/replace l
                             (str "$" var)
                             (str "[" idx "]"))
                  (str (format " ; $%s = %d" var idx)))))
          line
          (vars line)))

(defn var-lines
  [seq-of-lines]
  (let [source  (->> seq-of-lines
                     (filter (complement comment?)))
        var-lst (vec (mapcat vars source))]
    (if (> (count var-lst) 255)
      (throw (IllegalArgumentException. "Too many variables!")))
    (mapv (partial replace-vars var-lst) source)))

(defn check-length
  "The maximum length for a GHC program is 256 instructions.
  Throw an exception if the program is too long, otherwise
  just return it."
  [lines]
  (if (> (count lines) 256)
    (throw (IllegalArgumentException. (format "This program is too damn long! %d lines!" (count lines))))
    lines))

(defn tag-file*
  [fin-path]
  (->> fin-path
       io/reader
       line-seq
       tag-lines
       var-lines
       check-length
       (s/join "\n")))

(defn tag-file
  [fin-path fout-path]
