I want to save a reference (pointer) to a part of some Data I saved in another variable:
(let ((a (list 1 2 3)))
(let ((b (car (cdr a)))) ;here I want to set b to 2, but it is set to a copy of 2
(setf b 4))
a) ;evaluates to (1 2 3) instead of (1 4 2)
I could use macros, but then there would ever be much code to be executed if I want to change some Data in the middle of a list and I am not very flexible:
(defparameter *list* (create-some-list-of-arrays))
(macrolet ((a () '(nth 1000 *list*)))
(macrolet ((b () `(aref 100 ,(a))))
;; I would like to change the macro a here if it were possible
;; but then b would mean something different
(setf (b) "Hello")))
Is it possible, to create a variable as a reference and not as a copy?
cl-user> (let ((a '(1 2 3)))
(let ((b (car (cdr a))))
(setf b 4))
a)
;Compiler warnings :
; In an anonymous lambda form: Unused lexical variable B
(1 2 3)
A cons cell is a pair of pointers. car dereferences the first, and cdr dereferences the second. Your list is effectively
a -> [ | ] -> [ | ] -> [ | ] -> NIL
| | |
1 2 3
Up top where you're defining b, (cdr a) gets you that second arrow. Taking the car of that dereferences the first pointer of that second cell and hands you its value. In this case, 2. If you want to change the value of that pointer, you need to setf it rather than its value.
cl-user> (let ((a '(1 2 3)))
(let ((b (cdr a)))
(setf (car b) 4))
a)
(1 4 3)
If all you need is some syntactic sugar, try symbol-macrolet:
(let ((a (list 1 2 3 4)))
(symbol-macrolet ((b (car (cdr a))))
(format t "~&Old: ~S~%" b)
(setf b 'hello)
(format t "~&New: ~S~%" b)))
Note, that this is strictly a compile-time thing. Anywhere (in the scope of the symbol-macrolet), where b is used as variable, it is expanded into (car (cdr a)) at compile time. As Sylwester already stated, there are no "references" in Common Lisp.
I wouldn't recommend this practice for general use, though.
And by the way: never change quoted data. Using (setf (car ...) ...) (and similar) on a constant list literal like '(1 2 3) will have undefined consequences.
Building on what Baggers suggested. Not exactly what you are looking for but you can define setf-expanders to create 'accessors'. So lets say your list contains information about people in the for of (first-name last-name martial-status) and when someone marries you can update it as:
(defun marital-status (person)
(third person))
(defun (setf marital-status) (value person)
(setf (third person) value))
(let ((person (list "John" "Doe" "Single")))
(setf (marital-status person) "Married")
person)
;; => ("John" "Doe" "Married")
Related
So I have this line of code:
(foldl cons '() '(1 2 3 4))
And the output I get when I run it is this:
'(4 3 2 1)
Can you please explain to me why I don’t get '(1 2 3 4) instead?
I read the documentation but I am still a bit confused about how foldl works. Also if I wanted to define foldl how would I specify in Racket that the function can take a variable amount of lists as arguments?
Thanks!
Yes. By the definition of left fold, the combining function is called with the first element of the list and the accumulated result so far, and the result of that call is passed (as the new, updated accumulated result so far) to the recursive invocation of foldl with the same combining function and the rest of the list:
(foldl cons '() '(1 2 3))
=
(foldl cons (cons 1 '()) '(2 3))
=
(foldl cons (cons 2 (cons 1 '())) '(3))
=
(foldl cons (cons 3 (cons 2 (cons 1 '()))) '())
=
(cons 3 (cons 2 (cons 1 '())))
And when the list is empty, the accumulated result so far is returned as the final result.
To your second question, variadic functions in Scheme are specified with the dot . in the argument list, like so:
(define (fold-left f acc . lists)
(if (null? (first lists)) ;; assume all have same length
acc
(apply fold-left ;; recursive call
f
(apply f (append (map first lists) ;; combine first elts
(list acc))) ;; with result so far
(map rest lists)))) ;; the rests of lists
Indeed,
(fold-left (lambda (a b result)
(* result (- a b)))
1
'(1 2 3)
'(4 5 6))
returns -27.
I am working on program related to the different of dealing with even numbers in C and lisp , finished my c program but still having troubles with lisp
isprime function is defined and I need help in:
define function primesinlist that returns unique prime numbers in a lis
here what i got so far ,
any help with that please?
(defun comprimento (lista)
(if (null lista)
0
(1+ (comprimento (rest lista)))))
(defun primesinlist (number-list)
(let ((result ()))
(dolist (number number-list)
(when (isprime number)
( number result)))
(nreverse result)))
You need to either flatten the argument before processing:
(defun primesinlist (number-list)
(let ((result ()))
(dolist (number (flatten number-list))
(when (isprime number)
(push number result)))
(delete-duplicates (nreverse result))))
or, if you want to avoid consing up a fresh list, flatten it as you go:
(defun primesinlist (number-list)
(let ((result ()))
(labels ((f (l)
(dolist (x l)
(etypecase x
(integer (when (isprime x)
(push x result)))
(list (f x))))))
(f number-list))
(delete-duplicates (nreverse result))))
To count distinct primes, take the length of the list returned by primesinlist.
Alternatively, you can use count-if:
(count-if #'isprime (delete-duplicates (flatten number-list)))
It sounds like you've already got a primality test implemented, but for sake of completeness, lets add a very simple one that just tries to divide a number by the numbers less than it up to its square root:
(defun primep (x)
"Very simple implementation of a primality test. Checks
for each n above 1 and below (sqrt x) whether n divides x.
Example:
(mapcar 'primep '(2 3 4 5 6 7 8 9 10 11 12 13))
;=> (T T NIL T NIL T NIL NIL NIL T NIL T)
"
(do ((sqrt-x (sqrt x))
(i 2 (1+ i)))
((> i sqrt-x) t)
(when (zerop (mod x i))
(return nil))))
Now, you need a way to flatten a potentially nested list of lists into a single list. When approaching this problem, I usually find it a bit easier to think in terms of trees built of cons-cells. Here's an efficient flattening function that returns a completely new list. That is, it doesn't share any structure with the original tree. That can be useful, especially if we want to modify the resulting structure later, without modifying the original input.
(defun flatten-tree (x &optional (tail '()))
"Efficiently flatten a tree of cons cells into
a list of all the non-NIL leafs of the tree. A completely
fresh list is returned.
Examples:
(flatten-tree nil) ;=> ()
(flatten-tree 1) ;=> (1)
(flatten-tree '(1 (2 (3)) (4) 5)) ;=> (1 2 3 4 5)
(flatten-tree '(1 () () 5)) ;=> (1 5)
"
(cond
((null x) tail)
((atom x) (list* x tail))
((consp x) (flatten-tree (car x)
(flatten-tree (cdr x) tail)))))
Now it's just a matter of flatting a list, removing the number that are not prime, and removing duplicates from that list. Common Lisp includes functions for doing these things, namely remove-if-not and remove-duplicates. Those are the "safe" versions that don't modify their input arguments. Since we know that the flattened list is freshly generated, we can use their (potentially) destructive counterparts, delete-if-not and delete-duplicates.
There's a caveat when you're removing duplicate elements, though. If you have a list like (1 3 5 3), there are two possible results that could be returned (assuming you keep all the other elements in order): (1 3 5) and (1 5 3). That is, you can either remove the the later duplicate or the earlier duplicate. In general, you have the question of "which one should be left behind?" Common Lisp, by default, removes the earlier duplicate and leaves the last occurrence. That behavior can be customized by the :from-end keyword argument. It can be nice to duplicate that behavior in your own API.
So, here's a function that puts all those considerations together.
(defun primes-in-tree (tree &key from-end)
"Flatten the tree, remove elements which are not prime numbers,
using FROM-END to determine whether earlier or later occurrences
are kept in the list.
Examples:
(primes-in-list '(2 (7 4) ((3 3) 5) 6 7))
;;=> (2 3 5 7)
(primes-in-list '(2 (7 4) ((3 3) 5) 6 7) :from-end t)
;;=> (2 7 3 5)"
;; Because FLATTEN-TREE returns a fresh list, it's OK
;; to use the destructive functions DELETE-IF-NOT and
;; DELETE-DUPLICATES.
(delete-duplicates
(delete-if-not 'primep (flatten-tree list))
:from-end from-end))
When I try this code on Emacs SLIME, the apply function gives a different result. Isn't it supposed to give the same result? Why does it give a different result? Thanks.
CL-USER> (apply #'(lambda (n)
(cons n '(b a))) '(c))
(C B A)
CL-USER> (cons '(c) '(b a))
((C) B A)
cons takes an element and a list as arguments. So (cons 'x '(a b c d)) will return (x a b c d).
apply takes a function and a list of arguments -- but the arguments will not be passed to the function as a list! They will be split and passed individually:
(apply #'+ '(1 2 3))
6
(actually, it takes one function, several arguments, of which the last must be a list -- this list will be split and treated as "the rest of the arguments to the function". try, for example, (apply #'+ 5 1 '(1 2 3)), which will return 12)
Now to your code:
The last argument you passed to the apply function is '(c), a list with one element, c. Apply will treat it as a list of arguments, so the first argument you passed to your lambda-form is c.
In the second call, you passed '(c) as first argument to cons. This is a list, which was correctly included in the first place of the resulting list: ( (c) b a).
The second call would be equivalent to the first if you did
(cons 'c '(b a))
(c b a)
And the first call would be equivalent to the second if you did
(apply #'(lambda (n) (cons n '(b a))) '((c)))
((c) b a)
CL-USER 51 > (cons '(c) '(b a))
((C) B A)
CL-USER 52 > (apply #'(lambda (n)
(cons n '(b a)))
'(c))
(C B A)
Let's use FUNCALL:
CL-USER 53 > (funcall #'(lambda (n)
(cons n '(b a)))
'(c))
((C) B A)
See also what happens when we apply a two element list:
CL-USER 54 > (apply #'(lambda (n)
(cons n '(b a)))
'(c d))
Error: #<anonymous interpreted function 40600008E4> got 2 args, wanted 1.
There is a symmetry between &rest arguments in functions and apply.
(defun function-with-rest (arg1 &rest argn)
(list arg1 argn))
(function-with-rest 1) ; ==> (1 ())
(function-with-rest 1 2) ; ==> (1 (2))
(function-with-rest 1 2 3 4 5) ; ==> (1 (2 3 4 5))
Imagine we want to take arg1 and argn and use it the same way with a function of our choice in the same manner as function-with-rest. We double the first argument and sum the rest.
(defun double-first-and-sum (arg1 &rest argn)
(apply #'+ (* arg1 2) argn))
(double-first-and-sum 1 1) ; ==> 3
(double-first-and-sum 4 5 6 7) ; ==> 26
The arguments between the function and the list of "rest" arguments are additional arguments that are always first:
(apply #'+ 1 '(2 3 4)) ; ==> (+ 1 2 3 4)
(apply #'+ 1 2 3 '(4)) ; ==> (+ 1 2 3 4)
This is very handy since often we want to add more arguments than we are passed (or else we could just have used the function apply is using in the first place. Here is something called zip:
(defun zip (&rest args)
(apply #'mapcar #'list args))
So what happens when you call it like this: (zip '(a b c) '(1 2 3))? Well args will be ((a b c) (1 2 3)) and the apply will make it become (mapcar #'list '(a b c) '(1 2 3)) which will result in ((a 1) (b 2) (c 3)). Do you see the symmetry?
Thus you could in your example you could have done this:
(apply #'(lambda (&rest n)
(cons n '(b a))) '(c))
;==> ((c) b a)
(apply #'(lambda (&rest n)
(cons n '(b a))) '(c d e))
;==> ((c d e) b a)
I have a recursive function that basically keeps appending elements to a list recursively until a condition has been met. There's an issue though, and that's to use append, we must give it a quoted list. So doing
(append (1 2) 3)
gives us an error.
The problem is when I first pass a list to the argument, I can put the ' to make it a quoted list. However, once I append something to that list and it gets recursively passed to the same function again, the second time append tries to work, it will see the list is no longer quoted, so Scheme thinks it's a procedure rather than a list. Let me show you a simplified version of the code:
(define simple
(lambda (x y)
(if (equal? x '())
(display 'success!)
(simple (cdr x) (append y (car x))))))
We run the function by doing (simple '(1 2 3) '())
I realize the program above is useless; it's just to demonstrate what I'm saying.
Thanks!
The trouble with the code you posted isn't that Scheme is confusing a procedure with a list; the trouble is with the call to append.
It can be helpful to trace the execution of a procedure when debugging. Here's what's shown when I run your code with tracing turned on for simple and append, using trace-define in Petite Chez Scheme:
> (simple '(1 2 3) '())
|(simple (1 2 3) ())
| (append () 1)
| 1
|(simple (2 3) 1)
| (append 1 2)
Because (append () 1) returns 1, in the first recursive call to simple, the second argument is 1 rather than a list. So, you get an error on the next call to append.
You could fix it by wrapping your (car x) call in a call to list:
(define simple
(lambda (x y)
(if (equal? x '())
(display 'success!)
(simple (cdr x) (append y (list (car x)))))))
Here's a trace of the fixed version running:
> (simple '(1 2 3) '())
|(simple (1 2 3) ())
| (append () (1))
| (1)
|(simple (2 3) (1))
| (append (1) (2))
| (1 2)
|(simple (3) (1 2))
| (append (1 2) (3))
| (1 2 3)
|(simple () (1 2 3))
success!|#<void>
To append an element to the end of a list, put the element inside a list (append is defined only between lists). For example, in your code do this:
(append y (list (car x)))
Of course, that doesn't change the fact that the procedure is doing nothing as it is. At least, return the value accumulated in y:
(define simple
(lambda (x y)
(if (equal? x '())
y
(simple (cdr x)
(append y (list (car x)))))))
Given 2 lists, how can you produce an output of a 3rd list which has its elements as an interleaved set of L1 and L2? If they are uneven length, nil should be inserted for holes. On a second note, how can I reverse a list? I am super new to LISP and simply modifying existing code... I'd really love to have a good explanation, not just code.
First, I guess you use Common Lisp, as it is the one most used in Lisp courses. So, my examples will be in CL. If you use Scheme, you will get almost the same code. If modern Clojure, it will need some changes, through an idea will be the same.
Interleave
To interleave 2 lists you must go through both of them, collecting elements by turns. You can use loop statement or recursion for this. I'll use recursion since it has more functional style and may be used in any lisp, not only CL. Also note, that there's a feature called tail recursion, which lets you write recursive function that will be compiled to a loop.
So, base skeleton for our function will be:
(defun interleave (l1 l2)
??????
(interleave ?????))
To collect items in recursive functions you will need to return them from each call and then cons together (for a tail recursion you must have one more parameter, which will accumulate values). So, the end of the function will be (cons current-value (interleave ????)).
Also you must alternate lists to take elements from with each other. You may have additional parameter, but you also may just swap them in a recursive call. So, code becomes:
(defun interleave (l1 l2)
?????
(cons current-value (interleave l2 l1)))
Any recursion must stop somewhere. In this case, it must stop when both lists are empty (nil).
This is one condition (let give it number 1), and there are some more conditions:
2. if the list to take from is empty, and the other one is not, we must take nil instead.
3. if both lists are not empty, take first element as a current-value and proceed with it's tail.
There's only one more condition that 2 lists can be in: list to take from is not empty, and the second one is. But in fact we don't care about this and may go forward with a rule number 3.
So, the code (and this is the final one):
(defun interleave (l1 l2)
(cond ((and (eql l1 nil) (eql l2 nil)) nil) ;; rule #1
((eql l1 nil) (cons nil (interleave l2 l1))) ;; rule #2, current value is nil
(true (cons (first l1) (interleave l2 (rest l1)))))) ;; rule #3 in all other cases
Reverse
I'll show two implementations of this function: one with cond and another with built-in reduce function which is extremely useful in practice.
First approach for cond version is to go through the all list with a recursive calls and then go back, collecting elements:
(defun reverse-1-1 (li)
(if (eql li nil)
nil
(append (reverse-1-1 (rest li))
(list (first li)))))
But this is extremely inefficient, since append is O(n), and you must pass n elements, so the final complexity is O(n^2).
To reduce it you may use one more argument to the function (and make it tail recursive, if compiler lets you):
(defun reverse-1-2 (li)
(reverse-aux li nil))
(defun reverse-aux (li accumulator)
(if (eql li nil)
accumulator
(reverse-aux (rest li) (cons (first li) accumulator))))
That's you use one more parameter to collect your elements in while passing through the list, and then just return this accumulator.
There's one more interesting option. Lisp has extremely powerful function reduce (in other functional languages it is sometimes called fold, foldr, foldl or something like that). You may find description for it here, and I'll just show an example:
(defun reverse-2 (li)
(reduce #'cons li :from-end t :initial-value nil))
:from-end tells function to go through the the list from the end, and :initial-value tells to use as the very first reduced argument nil.
Note: in some implementations reduce with option :from-end true may first reverse list by itself, so if you need to create it from scratch or use the most efficient version, use reverse-1-2 instead.
In Common Lisp:
(defun merge-lists (lst1 lst2)
(let ((m (max (length lst1) (length lst2))))
(flatten (mapcar (lambda (a b) (list a b))
(append-nulls lst1 m)
(append-nulls lst2 m)))))
Examples:
(merge-lists '(1 2 3 4) '(5 6 7 8)) ;; => (1 5 2 6 3 7 4 8)
(merge-lists '(1 2 3 4) '(5 6 7)) ;; => (1 5 2 6 3 7 4 NULL)
(merge-lists '(1 2) '(5 6 7 8)) ;; => (1 5 2 6 NULL 7 NULL 8)
The helper functions flatten and append-nulls:
(defun flatten (tree)
(let ((result '()))
(labels ((scan (item)
(if (listp item)
(map nil #'scan item)
(push item result))))
(scan tree))
(nreverse result)))
(defun append-nulls (lst n)
(if (< (length lst) n)
(dotimes (i (- n (length lst)))
(setq lst (append lst (list 'null)))))
lst)
The answer above:
(defun interleave (l1 l2)
(cond ((and (eql l1 nil) (eql l2 nil)) nil) ;; rule #1
((eql l1 nil) (cons nil (interleave l2 l1))) ;; rule #2, current value is nil
(true (cons (first l1) (interleave l2 (rest l1)))))) ;; rule #3 in all other cases
If one of your lists is longer than the other, you will get something like (1 2 3 4 nil 5).
Replace:
((eql l1 nil) (cons nil (interleave l2 l1)))
with:
((null l1) l2)
:P
An example of a more idiomatic solution in Common Lisp:
(defun interleave (a b)
(flet ((nil-pad (list on-list)
(append list (make-list (max 0 (- (length on-list) (length list)))))))
(loop for x in (nil-pad a b)
for y in (nil-pad b a)
append (list x y))))