Reputation: 121
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
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
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