Gap1512
Gap1512

Reputation: 121

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"

Upvotes: 0

Views: 439

Answers (2)

Rainer Joswig
Rainer Joswig

Reputation: 139261

You can also use a simple LOOP instead of a recursive call:

(defun inputs (state)
  (loop
   (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)))
     (when (valid-call function)
       (apply (symbol-function (find-symbol function))
              state
              args)
       (return))
     (format *query-io* "Sorry, I don't know the command '~a'~%~%" function))))

Upvotes: 1

sds
sds

Reputation: 60014

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)
      ...)

Upvotes: 5

Related Questions