Tuesday, March 18, 2008

recursive lambda factorial in lisp

Following a "stupid" question I've asked my students: "how to write a recursive lambda function in common lisp without using any assignment statement?", I've written the following example of such lambda function:

(funcall (lambda (lfact n) (funcall lfact n lfact)) (lambda (n lfact) (cond ((> n 0) (* n (funcall lfact (- n 1) lfact))) (t 1) ) ) 4)

Apparently, to do the trick in pure functional style one needs to use two lambda functions, and symbol assignment operation is replaced with a function call, that receives another lambda as an argument which will be already evaluated inside the first lambda as a functional. The next step to do is just to call it and to send itself, again, as an argument.

I must admit, that I'm very surprised that Common Lisp has such a "poor" support for lambda, because it would be better to perform the same trick in a more shorter code sequence.


Eugeny L. Yakimovitch said...

I've found description of the same fact for the case of scheme dialect:

The Lambda Calculus, notes by Don Blaheta. October 12, 2000.

Rudy said...

Hello Eugeny!

The lambda macro has a poor suport for recursive lambdas. But you can define your own macro for supporting better recursive lambda:

(defun recursive-replace-list (l a b)
(if l
((listp (car l)) (list (recursive-replace-list (car l) a b)))
((eql (car l) a) b)
(t (list (car l))))
(recursive-replace-list (cdr l) a b))))

(defmacro adbmal (args &rest code)
`(lambda ,args
(funcall (lambda (adbmal ,@args) (funcall adbmal adbmal ,@args))
(lambda (adbmal ,@args)
,@(recursive-replace-list code 'adbmal '(funcall adbmal adbmal)))

; By defining these above, you can do a recursive factorial lambda by simply:

(adbmal (n)
(if (> n 0)
(* n (adbmal (- n 1)))

Common Lisp is a great language! If you are unsatisfied with default sintatical constructs, you can create your own! :)

jrwats said...

 (adbmal (n)
         (if (> n 0)
             (* n (adbmal (- n 1)))

is still kinda ugly though. Scheme is always a little more aesthetic, but that's what you get when you separate function and variable namespaces...