I have a data structure which is a list of lists, doesn't really matter.
(setf var1 create_data_Structure)
Now I need to insert a value inside the data structure to test something without var1 being modified.
(defun testsomething(data_str val)
(let ((data_str_aux data_str))
(progn (insert val data_str_aux)
(testData data_str_aux))))
Ok, doesn't really matter what I do with the rest of the function, but now if I write this:
>var1
It appears my my data structure with the value inside, but I didn't want to.
I tried also this:
(defun testsomething(data_str val)
(let ((data_str_aux))
(progn (setq data_str_aux data_str)
(insert val data_str_aux)
(testData data_str_aux))))
And it stills modifies my global structure. What would you do?
In your case, aux is just an extra reference to the same object in memory, so modifying it with insert modifies the same object.
What you need is something like
(defun test-something (data-str val)
(let ((aux (copy-my-structure data-str)))
(insert val aux)
(test-data aux)))
E.g.,
(defparameter var1 (list 1 2 3 4))
(defun copy-my-structure (str)
(copy-list str))
(defun insert (val str) ; assumes non-NIL str
(nconc str (list val)))
(defun test-data (data)
(list (every #'numberp data)
(length data)))
(test-something var1 7)
==> (T 5)
var1
==> (1 2 3 4)
Related
I have an assignment where I need to write a script using lisp. I am having issues with passing variables
Here is the code. Issues to follow:
(defmacro while (test &rest bodies)
`(do ()
((not ,test))
,# bodies)
)
(defmacro += (var inc)
`(print (eval var))
;(setf (eval var) (+ (eval var) inc))
)
(defmacro iterate (i begin end inc &rest others)
(setf i begin)
(while (<= i (eval end))
;(dolist (item others)
; (eval item)
;)
(print (list 'two i (eval end)))
(+= (eval end) 1)
(setf i (+ i inc))
)
)
(setf n 5)
(iterate i 1 n 1
(print (list 'one i))
(+= n 1)
)
The first issue lies in passing the statements to the iterate macro. When I try to run the commented out dolist, the print statement will throw an error when it comes to the variable i. For some reason I can not get it to print using the macro variable i which has a value, but it seems to want to default to the global variable i which has not been set. I get the error:
- EVAL: variable I has no value
The second issue is when I call the "+=" macro. The value of end in the iterate macro is 5 as passed to the macro by use of the variable N which it is set to 5, however, when I pass it to the "+=" macro using the line "(+= (eval end) 1)" I can not get it to pass the value. I tried removing the eval in the line "(+= (eval end) 1)" and when I try printing it with "(print (eval var))" in the "+=" macro, I get the error
- EVAL: variable END has no value
How would I solve these issues?
Your first macro is basically correct. It generates code.
(defmacro while (test &body body)
`(do ()
((not ,test))
,#body))
One can check it with an example. We expand the macro using example code. The function MACROEXPAND-1 expands the top-level macro exactly once. You need to pass code to the function MACROEXPAND-1:
CL-USER 1 > (macroexpand-1 '(while (< i 10)
(print i)
(incf i)))
(DO NIL ; NIL is the same as ()
((NOT (< I 10)))
(PRINT I)
(INCF I))
T
The generated code is a DO loop. Just like intended.
Thus we can use your macro:
CL-USER 2 > (let ((i 5))
(while (< i 10)
(print i)
(incf i)))
5
6
7
8
9
NIL
Your other macros should be like that
they should generate code
macro expansion of examples should show the right generated code
the generated code should work
Your macros should NOT
be using EVAL
try to compute results other than code
I have the following common lisp functions: (aggregate line1 line2) and (queuer data result).
queuer should push into result either the values line1 and line2 if they have the 1st field different, or the aggregate of those 2 lines if they have the 1st field equal.
I do not know why it doesn't change my result list.
Note: I am initializing the result list with a (push (pop data) result) to have the first element there. The 2 lists are 1-depth nested lists (("1" "text") ("2" "text") (...)).
(defun aggregate (line1 line2)
(progn
(list
(nth 0 line1)
(nth 1 line1)
(nth 2 line1)
(concatenate 'string (nth 3 line1) ", " (nth 3 line2))
(concatenate 'string (nth 4 line1) ", " (nth 4 line2)))))
(push (pop x) y)
(defun queuer (data result)
(loop do
(let ((line1 (pop data))
(line2 (pop result)))
(if (equal (first line1) (first line2))
(progn
(push (aggregate line1 line2) result)
(print "=="))
(progn
(push line2 result)
(push line1 result)
(print "<>"))))
while data))
Thank you for any insights.
If you write functions in Lisp it is preferable to think 'functionally'. A function takes values and returns values. A typical rule would be to avoid side effects. So your function should return a result value, not 'modify' a variable value.
Instead of:
(defparameter *result* '())
(defun foo (a)
(push a *result*))
use:
(defparameter *result* '())
(defun foo (a result)
(push a result)
result)
(setf *result* (foo a *result*))
Note also that aggregate does not need the progn.
Slightly advanced (don't do that):
If you have a global list:
(defparameter *foo* '())
You can't push onto it, as we have seen, like this:
(defun foo (l)
(push 1 l))
If you call foo the variable *foo* is unchanged. Reason: Lisp does not pass a variable reference, it passes the value of the variable.
But how can we pass a reference? Well, pass a reference: a cons cell would do it (or a structure, a vector, a CLOS object, ...):
CL-USER 38 > (defparameter *foo* (list '()))
*FOO*
CL-USER 39 > (defun foo (ref)
(push 1 (first ref)))
FOO
CL-USER 40 > (foo *foo*)
(1)
CL-USER 41 > (foo *foo*)
(1 1)
Now, if we look at *foo*, it is changed. But we haven't really changed the variable. We have changed the first entry of the list.
CL-USER 42 > *foo*
((1 1))
But, don't do it. Program in a functional style.
You cannot modify the contents of a variable with a function that only takes the variable's value.
Take the following simple example:
(defun futile-push (thing list)
(push thing list))
(let ((foo (list 1)))
(futile-push 2 foo))
What happens?
Foo is evaluated to the list it points to.
2 evaluates to 2.
These two arguments are passed to the function.
Inside the function invocation:
Thing is now bound to 2.
List is now bound to the list (1).
Note that the list does not know that it is also referenced by the variable
foo outside the function.
foo
|
v
---------
list -> | 1 |NIL|
---------
Push modifies the variable list in such a way that it is now bound to
the list (2 1).
Note that this does not affect foo outside. Foo still points to
the same thing as before.
foo
|
v
--------- ---------
list -> | 2 | ----> | 1 |NIL|
--------- ---------
Futile-push returns the return value of the push form, which happens
to be the new value of list.
That return value is never used or bound, so it vanishes.
foo
|
v
---------
| 1 |NIL|
---------
The most straightforward way to do what you want is to return the new
value and then set the variable outside:
(let ((foo (list 1)))
(setf foo (not-so-futile-push 2 foo)))
If you need to do that at more than one place, it might be worthwhile
to write a macro for that which expands to the setf form. Note that
push is itself a macro for exactly these reasons.
When you call push in queuer, this changes the value of the binding "result", not the cons cell that result is pointing to.
(push x list)
is essentially equivalent to:
(setq list (cons x list))
As long as your queuer function is a function, it couldn't really be any other way. If you call it with the argument "my-queue", then that argument (a symbol) is evaluated when you call the function and the result of the evaluation -- a cons cell -- is passed to the function. There is no way to modify that cons cell to indicate that another cons cell should be "prepended" to it -- cons cells don't keep track of the things that point to them.
There are (at least) three possible solutions:
Write your code so that queuer returns the new queue, instead of expecting the argument to be modified (or "mutated").
Wrap the queue inside a mutable layer of indirection. You could for instance hold the queue in the car or the cdr of a cons cell. You would then be able to mutate (car result) or (cdr result) in your queuer function, for instance with push.
Convert queuer to be a macro instead of a function. You can then write code to mutate its argument that will essentially be 'inserted' in your code wherever you use the queuer macro.
I would personally recommend the first solution. Where you would then, if you had your mutating queuer, want to write:
(queuer-mutating data my-queue)
You would instead write something like:
(setf my-queue (queuer-not-mutating data my-queue))
When you initialize data variable using (push (pop data) result), it moves items from data to result instead of copying:
CL-USER> (setq data '(("1" "text1") ("2" "text2") ("3" "text3")))
(("1" "text1") ("2" "text2") ("3" "text3"))
CL-USER> (setq result nil)
NIL
CL-USER> (push (pop data) result)
;Compiler warnings :
; In an anonymous lambda form: Undeclared free variable DATA (3 references)
(("1" "text1"))
CL-USER> (print data)
(("2" "text2") ("3" "text3"))
(("2" "text2") ("3" "text3"))
CL-USER> (print result)
(("1" "text1"))
(("1" "text1"))
What you might want to use instead is (copy-list list) function:
CL-USER> (setq copy2 (copy-list data))
(("2" "text2") ("3" "text3"))
I have a list of lists as follows in Common Lisp of the form
((1 2) (3 4) (5 6))
and which is the value of the variable list, and I want to have three new variables whose values are the elements of the list. For instance:
list-1 (1 2)
list-2 (3 4)
list-3 (5 6)
Is there any function which does this operation?
Use setq, first (or nth and elt) to set:
(setq list-1 (first list)
list-2 (second list)
list-3 (third list))
Or destructuring-bind to bind:
(destructuring-bind (list-1 list-2 list-3) list
...)
Again, destructuring-bind binds the variables instead of assigning them (i.e., it is like let, not like setq).
The notion of binding elements of a list to names of the form list-# can be generalized.
You can create a function to generate a lambda with the ordinal list names as arguments, and a given body:
(defun make-list-lambda (n body)
(let ((list-names (loop for index from 1 to n
collect (intern (format nil "LIST-~D" index)))))
`(lambda ,list-names
(declare (ignorable ,#list-names))
,#body)))
And then create a macro to create the lambda, compile it, and apply it to the list:
(defmacro letlist (list &body body)
(let ((assignments (gensym)))
`(let ((,assignments ,list))
(apply (compile nil (make-list-lambda (length ,assignments) ',body))
,assignments))))
In this way, the assignments are localized to the lambda body:
CL-USER> (letlist '(a b c d e f)
(format t "list-1: ~A~%" list-1)
(format t "list-3: ~A~%" list-3))
list-1: A
list-3: C
NIL
Note: The forms will be compiled every time the macro is invoked, since it will not be known how many list-# arguments will be present until the list is presented!
First set your list to a variable, for instance mylist. Then spit out the required
output using the function format. I'm using CLISP. Hope this helps. This is the actual REPL output.
(setf mylist '((1 2) (3 4) (5 6)) )
((1 2) (3 4) (5 6))
(format t "list-1 ~d~%list-2 ~d~%list-3 ~d" (car mylist)
(second mylist) (last mylist))
list-1 (1 2)
list-2 (3 4)
list-3 ((5 6))
NIL
[142]>
Can someone show me how to get rid of "NIL' in the above output?
I'm new to Lisp. Just learning for fun.
I'm trying to build a hash table (among other actions) while reading. I don't want the hash table to have global scope (yet), so I'm doing this with a macro and gensym. Inside the macro x, I'm defining a macro s which is similar to setf, but defines an entry in a hash table instead of defining a symbol somewhere. It blows up. I think I understand the error message, but how do I make it work?
The code:
#!/usr/bin/clisp -repl
(defmacro x (&rest statements)
(let ((config-variables (gensym)))
`(macrolet ((s (place value)
(setf (gethash 'place ,config-variables) value)))
(let ((,config-variables (make-hash-table :test #'eq)))
(progn ,#statements)
,config-variables))))
(defun load-config ()
(let ((config-file-tree (read *standard-input*)))
(eval config-file-tree)))
(defun load-test-config ()
(with-input-from-string (*standard-input* "(x (s fred 3) (s barney 5))")
(load-config)))
(load-test-config)
The output:
*** - LET*: variable #:G12655 has no value
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead of #:G12655.
STORE-VALUE :R2 Input a new value for #:G12655.
SKIP :R3 skip (LOAD-TEST-CONFIG)
STOP :R4 stop loading file /u/asterisk/semicolon/build.l/stackoverflow-semi
Just guessing what Bill might really want.
Let's say he wants a mapping from some keys to some values as a configuration in a file.
Here is the procedural way.
open a stream to the data
read it as an s-expression
walk the data and fill a hash-table
Example code:
(defun read-mapping (&optional (stream *standard-input*))
(destructuring-bind (type &rest mappings) (read stream)
(assert (eq type 'mapping))
(let ((table (make-hash-table)))
(loop for (key value) in mappings
do (setf (gethash key table) value))
table)))
(defun load-config ()
(read-mapping))
(defun load-test-config ()
(with-input-from-string (*standard-input* "(mapping (fred 3) (barney 5))")
(load-config)))
(load-test-config)
Use:
CL-USER 57 > (load-test-config)
#<EQL Hash Table{2} 402000151B>
CL-USER 58 > (describe *)
#<EQL Hash Table{2} 402000151B> is a HASH-TABLE
BARNEY 5
FRED 3
Advantages:
no macros
data does not get encoded in source code and generated source code
no evaluation (security!) via EVAL needed
no object code bloat via macros which are expanding to larger code
functional abstraction
much easier to understand and debug
Alternatively I would write a read-macro for { such that {(fred 3) (barney 5)} would be directly read as an hash-table.
If you want to have computed values:
(defun make-table (mappings &aux (table (make-hash-table)))
(loop for (key value) in mappings
do (setf (gethash key table) (eval value)))
table)
CL-USER 66> (describe (make-table '((fred (- 10 7)) (barney (- 10 5)))))
#<EQL Hash Table{2} 4020000A4B> is a HASH-TABLE
BARNEY 5
FRED 3
Turning that into a macro:
(defmacro defmapping (&body mappings)
`(make-table ',mappings))
(defmapping
(fred 3)
(barney 5))
In a macrolet you are as well defining a macro, so the usual rules apply, i.e. you have to backquote expressions, that are to be evaluated at run-time. Like this:
(defmacro x (&rest statements)
(let ((config-variables (gensym)))
`(macrolet ((s (place value)
`(setf (gethash ',place ,',config-variables) ,value)))
(let ((,config-variables (make-hash-table :test #'eq)))
(progn ,#statements)
,config-variables))))
I want to save data to a file in my elisp program. I have a multi-dimensional list that I want to save to a file, so I can restore it the next time my program runs. What's the easiest / best way to do this?
I realise, of course, that I can simply write my data to a buffer in a custom format and then save the buffer, but then I'd have to write a function to parse that data format when I want to restore it. I'd rather not have to do that.
In Python, there's the Pickle module that lets you "dump" objects to disk and restore them, very easily. Is there something similar for elisp?
This 'dump-vars-to-file routine will create some expressions that can be read by simply evaluating the expressions later (via a 'load command or 'read):
(defun dump-vars-to-file (varlist filename)
"simplistic dumping of variables in VARLIST to a file FILENAME"
(save-excursion
(let ((buf (find-file-noselect filename)))
(set-buffer buf)
(erase-buffer)
(dump varlist buf)
(save-buffer)
(kill-buffer))))
(defun dump (varlist buffer)
"insert into buffer the setq statement to recreate the variables in VARLIST"
(loop for var in varlist do
(print (list 'setq var (list 'quote (symbol-value var)))
buffer)))
I'm sure I'm missing some built-in routine that does a nicer job or is more flexible.
I tested it with this little routine:
(defun checkit ()
(let ((a '(1 2 3 (4 5)))
(b '(a b c))
(c (make-vector 3 'a)))
(dump-vars-to-file '(a b c) "/some/path/to/file.el")))
Which produced the output:
(setq a (quote (1 2 3 (4 5))))
(setq b (quote (a b c)))
(setq c (quote [a a a]))
For more information, see the info page on reading and printing lisp objects
Another proposal. Instead of serialising setq calls, this one basically lets you use the file as a variable.
(defun print-to-file (filename data)
(with-temp-file filename
(prin1 data (current-buffer))))
(defun read-from-file (filename)
(with-temp-buffer
(insert-file-contents filename)
(cl-assert (eq (point) (point-min)))
(read (current-buffer))))
Usage:
(print-to-file "bla.el" '(1 2 "foo" 'bar))
(1 2 "foo" (quote bar))
(read-from-file "bla.el")
(1 2 "foo" (quote bar))