Skip to content

Instantly share code, notes, and snippets.

@jennifersmith
Created January 4, 2012 02:11
Show Gist options
  • Save jennifersmith/1558084 to your computer and use it in GitHub Desktop.
Save jennifersmith/1558084 to your computer and use it in GitHub Desktop.
Weird non lazy behaviour
;; I thought map was lazy and that first only took the first thing but ...
(first (map (fn [x] (print "XXXX" x "XXXX") x) [1 2 3 4])) ;; XXXX 1 XXXXXXXX 2 XXXXXXXX 3 XXXXXXXX 4 XXXX1
;; Unless it is a list
(first (map (fn [x] (print "XXXX" x "XXXX") x) '(1 2 3 4)));; XXXX 1 XXXX1
;; deffing it gives no output
(def foo (map (fn [x] (print "XXXX" x "XXXX") x) [1 2 3 4]))
;; but this does
(first foo) ;; XXXX 1 XXXXXXXX 2 XXXXXXXX 3 XXXXXXXX 4 XXXX1
;; this doesn't eval the map result
(first (cons "A" (map (fn [x] (print "XXXX" x "XXXX") x) [1 2 3 4]))) ;; "A"
@cocodrino
Copy link

Hi..well this behaviour is a bit weird..exactly I can't explain you why happen (the problems is related to how clojure is implemented) but the problem is than u are using a side effect function inside a map and that's wrong because first clojure is evaluating the side effect (print) and then evaluate your x...if you wanna try your code must use (swank.core/break) inside your code instead print because this has side effect...if you wanna use side effect functions use doseq...now playing a bit with the repl you can notice a few things:

if you write:
(first (map #(* 10 %) (iterate inc 1)))
your are evaluating the first term in a infinite sequence..

but if you write:
(first (map #((print %) * 10 %) (iterate inc 1)))
you get a overflow..that is because clojure first try print every number until infinite and then take the first number...of course..this never get the first number

now I use a little modification your script
(interleave (map (fn x x) [1 2 3 4]) (repeat "-")) or more readable

(->
(map (fn x x) [1 2 3 4])
(interleave (repeat "-")))

you will get (XXXX 1 XXXXXXXX 2 XXXXXXXX 3 XXXXXXXX 4 XXXX1 "-" 2 "-" 3 "-" 4 "-")
here print every side effect and then print the numbers
notice than XXXX 1 XXXXXXXX 2 XXXXXXXX 3 XXXXXXXX 4 XXXX isn't a term..but the repl mix these with the real sequence because they are evaluate first...weird??
you can notice it if you do in the repl...writing this in 2 steps..first write
(map (fn x x) [1 2 3 4]) and then write

(interleave *1 (repeat "-"))
you will get a perfect (1 "-" 2 "-" 3 "-" 4 "-")

if you've the book pragmatic clojure in the macro part the author gives a explanation why this happen ("....The problem is that Clojure evaluates
all the arguments before passing them to a function, so the println
is called before unless ever sees it. ...")

I hope than it can help u...bye :) ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment