Jump to content

Recommended Posts

Posted

Good evening, everyone.

 

I've recently started to watch the Abelson-Sussman MIT lectures on computer science (mostly because I find them very interesting, not because they have much to do with what I do) and I've ran across this piece of code to create a counter:

 

(define make-counter
 (lambda (N)
   (lambda ()
     (set! N (1+ N))
     N)))

(define c1 (make-counter 1))
(define c2 (make-counter 10))

The explanation concerning the mentioned code starts at around the 48 minute mark.

 

The syntax is not that of AutoLISP and neither that of Common Lisp, I believe, mostly because it's a fragment taken from the middle of a lecture and there's a good reason for the way the code above is written.

 

Anyway, what is supposed to happen is that when you run (c1) for the first time you get a 2; for the second time you get a 3 etc.; when you run (c2) you get (regardless of when you run (c1)) 11; the next time you get 12 etc.

 

I attempted to translate it to AutoLISP:

 

(defun make-counter (N)
 (lambda () (setq N (1+ N)) N)
)

(defun c1 ()
 ((make-counter 1))
)

(defun c2 ()
 ((make-counter 10))
)

The problem is that this does not work. When I attempt to evaluate this with N being nil I get an error. If N is preset to some integer/real then it will be incremented, regardless of calling c1 or c2.

 

I'd like to know if I'm doing something wrong or if this is something that I simply cannot do in AutoLISP. Can this piece of code run the way Sussman shows it in his lecture? Is there a catch here?

 

This is not a matter of life or death, obviously, and I'm not interested in another piece of code that works as a counter (though I'd be delighted to see whichever ones you guys came up withd) since this is something I can easily get around. All I wanted is to know if this can work in AutoLISP and, if so, how.

 

Thank you all!

Posted

After you finish using (c1) and (c2) you must nil variables m and n to make (c1) and (c2) can start over...

 

(defun make-counter (N)
 ((lambda (N) (setq N (1+ N))) N)
)

(defun c1 nil
 (if n (setq n (1+ n)) (setq n 1))
 (make-counter n)
)

(defun c2 nil
 (if m (setq m (1+ m)) (setq m 10))
 (make-counter m)
)

(defun nil-mn nil
 (setq n nil m nil)
)

 

M.R.

Posted

Hi Jack,

 

In your example, since the symbol 'N' is an argument for the 'make-counter' function, it's scope will lie within the 'make-counter' function. When this function is called, the argument 'N' will inherit the value passed to the function, then, when the 'make-counter' function completes execution, the symbol 'N' will resume any value it held before the 'make-counter' function was called.

 

Marko's examples utilise global variables which are not localised to any function and hence reside in the document namespace, and are availabel to all functions for which they are not local variables or arguments.

  • 2 months later...
Posted (edited)

Gentlemen,

 

Thank you for your assitance. However, I was left unsatisfied with the use of global variables (other than the name of the counter function itself) to make this counter possible.

 

I left this problem alone for some time but just yesterday I found out about the functions defun-q, defun-q-list-ref and defun-q-list-set and the make-counter routine seemed possible again in my mind.

 

After a few hours of working with these functions I finally managed to do what I wanted. My code looks nothing like the Abelson-Sussman one, that is for sure, but I believe I have managed to simulate a frame by rewriting the functions c1 and c2 every time they are called.

 

 

(defun-q make-counter
        (N)
        (set 'N (1+ N)))

(defun boot-c1 ()
(defun-q c1
        ()
        (defun-q-list-set 'c1
          (cons nil
          (cons (cadr c1) (list (cons 'make-counter (list (last c1)))))))
        (make-counter 0)))


(defun boot-c2 ()
(defun-q c2
        ()
        (defun-q-list-set 'c2
          (cons nil
          (cons (cadr c2) (list (cons 'make-counter (list (last c2)))))))
        (make-counter 0)))

Every time you need to reset the counter you call boot-*CounterName*. From then on, every time you call the counter (such as (c1), for example) it will be incremented and the c1 function itself will be rewritten. The counters c1 and c2 (and any other you would like to create) work independently.

 

I posted the code here so I could get your opinion on it. I have never written something like this before, so I need to know if it's buggy or something.

 

Thank you all for your time and collaboration.

 

Edit: slight improvements.

 

(defun-q [b]make-counter[/b]
        (N)
        (set 'N (1+ N)))

(defun-q
 [b]boot-CounterX[/b]
 ()
 (defun-q
   [b]CounterX[/b]
   ()
   (defun-q-list-set
     '[b]CounterX[/b]
     (cons nil
           (cons (cadr [b]CounterX[/b])
                 (list (cons '[b]make-counter[/b] (list (last [b]CounterX[/b])))))))
   ([b]make-counter[/b] 0)))

(defun [b]replace-instances[/b]  (#Searched #Placed #List)
 (if (listp #List)
   (mapcar '(lambda (@Element)
              (if ([b]match[/b] @Element 'LIST)
                ([b]replace-instances[/b] #Searched #Placed @Element)
                (if (equal @Element #Searched)
                  #Placed
                  @Element)))
           #List)
   (progn
     (princ "\nREPLACE-INSTANCES error: invalid argument.")
     (exit))))

(defun [b]boot-counter[/b]  (#Name)
 (if ([b]match[/b] #Name 'SYM)
   (progn
     (defun-q-list-set
       #Name
       ([b]replace-instances[/b]
         '[b]CounterX[/b]
         #Name
         (defun-q-list-ref '[b]boot-CounterX[/b])))
     ((eval #Name))
     (princ (strcat "Counter " (vl-symbol-name #Name) " set."))
     (princ))
   (progn
     (princ "\nBOOT-COUNTER error: invalid argument.")
     (exit))))

 

With such routines you can create a counter and reboot with any name using boot-counter. I didn't add any options to start from any number different from zero, but that can be easily done.

Edited by JackStone

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...