Saturday 12 January 2013

Ignoring Arguments in Anonymous Functions

Anonymous functions are a useful (hmm, that's an understatement) feature of Common Lisp. I use them a lot. While using them, sometimes I want to ignore some arguments that are required by the consumer of the anonymous function. For example, here is an example of collecting the keys in a hash-table into a list:
(let (result)
    (maphash (lambda (key value)
                (declare (ignore value))
                (push key result))

             hash-table)

    result)
In this situation, the anonymous function is quite simple, and the ignore advice is swamping it. I wrote a small macro (named fn) to make ignoring arguments in anonymous functions easier. It's included and used extensively in the MathP code. To ignore an argument, use an underscore for it in the argument list. For example, the above code becomes:
(let (result)
    (maphash (fn (key _) (push key result))

             hash-table)
    result)
Because the code is that much shorter, I find it that much easier to read. Here is the macro that does the magic:
(defmacro fn (args &body body)
    (let (arg-list ignores)
        (loop for arg in args
            if (string= (symbol-name arg) "_")
            do (let ((sym (gensym)))
                   
(push sym arg-list) (push sym ignores))
            else do (push arg arg-list))
        `(lambda ,(nreverse arg-list) (declare (ignore ,@ignores)) ,@body)))

I hope the above code is useful to you; Use it however you want. I accept no responsibility for problems arising from it's use, but if you do find it useful, I'd be tickled pink to hear from you.

Do you know of a similar macro? Please leave a comment.

2 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. What about this?

    (Unfortunately I can't seem to get the indentation to work with Blogger, and the "preview" function actually posts the comment, so that's my other deleted comment. WTF.)

    ;; collect the keys
    (let (result)
    (maphash (plambda:plambda :2 (push :1 result))
    (make-hash-table))
    result)

    ;; collect the values
    (let (result)
    (maphash (plambda:plambda (push :2 result))
    (make-hash-table))
    result)

    positional-lambda is in Quicklisp: (ql:quickload "positional-lambda")

    ReplyDelete