Substitutions in Common Lisp - lisp

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)

Related

push macro storing in-function but not out of function [duplicate]

This question already has answers here:
Common lisp push from function
(4 answers)
Closed 3 years ago.
I have a function:
(defun multi-push (L P)
(print (if L "T" "F"))
(print P)
(when L
(multi-push (cdr L) (push (car L) P)))
P)
which I have made in an to attempt to push a list onto another list (I am aware the input list L is reversed. This is by design). The print statements make sense, but when I look at the variable P, it is not mutated as I expect.
Sample REPL output:
CL-USER> bob
(3 3 3)
CL-USER> (multi-push (list 1 2) bob)
"T"
(3 3 3)
"T"
(1 3 3 3)
"F"
(2 1 3 3 3)
(1 3 3 3)
CL-USER> bob
(3 3 3)
What have I done wrong? I thought PUSH (according to [http://clhs.lisp.se/Body/m_push.htm]) mutates its second argument in place. I have also tried variations where I POP L and PUSH it onto P before calling multi-push on L and P again.
one thing of note is that the line (1 3 3 3) is the output of the function of multi-push. This also confuses me.
What push mutates destructively is a binding, not a list. More correctly what push modifies is a 'place' which is
a form which is suitable for use as a generalized reference
where a 'generalized reference' is
a reference to a location storing an object as if to a variable.
These two quotes are from the CLHS glossary: the section which talks about this is 5.1.
In particular:
> (let* ((l1 '(1 2 3))
(l2 l1))
(push 0 l1)
(values l1 l2))
(0 1 2 3)
(1 2 3)
And also note that this is legal CL since it doesn't destructively alter the quoted list structure. push must be a macro since a function can't do what it does: you can't write a function f such that:
(let* ((a (list 1 2 3))
(b a))
(f a b)
(not (eq a b)))
would be true.
You can think of (push x y) as expanding to something like (setf y (cons x y)), except that it will deal with multiple-evaluation properly.

List of lists in racket

I need to create this:
Define a min&max-lists function that consumes a list of lists
(where the type of the elements in the inner list may be any type).
The function returns a list of lists – such that for each inner list (in the
original list) the following is done –
If the list contains at least one number, then the list is replaced with a list of size two, containing the minimum and maximum in the list.
Otherwise, the list is replaced with a null.
For example
written in a form of a test that you can use:
(test (min&max-lists '((any "Benny" 10 OP 8) (any "Benny" OP (2 3))))
=> '((8 10) ()))
(test (min&max-lists '((2 5 1 5 L) (4 5 6 7 3 2 1) ())) >> '((1 5) (1 7) ()))
For now, I have created a function that do it for one list.
How I do it for the list of lists??
for example:
(listhelp '(2 5 1 5 L))
-> : (Listof Number)>>'(1 5)
Given that you have min&max with the strange name listhelp you can use map, use for/list, or roll your own recursion:
(define (min&max-lists lol)
(map min&max lol))
(define (min&max-lists lol)
(for/list ([e (in-list lol)])
(min&max e)))
(define (min&max-lists lol)
(if (null? lol)
'()
(cons (min&max (car lol))
(min&max-lists (cdr lol)))))

Exercise about substitution in nested lisp [duplicate]

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)

Writing the Foo Function In LISP With the following Specification

I am struggling to find the right approach to solve the following function
(FOO #'– '(1 2 3 4 5))
=> ((–1 2 3 4 5) (1 –2 3 4 5) (1 2 –3 4 5) (1 2 3 –4 5) (1 2 3 4 –5))
The first Parameter to the foo function is supposed to be a function "-" that has to be applied to each element returning a list of list as shown above. I am not sure as to what approach I can take to create this function. I thought of recursion but not sure how I will preserve the list in each call and what kind of base criteria would I have. Any help would be appreciated. I cannot use loops as this is functional programming.
It's a pity you cannot use loop because this could be elegantly solved like so:
(defun foo (fctn lst)
(loop
for n from 0 below (length lst) ; outer
collect (loop
for elt in lst ; inner
for i from 0
collect (if (= i n) (funcall fctn elt) elt))))
So we've got an outer loop that increments n from 0 to (length lst) excluded, and an inner loop that will copy verbatim the list except for element n where fctn is applied:
CL-USER> (foo #'- '(1 2 3 4 5))
((-1 2 3 4 5) (1 -2 3 4 5) (1 2 -3 4 5) (1 2 3 -4 5) (1 2 3 4 -5))
Replacing loop by recursion means creating local functions by using labels that replace the inner and the outer loop, for example:
(defun foo (fctn lst)
(let ((len (length lst)))
(labels
((inner (lst n &optional (i 0))
(unless (= i len)
(cons (if (= i n) (funcall fctn (car lst)) (car lst))
(inner (cdr lst) n (1+ i)))))
(outer (&optional (i 0))
(unless (= i len)
(cons (inner lst i) (outer (1+ i))))))
(outer))))
Part of the implementation strategy that you choose here will depend on whether you want to support structure sharing or not. Some of the answers have provided solutions where you get completely new lists, which may be what you want. If you want to actually share some of the common structure, you can do that too, with a solution like this. (Note: I'm using first/rest/list* in preference to car/car/cons, since we're working with lists, not arbitrary trees.)
(defun foo (operation list)
(labels ((foo% (left right result)
(if (endp right)
(nreverse result)
(let* ((x (first right))
(ox (funcall operation x)))
(foo% (list* x left)
(rest right)
(list* (revappend left
(list* ox (rest right)))
result))))))
(foo% '() list '())))
The idea is to walk down list once, keeping track of the left side (in reverse) and the right side as we've gone through them, so we get as left and right:
() (1 2 3 4)
(1) (2 3 4)
(2 1) (3 4)
(3 2 1) (4)
(4 3 2 1) ()
At each step but the last, we take the the first element from the right side, apply the operation, and create a new list use revappend with the left, the result of the operation, and the rest of right. The results from all those operations are accumulated in result (in reverse order). At the end, we simply return result, reversed. We can check that this has the right result, along with observing the structure sharing:
CL-USER> (foo '- '(1 2 3 4 5))
((-1 2 3 4 5) (1 -2 3 4 5) (1 2 -3 4 5) (1 2 3 -4 5) (1 2 3 4 -5))
By setting *print-circle* to true, we can see the structure sharing:
CL-USER> (setf *print-circle* t)
T
CL-USER> (let ((l '(1 2 3 4 5)))
(list l (foo '- l)))
((1 . #1=(2 . #2=(3 . #3=(4 . #4=(5))))) ; input L
((-1 . #1#)
(1 -2 . #2#)
(1 2 -3 . #3#)
(1 2 3 -4 . #4#)
(1 2 3 4 -5)))
Each list in the output shares as much structure with the original input list as possible.
I find it easier, conceptually, to write some of these kind of functions recursively, using labels, but Common Lisp doesn't guarantee tail call optimization, so it's worth writing this iteratively, too. Here's one way that could be done:
(defun phoo (operation list)
(do ((left '())
(right list)
(result '()))
((endp right)
(nreverse result))
(let* ((x (pop right))
(ox (funcall operation x)))
(push (revappend left (list* ox right)) result)
(push x left))))
The base case of a recursion can be determined by asking yourself "When do I want to stop?".
As an example, when I want to compute the sum of an integer and all positive integers below it, I can do this recusively with a base case determined by answering "When do I want to stop?" with "When the value I might add in is zero.":
(defun sumdown (val)
(if (zerop val)
0
(+ (sumdown (1- val)) val)))
With regard to 'preserve the list in each call', rather than trying to preserve anything I would just build up a result as you go along. Using the 'sumdown' example, this can be done in various ways that are all fundamentally the same approach.
The approach is to have an auxiliary function with a result argument that lets you build up a result as you recurse, and a function that is intended for the user to call, which calls the auxiliary function:
(defun sumdown1-aux (val result)
(if (zerop val)
result
(sumdown1-aux (1- val) (+ val result))))
(defun sumdown1 (val)
(sumdown1-aux val 0))
You can combine the auxiliary function and the function intended to be called by the user by using optional arguments:
(defun sumdown2 (val &optional (result 0))
(if (zerop val)
result
(sumdown2 (1- val) (+ val result))))
You can hide the fact that an auxiliary function is being used by locally binding it within the function the user would call:
(defun sumdown3 (val)
(labels ((sumdown3-aux (val result)
(if (zerop val)
result
(sumdown3-aux (1- val) (+ val result)))))
(sumdown3-aux val 0)))
A recursive solution to your problem can be implemented by answering the question "When do I want to stop when I want to operate on every element of a list?" to determine the base case, and building up a result list-of-lists (instead of adding as in the example) as you recurse. Breaking the problem into smaller pieces will help - "Make a copy of the original list with the nth element replaced by the result of calling the function on that element" can be considered a subproblem, so you might want to write a function that does that first, then use that function to write a function that solves the whole problem. It will be easier if you are allowed to use functions like mapcar and substitute or substitute-if, but if you are not, then you can write equivalents yourself out of what you are allowed to use.

DELETE + SETF inside a function

I'm trying to write a function that will destructively remove N elements from a list and return them. The code I came up with (see below) looks fine, except the SETF is not working the way I intended.
(defun pick (n from)
"Deletes (destructively) n random items from FROM list and returns them"
(loop with removed = nil
for i below (min n (length from)) do
(let ((to-delete (alexandria:random-elt from)))
(setf from (delete to-delete from :count 1 :test #'equal)
removed (nconc removed (list to-delete))))
finally (return removed)))
For most cases, this works just fine:
CL-USER> (defparameter foo (loop for i below 10 collect i))
CL-USER> (pick 3 foo)
(1 3 6)
CL-USER> foo
(0 2 4 5 7 8 9)
CL-USER> (pick 3 foo)
(8 7 0)
CL-USER> foo
(0 2 4 5 9)
As you can see, PICK works just fine (on SBCL) unless the element being picked happens to be the first on the list. In that case, it doesn't get deleted. That's because the only reassignment happening is the one that goes on inside DELETE. The SETF doesn't work properly (i.e. if I use REMOVE instead, FOO does not change at all).
Is there any scoping rule going on that I'm not aware of?
A (proper) list consists of cons cells that each hold a reference to the next
cell. So, it is actually a chain of references, and your variable has a
reference to the first cell. To make this clear, I rename the binding outside
of your function to var:
var ---> [a|]--->[b|]--->[c|nil]
When you pass the value of the variable to your function, the parameter gets
bound to the same reference.
var ---> [a|]--->[b|]--->[c|nil]
/
from --'
You can update the references in the chain, for example eliminate b:
var ---> [a|]--->[c|nil]
/
from --'
This has an effect on the list that var sees outside.
If you change the first reference, for example eliminating a, this is just the
one originating from from:
var ---> [a|]--->[b|]--->[c|nil]
/
from --'
This has obviously no effect on what var sees.
You need to actually update the variable binding in question. You can do that
by setting it to a value returned by function. Since you already return a
different value, this would then be an additional return value.
(defun pick (n list)
(;; … separate picked and rest, then
(values picked rest)))
Which you then use like this, for example:
(let ((var (list 1 2 3)))
(multiple-value-bind (picked rest) (pick 2 var)
(setf var rest)
(do-something-with picked var)))
Now to the separation: unless the list is prohibitively long, I'd stick to
non-destructive operations. I also would not use random-elt, because it needs
to traverse O(m) elements each time (m being the size of the list),
resulting in a runtime of O(n·m).
You can get O(m) overall runtime by determining the current chance of picking
the current item while linearly running over the list. You then collect the
item into either the picked or rest list.
(defun pick (n list)
(loop :for e :in list
:and l :downfrom (length list)
:when (or (zerop n)
(>= (random 1.0) (/ n l)))
:collect e :into rest
:else
:collect e :into picked
:and :do (decf n)
:finally (return (values picked rest))))
Delete isn't required to modify any structure, it's just permitted to. In fact, you can't always do a destructive delete. If you wanted to delete 42 from (42), you'd need to return the empty list (), which is the symbol NIL, but there's no way that you can turn the list (42), which is a cons cell (42 . NIL) into a different type of object (the symbol NIL). As such, you'll probably need to return both the updated list, as well as the elements that were removed. You can do that with something like this, which returns multiple values:
(defun pick (n from)
(do ((elements '()))
((or (endp from) (zerop n))
(values elements from))
(let ((element (alexandria:random-elt from)))
(setf from (delete element from)
elements (list* element elements))
(decf n))))
CL-USER> (pick 3 (list 1 2 3 2 3 4 4 5 6))
(2 6 4)
(1 3 3 5)
CL-USER> (pick 3 (list 1 2 3 4 5 6 7))
(2 7 5)
(1 3 4 6)
CL-USER> (pick 2 (list 1 2 3))
(2 3)
(1)
CL-USER> (pick 2 (list 1))
(1)
NIL
On the receiving end, you'll want to use something like multiple-value-bind or multiple-value-setq:
(let ((from (list 1 2 3 4 5 6 7)))
(multiple-value-bind (removed from)
(pick 2 from)
(format t "removed: ~a, from: ~a" removed from)))
; removed: (7 4), from: (1 2 3 5 6)
(let ((from (list 1 2 3 4 5 6 7))
(removed '()))
(multiple-value-setq (removed from) (pick 2 from))
(format t "removed: ~a, from: ~a" removed from))
; removed: (3 5), from: (1 2 4 6 7)
delete does not necessarily modify its sequence argument. As the hyperspec says:
delete, delete-if, and delete-if-not return a sequence of the same type as sequence that has the same elements except that those in the subsequence bounded by start and end and satisfying the test have been deleted. Sequence may be destroyed and used to construct the result; however, the result might or might not be identical to sequence.
For instance, in SBCL:
* (defvar f (loop for i below 10 collect i))
F
* (defvar g (delete 0 f :count 1 :test #'equal))
G
* g
(1 2 3 4 5 6 7 8 9)
* f
(0 1 2 3 4 5 6 7 8 9)
*
Note that in your function setf modifies the local variable from, and since delete in the case of first element does not modify the original list, at the end of the function the variable foo maintains the old values.