Bookmark and Share

EG Information

Main Index
EG Manual
Disclaimer
Legal Information
Hall of Fame
Hall of Shame
Member Rankings
Members List
Meet the Staff

Training Missions

Read Me First New
Basic Skills
Realistic Scenarios
Cryptography
Software Cracking
Linux ELF Binary Cracking
Logical Thinking
Programming
Patching
Steganography
Deface This Wall
/dev/null
/dev/urandom

Knowledge Bank

Discussion Forums
Enigma Chat New
RSS Feeds RSS
Articles / Tutorials
Videos
Online EG MP3 Player Radio
Enigma Zine
Downloads
Tools New

Code Resources

Submit Code
Ajax
ASM
Bash
C
CPP
Csharp
Delphi
Haskell
Java
Javascript
Jython
Lisp
mIRC
MySQL
Perl
PHP
Python
QBASIC
VisualBasic

The Urinal

Click Here To Vote For EG!

hakipedia

Has Enigma Group Helped You? Then Help Us By Advertising For Us. Place One Of The Following Images On Your Site.

enigma group

enigma group

enigma group

enigma group

Enigma Group's Articles


Closures in Lisp - Submitted By: ishkur88 2009-03-14 21:52:29
============================================================================
|| Today we're going to be talking about lexical closures in Common Lisp. ||
============================================================================

------------------------------
| What IS a lexical closure? |
------------------------------

A lexical closure is a function that captures free variables in an
instance and is able to refer back to their address space at a later
time.

---------------------------------
| What the hell does that mean? |
---------------------------------

Declaring free variables in a lexical scope would simply be defining
a variable and then it's value in a single use context, such as in a
LET statement:

; lexical scoping of the variable "a"

