I am familiar with how to set elements in a 2D array, which can be done using the following statement.
(setf (aref array2D 0 0) 3)
However, I am not familiar how to set elements in a list of lists, such as the following input: '((1) (2) (2) (1)). I can't use aref, since it only works on arrays.
As mentioned, while aref works on arrays, elt works on sequences which can be:
an ordered collection of elements
a vector or a list.
* (setf test-list '((1) (2) (2) (1)))
((1) (2) (2) (1))
* (setf (elt test-list 2) 'hi)
HI
* test-list
((1) (2) HI (1))
You can indeed use variables in place of fixed offsets:
* (setf test-list '((1) (2) (2) (1)))
((1) (2) (2) (1))
* (setf offset 2)
2
* (setf (elt test-list offset) 'hi)
HI
* test-list
((1) (2) HI (1))
To access the nth element of a list, there are (at least) two functions: nth and elt. The order of the parameters is different, and nth only work on lists while elt works on any sequence (i.e. lists, vector, strings ...):
(nth 1 '(foo bar baz)) => BAR
(nth 1 #(foo bar baz)) => ERROR
(elt '(foo bar baz) 1) => BAR
(elt #(foo bar baz) 1) => BAR
Now, in general, the way to set a value (as opposed to simply access it) is very straightforward, and at least for built-in functions this is almost always the case: whenever you have some form FORM which retrieves some value from what is called a place, the form (setf FORM <value>) will set this element to the given <value>. This works for functions such as car, cdr, gethash, aref, slot-value, symbol-function and many others, and any combination of those.
In your example, you have a list of lists. So, for example, to modify the "inner integer" in say the third list:
* (setf test-list '((0) (1) (2) (3))) ; changed the values to have something clearer
((0) (1) (2) (3))
* (car (nth 2 test-list)) ; this accesses the integer in the second list
2
* (setf (car (nth 2 test-list)) 12) ; this modifies it. Notice the syntax
12
* test-list
((0) (1) (12) (3))
On a side note, you should avoid modifying literal lists (created using the quote symbol '). If you want to modify lists, create them at runtime using the list function.
EDIT:
What happens is that setf knows, by "looking" at the form you give it, how to actually find the place that you want to modify, potentially using functions in this process.
If you look at other languages, such as Python, you also have some kind of duality in the syntax used both to get and to set values. Indeed, if you have a list L or a dictionary d, then L[index] and d[thing] will get the corresponding element while L[index] = 12 and d[thing] = "hello" will modify it.
However, in Python, those accessors use a special syntax, namely, the squares brackets []. Other types of objects use another syntax, for example, the dot notation to access slots/attributes of an object as in my-object.attr. A consequence is that the following code is invalid in Python:
>>> L = [1, 2, 3, 2, 1]
>>> max(L)
3
>>> max(L) = 12
Traceback (most recent call last):
File "<string>", line 9, in __PYTHON_EL_eval
File "/usr/lib/python3.8/ast.py", line 47, in parse
return compile(source, filename, mode, flags,
File "<string>", line 1
SyntaxError: cannot assign to function call
You have to write an other function, for example, setMax(L, val), to change the maximum of a list. This means that you now have to functions, and no symmetry anymore.
In Common Lisp, everything is (at least syntactically) a function call. This means that you can define new ways to access and modify things, for any function ! As a (bad) example of what you could do:
* (defun my-max (list)
(reduce #'max list))
MY-MAX
* (my-max '(1 2 3 8 4 5))
8
* (defun (setf my-max) (val list)
(do ((cur list (cdr cur))
(cur-max list (if (< (car cur-max) (car cur))
cur
cur-max)))
((endp (cdr cur)) (setf (car cur-max) val))))
(SETF MY-MAX)
* (setf test-list (list 0 4 5 2 3 8 6 3))
(0 4 5 2 3 8 6 3)
* (setf (my-max test-list) 42)
42
* test-list
(0 4 5 2 3 42 6 3)
This way, the syntax used to both set and get the maximum of a list is identical (FORM to get, (setf FORM val) to set), and combines automatically with every other "setter". No explicit pointers/references involved, it's just functions.
I want to define a functionality in common lisp which uses some words/symbols not known to lisp, for example having such a function/macro:
(my-func-or-macro lst key-word idx)
which returns items in the lst upto the idx if the key-word is to and from the idx to the end if the key-word is from.
So practically it should work like:
(my-func-or-macro '(1 2 3 4 5 6) from 3) => '(4 5 6)
and
(my-func-or-macro '(1 2 3 4 5 6) to 3) => '(1 2 3)
Since macros don't evaluate their arguments i think i should be using a macro which doesn't care about from and to (note i don't want to pass quoted args like 'from 'to).
Since every argument to a function is evaluated before the function is executed, you need a symbol that evaluates to itself.
Such symbols are already part of the language: all symbols in the special KEYWORD package evaluate to themselves. Symbols that are written with a leading colon, e. g. :foo are interned into that package.
Also part of the language are keyword arguments that use such keywords to identify parameters:
(defun my-func (list &key from)
(subseq list from))
(my-func '(0 1 2 3 4 5) :from 3)
=> (3 4 5)
You can give default values to such parameters:
(defun my-func (list &key (from 0) (to (length list)))
(subseq list from to))
(my-func '(0 1 2 3 4 5) :from 3)
=> (3 4 5)
(my-func '(0 1 2 3 4 5) :to 3)
=> (0 1 2)
(my-func '(0 1 2 3 4 5) :from 1 :to 4)
=> (1 2 3)
Keyword arguments can be given in any order:
(my-func '(0 1 2 3 4 5) :to 4 :from 1)
=> (1 2 3)
For example:
(setf s 2)
s => 2
(setf list1 '(1 s 3 4))
list1 => (1 s 3 4)
How do i get it to add the value stored in s to the list?
For this example I would want to use s to generate a list (1 2 3 4)
I have a lisp book I'm reading and I can't seem to find any mention of how to do this so I thought i'd ask.
Thanks
So quoted data in Scheme are like String constants.. If I wrote "1 s 3 4" in Java I wouldn't be able to get s replaced with the variable contents. I 'd have to write "1 " + s + " 3 4". In Lisp we have backquote to do this in list structures:
`(1 ,s 3 4)
; ==> (1 2 3 4)
Note that this is a trick.. It's like "1 $s 3 4" in PHP as it's representing code that creates the list with the unquoted variables evaluated and return a new list structure. Under the hood it's very similar to writing:
(list 1 s 3 4)
; ==> (1 2 3 4)
And of course list is not a primitive since it just uses cons. What it does is this:
(cons 1 (cons s (cons 3 (cons 4 '()))))
; ==> (1 2 3 4)
I would want to use s to generate a list (1 2 3 4)
The function list can be handy:
CL-USER 14 > (let ((s '2))
(list 1 s 3 4))
(1 2 3 4)
The function LIST creates a fresh new list from its arguments.
I’m trying to write a function with two arguments of this type:
substitutions (list_one, list_two)
list_one has always this form (letters can change according to the input):
(1 ((1 2 ((1 2 r) (3 2 t) (4 3 c))) (3 4 ((5 6 y) (5 7 i)))))
list_two has always this form (numbers can change according to the input):
(2 3 4 5 6)
I want to substitute in this way:
r-> 2
t -> 3
c -> 4
y -> 5
i -> 6
Can you help me please?
A not so efficient solution is to first find a list of all the letters in the fist tree structure (the first list) and then to LOOP over the results calling SUBST repeatedly.
To find the list of non numeric atoms in the first list (the 'letters') you need to traverse the tree structure (le first list) recurring both on the FIRST and on the REST of the list.
Hope it helps.
MA
If the lists are proper you can iterate them with the loop macro and pop off the arguments in the accessible free variable:
(defun template-replace (template replacements)
(labels ((iterate (template)
(loop :for element :in template
:collect
(cond ((consp element) (iterate element))
((symbolp element) (pop replacements))
(t element)))))
(iterate template)))
(template-replace '(1 rep (4 rep (9 rep)) rep) '(foot inch mm multiplied))
; ==> (1 foot (4 inch (9 mm)) multiplied)
Some output from the CLISP REPL:
[1]> (list 'list 1 2 3)
(LIST 1 2 3)
[2]> (list 'list '(1 2 3))
(LIST (1 2 3))
[3]> (list 'quote 1 2 3)
(QUOTE 1 2 3)
[4]> (list 'quote '(1 2 3))
'(1 2 3)
The first three, I understand exactly what's going on: The list function is passed a symbol ('list or 'quote) and so the result is a list that begins with the list or quote symbol. It's the fourth that confuses me. Why doesn't it return (QUOTE (1 2 3))?
I realise that if you enter (QUOTE '(1 2 3)) into the REPL, you get '(1 2 3) back, so the expression are equivalent in that sense. But (LIST 1 2 3) is equivalent to (1 2 3), and yet the first expression doesn't return that.
It seems inconsitent that (list 'quote 1 2 3) returns a list with the first item being a quote symbol, but (list 'quote (1 2 3)) returns a quoted list. Especially since expressions like (list 'list ...) seem to always return a list beginning with the symbol - so far, at least, quote is the only 'special case' like this.
It's not the easiest question to articulate, so I'm hoping I've managed to get my confusion across. Can anyone explain why quote gets treated in this seemingly-unique way?
'something is the same as (quote something) for the lisp reader. Even when nested it will be the case. The next expressions I will double quote so that after evaluation one of the quotes are still in there.
When printing the implementations can choose what to output where there are several possible representations, so some implementations would print the evaluation of ''something as
(quote something) while others may use the abbreviation 'something.
'(quote 1 2 3) cannot be abbreviated since a quoted form only has one argument. Thus here both lisp systems would print (quote 1 2 3).
Here is a way to look at your last expression:
(let ((data (list 'quote '(1 2 3))))
(format nil
"whole thing: ~a first element: ~a second-element: ~a"
data
(car data)
(cadr data)))
This will either evaluate to "whole thing: '(1 2 3) first element: QUOTE second-element: (1 2 3)" or "whole thing: (QUOTE (1 2 3)) first element: QUOTE second-element: (1 2 3)".
Since the printer never sees if the input is abbreviated and the data has the same structure in memory the output is never affected by how you input the data. Thus (quote (quote (1 2 3))) will print the same as ''(1 2 3).
You have the same behaviour with cons cells but the standard dictates how the rules are. (cons 1 (cons 2 (cons 3 '()))) would be (1 . (2 . (3 . ()))) but is actually just printed (1 2 3) However if you (cons 1 2) you get (1 . 2) showing that print treats the output differently based on the cdr. However the reader can read any of these and they will all print the same eg. '(1 . (2 . (3 . ()))) ==> (1 2 3) and (+ . (2 . ( 3 . ()))) ; ==> 5
Numbers can have as many visual forms as there are bases below the number in question.
(let ((*print-base* 16))
(print 255)) ; prints FF (255 in hexadecimal)
list does not have any abbreviation or specialness in Lisp. It's not even a primitive function but it's very helpful as it removes the inconvenience of having to cons by hand everytime. It can be defined like this:
(defun my-list (&rest lst)
lst)
(my-list 1 2 3 4) ; ==> (1 2 3 4)
Note that a REPL (the READ-EVAL-PRINT-LOOP) does three things:
reading using the function READ
evaluating using the function EVAL
and printing the result using something like the function PRINT
To understand what is going on you have to look at all three functions.
Let's look at the third form:
(list 'quote 1 2 3)
This is read as a list of five elements:
LIST
(QUOTE QUOTE)
1
2
3
EVAL then evaluates the arguments, and calls the function list with the four results and returns a new result, a list of four elements:
QUOTE
1
2
3
PRINT then takes this list and writes it as: (QUOTE 1 2 3). There is no abbreviated way to print it.
Let's look at the fourth form:
(list 'quote '(1 2 3))
This is read as a list of three elements:
LIST
(QUOTE QUOTE)
(QUOTE (1 2 3))
eval calls list with two arguments:
QUOTE
(1 2 3)
eval then returns a list of length two:
QUOTE
(1 2 3)
print now can print this list in two different ways:
(QUOTE (1 2 3)) or the abbreviated form '(1 2 3). Here a quote character is in front of a single expression.
Your implementation used the first version.