jayunit100
jayunit100

Reputation: 17650

Clojure : Return value being evaluated

*Simple question : Why does this function throw an exception when evaluated ? *

*The Code *

(defn first-duplicate-char [str-in]
      (loop [list-Rem (seq str-in) set-Seen (set [])]
        (print (type list-Rem) " " list-Rem (next list-Rem) "\n")
        (if (= 0 (count str-in))
            nil
            (if (some #(= (first list-Rem) %) set-Seen)
                (first list-Rem)
                (recur  
                    (seq (next list-Rem))
                    (conj set-Seen (first list-Rem)))))))

Upvotes: 1

Views: 212

Answers (1)

Your problem is that (= 0 (count str-in)) never changes, so you eventually try to call first on nil. [EDIT: I'm wrong, your code actually works as is -- that if statement is just a no-op. I hope you enjoy the rest of this answer anyway.]

Instead, you should be calling next (not rest) on list-Rem in the recur and using list-Rem directly in the if test, using the property of next that returns nil for an empty seq. Here's how I would rewrite your code:

(defn first-duplicate [in]
  (loop [seen #{}
         remain (seq in)]
    (when-let [[head & tail] remain]
      (if (contains? seen head)
        head
        (recur (conj seen head) tail)))))

Changes:

  • lowercasing names
  • no need to call seq on the output of next or rest
  • with sets, contains? (check for existence of key) is faster than some (run a predicate on elements until something yields a truthy value)
  • set literal
  • using when to return nil on test failure
  • using when-let to destructure and bind first char and rest

Stylistic changes:

  • names changed to be less specific (not restricted to strings, for instance)
  • change order of loop locals so that recur looks more like structural recursion
  • put loop locals on separate lines

Upvotes: 2

Related Questions