Search code examples
clojurerecord

iterating over a sequence of records


I'm trying to display the items in the menu-items variable using the for-macro:

(defrecord MenuItem
  [select-char description])

(def menu-items [(MenuItem. "1" "add an expense")
         (MenuItem. "2" "add an income")
         (MenuItem. "0" "exit")])

(defn display-menu [items]
  (for [item items]
    (println (:select-char item))))

(defn menu-prompt [items]
  (display-menu items)
  (read-val ">>>"))

(println menu-items)
(menu-prompt menu-items)

However, nothing but the >>> prompt is displayed. Could someone explain why that is, and how to display the items?


Solution

  • this is a case of "the lazy bug"

    for produces a lazy sequence that is only evaluated as it is read.
    the call to display-menu just returns a reference to the list and then goes on it's marry way having done nothing.

    wrap it in a call to doall

    user> (def a (for [x (range 10)] (println "doing work " x)))
    #'user/a
    user> a
    (doing work  0
    doing work  1
    doing work  2
    doing work  3
    doing work  4
    doing work  5
    doing work  6
    doing work  7
    doing work  8
    doing work  9
    nil nil nil nil nil nil nil nil nil nil)
    

    if you use doall or dorun then it will do the work immediately.

    user> (dorun (for [x (range 10)] (println "doing work " x)))
    doing work  0
    doing work  1
    doing work  2
    doing work  3
    doing work  4
    doing work  5
    doing work  6
    doing work  7
    doing work  8
    doing work  9
    nil
    user> (doall (for [x (range 10)] (println "doing work " x)))
    doing work  0
    doing work  1
    doing work  2
    doing work  3
    doing work  4
    doing work  5
    doing work  6
    doing work  7
    doing work  8
    doing work  9
    (nil nil nil nil nil nil nil nil nil nil)