nextjournal / clerk

⚡️ Moldable Live Programming for Clojure
https://clerk.vision
ISC License
1.82k stars 78 forks source link

Lazy seqs in clerk/example are not realized in given order. #435

Open genmeblog opened 1 year ago

genmeblog commented 1 year ago

Found working example finally. It appears when forms return a sequence. More details in the code below.

With deps: io.github.nextjournal/clerk {:mvn/version "0.13.842"}

(ns clerk-rng.clerk-rng
  (:require [nextjournal.clerk :as clerk]))

;; ### Case 1, wrong result

;; In the following example, reseeding RNG has no effect when returning a sequence. 
;; Check the result of the last form, which should be the same as the first one.

^{::clerk/no-cache true}
(def rng1 (java.util.Random. 2288)) 

^{::clerk/no-cache true}
(clerk/example
 (repeatedly 3 #(.nextDouble rng1))
 (repeatedly 3 #(.nextDouble rng1))
 (do (.setSeed ^java.util.Random rng1 2288) rng1) ;; <---- this has no effect
 (repeatedly 3 #(.nextDouble rng1)))

;; ### Case 2, correct result

;; Here, reseeding RNG works as intended

^{::clerk/no-cache true}
(def rng2 (java.util.Random. 2288)) 

^{::clerk/no-cache true}
(repeatedly 3 #(.nextDouble rng2))
^{::clerk/no-cache true}
(repeatedly 3 #(.nextDouble rng2))
^{::clerk/no-cache true}
(do (.setSeed ^java.util.Random rng2 2288) rng2)
^{::clerk/no-cache true}
(repeatedly 3 #(.nextDouble rng2))

;; ### Case 3, correct result

;; It's similar to Case 1 but returns a primitive instead of sequence.

^{::clerk/no-cache true}
(def rng3 (java.util.Random. 2288)) 

^{::clerk/no-cache true}
(clerk/example
 (.nextDouble rng3)
 (.nextDouble rng3)
 (do (.setSeed ^java.util.Random rng3 2288) rng3)
 (.nextDouble rng3))

(comment
  (clerk/serve! {:browse? false})
  (clerk/clear-cache!)
  (clerk/halt!))
genmeblog commented 1 year ago

After discussion with @zampino on Slack

Any forms returning lazy sequences wrapped in the clerk/example (applies als to clerk/table and possibly any other container) realized in the order. In Case 1, lazy sequences are realized after setSeed is called.

IMHO the behaviour should be the same as with top level forms. Ie. all nested lazy sequences should be realized as they appear.

genmeblog commented 1 year ago

Temporary solution is to force realization, ie. wrapping all lazy seq forms into doall or vec.