closures

Discussion of Common Lisp

closures

Postby MaartenM » Wed Jul 16, 2008 9:43 am

I am just learning Lisp. My first reaction when I saw this..:

Code: Select all
? (let ((counter 0))
    (defun counter-next ()
      (incf counter))
    (defun counter-reset ()
      (setq counter 0)))
COUNTER-RESET

? (counter-next)
1
? (counter-next)
2
? (counter-next)
3
? (counter-next)
4
? (counter-reset)
0
? (counter-next)
1

..was something to the effect of: holy shit!

Is this good Lisp code? Is this an inherent part of the Lisp Way? Would it be wise for me to start thinking about closures in this form of manner and try to come up with nifty implementations, or should I best forget I ever saw this?
MaartenM
 
Posts: 5
Joined: Tue Jul 15, 2008 7:55 am

Re: closures

Postby dmgenp » Wed Jul 16, 2008 10:38 am

Personally, i don't strive to always write my code 'the lisp way'. I try to write code the right way.
If creating closures with side effects solves my problem efficiently and elegantly, i'd do it.
If my code is functional, i won't pollute it with side effects.
dmgenp
 
Posts: 13
Joined: Sat Jun 28, 2008 10:15 am

Re: closures

Postby qbg » Wed Jul 16, 2008 10:54 am

Closures can be powerful, but typically you wouldn't see top level functions be closures; in this example, what if you wanted two counters? You could do something like this:
Code: Select all
CL-USER 12 > (defun make-counter ()
              (let ((count 0))
                (lambda (operation)
                  (case operation
                    (increment (incf count))
                    (reset (setf count 0))
                    (otherwise (error "Unknown operation ~a" operation))))))
MAKE-COUNTER

CL-USER 13 > (defvar *foo* (make-counter))
*FOO*

CL-USER 14 > (funcall *foo* 'increment)
1

CL-USER 15 > (funcall *foo* 'increment)
2

CL-USER 16 > (funcall *foo* 'reset)
0

CL-USER 17 > (funcall *foo* 'increment)
1

CL-USER 18 > (funcall *foo* 'blah)

Error: Unknown operation BLAH
  1 (abort) Return to level 0.
  2 Return to top loop level 0.

Type :b for backtrace, :c <option number> to proceed,  or :? for other options

CL-USER 19 : 1 > :c 2


This also shows that closures are a poor man's objects and objects are a poor man's closures. :)
qbg
 
Posts: 64
Joined: Mon Jun 30, 2008 1:05 pm
Location: Minnesota

Re: closures

Postby findinglisp » Wed Jul 16, 2008 12:52 pm

qbg wrote:This also shows that closures are a poor man's objects and objects are a poor man's closures. :)


Exactly. There are times when closures are the wicked-cool, just-right-for-the-problem solution. And they are very helpful for a variety of problems. But when I really want an object, I typically just use CLOS. While the two are the poor-man's inverse of each other, there is a time and place for both.
Cheers, Dave
Slowly but surely the world is finding Lisp. http://www.findinglisp.com/blog/
findinglisp
 
Posts: 440
Joined: Sat Jun 28, 2008 7:49 am
Location: Austin, TX

Re: closures

Postby danb » Wed Jul 16, 2008 3:20 pm

qbg wrote:what if you wanted two counters? You could do something like this:
Code: Select all
CL-USER 12 > (defun make-counter ()
              (let ((count 0))
                (lambda (operation)
                  (case operation
                    (increment (incf count))
                    (reset (setf count 0))
                    (otherwise (error "Unknown operation ~a" operation))))))
MAKE-COUNTER



Or, at compile time:

Code: Select all
(defmacro defcounter (name)
  (let* ((namestr (symbol-name name))
         (next  (intern (concatenate 'string "NEXT-"  namestr)))
         (reset (intern (concatenate 'string "RESET-" namestr))))
    `(let ((counter -1))
      (defun ,next  () (incf counter))
      (defun ,reset () (setf counter -1)))))

(defcounter foo)
(defcounter bar)


To the OP,

MaartenM wrote:Is this good Lisp code? Is this an inherent part of the Lisp Way?

Yes, it's fine.

Would it be wise for me to start thinking about closures in this form of manner and try to come up with nifty implementations, or should I best forget I ever saw this?


No, don't forget it. Use it when it's useful, don't use it when it's not useful.
danb
 
Posts: 35
Joined: Sat Jun 28, 2008 1:05 pm
Location: Urbana, Illinois, US

Re: closures

Postby luskwater » Thu Jul 17, 2008 9:18 am

Well, I just recently saw this somewhere....ah, the config.lisp file for SBCL, or CLISP, or CMUCL...not sure which at the moment.
Code: Select all
(let ((cache nil))
  (defun long-site-name ()
    (if cache cache
   (setq cache
         (some-lengthy-calculation-with-IO-from-shell)))))       

so there's an idiom for regular use of closures and top-level functions.
luskwater
 
Posts: 3
Joined: Tue Jul 08, 2008 5:29 am
Location: Philadelphia, PA, USA

Re: closures

Postby dlweinreb » Fri Jul 18, 2008 5:12 am

There's nothing wrong with your code.

However, what you're doing looks a lot like object-oriented programming. As was pointed out, closures can sort of be used as a poor person's OOP mechanism. But, using Common Lisp, you are a rich person: you have CLOS!

There are plenty of other uses for closures that are less like OOP. Often you can use either, but one of them usually ends up being more clear and stylish, reflecting the programmer's intent more clearly.
dlweinreb
 
Posts: 41
Joined: Tue Jul 01, 2008 5:11 am
Location: Lexington, MA


Return to Common Lisp

Who is online

Users browsing this forum: No registered users and 4 guests