diff options
-rw-r--r-- | lambda.lisp | 56 | ||||
-rw-r--r-- | mulkutils.asd | 4 | ||||
-rw-r--r-- | tests.lisp | 7 |
3 files changed, 29 insertions, 38 deletions
diff --git a/lambda.lisp b/lambda.lisp index 840b60d..e6c60dd 100644 --- a/lambda.lisp +++ b/lambda.lisp @@ -29,9 +29,11 @@ | ================================ | | (funcall (fn (fn () _))) ;=> #<LAMBDA ...> - | (funcall (efn (efn () _))) ;=> error + | (funcall (efn (efn () _))) ;=> #<LAMBDA ...> ; new! | (funcall (fn1 (fn1 _))) ;=> #<LAMBDA ...> - | (funcall (efn1 (efn1 _))) ;=> error + | (funcall (efn1 (efn1 _))) ;=> #<LAMBDA ...> ; new! + | (funcall (fn1 _3) 1 2 3 4 5) ;=> 4 + | (funcall (efn1 _3) 1 2 3 4 5) ;=> error |# @@ -41,16 +43,22 @@ (in-package #:mulk.lambda) -(defun collect-lambda-args (clause) - (typecase clause - (list (mapcan #'collect-lambda-args clause)) - (symbol (let ((name (symbol-name clause))) - (if (or (string= "_" name) - (and (char= #\_ (char name 0)) - (ignore-errors - (parse-integer (subseq name 1))))) - (list clause) - nil))))) +(defun collect-lambda-args (form) + (let ((lambda-args (list))) + (handler-bind + ((arnesi:undefined-variable-reference + #'(lambda (c) + (with-accessors ((symbol arnesi:name)) c + (let ((name (symbol-name symbol))) + (when (or (string= "_" name) + (and (char= #\_ (char name 0)) + (ignore-errors + (parse-integer (subseq name 1))))) + (push symbol lambda-args)))) + (invoke-restart 'muffle-warning)))) + (let ((arnesi:*warn-undefined* t)) + (arnesi:walk-form form) + (nreverse lambda-args))))) (defun find-lambda-args (clause) @@ -95,25 +103,7 @@ removed symbol (if found)." "A convenience wrapper for LAMBDA. Positional arguments are numbered from 0 and follow the pattern given by the -format string \"_~D\". _ can be used as an abbreviation for _0. - -FN can be used recursively, but this has to be done with care, for the -macro will inevitably get confused about the number of arguments it -should use if a subform uses more lambda arguments than its enclosing FN -form. For instance, the following will work: - - (funcall (efn (efn () 10) _) 'foo) - -But the following will not, because the inner _ is detected by the outer -FN as an argument, making the latter expect an argument where none is -given: - - (funcall (efn (efn () _))) - -NOTE: RELYING ON THE ERRONEOUS BEHAVIOUR OF THIS MACRO IN ORDER TO WRITE -SLOPPY FUNCTION DEFINITIONS IS NOT GUARANTEED TO WORK IN FUTURE VERSIONS -OF THE SYSTEM. IF YOU NEED TO IGNORE VARIABLE ARGUMENT LISTS, USE THE -FN MACRO INSTEAD. YOU HAVE BEEN WARNED." +format string \"_~D\". _ can be used as an abbreviation for _0." (cond ((or (not (listp function-or-form)) (eq 'function (first function-or-form))) `(efn (funcall ,function-or-form ,@args))) @@ -136,9 +126,7 @@ FN MACRO INSTEAD. YOU HAVE BEEN WARNED." "A less safe but recursively callable variant of EFN. This macro is like EFN save the fact that the anonymous functions it -produces do not check the number of their arguments, thereby -circumventing lambda argument misidentification errors in -COLLECT-LAMBDA-ARGS." +produces do not check the number of their arguments." (cond ((or (not (listp function-or-form)) (eq 'function (first function-or-form))) `(fn (funcall ,function-or-form ,@args))) diff --git a/mulkutils.asd b/mulkutils.asd index 696584f..767a0d9 100644 --- a/mulkutils.asd +++ b/mulkutils.asd @@ -1,8 +1,8 @@ (defsystem "mulkutils" :description "Random utilities by Matthias Benkard." - :version "0.0.2" + :version "0.1.0" :author "Matthias Benkard <matthias@benkard.de>" :licence "GNU General Public License, version 2 or higher" - :depends-on () + :depends-on (:arnesi) :components ((:file "lambda")) :serial t) @@ -45,9 +45,12 @@ () (:tests ((ensure (functionp (funcall (fn (fn () _)))))) - ((ensure-error (funcall (efn (efn () _))))) + ((ensure (functionp (funcall (efn (efn () _)))))) ((ensure (functionp (funcall (fn1 (fn1 _)))))) - ((ensure-error (funcall (efn1 (efn1 _))))))) + ((ensure (functionp (funcall (efn1 (efn1 _)))))) + ((ensure-same (funcall (fn1 _3) 1 2 3 4 5) + 4)) + ((ensure-error (funcall (efn1 _3) 1 2 3 4 5))))) (deftestsuite mulk-lambda-fn* (mulk-lambda) |