Search code examples
lispcommon-lisp

Is there a way to not pass an argument in Common-Lisp instead of passing "NIL"?


I'm calling functions according to user input, but some have two parameters and others just one. Instead of using &optional parameter on every function (and never using it), is there a way to simply not pass an argument when it's value is "NIL"?

This is for an interactive fiction game, in which the user type some commands and these are converted into function calls.

(defun inputs (state)
    (format *query-io* "> ")
    (force-output *query-io*)
    (let* ((entry (cl-ppcre:split "\\s+" (string-downcase (read-line *query-io*))))
      (function (car entry))
      (args (cdr entry)))
      (if (valid-call function)
      (funcall (symbol-function (read-from-string function))
           state
           args)
      (progn
        (format *query-io* "Sorry, I don't know the command '~a'~%~%" function)
        (inputs state)))))

If the user input is "equip sword", I need to call the function "equip" passing the '("Sword") as argument, but if the user input is "status", I need to call the function "status" without passing the 'args', instead of passing them as "NIL"


Solution

  • I think you want to use apply instead of funcall, find-symbol instead of read-from-string (this is actually important for security reasons!) and destructuring-bind instead of let*:

    (defun inputs (state)
      (format *query-io* "> ")
      (force-output *query-io*)
      (destructuring-bind (command &rest args)
          (cl-ppcre:split "\\s+" (string-downcase (read-line *query-io*)))
        (if (valid-call command)
            (apply (find-symbol command) state args)
            (progn
              (format *query-io* "Sorry, I don't know the command '~a'~%~%" command)
              (inputs state)))))
    

    Using apply lets your commands accept an arbitrary number of arguments instead of one.

    In fact, your valid-call should probably return the function to be called:

    (let ((f (valid-call function)))
      (if f
          (apply f state args)
          ...)