modify plist inside list? - lisp

I have a list of plists such as
'((:atom Toddler :visited nil :on-clauses (0 1))
(:atom Child :visited nil :on-clauses 1))
how should I change the :onclauses property on a given :atom? I'd like to update this property, e.g. making the second plist (:atom Child :visited nil :on-clauses (1 2)) (only adding new values, never deleting the old ones).
the best I could do was to create a new list from scratch using
(remove-if-not #'(lambda(record)
(equal (getf record :atom) atom))
*ATOMS*)
to get the initial value, updating it, then using its analogue to get a list without this value, and append both together, but this is probably terribly inneficient (I know premature optimatization is bad, but I'm learning LISP and want to know how to do things properly!)

Use POSITION to find the plist with the specific :atom, and then REMF to remove the property from that plist.
(defun update-on-clauses (atom new-on-clause)
(let ((pos (position atom *atoms*
:key #'(lambda (record) (getf record :atom)))))
(when pos
(setf (getf (nth pos *atoms*) :on-clauses) new-on-clause))))
It might be simpler to make *ATOMS* an alist that maps atoms to property lists.

these three functions seem to do the trick, as plists are destructively modified.
(defun update-atom(atom ix)
"adds to the atom's on-clauses property another clause where it was found."
(let ((atomo (find-atom atom)))
(setf (getf atomo :on-clauses) (cons ix (get-indices atom)))))
(defun find-atom(atom) "returns the property list of a given atom"
(first (remove-if-not #'(lambda(record) (equal (getf record :atom) atom)) *ATOMS*)))
(defun get-indices(atom)
"gets indices of clauses where atom is found."
(getf (find-atom atom) :on-clauses))

Related

Advanced symbol-macrolet

Suppose I have a class class with slots first and second. Inside my function I can bind a variable to one of those slots like
(symbol-macrolet ((var (first cls)))
....)
Obviously I can also bind the second slot to smth.
Questions is, let's say that first and second are either some number or nil. Let's also say that if second is non-nil, first is always nil. Now, can I bind my var to a non-nil one with just one macro? So it just looks at instance of the class given and then check if second is nil. If no, it binds var to second, otherwise to first.
Seems complicated, but I'm pretty sure it can be done, just don't know where to start.
To further generalize -- is it possible to bond a variable not to a single place, but to one of a specific set, depending on some state?
I think this is not quite simple. You could do something like this which works for reading only (I've used a fake toy structure so my code works, which is given here):
(defstruct toy
(first nil)
(second nil))
(defun foo (a-toy)
(symbol-macrolet ((x (or (toy-first a-toy) (toy-second a-toy))))
...))
But now (setf x ...) is horribly illegal. You can get around this, once you've decided what (setf x ...) should do, by defining some local functions. I've decided here that it should set the non-nil slot, as that makes sense to me.
(defun bar (a-toy)
(flet ((toy-slot (the-toy)
(or (toy-first the-toy) (toy-second the-toy)))
((setf toy-slot) (new the-toy)
(if (toy-first the-toy)
(setf (toy-first the-toy) new)
(setf (toy-second the-toy) new))))
(symbol-macrolet ((x (toy-slot a-toy)))
(setf x 2)
a-toy)))
And now you can wrap this all in a single macro:
(defmacro binding-toy-slot ((x toy) &body forms)
(let ((tsn (make-symbol "TOY-SLOT")))
`(flet ((,tsn (the-toy)
(or (toy-first the-toy) (toy-second the-toy)))
((setf ,tsn) (new the-toy)
(if (toy-first the-toy)
(setf (toy-first the-toy) new)
(setf (toy-second the-toy) new))))
(symbol-macrolet ((,x (,tsn ,toy)))
,#forms))))
(defun bar (a-toy)
(binding-toy-slot (x a-toy)
(setf x 3)
a-toy))
Obviously you might want to generalise binding-toy-slot, so it, for instance, takes a list of slot accessor names or something like that.
There may also be better ways of doing this I haven't thought of: there might be clever tricks with setf-expansions that let you do it without the little helper functions. You could also have global helper functions which get passed an object and a list of accessors to try which would make the code slightly smaller (although you can probably achieve similarly small code in any serious implementation by declaring the helpers inline which should cause them to be completely compiled away).
An alternative, and perhaps better, approach, is to define the protocol you want to achieve using generic functions. This means things are defined globally, and it's related to but not quite the same as Kaz's answer.
So again, let's say I have some class (this can be a structure, but making it a fully-fledged standard-class lets us have unbound slots, which is nice):
(defclass toy ()
((first :initarg :first)
(second :initarg :second)))
Now you could either define generic functions with names like appropriate-slot-value & (setf appropriate-slot-value), or you could define GF which returns the name of the appropriate slot, like so:
(define-condition no-appropriate-slot (unbound-slot)
;; this is not the right place in the condition heirarchy probably
()
(:report "no appropriate slot was bound"))
(defgeneric appropriate-slot-name (object &key for)
(:method :around (object &key (for ':read))
(call-next-method object :for for)))
(defmethod appropriate-slot-name ((object toy) &key for)
(let ((found (find-if (lambda (slot)
(slot-boundp object slot))
'(first second))))
(ecase for
((:read)
(unless found
(error 'no-appropriate-slot :name '(first second) :instance object))
found)
((:write)
(or found 'first)))))
And now the accessor function pair can be plain functions which will work for any class where there is a method for appropriate-slot-name:
(defun appropriate-slot-value (object)
(slot-value object (appropriate-slot-name object :for ':read)))
(defun (setf appropriate-slot-value) (new object)
;; set the bound slot, or the first slot
(setf (slot-value object (appropriate-slot-name object :for ':write)) new))
Finally, we can now have functions which just use symbol-macrolet in the obvious way:
(defun foo (something)
(symbol-macrolet ((s (appropriate-slot-value something)))
... s ... (setf s ...) ...))
So, that's another approach.
Simple, inefficient way with defsetf:
(defun second-or-first (list)
(or (second list) (first list)))
(defun set-second-or-first (list val)
(if (second list)
(setf (second list) val)
(setf (first list) val)))
(defsetf second-or-first set-second-or-first)
(defun test ()
(let ((list (list nil nil)))
(symbol-macrolet ((sof (second-or-first list)))
(flet ((prn ()
(prin1 list) (terpri)
(prin1 sof) (terpri)))
(prn)
(setf sof 0)
(prn)
(setf sof 1)
(prn)
(setf (second list) 3)
(prn)
(setf sof nil)
(prn)
(setf sof nil)
(prn)))))
If it is okay that update expressions like (incf sof) wastefully traverse the structure twice, this is adequate.
Otherwise a more sophisticated implementation is required using define-setf-expander. The gist of such a solution is that the generated code has to calculate which of the two cons cells of the list holds the current place, storing that cons cell in a temporary variable #:temp. Then the place we are interested in is denoted by (car #:temp). If #:temp is the second cell, avoiding two accesses to are tricky (one access to determine it's the one we want, then the other to get the prior value). Basically what we can do is have another temp variable which holds the value of the place that we obtained as a side effect of checking whether it is not nil. Then designate that temporary variable as the access form for getting the prior value.
Here’s how you might not use symbol macros without any huge loss:
(defgeneric firsty-secondy (thing))
(defgeneric (setf firsty-secondy) (newval thing))
(defmethod firsty-secondy ((x my-class))
(or (secondy x) (firsty x)))
(defmethod (setf firsty-secondy) (nv (x my-class))
(if (secondy x)
(setf (secondy x) nv)
(setf (firsty x) nv)))
You may find that the compiler does better with these because within the methods it can be more sure about where the slots for the fields are in memory.
Here is a way to structure your object to not need to do this and enforce your invariant a bit better:
(defclass my-class
((is-first :initform nil)
(thingy :initform nil)))
Here is a comparison:
first=nil,second=nil : is-first=nil,thingy=nil
first=123,second=nil : is-first=t ,thingy=123
first=nil,second=123 : is-first=nil,thingy=123
first=123,second=456 : unrepresentable

Checking circularity in lisp - same variable through recursive function

I'm trying to create a function that would test whether the given list is circular with a re-starting point being the beginning of the list.
Expected results:
(setq liste '(a b c))
(rplacd (cddr liste) liste)
(circular liste) => t
(circular '(a b c a b c)) => nil
As I simply want to test if any subsequent item is 'eq' to the first one, I don't want to build the whole tortoise and hare algorithm.
Here is my code :
(defun circular (liste)
(let (beginningliste (car liste)))
(labels ( (circ2 (liste)
(cond
((atom liste) nil)
((eq (car liste) beginningliste) t)
(t (circ2 (cdr liste)))
) ) ) ) )
It doesn't give the expected result but I don't understand where my error is
I'm not sure I'm using 'labels' correctly
Is there a way to do that without using 'labels'?
Edit. I guess I have answered my third question as I think I have found a simpler way. Would this work?
(defun circular (liste)
(cond
((atom liste) nil)
((eq (car liste) (cadr liste)) t)
(t (circular (rplacd liste (cddr liste))))
)
)
First, the behavior is undefined when you mutate constant data: when you quote something (here the list), the Lisp environment has the right to treat it as a constant. See also this question for why defparameter or defvar is preferred over setq. And so...
(setq list '(a b c))
(rplacd (cddr list) list)
... would be better written as:
(defparameter *list* (copy-list '(a b c)))
(setf (cdr (last *list*)) *list*)
Second, your code is badly formatted and has bad naming conventions (please use dashes to separate words); here it is with a conventional layout, with the help of emacs:
(defun circularp (list)
(let (first (car list)))
(labels ((circ2 (list)
(cond
((atom list) nil)
((eq (car list) first) t)
(t (circ2 (cdr list))))))))
With that formatting, two things should be apparent:
The let contains no body forms: you define local variables and never use them; you could as well delete the let line.
Furthermore, the let is missing one pair of parenthesis: what you wrote defines a variable name first and another one named car, bound to list. I presume you want to define first as (car list).
You define a local circ2 function but never use it. I would expect the circularp function (the -p is for "predicate", like numberp, stringp) to call (circ2 (cdr list)). I prefer renaming circ2 as visit (or recurse), because it means something.
With the above corrections, that would be:
(defun circularp (list)
(let ((first (car list)))
(labels ((visit (list)
(cond
((atom list) nil)
((eq (car list) first) t)
(t (visit (cdr list))))))
(visit (cdr list)))))
However, if your list is not circular but contains the same element multiple times (like '(a a b)), you will report it as circular, because you inspect the data it holds instead of the structure only. Don't look into the CAR here:
(defun circularp (list)
(let ((first list))
(labels ((visit (list)
(cond
((atom list) nil)
((eq list first) t)
(t (visit (cdr list))))))
(visit (cdr list)))))
Also, the inner function is tail recursive but there is no guarantee that a Common Lisp implementation automatically eliminates tail calls (you should check with your implementation; most can do it on request). That means you risk allocating as many call stack frames as you have elements in the list, which is bad. Better use a loop directly:
(defun circularp (list)
(loop
for cursor on (cdr list)
while (consp cursor)
thereis (eq cursor list)))
Last, but not least: your approach is a very common one but fails when the list is not one big circular chain of cells, but merely contains a loop somewhere. Consider for example:
CL-USER> *list*
#1=(A B C . #1#)
CL-USER> (push 10 *list*)
(10 . #1=(A B C . #1#))
CL-USER> (push 20 *list*)
(20 10 . #1=(A B C . #1#))
(see that answer where I explain what #1= and #1# mean)
The lists with numbers in front exhibit circularity but you can't just use the first cons cell as a marker, because you will be looping forever inside the sublist that is circular. This is the kind or problems the Tortoise and Hare algorithm solves (there might be other techniques, the most common being storing visited elements in a hash table).
After your last edit, here is what I would do if I wanted to check for circularity, in a recursive fashion, without labels:
(defun circularp (list &optional seen)
(and (consp list)
(or (if (member list seen) t nil)
(circularp (cdr list) (cons list seen)))))
We keep track of all the visited cons cells in seen, which is optional and initialized to NIL (you could pass another value, but that can be seen as a feature).
Then, we say that a list is circular with respect to seen if it is a cons cell which either: (i) already exists in seen, or (ii) is such that its CDR is circular with respect to (cons list seen).
The only additional trick here is to ensure the result is a boolean, and not the return value of member (which is the sublist where the element being searched for is the first element): if your environment has *PRINT-CIRCLE* set to NIL and the list is actually circular, you don't want it to try printing the result.
Instead of (if (member list seen) t nil), you could also use:
(when (member list seen))
(position list seen)
and of course (not (not (member list seen)))

Assignment in Lisp

I have the following setup in Common Lisp. my-object is a list of 5 binary trees.
(defun make-my-object ()
(loop for i from 0 to 5
for nde = (init-tree)
collect nde))
Each binary tree is a list of size 3 with a node, a left child and a right child
(defstruct node
(min 0)
(max 0)
(ctr 0))
(defun vals (tree)
(car tree))
(defun left-branch (tree)
(cadr tree))
(defun right-branch (tree)
(caddr tree))
(defun make-tree (vals left right)
(list vals left right))
(defun init-tree (&key (min 0) (max 1))
(let ((n (make-node :min min :max max)))
(make-tree n '() '())))
Now, I was trying to add an element to one of the binary trees manually, like this:
(defparameter my-object (make-my-object))
(print (left-branch (car my-object))) ;; returns NIL
(let ((x (left-branch (car my-object))))
(setf x (cons (init-tree) x)))
(print (left-branch (car my-object))) ;; still returns NIL
The second call to print still returns NIL. Why is this? How can I add an element to the binary tree?
The first function is just:
(defun make-my-object ()
(loop repeat 5 collect (init-tree)))
Now you define a structure for node, but you use a list for the tree and my-object? Why aren't they structures?
Instead of car, cadr and caddr one would use first, second, third.
(let ((x (left-branch (car my-object))))
(setf x (cons (init-tree) x)))
You set the local variable x to a new value. Why? After the let the local variable is also gone. Why aren't you setting the left branch instead? You would need to define a way to do so. Remember: Lisp functions return values, not memory locations you can later set. How can you change the contents in a list? Even better: use structures and change the slot value. The structure (or even CLOS classes) has following advantages over plain lists: objects carry a type, slots are named, accessors are created, a make function is created, a type predicate is created, ...
Anyway, I would define structures or CLOS classes for node, tree and object...
Most of the code in this question isn't essential to the real problem here. The real problem comes in with the misunderstanding of this code:
(let ((x (left-branch (car my-object))))
(setf x (cons (init-tree) x)))
We can see the same kind of behavior without user-defined structures of any kind:
(let ((cell (cons 1 2)))
(print cell) ; prints (1 . 2)
(let ((x (car cell)))
(setf x 3)
(print cell))) ; prints (1 . 2)
If you understand why both print statements produce (1 . 2), then you've got enough to understand why your own code isn't doing what you (previously) expected it to do.
There are two variables in play here: cell and x. There are three values that we're concerned with 1, 2, and the cons-cell produced by the call (cons 1 2). Variables in Lisp are often called bindings; the variable, or name, is bound to a value. The variable cell is bound to the the cons cell (1 . 2). When we go into the inner let, we evaluate (car cell) to produce the value 1, which is then bound to the variable x. Then, we assign a new value, 3, to the variable x. That doesn't modify the cons cell that contains the value that x was originally bound to. Indeed, the value that was originally bound to x was produced by (car cell), and once the call to (car cell) returned, the only value that mattered was 1.
If you have some experience in other programming languages, this is directly analogous to something like
int[] array = ...;
int x = array[2]; // read from the array; assign result to x
x = 42; // doesn't modify the array
If you want to modify a structure, you need to setf the appropriate part of the structure. E.g.:
(let ((cell (cons 1 2)))
(print cell) ; prints (1 . 2)
(setf (car cell) 3)
(print cell)) ; prints (3 . 2)

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
⇒ 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?

Common Lisp: non-nil arguments and their names to alist, how?

I am quite new to Common Lisp and programming, and I'm trying to write a certain function that turns all non-nil args into an alist. The only way I can think of so far is:
(let ((temp nil))
(if arg1
(setf temp (acons 'arg1 arg1 nil)))
(if arg2
(setf temp (acons 'arg2 arg2 temp)))
...
(if arg20-ish
(setf temp (acons 'arg20-ish arg20-ish temp)))
(do-something-with temp))
which does not seem very elegant, it would be messy with many arguments and when these need to be changed. I am looking for a smarter way to do this, both for the sake of writing this particular function and for learning how to think in Lisp and/or functional programming.
The tricky part for me is figuring out how to get the names of the arguments or what symbol to use, without hand coding each case. If &rest provided arg names it would be easy to filter out NILs with loop or mapcar, but since it doesn't, I can't see how to "automate" this.
I'm totally interested in other solutions than the one described, if people think this way is unnatural.
Edit: Below is an example of what I am trying to do:
An object is created, with a non-fixed number of data pairs and some tags, e.g.:
user = "someone"
creation-time = (get-universal-time)
color-of-sky = "blue"
temperature-in-celsius = 32
language = "Common Lisp"
...
tags = '("one" "two" "three")
These properties (i.e. key/arg names) could be different each time. The new object will then be added to a collection; I thought the array might work well since I want constant access time and only need a numeric ID.
The collection will hold more and more such custom objects, indefinitely.
I want to be able to quickly access all objects matching any combination of any of the tags used in these objects.
Since the array is supposed to store more and more data over a long period, I don't want to parse every item in it each time I need to search for a tag. Thus I also store the index of each object with a given tag in a hash-table, under the tag name. I have written this function, what I find difficult is figuring out how to collect the data and turn it into an alist or anything that I can easily parse, index, and store.
This macro will define a function that turns its non-nil arguments into an alist bound during execution of the body:
(defmacro defnamed (fun-name alist-sym (&rest args) &body body)
`(defun ,fun-name (,#args)
(let ((,alist-sym))
,#(mapcar
(lambda (s)
`(when ,s
(push (cons ',s ,s) ,alist-sym)))
(reverse args))
,#body)))
Demonstration:
(defnamed make-my alist (a b c)
alist)
(make-my 1 NIL 3)
=> ((A . 1) (C . 3))
Here's a sort of solution using macros:
(defmacro named-args (fun-name alist-sym (&rest syms) &body body)
`(defun ,fun-name (&key ,#syms)
(declare (special ,#syms))
(let ((,alist-sym
(loop
for s in ',syms
collecting (cons s (symbol-value s)))))
,#body)))
You can then use it with something like
(named-args f u (a b c)
(format t "~A~%" u))
which expands to
(DEFUN F (&KEY A B C)
(DECLARE (SPECIAL A B C))
(LET ((U
(LOOP FOR S IN '(A B C)
COLLECTING (CONS S (SYMBOL-VALUE S)))))
(FORMAT T "~A~%" U)))
Finally, calling will give
(f :a 3) => ((A . 3) (B) (C))
Note that we need the special declaration otherwise symbol-value doesn't work (you need a global binding for symbol-value). I couldn't find a way to get rid of that.
Looking at your question again, it looks like you actually don't want the keyword arguments that didn't get passed. In which case you could parse a &rest argument (although that's a flat list, so you'd need to map along it in twos) or you could modify the macro as follows:
(defmacro named-args (fun-name alist-sym (&rest syms) &body body)
`(defun ,fun-name (&key ,#syms)
(declare (special ,#syms))
(let ((,alist-sym
(loop
for s in ',syms
when (symbol-value s)
collecting (cons s (symbol-value s)))))
,#body)))
and then you get
(f :a 3) => ((A . 3))