this post was submitted on 24 Nov 2023
1 points (100.0% liked)

Lisp

52 readers
3 users here now

founded 1 year ago
MODERATORS
 

Hi. Need help with creating the 'for' macro. It must take a parameter, an initial value, an end value, and a loop step. Macro must return amount of iteration. Various operations should take place inside it. It should be designed without leaks.The preliminary version looks like this:

(defmacro for ((param-name start-value end-value &optional (step1 1)) &body body)
  (let* ((func-name (gensym))
(start (gensym))
(param-name (gensym))
(comparison (if (< step1 0) '< '>))
(end (gensym))
(step (gensym))
(k (gensym)))
'(labels ((,func-name (,param-name ,start ,end ,step ,k)
(let ((new-exprs (progn ,@body))
(newK (+ 1 ,k)))
(if (,comparison ,end ,param-name)
(,func-name (+ ,param-name ,step) ,start ,end ,step newK)
newK))))
(,func-name ,param-name ,start-value ,end-value ,step1 0))))

I understand that it looks terrible. I don't understand how you can access the parameter without violating the rule about leaks.

you are viewing a single comment's thread
view the rest of the comments
[–] lispm@alien.top 1 points 10 months ago (1 children)
[–] Revolutionary_Utena@alien.top 1 points 10 months ago (1 children)

(defmacro for
  ((param-name start-value end-value &optional (step1 1)) &body body)
    (let* ((func-name (gensym))
           (comp (gensym))
           (comparison (if (< step1 0) '<= '>=))
           (start (gensym))
           (end (gensym))
           (step (gensym))
           (k (gensym)))
      `(let ((,start ,start-value)
             (,comp ,comparison)
             (,end ,end-value)
             (,step ,step1))
        (labels ((,func-name (,param-name ,k)
                   (if (,comparison ,end ,param-name)
                       (progn (progn ,@body)
                         (,func-name (+ ,param-name ,step)
                                     (1+ ,k)) ,k))))
        (,func-name ,start 1)))))

Do you know how can I close leak with comparison? When I am trying to bound comp to evaluated operator of comparison I receive error.

[–] lispm@alien.top 1 points 10 months ago (1 children)

(defmacro for   ((param-name start-value end-value &optional (step1 1)) &body body)     (let* ((func-name (gensym))            (comp (gensym))            (comparison (if (< step1 0) '<= '>=))            (start (gensym))            (end (gensym))            (step (gensym))            (k (gensym)))       `(let ((,start ,start-value)              (,comp ,comparison)              (,end ,end-value)              (,step ,step1))         (labels ((,func-name (,param-name ,k)                    (if (,comparison ,end ,param-name)                        (progn (progn ,@body)                          (,func-name (+ ,param-name ,step)                                      (1+ ,k)) ,k))))         (,func-name ,start 1)))))

Your indentation is wrong. The last ,k is at a wrong place. Shouldn't it be returned by the other if clause.

If you have an error and you need help, then you need to provide the necessary information:

  • a reproducible example
  • the error message
[–] Revolutionary_Utena@alien.top 1 points 10 months ago (1 children)

(defmacro for
  ((param-name start-value end-value &optional (step1 1)) &body body)
    (let* ((func-name (gensym))
           (comp (gensym))
           (comparison (if (< step1 0) '<= '>=))
           (start (gensym))
           (end (gensym))
           (step (gensym))
           (k (gensym)))
      `(let ((,start ,start-value)
             (,comp ,comparison)
             (,end ,end-value)
             (,step ,step1))
        (labels ((,func-name (,param-name ,k)
                   (if (,comp ,end ,param-name)
                       (progn (progn ,@body)
                         (,func-name (+ ,param-name ,step)
                                     (1+ ,k)) ) ,k)))
        (,func-name ,start 0)))))

Sorry man. I kinda fixed the issue. When I am trying to call macros, it return me error
; compilation unit finished

; Undefined functions:

; #:G1 #:G7

; Undefined variable:

; >=
I don't know how to deal with bounding <= or >= to generated variable.

[–] lispm@alien.top 1 points 10 months ago

why would evaluate the comparison? The comparison is a symbol, which a name for the function. Just use that symbol and insert it into the code.

(defmacro for ((param-name start-value end-value &amp;optional (step1 1)) &amp;body body)
  (let* ((func-name (gensym))
         (comparison (if (&lt; step1 0) '&lt;= '>=))
         (start (gensym))
         (end (gensym))
         (step (gensym))
         (k (gensym)))
    `(let ((,start ,start-value)
           (,end ,end-value)
           (,step ,step1))
       (labels ((,func-name (,param-name ,k)
                  (if (,comparison ,end ,param-name)
                      (progn (progn ,@body)
                        (,func-name (+ ,param-name ,step)
                                    (1+ ,k)))
                    ,k)))
         (,func-name ,start 0)))))

If you actually want to make sure that function does not get redefined, you need to understand that functions and variables are in different namespaces. You would need to get a function object and funcall it.

(defmacro for ((param-name start-value end-value &amp;optional (step1 1))
               &amp;body body)
  (let* ((func-name (gensym))
         (comp (gensym))
         (comparison (if (&lt; step1 0) '#'&lt;= '#'>=))
         (start (gensym))
         (end (gensym))
         (step (gensym))
         (k (gensym)))
    `(let ((,start ,start-value)
           (,comp ,comparison)
           (,end ,end-value)
           (,step ,step1))
       (labels ((,func-name (,param-name ,k)
                  (if (funcall ,comp ,end ,param-name)
                      (progn (progn ,@body)
                        (,func-name (+ ,param-name ,step)
                                    (1+ ,k)) ) ,k)))
         (,func-name ,start 0)))))

But you don't need that.

If you want to debug macros, you need to see the expansion. Do it like this:

CL-USER 14 > (pprint
              (macroexpand
               '(for (i start end)
                  (print i))))

(LET ((#:G1788 START) (#:G1789 END) (#:G1790 1))
  (LABELS ((#:G1787 (I #:G1791)
             (IF (>= #:G1789 I)
                 (PROGN
                   (PROGN (PRINT I))
                   (#:G1787 (+ I #:G1790) (1+ #:G1791)))
               #:G1791)))
    (#:G1787 #:G1788 0)))