USER> (let ((a '(1 2 3)))
        (print a))
(1 2 3)

There you can see that "a" is defined inside of the LET statement
and is then called to *standard-output* via the PRINT function.

----------------------------------
| So.. why is that useful to me? |
----------------------------------

At a glance, the ability to do that seems pointless. But, the truth
of the matter is that it allows for some interesting things to be
done in your scripts. Things that are downright impossible in a
language that doesn't have support for closures.

---------------------------------------------------
| So what does one of these "closures" look like? |
---------------------------------------------------

A simple example of a closure would be a function that calls to a
counter that displays a number and increases the value by a
specified increment by one each time its called.

; simple example of a closure

(let ((calls 0))
  (defun counter ()
    (incf calls)))

What this does is create a local variable named "calls", then
binds the function's use of it to its address space, allowing it
to call that variable later.

You would then be able to call COUNTER as such:

USER> (counter)
1
USER> (counter)
2
USER> (counter)
3

and so on.

-----------------------------------------------
| Well that's sorta neat, what else can I do? |
-----------------------------------------------

You can actually define as many controlling functions as you
need to in order to get the job done.

Example being:

(let ((calls 0))
  (defun count-up ()
    (incf calls))
  (defun count-down ()
    (decf calls))
  (defun count-reset ()
    (setq calls 0)))

With this, you can increase the count, decrease it, and start
the count over.

-----------------------------
| *Yawn* Ok, so is that it? |
-----------------------------

Nope. Lets take a little detour into mathematics for a second.

There is a formula to directly calculate the nth Fibonacci term:
     
     F(n) =  round( ( phi^n / sqrt( 5 ) )
          
     and
 
     phi = ( 1 + sqrt( 5 ) ) / 2

Given that, we can write a nifty little closure to give us
sequential terms of the fibonacci sequence:

(let ((term 0)
      (phi (/ (1+ (sqrt 5)) 2)))
  (defun next-fib ()
    (progn
     (incf term)
     (round (/ (expt phi term) (sqrt 5))))))

Then it's just a matter of calling the function:

USER> (next-fib)
1
USER> (next-fib)
1
USER> (next-fib)
2
USER> (next-fib)
3

and so on.

-----------------------------
| Ok, thats kinda neat too. |
-----------------------------

Hell yeah it is. But there's just one problem with it. It only
allows for one instance of the sequence to be used. What if, for
some reason, we wanted two or more sequences running. What would
we do then?

You would need to assign a name to each instance, and then pass
the actions you'd like to do with it via function parameters.

Here's an example of how you could do something like this:

(defun fibonacci-sequence ()
  (let ((term 0)
   (phi (/ (1+ (sqrt 5)) 2)))
    #'(lambda (operation)
   (ecase operation
     (next-fib
      (progn
        (incf term)
        (round (/ (expt phi term) (sqrt 5)))))
     (prev-fib
      (progn
        (decf term)
        (round (/ (expt phi term) (sqrt 5)))))
     (reset-fib
      (setq term 0))))))

What this is, is a factory for getting sequential terms of the
Fibonacci sequence.

You would use it as such:

USER> (defparameter fib-terms-1 (fibonacci-sequence))
FIB-TERMS-1
USER> (defparameter fib-terms-2 (fibonacci-sequence))
FIB-TERMS-2
USER> (funcall fib-terms-1 'next-fib)
1
USER> (funcall fib-terms-1 'next-fib)
1
USER> (funcall fib-terms-1 'next-fib)
2
USER> (funcall fib-terms-2 'next-fib)
1
USER> (funcall fib-terms-1 'prev-fib)
1

and so on.

You are now able to create multiple named instances of this
object.

------------------------------------
| Well.. ok. But how does it work? |
------------------------------------

The above script might look a little awkward to you, and that's
alright. It is a litte weird, but it's nothing you can't
understand.

What the LAMBDA expression does, is create a new address space
for each new named instance by making an anonymous function.

ECASE is actually just a typical case switch like you'd see in
any other language, except it has no default behavior. A given
case has to match, or an error is signalled.

So, from there, you can see that a new set of local variables
are defined every time a named instance, and allows calls
to the enclosed functions.

------------
| Err.. Ok |
------------

If anything up there is a little unclear or you dont understand,
dont bug out. I jumped into a semi-advanced topic without much
warning.

Don't be afraid of the topic, and explore it as much as possible.

Happy Hacking.
~Ishkur

Return to Programming category list

 

Who's Online

388 Guests, 98 Users
alexelixir, sharpestharp, alpineH@cker, BioHazard, alien007, f4nt0mx, Ausome1, themastersinner, Valterri, st3alth, thiscalling, FlamingLemming, psychomarine, ishkur88, chess_rock, teehee, nuxglwk, Psiber_Syn, Rik, crazyhacker54, enyo, upinsmoke, hawkcannon, jinx707, blink_212, NotMyOwn, Stumble, re6ter, vander130, Bengali, marv_92, R00tMANiAC, hawx_ps3, ruio, InjectioN, slyjakes, Red_beard, raj gupta, Nemehinmeli, Rex_Mundi, klesco, kazlu, geezer105, Blizer, th3punish3r, !~george~!, Ops, aVoid, it_trainee, Tony the Computer Guy, dasmasta, avalor, N4g4c3N, Nasrudin, aloksaini, TheRetech, exploit100, impairedyeti, gadjomatto, WhiteZ, jaiaccet, 0x80483fb, Posix, bharaniravikanth, Sloppypapi, ANdeRS06, c0zy, BlankBender, darkang3l, shogun, zinoustyle, arppan.009, dxmchurch1991, destroyer, raj.kiran.hero, nightstalker772, blackhat11907, JohnJohnJohn, beco_labise, bushranger, Abhinav2107, dtpvb2010, hackaday, zah2an, nocrew, ani_1, neofish, rad, m0ng00s3, norwood8, invas10n, dnatrixene135, Link-, Insp!red, xxreedxx222, samron7709, vkadarshvk, cutie117098