bobbicodes / bobbi-lisp

Interactive Lisp environment for learning Clojure
https://bobbicodes.github.io/bobbi-lisp/
0 stars 0 forks source link

For macro fails sometimes #30

Open bobbicodes opened 11 months ago

bobbicodes commented 11 months ago

The only discernible pattern seems to be that :when clauses never work. But those aren't the only ones that are failing.

I'm not sure how long it's been this way, but I seem to remember that :when used to work. My guess is that it was when destructuring was added.

These examples all work:

(def digits [1 2 3])

(for [x1 digits
      x2 digits]
  (* x1 x2))

(for [x ['a 'b 'c] 
      y [1 2 3]]
  [x y])

(for [x (range 1 6) 
      :let [y (* x x) 
            z (* x x x)]] 
  [x y z])

(for [x (range 6)] 
  (* x x))

(for [x (range 3) y (range 3)] [x y])

(for [x (range 3) :while (not= x 1) y (range 3)] [x y])

(defn prime? [n]
         (not-any? zero? (map #(rem n %) (range 2 n))))

(for [x (range 3 33 2) :while (prime? x)]
         x)

(for [x (range 3 17 2) :while (prime? x)
             y (range 3 17 2) :while (prime? y)]
         [x y])

These do not:

(for [x [0 1 2 3 4 5]
      :let [y (* x 3)]
      :when (even? y)]
  y)
=> 
Error: seq: called on non-sequence 

(for [[x y] '([:a 1] [:b 2] [:c 0]) :when (= y 0)] x)
=> 
Error: Invalid 'for' keyword :b 

(for [x (range 3) y (range 3) :when (not= x y)] [x y])
=> 
Error: seq: called on non-sequence 

(for [x (range 3) y (range 3) :while (not= x y)] [x y])
=> 
Error: seq: called on non-sequence 

(for [x (range 3) y (range 3) :while (not= x 1)] [x y])
=> 
Error: seq: called on non-sequence 

(defn prime? [n]
         (not-any? zero? (map #(rem n %) (range 2 n))))

(for [x (range 3 33 2) :when (prime? x)]
         x)
=> 
Error: seq: called on non-sequence 

(for [x (range 3 17 2) :when (prime? x)
             y (range 3 17 2) :when (prime? y)]
         [x y])

(for [x [1 2 3]
             y [1 2 3]
             :while (<= x y)
             z [1 2 3]]
         [x y z])
bobbicodes commented 11 months ago

Here is a macroexpansion of a call to for that fails, followed by one that works:

(let* [G__2561 (defn iter__2562 [s__2563]
                 (loop [s__2563 s__2563]
                   (when-let [s__2563 (seq s__2563)]
                     (let [[x y] (first s__2563)]
                       (if (= y 0)
                         (cons x (iter__2562 (rest s__2563)))
                         (#function[do-mod] (rest s__2563)))))))]
      (remove nil?
              (G__2561 (quote ([:a 1] [:b 2] [:c 0])))))

(let* [G__2849 (defn iter__2850 [s__2851]
                  (loop [s__2851 s__2851]
                    (when-first [x s__2851]
                      (when (not= x 1)
                        (let [iterys__2852 (defn iter__2868 [s__2869]
                                             (loop [s__2869 s__2869]
                                               (when-let [s__2869 (seq s__2869)]
                                                 (let [y (first s__2869)]
                                                   (cons [x y] (iter__2868 (rest s__2869)))))))
                              fs__2853     (seq (iterys__2852 (range 3)))]
                          (if fs__2853
                            (concat fs__2853 (iter__2850 (rest s__2851)))
                            (#function[do-mod] (rest s__2851))))))))]
  (remove nil? (G__2849 (range 3))))

clj-kondo informs me that the loop expressions are missing recurs. That is because the recur happens in do-mod.

Come to think of it, the way loop/recur works was also changed significantly. But that's because the old implementation was very much wrong. It used to hold the loop locals in a global variable, and now recur works by constructing a new call to loop using the new values.

bobbicodes commented 11 months ago

I made it so the error message from seq prints the object attempted to sequence. They happen to be numbers:

(for [x [0 1 2 3 4 5]
      :let [y (* x 3)]
      :when (even? y)]
  y)
=> 
Error: seq: called on non-sequence: 2