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!