Return values with indexes from list in AutoLisp - lisp

I am trying to create a new list by taking values from the user. Then I want to display the values in this list along with their indexes. For example for the values 5,4,3,2 I want the output to be:
5 0
4 1
3 2
2 3
This is my code:
(setq n (getint "How many elements you want to input"))
(defun CreateList(n)
(setq lista '())
(repeat n
(setq temp (getstring "Enter value"))
(setq lista (append lista (list temp)))
)
(foreach el lista
(print(strcat el vl-position el lista))
)
)
(CreateList n)
As result I am getting: error: bad argument type: stringp #<SUBR #0000027b44742e88 VL-POSITION>
I have tried to change the print line to something like (print(strcat el (rtos vl-position el lista)))
But It didn't work also. Any ideas?

Firstly, a few comments about your code:
(defun CreateList(n)
Always declare your local variables as part of the defun expression - this will limit the scope of the variables to the function in which they are declared. Without limiting the scope of the variable, its value will be retained after the function has completed evaluation and this can lead to headaches such as that which I describe here.
(setq lista '())
If lista is declared as a local variable, there is no need to initialise it as an empty list, as the symbol will already have no initial value within the scope of the function.
(setq temp (getstring "Enter value"))
If you're always looking obtain integers (per your example), consider using the getint function in place of getstring.
(setq lista (append lista (list temp)))
When building lists, the use of cons is far more efficient, i.e.:
(setq lista (cons temp lista))
Note however, that this will build the list in reverse.
(print(strcat el vl-position el lista))
The above line contains the source of your error, specifically:
(strcat el vl-position el lista)
Here, vl-position is a function and not a string and so cannot be passed as an argument to the strcat function (similarly, neither can lista, which points to list data).
Instead, vl-position should be enclosed in parentheses to form its own expression:
(vl-position el lista)
However, be aware that this approach may return undesired results if duplicate input values have been supplied.

LISP means: Lost In Stupid Parenthesis ;)
in this case
vl-position should be (vl-position ... )
rtos should be used for conversion real values while vl-position returns int, so better would be itoa
So the correct format is:
(print(strcat el " " (itoa (vl-position el lista))))

Related

Using Lisp: define a function that takes a list and a number and returns true if the number occurs in the list

I am new to lisp and I have a problem, I'm trying to find the number in the list but it is not working. I haven't made the return statement yet
(defun num (x 'y)
(if (member x '(y)) 't nil))
(write (num 10 '(5 10 15 20)))
My output just outputs the nil instead of doing the function and I'm confused of what I am doing wrong.
Solution
(defun member-p (element list)
"Return T if the object is present in the list"
(not (null (member element list))))
The not/null pattern is equivalent to (if (member element list) t nil) but is more common.
In fact, you do not really need this separate function,
member is good enough.
The -p suffix stands for predicate, cf. integerp and upper-case-p.
Your code
You cannot quote lambda list elements, so you need to replace defun num (x 'y) with defun num (x y)
You need not quote t
Quoting '(y) makes no sense, replace it with y.
You do not need to write the function call, the REPL will do it for you.
See also
When to use ' (or quote) in Lisp?
Can you program without REPL on Lisp?
You are almost certainly expected to not just use member, but to write a function which does what you need (obviously in real life you would just use member because that's what it's for).
So. To know if an object is in a list:
if the list is empty it's not;
if the head of the list is equal to the object it is;
otherwise it is in the list if it's in the tail of the list.
And you turn this into a function very straightforwardly:
(defun num-in-list-p (n l)
;; is N in L: N is assumed to be a number, L a list of numbers
(cond ((null l)
nil)
((= n (first l))
t)
(t
(num-in-list-p n (rest l)))))
You could use the built in position function which will return the index of the number if it is in the list:
(position 1 '(5 4 3 2 1))
If you want to define your own function:
CL-USER> (defun our-member(obj lst)
(if(zerop (length lst))
nil
(if(equal(car lst)obj)
T
(our-member obj (cdr lst)))))
OUR-MEMBER
CL-USER> (our-member 1 '(5 4 3 2 1))
T
CL-USER> (our-member 99 '(1 2 3 4 5))
NIL
We can create a function called "our-member" that will take an object (in your case a number) and a list (in your case a list of numbers) as an argument. In this situation our "base-case" will be whether or not the length of the list is equal to zero. If it is and we still haven't found a match, we will return nil. Otherwise, we will check to see if the car of the list (the first element in the list) is equal to the obj that we passed. If so, we will return T (true). However, if it is not, we will call the function again passing the object and the cdr of the list (everything after the car of the list) to the function again, until there are no items left within the list. As you can see, The first example of a call to this function returns T, and the second example call returns NIL.
What makes this utility function a good example is that it essentially shows you the under workings of the member function as well and what is going on inside.

Common Lisp: read each input character as a list element

Lisp newbie here.
I want to read from standard-in a string of characters such as:
aabc
I want to convert that input into a list, where each character becomes a list element:
(a a b c)
And I want the list assigned to a global variable, text.
I created this function:
(defun get-line ()
(setf text (read)))
but that just results in assigning a single symbol to text, not tokenizing the input into a list of symbols.
What's the right way to implement get-line() please?
Here you go: First using coerce to convert the string to a list of characters, then mapcar to convert each character to a string.
(defun get-line ()
(setf text (mapcar 'string (coerce (string (read)) 'list))))
(loop
for x = (string-upcase (string (read-char)))
while (not (equal " " x))
collecting (intern x))
Note the upcase is there because symbols in CL are not case sensitive and are upcased by default by the reader.

About generalized variable in onlisp

I am not sure what is going on here, a macro example in the text.
Basically, not comfortable with how to use get-setf-method, a built-in macro (maybe function?).
To be specific, how about the case that some of the return values of get-setf-method are nil?
e.g.
(get-setf-method 'x)
NIL ;
NIL ;
(#:NEW-3069) ;
(SETQ X #:NEW-3069) ;
X
And why this example code set the fifth return value to the second return value first, for initialization?
Finally how it can handle the order of setting the variables in an expression, such as (aref ar (incf i)
(get-setf-method '(aref ar (incf i)))
(#:G3070 #:G3071) ;
(AR (INCF I)) ;
(#:G3072) ;
(SYSTEM::STORE #:G3070 #:G3071 #:G3072) ;
(AREF #:G3070 #:G3071)
Here is the definition of the macro :
(defmacro sortf (op &rest places)
(let* ((meths (mapcar #'(lambda (p)
(multiple-value-list
(get-setf-method p)))
places))
(temps (apply #'append (mapcar #'third meths))))
`(let* ,(mapcar #'list
(mapcan #'(lambda (m)
(append (first m)
(third m)))
meths)
(mapcan #'(lambda (m)
(append (second m)
(list (fifth m))))
meths))
,#(mapcon #'(lambda (rest)
(mapcar
#'(lambda (arg)
`(unless (,op ,(car rest) ,arg)
(rotatef ,(car rest) ,arg)))
(cdr rest)))
temps)
,#(mapcar #'fourth meths))))
That's actually some older code. get-setf-method was actually replaced by get-setf-expansion as described in Issue SETF-METHOD-VS-SETF-METHOD Writeup. So what you should be interested in these days is get-setf-expansion. The values that it returns are the pieces of code that you need to safely store a value in a location. This is very important because it's very easy to write modyfing macros incorrectly.
As to why some of the values can be nil, one of the examples in the documentation for get-setf-expansion actually shows how some of the values can be nil:
(get-setf-expansion 'x)
;=> NIL, NIL, (#:G0001), (SETQ X #:G0001), X
But what are those values? For that we need to look at the syntax of the documentation:
Syntax:
get-setf-expansion place &optional environment
&Rightarrow; vars, vals, store-vars, writer-form, reader-form
Arguments and Values:
place—a place.
environment—an environment object.
vars, vals, store-vars, writer-form, reader-form—a setf expansion.
Those five return values are described in 5.1.1.2 Setf Expansions:
List of temporary variables a list of symbols naming temporary variables to be bound sequentially, as if by let*, to values resulting
from value forms.
List of value forms a list of forms (typically, subforms of the place) which when evaluated yield the values to which the
corresponding temporary variables should be bound.
List of store variables a list of symbols naming temporary store variables which are to hold the new values that will be assigned to
the place.
Storing form a form which can reference both the temporary and the store variables, and which changes the value of the place and
guarantees to return as its values the values of the store variables,
which are the correct values for setf to return.
Accessing form a form which can reference the temporary variables, and which returns the value of the place.
So what do those values in the example mean?
(get-setf-expansion 'x)
;⇒ NIL, NIL, (#:G0001), (SETQ X #:G0001), X
To write to variable x, we don't need any temporary storage, and since there are no temporary values, we don't need any forms to produce values for them. We can notice here that the first and second values are always lists, and they should always have the same length. The third value is a list of store variables. This is a list, because we can actually use setf to modify multiple values, but in this case there's just one. The variables here are where the macro should actually store the new values for the place. Then, it's the writer-form (setq x #:g0001) that will actually take care of putting the value in the place. x, of course, is a simple way of reading the value.
As a more complex example, have a look at this transcript from SBCL:
CL-USER> (defstruct person
person-name)
;⇒ PERSON
CL-USER> (get-setf-expansion '(char (person-name (first (second list-of-list-of-persons))) 3))
; (#:TMP965)
; ((PERSON-NAME (FIRST (SECOND LIST-OF-LIST-OF-PERSONS))))
; (#:NEW964)
; (SB-KERNEL:%CHARSET #:TMP965 3 #:NEW964)
; (CHAR #:TMP965 3)
This means that if we wanted to change the fourth character of the name of the first person in the second list of persons in a list of lists of persons, we could do it with:
(let* ((temp965 (person-name (first (second list-of-list-of-persons))))
(old-char (char tmp965 3))) ; optional
(setq new964 <compute-new-value>)
(sb-kernel:%charset tmp965 3 new964))
We can compute the new value however we want (just fill in for <compute-new-value>), and we can even reference the old value if we want to (by including the optional line). All we need to do is set new964 to the new value, and then execute the writer-form that was given to us.
There are more examples of get-setf-expansion on Stack Overflow:
what is to append as push is to cons, in Lisp?
Writing a destructive macro or function like incf?
Writing a ++ macro in Common Lisp
How could I implement the push macro?

Writing a Lisp macro with nested quasiquoting

I'm trying to write a Lisp macro that writes a bunch of macros, but I'm having problems generating macro code that uses the splice operator (in build-bind) that expands inside expressions first.
(defmacro define-term-construct (name filter-p list-keywords)
(let* ((do-list-name (output-symbol "do-~a-list" name))
(with-name (output-symbol "with-~a" name))
(do-filter-name (output-symbol "do-~as" name)))
`(progn
(defmacro ,do-list-name
(ls (&key ,#(append list-keywords '(id operation))) &body body)
(with-gensyms (el)
`(loop-list (,el ,ls :id ,id :operation ,operation)
(let (XXX,#(build-bind ,,name ,el))
(when (,',filter-p ,el)
(,',with-name ,el
,#body)))))))))
After the first pass I want to get:
(define-term-construct some some-p (args name))
->
(PROGN
(DEFMACRO DO-SOME-LIST (LS (&KEY ARGS NAME ID OPERATION) &BODY BODY)
(WITH-GENSYMS (EL)
`(LOOP-LIST (,EL ,LS :ID ,ID :OPERATION ,OPERATION)
(LET (,#(BUILD-BIND ,SOME ,EL))
(WHEN (SOME-P ,EL)
(WITH-SOME ,EL
,#BODY)))))))
Any idea what quote/quasiquotes should I use to get the desired code?
The output that you say that you want want to get has unbalanced commas. ,# already balances the backquote, so you cannot have ,SOME and ,EL. That's two levels of unquoting/splicing inside only one level of backquoting.
I suspect you want:
`(WITH-GENSYMS (EL) ... (LET (,#(BUILD-BIND 'SOME EL)) ...))
The some symbol comes in as an argument to the original macro and has to end up as a quoted symbol when passed to the build-bind function. The EL is evaluated straight. It's just a local variable introduced by the WITH-GENSYMS binding construct, and it is not in backquote context anymore because it is inside the splice.
Transliterating that back to the the original outer macro's backquote: SOME becomes ,name:
,#(build-bind ',name el) ;; two commas out balance two backquotes in
The symbol is spliced in under the umbrella of a protecting quote which will make sure it is treated as a symbol and not a variable.
The el does not need to be spliced in; it's not variable material but a hard-coded feature of the template being generated. If you were to put ,el it would look for an el variable in the define-term-construct macro's scope, where no such thing exists.

Treating the values from a list of slots and strings

I want to do a macro in common lisp which is supposed to take in one of its arguments a list made of slots and strings. Here is the prototype :
(defclass time-info ()
((name :initarg name)
(calls :initarg calls)
(second :initarg second)
(consing :initarg consing)
(gc-run-time :initarg gc-run-time)))
(defun print-table (output arg-list time-info-list) ())
The idea is to print a table based on the arg-list which defines its structure. Here is an example of a call to the function:
(print-table *trace-output*
'("|" name "||" calls "|" second "\")
my-time-info-list)
This print a table in ascII on the trace output. The problem, is that I don't know how to explicitely get the elements of the list to use them in the different parts of my macro.
I have no idea how to do this yet, but I'm sure it can be done. Maybe you can help me :)
I would base this on format. The idea is to build a format string
from your arg-list.
I define a helper function for that:
(defun make-format-string-and-args (arg-list)
(let ((symbols ()))
(values (apply #'concatenate 'string
(mapcar (lambda (arg)
(ctypecase arg
(string
(cl-ppcre:regex-replace-all "~" arg "~~"))
(symbol
(push arg symbols)
"~a")))
arg-list))
(nreverse symbols))))
Note that ~ must be doubled in format strings in order to escape them.
The printing macro itself then just produces a mapcar of format:
(defmacro print-table (stream arg-list time-info-list)
(let ((time-info (gensym)))
(multiple-value-bind (format-string arguments)
(make-format-string-and-args arg-list)
`(mapcar (lambda (,time-info)
(format ,stream ,format-string
,#(mapcar (lambda (arg)
(list arg time-info))
arguments)))
,time-info-list)))
You can then call it like this:
(print-table *trace-output*
("|" name "||" calls "|" second "\\")
my-time-info-list)
Please note the following errors in your code:
You need to escape \ in strings.
Second is already a function name exported from the common-lisp
package. You should not clobber that with a generic function.
You need to be more precise with your requirements. Macros and Functions are different things. Arrays and Lists are also different.
We need to iterate over the TIME-INFO-LIST. So that's the first DOLIST.
The table has a description for a line. Each item in the description is either a slot-name or a string. So we iterate over the description. That's the second DOLIST. A string is just printed. A symbol is a slot-name, where we retrieve the slot-value from the current time-info instance.
(defun print-table (stream line-format-description time-info-list)
(dolist (time-info time-info-list)
(terpri stream)
(dolist (slot-or-string line-format-description)
(princ (etypecase slot-or-string
(string slot-or-string)
(symbol (slot-value time-info slot-or-string)))
stream))))
Test:
> (print-table *standard-output*
'("|" name "||" calls "|" second "\\")
(list (make-instance 'time-info
:name "foo"
:calls 100
:second 10)
(make-instance 'time-info
:name "bar"
:calls 20
:second 20)))
|foo||100|10\
|bar||20|20\
First, you probably don't want the quote there, if you're using a macro (you do want it there if you're using a function, however). Second, do you want any padding between your separators and your values? Third, you're probably better off with a function, rather than a macro.
You also seem to be using "array" and "list" interchangeably. They're quite different things in Common Lisp. There are operations that work on generic sequences, but typically you would use one way of iterating over a list and another to iterate over an array.