Simple LISP question - lisp

I'm just learning LISP and i am having trouble doing the following:
; return ":h :i"
(defun get-char()
(loop for char across "ab"
collect (concatenate 'string ":" (string char))))
; plist
(defun get-list() (list :a "1" :b "2"))
; I cannot get this to work
; <-- returns all null, cannot get plist values :-(
(loop for x in (get-char)
collect (getf (get-list) x))
; this works fine...
(loop for x in '(:a :b)
collect (getf (get-list) x))
I know im close, but i am just missing something.
Thanks a lot :-)

Change the get-char function to return a list of keywords from the characters:
(defun get-char()
(loop
for char across "ab"
collect (intern (string-upcase char) :keyword)))
Evaluating (get-char) => (:A :B). Furthermore:
(loop for x in (get-char) collect (getf (get-list) x))
=>
("1" "2")

Related

How to compare a list to another list in LISP and avoid an EVAL error due to an undefined variable?

I am trying to compare two lists in common lisp and then print "ROBOT ROBBIE" if they match. One of the inputs is a list given by the user (stored in wff) and the other input is a list from a list of lists called "nums". However, when I run my code I get the following error:
- EVAL: undefined function X
Why is this happening and how do I fix this? I have attached my code below for reference:
(defun same-elements (l1 l2)
(and (subsetp l1 l2) (subsetp l2 l1)))
(defun answer-ynq()
;;;Defining the hash-table
(setq nums '(13 15 19 33))
(setq numsstuff '())
(setq nums (loop for i below 2
collect (loop for e in '(Robot Robbie)
for j from 0
when (equal i j) collect '- else collect e)))
(print nums)
(print "Hello, please enter a command")
(setq wff (read-delimited-list #\~))
(terpri)
(loop for x in nums
do (if (same-elements (x wff))
(print "(ROBOT ROBBIE)")
))
)
(answer-ynq)
Try this:
(defun same-elements (l1 l2)
(and (subsetp l1 l2) (subsetp l2 l1)))
(defun answer-ynq()
;;;Defining the hash-table
(setq nums '(13 15 19 33))
(setq numsstuff '())
(setq nums (loop for i below 2
collect (loop for e in '(Robot Robbie)
for j from 0
when (equal i j) collect '- else collect e)))
(print nums)
(print "Hello, please enter a command")
(setq wff (read-delimited-list #\~))
(terpri)
(loop for x in nums
do (if (same-elements x wff)
(print "(ROBOT ROBBIE)")
))
)
(answer-ynq)
The only change needed is (same-elements x wff)
(same-elements (x wff)) means call a function x then pass the result to same-elements. Not what you want.
Note: As others have pointed out, its not a good idea to use setq this way.

What does gensym do in Lisp?

contextualization: I've been doing a university project in which I have to write a parser for regular expressions and build the corresponding epsilon-NFA. I have to do this in Prolog and Lisp.
I don't know if questions like this are allowed, if not I apologize.
I heard some of my classmates talking about how they used the function gensym for that, I asked them what it did and even checked up online but I literally can't understand what this function does neither why or when is best to use it.
In particular, I'm more intrested in what it does in Lisp.
Thank you all.
GENSYM creates unique symbols. Each call creates a new symbol. The symbol usually has a name which includes a number, which is counted up. The name is also unique (the symbol itself is already unique) with a number, so that a human reader can identify different uninterned symbols in the source code.
CL-USER 39 > (gensym)
#:G1083
CL-USER 40 > (gensym)
#:G1084
CL-USER 41 > (gensym)
#:G1085
CL-USER 42 > (gensym)
#:G1086
gensym is often used in Lisp macros for code generation, when the macro needs to create new identifiers, which then don't clash with existing identifiers.
Example: we are going to double the result of a Lisp form and we are making sure that the Lisp form itself will be computed only once. We do that by saving the value in a local variable. The identifier for the local variable will be computed by gensym.
CL-USER 43 > (defmacro double-it (it)
(let ((new-identifier (gensym)))
`(let ((,new-identifier ,it))
(+ ,new-identifier ,new-identifier))))
DOUBLE-IT
CL-USER 44 > (macroexpand-1 '(double-it (cos 1.4)))
(LET ((#:G1091 (COS 1.4)))
(+ #:G1091 #:G1091))
T
CL-USER 45 > (double-it (cos 1.4))
0.33993432
a little clarification of the existing answers (as the op is not yet aware of the typical common lisp macros workflow):
consider the macro double-it, proposed by mr. Joswig. Why would we bother creating this whole bunch of let? when it can be simply:
(defmacro double-it (it)
`(+ ,it ,it))
and ok, it seems to be working:
CL-USER> (double-it 1)
;;=> 2
but look at this, we want to increment x and double it
CL-USER> (let ((x 1))
(double-it (incf x)))
;;=> 5
;; WHAT? it should be 4!
the reason can be seen in macro expansion:
(let ((x 1))
(+ (setq x (+ 1 x)) (setq x (+ 1 x))))
you see, as the macro doesn't evaluate form, just splices it into generated code, it leads to incf being executed twice.
the simple solution is to bind it somewhere, and then double the result:
(defmacro double-it (it)
`(let ((x ,it))
(+ x x)))
CL-USER> (let ((x 1))
(double-it (incf x)))
;;=> 4
;; NICE!
it seems to be ok now. really it expands like this:
(let ((x 1))
(let ((x (setq x (+ 1 x))))
(+ x x)))
ok, so what about the gensym thing?
let's say, you want to print some message, before doubling your value:
(defmacro double-it (it)
`(let* ((v "DOUBLING IT")
(val ,it))
(princ v)
(+ val val)))
CL-USER> (let ((x 1))
(double-it (incf x)))
;;=> DOUBLING IT
;;=> 4
;; still ok!
but what if you accidentally name value v instead of x:
CL-USER> (let ((v 1))
(double-it (incf v)))
;;Value of V in (+ 1 V) is "DOUBLING IT", not a NUMBER.
;; [Condition of type SIMPLE-TYPE-ERROR]
It throws this weird error! Look at the expansion:
(let ((v 1))
(let* ((v "DOUBLING IT") (val (setq v (+ 1 v))))
(princ v)
(+ val val)))
it shadows the v from the outer scope with string, and when you are trying to add 1, well it obviously can't. Too bad.
another example, say you want to call the function twice, and return 2 results as a list:
(defmacro two-funcalls (f v)
`(let ((x ,f))
(list (funcall x ,v) (funcall x ,v))))
CL-USER> (let ((y 10))
(two-funcalls (lambda (z) z) y))
;;=> (10 10)
;; OK
CL-USER> (let ((x 10))
(two-funcalls (lambda (z) z) x))
;; (#<FUNCTION (LAMBDA (Z)) {52D2D4AB}> #<FUNCTION (LAMBDA (Z)) {52D2D4AB}>)
;; NOT OK!
this class of bugs is very nasty, since you can't easily say what's happened.
What is the solution? Obviously not to name the value v inside macro. You need to generate some sophisticated name that no one would reproduce in their code, like my-super-unique-value-identifier-2019-12-27. This would probably save you, but still you can't really be sure. That's why gensym is there:
(defmacro two-funcalls (f v)
(let ((fname (gensym)))
`(let ((,fname ,f))
(list (funcall ,fname ,v) (funcall ,fname ,v)))))
expanding to:
(let ((y 10))
(let ((#:g654 (lambda (z) z)))
(list (funcall #:g654 y) (funcall #:g654 y))))
you just generate the var name for the generated code, it is guaranteed to be unique (meaning no two gensym calls would generate the same name for the runtime session),
(loop repeat 3 collect (gensym))
;;=> (#:G645 #:G646 #:G647)
it still can potentially be clashed with user var somehow, but everybody knows about the naming and doesn't call the var #:GXXXX, so you can consider it to be impossible. You can further secure it, adding prefix
(loop repeat 3 collect (gensym "MY_GUID"))
;;=> (#:MY_GUID651 #:MY_GUID652 #:MY_GUID653)
GENSYM will generate a new symbol at each call. It will be garanteed, that the symbol did not exist before it will be generated and that it will never be generated again. You may specify a symbols prefix, if you like:
CL-USER> (gensym)
#:G736
CL-USER> (gensym "SOMETHING")
#:SOMETHING737
The most common use of GENSYM is generating names for items to avoid name clashes in macro expansion.
Another common purpose is the generaton of symbols for the construction of graphs, if the only thing demand you have is to attach a property list to them, while the name of the node is not of interest.
I think, the task of NFA-generation could make good use of the second purpose.
This is a note to some of the other answers, which I think are fine. While gensym is the traditional way of making new symbols, in fact there is another way which works perfectly well and is often better I find: make-symbol:
make-symbol creates and returns a fresh, uninterned symbol whose name is the given name. The new-symbol is neither bound nor fbound and has a null property list.
So, the nice thing about make-symbol is it makes a symbol with the name you asked for, exactly, without any weird numerical suffix. This can be helpful when writing macros because it makes the macroexpansion more readable. Consider this simple list-collection macro:
(defmacro collecting (&body forms)
(let ((resultsn (make-symbol "RESULTS"))
(rtailn (make-symbol "RTAIL")))
`(let ((,resultsn '())
(,rtailn nil))
(flet ((collect (it)
(let ((new (list it)))
(if (null ,rtailn)
(setf ,resultsn new
,rtailn new)
(setf (cdr ,rtailn) new
,rtailn new)))
it))
,#forms
,resultsn))))
This needs two bindings which the body can't refer to, for the results, and the last cons of the results. It also introduces a function in a way which is intentionally 'unhygienic': inside collecting, collect means 'collect something'.
So now
> (collecting (collect 1) (collect 2) 3)
(1 2)
as we want, and we can look at the macroexpansion to see that the introduced bindings have names which make some kind of sense:
> (macroexpand '(collecting (collect 1)))
(let ((#:results 'nil) (#:rtail nil))
(flet ((collect (it)
(let ((new (list it)))
(if (null #:rtail)
(setf #:results new #:rtail new)
(setf (cdr #:rtail) new #:rtail new)))
it))
(collect 1)
#:results))
t
And we can persuade the Lisp printer to tell us that in fact all these uninterned symbols are the same:
> (let ((*print-circle* t))
(pprint (macroexpand '(collecting (collect 1)))))
(let ((#2=#:results 'nil) (#1=#:rtail nil))
(flet ((collect (it)
(let ((new (list it)))
(if (null #1#)
(setf #2# new #1# new)
(setf (cdr #1#) new #1# new)))
it))
(collect 1)
#2#))
So, for writing macros I generally find make-symbol more useful than gensym. For writing things where I just need a symbol as an object, such as naming a node in some structure, then gensym is probably more useful. Finally note that gensym can be implemented in terms of make-symbol:
(defun my-gensym (&optional (thing "G"))
;; I think this is GENSYM
(check-type thing (or string (integer 0)))
(let ((prefix (typecase thing
(string thing)
(t "G")))
(count (typecase thing
((integer 0) thing)
(t (prog1 *gensym-counter*
(incf *gensym-counter*))))))
(make-symbol (format nil "~A~D" prefix count))))
(This may be buggy.)

Creating equivalent to incf as macro-function in lisp

I'm just starting to learn the concept of macro functions.
My teacher has asked us to create a macro function that would function exactly the same way as incf.
Here is an example he has given us for pop
(defmacro mypop (nom)
(list 'prog1 (list 'car nom) (list 'setq nom (list 'cdr nom))) )
Here is the regular function I'm trying to turn into a macro:
(defun iincf (elem &optional num )
(cond
((not num) (setq elem (+ 1 elem)))
(t (setq elem (+ num elem))) ) )
Here is my attempt at turning it into a macro :
(defmacro myincf (elem &optional num )
(list 'cond
((list 'not num) (list 'setq elem (list '+ 1 elem)))
(t (list 'setq elem (list '+ num elem))) ) )
However, I get this error and I don't know why:
*** - system::%expand-form: (list 'not num) should be a lambda expression
Also, I'm not sure whether my function would actually change the value of the variable at the top level.
So here are my 2 questions:
Why do I get this error?
Is the function I'm trying to turn into a macro fine? (if successfully turning it into a macro function, would it do what I intend to?)
PS: I know this exercise would probably infringe many common rules in lisp, but this is just for practice. Thanks! :)
The reason for the error is that your syntax is invalid:
((list ...) ...)
(t (list ...))
The first element should be a function name or a lambda expression, so you would need to change it to something like
(list (list ...) ...)
(list t (list ...))
Although the macro isn't a very good one yet. First of all, the backquote syntax would make the code much more readable. It allows you to write a template where only the specified forms are evaluated. For example, the given MYPOP macro would look like
(defmacro mypop (nom)
`(prog1 (car ,nom)
(setq ,nom (cdr ,nom))))
Only the forms with a comma before them are evaluated. Same with your macro:
(defmacro myincf (elem &optional num)
`(cond
((not ,num) (setq ,elem (+ 1 ,elem)))
(t (setq ,elem (+ ,num ,elem)))))
The COND shouldn't really be part of the expansion though. It should be evaluated during macroexpansion, and only the SETQ form from one of the branches returned.
(defmacro myincf (elem &optional num)
(cond
((not num) `(setq ,elem (+ 1 ,elem)))
(t `(setq ,elem (+ ,num ,elem)))))
The only difference between the two branches is that the first one defaults to 1 for NUM. A simpler way to achieve the same would be to give NUM a default value.
(defmacro myincf (elem &optional (num 1))
`(setq ,elem (+ ,num ,elem)))
Of course, the standard INCF is a bit more complex, since it works for all sorts of places (not just variables) and ensures that the subforms of the place are evaluated only once. However, since the MYPOP example doesn't handle those, I don't think you have to either.
If you want to, a simple way to define such a macro would be
(define-modify-macro myincf (&optional (num 1)) +)
Or you could do the same manually with something like
(defmacro myincf (place &optional (num 1) &environment env)
(multiple-value-bind (dummies vals store setter getter)
(get-setf-expansion place env)
`(let* (,#(mapcar #'list dummies vals)
(,(first store) (+ ,getter ,num)))
,setter)))
But using DEFINE-MODIFY-MACRO would be preferrable in a real program (shorter code, less bugs). You could read about GET-SETF-EXPANSION and DEFINE-MODIFY-MACRO if you're interested.

How to get a property from a plist

I am a newbie in Lisp.
I want to access a particular property from a property list with a string variable like this
(setf sym (list :p1 1))
(setf x "p1")
(getf sym :x)
About cl:getf
Let Petit Prince's answer is right that getf is probably the function you want to use here, but note that it can be used for more than just keyword symbols. You can use it for any objects. A property list is just a list of alternating indicators and values, and any object can be an indicator:
(let ((plist (list 'a 'b 'c 'd)))
(getf plist 'c))
;=> D
You can even use strings as indicators:
(let* ((name "p1")
(plist (list name 1)))
(getf plist name))
;=> 1
However, that's probably not great practice, since getf compares indicators with eq. That means that using strings as indicators might not be reliable, depending on your use case:
(let ((plist (list "p1" 1)))
(getf plist "p1"))
;=> NIL
For your example
In your case, you're trying to take a string and find the object for a symbol with a name that's string-equal (i.e., with the same characters, but disregarding case). It probably makes more sense to loop over the list and compare indicators with string-equal.
(let ((plist '(:p1 1 :p2 2)))
(loop
for (indicator value) on plist by #'cddr
when (string-equal indicator "p1")
return value))
;=> 1
And of course, you can wrap that up in a function for abstraction:
(defun getf-string-equal (plist indicator)
(loop
for (i v) on plist by #'cddr
when (string-equal i indicator)
return v))
(getf-string-equal '(:p1 1 :p2 2) "p1")
;=> 1
The second parameter to getf is a keyword, and you have string. A keyword is a symbol that lives in the package KEYWORD and has usually been uppercased by the reader:
? (setf sym (list :p1 1))
(:P1 1)
? sym
(:P1 1)
So you need to use:
? (getf sym (find-symbol (string-upcase x) "KEYWORD"))
1

Lisp recursion with lists

I need a function that will take in a list with words and split that list into two lists if at any point the word 'FOO' is found. I have come up with a recursive solution, may not be the best, but I am having a bit of trouble. I only need to pass 1 argument, the list to be analyzed, but I do not know how to build up the second list off to the side. Any suggestions? Thanks!
;Splits a list into 2 if the word 'FOO' is present
;----------------------------------------------------------------------
;LOAD FILE: (load "C:\\split.lisp")
;USAGE: (split '(with great power foo comes great responsibility) '())
;OUTPUT: ((with great power)(comes great responsibility))
(defun split (x y)
(cond
( ;IF: first element in list is nil
(EQ (car x) nil)
x ;RETURN the list
)
( ;ELSE IF: first element is 'FOO'
(EQ (car x) 'FOO)
(cons (reverse y ) (cons (cdr x) nil))
)
( ;ELSE: recursively call split but pass the rest of x and
;prepend y with the head of x
t
(split (cdr x) (cons (car x) y))
)
) ;END cond
) ;END split
The first test should be different.
The following is not a really good solution: it is not tail-recursive and it uses side-effects. But still...
(defun split (x)
(cond ((null x) x)
((eq (first x) 'foo)
(list nil (rest x)))
(t (let ((l (split (rest x))))
(push (first x) (first l))
l))))
Above uses the PUSH macro. One of the interesting facilities of Common Lisp is that you can use places to modify. In this cases we modify the first sublist of our list to be returned. We push the first element of the list onto the first sublist.
CL-USER 12 > (split '(1 2 3 foo a b c))
((1 2 3) (A B C))
In Common Lisp one would usually write a solution in a non-recursive fashion.
In your recursive version, the typical way to reduce a function to one argument is this: Write the function with one argument and this function then calls a helper function with two arguments. The helper function can also be locally defined using LABELS.
Here's my take on it, using nothing but lists:
(defun split (lst)
(labels ((split-rec (lst a)
(cond
((or (null lst)
(eq (car lst) 'foo))
(values (reverse a) (cdr lst)))
(t (split-rec (cdr lst) (cons (car lst) a))))))
(split-rec lst ())))
split offloads most of the work to split-rec (defined in the labels call), which recursively consumes the list of tokens, until it reaches the end of the list, or sees 'foo. At that point, it immediately takes the remainder of the list and treats that as the second list. Because the first list (a) is being built-up recursively, split-rec has to reverse it before returning it.
Here are a couple of runs through the REPL:
> (split '(with great power foo comes great responsibility))
(WITH GREAT POWER) ;
(COMES GREAT RESPONSIBILITY)
> (split '(with great power comes great responsibility))
(WITH GREAT POWER COMES GREAT RESPONSIBILITY) ;
NIL
> (split nil)
NIL ;
NIL
> (split '(with great power foo comes great foo responsibility) :on 'foo)
(COMES GREAT) ;
(WITH GREAT POWER RESPONSIBILITY)
> (split '(foo with great power comes great responsibility) :on 'foo)
NIL ;
(WITH GREAT POWER COMES GREAT RESPONSIBILITY)
Most of the edge cases that I could think up are handled, and two lists are always returned. Callers can use multiple-value-bind to get both lists out, i.e.:
(multiple-value-bind (a b)
(split '(with great power foo comes great responsibility))
; do something useful with a and b
)
(defun split (lst)
(let* ((a (make-array (length lst) :initial-contents lst))
(index (position 'foo a)))
(cond ((null index) a)
(t (cons (loop for i from 0 to (1- index)
collect (aref a i))
(list (loop for i from (1+ index) to (1- (length a))
collect (aref a i))))))))
Create an array from the list so that there elements are easier to access.
Check if foo exists, if it does mark the index
Use loop to create two lists, one of the elements before foo, and another one of the elements after foo, and cons them together.
Here I've also tried! :)
There's one thing you would want to clarify though: in corner cases like: foo is the first element of the list, should you return two lists or only the second one? If foo is the last element in the list, should you return list and nil or only the first list? If foo isn't in the list, should you return just the list, or list and nil / nil and list?
(defun split (list &key (on-symbol 'foo))
(let (result result-head)
(mapl
#'(lambda (a)
(if (eql (car a) on-symbol)
(return-from split
(if result
(values result (copy-list (cdr a)))
(copy-list (cdr a))))
(if result
(setf (cdr result-head) (list (car a))
result-head (cdr result-head))
(setf result (list (car a))
result-head result)))) list) result))
(split '(1 2 3 4 5 foo a b c))
(split '(foo 1 2 3 4 5 foo a b c))
(split '(1 2 3 4 5 a b c))