code-reviews

2020-09-04T20:45:20.043900Z

Hey team, potentially, complicated question: Context I am playing with a stream library, that works with delay [1]:

(defmacro my-delay [& forms]
  `(memoize (fn [] ~@forms)))

(defn my-force [f]
  (f))

(defmacro cons-stream [a b]
  `[~a (my-delay ~b)])

(defn car-stream [s] (first s))
(defn cdr-stream [s]
  (my-force (second s)))
[1] https://github.com/nezaj/clj-sicp/blob/master/src/chp3.clj#L132-L143 By delaying the second form of cons-stream until cdr-stream is called, I can create infinite sequences. Example This works fine and dandy: here’s an infinite sequence of integers [2]:
(defn numbers-starting-from [n]
  (cons-stream n (numbers-starting-from (+ 1 n))))

(def integers (numbers-starting-from 1))

(car-stream (cdr-stream (cdr-stream integers))) ;; 3
[2] https://github.com/nezaj/clj-sicp/blob/master/src/chp3.clj#L145-L146 Interleave Now, I wrote a function called interleave, that works like this:
(defn interleave [s1 s2]
  (cons-stream (car-stream s1) (interleave s2 (cdr-stream s1))))
This can work great, as long as I use interleave in some delayed way, but I cannot write:
(defn pairs [s1 s2]
  (interleave
    (map-stream
      (fn [x] (list (car-stream s1) x))
      s2)
    (pairs (cdr-stream s1) (cdr-stream s2))))
Problem The problem is , interleave is a normal function, is it will try to evaluate (pairs (cdr-stream s1) (cdr-stream s2) , which will get stuck in an infinite loop. I thought, maybe I can rewrite interleave to be a macro, so that it doesn’t evaluate that form:
(defmacro interleave [s1 s2]
  `(cons-stream (car-stream ~s1) (interleave ~s2 (cdr-stream ~s1))))
Buut this doesn’t seem to work:
(cdr-stream (interleave integers integers))
=>
(1
 2
 #object[clojure.core$memoize$fn__6877 0x548d61e6 "clojure.core$memoize$fn__6877@548d61e6"]
 #object[clojure.core$memoize$fn__6877 0x3b448ef "clojure.core$memoize$fn__6877@3b448ef"])
``` This seems entirely unexpected. Am sure I am writing this macro wrong. If you thoughts lmk!