Push doesn't modify the list being a function argument [duplicate] - arguments

This question already has answers here:
Common lisp push from function
(4 answers)
Closed 3 years ago.
I'm new to common lisp, so hope someone would clarify this to me:
say we have a list and want to add an item with push to modify it:
CL-USER> (defparameter xx '(1 2 3))
XX
CL-USER> xx
(1 2 3)
CL-USER> (push 100 xx)
(100 1 2 3)
CL-USER> xx
(100 1 2 3)
as expected. But when i try to do the same with the function, it doesn't modify a list:
CL-USER> (defun push-200 (my-list)
(push 200 my-list))
PUSH-200
CL-USER> (push-200 xx)
(200 100 1 2 3)
CL-USER> xx
(100 1 2 3)
so i tried to compare argument and my list like this:
CL-USER> (defun push-200 (my-list)
(format t "~a" (eq my-list xx))
(push 200 my-list))
WARNING: redefining COMMON-LISP-USER::PUSH-200 in DEFUN
PUSH-200
CL-USER> (push-200 xx)
T
(200 100 1 2 3)
CL-USER> xx
(100 1 2 3)
it says the objects are identical.
So the question is: what was the thing I've overlooked here?

(defun push-200 (my-list)
(push 200 my-list))
This modifies the variable my-list. The variable now points to a new cons.
It is basically: (setq my-list (cons 200 my-list).
(push-200 xx)
Common Lisp evaluates xx to a value and passes the list to push-200. xx is not passed, but the value of it. So, the Lisp system can't modify xx to point to a different cons, since it is not passed.

This is (essentially) the same problem highlighted by the following:
(let ((a (list 2 3 4 5)))
(let ((b a))
(push 1 a)
(list (eql a b)
(eql (cdr a) b))))
This form should return (NIL T) when run.

What Rainer Joswig writes (and Vatine demonstrates). Just replace (push <A> <B>) with (setq <B> (cons <A> <B>)) wherever you see it, because push is a macro:
"push item place => new-place-value"
And,
"new-place-value [is] a list (the new value of place)"
Notice CLHS didn't say "(the updated structure referred to by place)".
So, the value of place changes. And that place, in your case, is the local variable my-list. It was eq to xx before the (setq ...), but obviously not, after it. To actually alter a list structure you can use rplaca and ⁄ or rplacd.
We can think about argument passing in Common Lisp mostly as if what was passed is a pointer to a value; the pointer itself is passed by value, i.e. copied. So xx "points" at some list; and initially my-list "points" at the same memory location. That's why the initial eq test succeeds.

Related

How to represent the following data structure in scheme r5rs

In Python the data structure looks like this: [([1 2 3], [8 9 10])] (a list of tuple, where tuple is of size 2, and each tuple element is a list again)
How would I represent the same in Scheme r5rs?
This is what I tried: (list (cons `(1 2 3) `(8 9 10)))
But running (display (list (cons `(1 2 3) `(8 9 10)))) gives (((1 2 3) 8 9 10)) whereas I want (((1 2 3) (8 9 10)))
Edit
Using only lists (as per #Will Ness answer here):
(list ; a pair of elements,
(list 1 2 3) ; 1 each is itself
(list 8 9 10))) ; 2 a list
works.
And I can access the 2nd element of the tuple by
(cadr (car x)) which gives (8 9 10) (which is correct)
I was just thinking how would I build this up using cons since my tuple will only contain 2 elements and from what I know cons are used to represent a pair in Scheme. Any ideas on how to do this using cons?
[([1 2 3], [8 9 10])] (a list of tuple, where tuple is of size 2, and each tuple element is a list again)
(list ; a list of
(list ; a pair of elements,
(list 1 2 3) ; 1 each is itself
(list 8 9 10))) ; 2 a list
Scheme is untyped, so we can just use lists for tuples. It is simpler that way -- the access is uniform. The first is car, the second cadr.
Your way is correct as well. What really determines whether it is or not is how you can access your data to retrieve its constituents back. And with your way you can indeed, too: the first element will be car and the second -- cdr.
(update to the question edit:) whether you use (cons 1 (cons 2 '())) or (list 1 2) is immaterial. the resulting structure in memory is the same.
There is an infinity of ways to represent data. You have been presented a way. Here is other way:
(define mk/data
(lambda (a b)
(lambda (?)
(cond ((eq? ? 'repr) (list (list a b)))
((eq? ? 'first) a)
((eq? ? 'second) b)))))
(define data/test (mk/data '(1 2 3) '(8 9 10)))
(data/test 'repr)
(data/test 'first)
(data/test 'second)
This is another way how the big systems actually represent data.

Scheme higher-order function

I try to create a procedure that converts a binary number in a list to a string. Sample output: (binary->string '(1 1 0 1 0 0)) should give "110100".
(define reduce
(lambda (op base x) ;passing by name
(if (null? x)
base
(op (car x) (reduce op base (cdr x))))))
And here is my code:
(define (binary->string lst)
(reduce (number->string lst list->string )))
I know it is wrong but it is the best I came out with so far. Please help me to make it work properly.
Before I will show you solution, here is some advice: when you write Racket code, you should check correct number of arguments and their type.
In this case, you know that reduce needs (op base x), that are three arguments, but when you use some unknown function, like number->string, there is Racket documentation and after short search, you fill find number->string entry:
(number->string z [radix]) → string?
z : number?
radix : (or/c 2 8 10 16) = 10
Returns a string that is the printed form of z (see Printing Numbers) in the base specified by radix. If z is inexact, radix must be 10, otherwise the exn:fail:contract exception is raised.
Examples:
(number->string 3.0)
"3.0"
(number->string 255 8)
"377"
As you can see, you can call this function with one or two arguments, but in both cases, they have to be number. But with this call (number->string lst list->string ), you are passing list and procedure- so I can already tell that your code will end with error. And when you try to call your function in REPL, exactly this happens:
> (binary->string '(1 0 0 1))
. . number->string: contract violation
expected: number?
given: '(1 0 0 1)
argument position: 1st
other arguments...:
After you carefully check what did you write, you should be able to predict what will happen, before you even run your code.
Here is solution:
(define (binary->string lst)
(reduce string-append "" (map number->string lst)))
You will use map to create string from each number in list, then you join these strings with your reduce and string-append.

Update list in racket without hash

I have the 2 lists, '(1 2 3 4), and '(add1 sub1 add1). They do not have same length. The first list is numbers, the second list is functions. I want to apply the functions to each of element in the number list.
'(1 2 3 4) (add1 sub1 add1) -> '(2 3 4 5) '(sub1 add1)
It look very simple, but I find I can not update the lists. Because in Scheme there is no way to update lists without hash. I can only create new lists. So every time I have to create a new list for each function in the second list. Can someone help me code this question?
Alternatively you could use map and compose in combination.
This is much easier to read and understand.
(map (compose add1 sub1 add1) '(1 2 3 4))
;; '(2 3 4 5)
(compose add1 sub1 add1) chains the functions one after another
and map applies this chained/composed function on each element of the input list '(1 2 3 4).
Generalize to a function:
(define (map-functions funcs . args)
(apply map (apply compose funcs) args))
(map-functions (list add1 sub1 add1) '(1 2 3 4)) ;; '(2 3 4 5)
compose is inbuilt but one can define it like this (% in names to not to overwrite the existing compose.
;; first a compose to compose to functions
(define (%%compose f1 f2)
(lambda args
(f1 (apply f2 args))))
;; then, generalize it for as many functions as one wants (as a variadic function) using `foldl`
(define (%compose . funcs)
(foldl %%compose (car funcs) (cdr funcs)))
You're looking for a left fold. It looks like Racket calls it foldl, which will do the job, combined with map. Something like (Untested, because I don't have Racket installed):
(define functions (list add1 sub1 add1)) ; So you have functions instead of symbols like you get when using quote
(define numbers '(1 2 3 4))
(foldl (lambda (f lst) (map f lst)) numbers functions)
Basically, for each function in that list, it maps the function against the list returned by mapping the previous function (Starting with the initial list of numbers when there is no previous).
If you're stuck with a list of symbols and can't use the (list add1 ... trick to get references to the actual functions, one approach (And I hope there are better ones) is to use eval and some quasiquoting:
(foldl (lambda (f lst) (eval `(map ,f (quote ,lst)))) '(1 2 3 4) '(add1 sub1 add1))

#<Closure> in output

I was writing a function to switch the last element of a list to the beginning:
(define last-elem
(lambda (l)
(car (reverse l))))
(define all-but-last
(lambda (l)
(reverse (cdr (reverse l)))))
(define (last-to-first x) (append (list last-elem x) (all-but-last x)))
(last-to-first '(1 2 3 4 5 6))
It didn't work and I knew why. I forgot to put the brackets around list last-elem x
The thing is, I was curious about the output of the wrongly-typed code:
(#<Closure> (1 2 3 4 5 6) 1 2 3 4 5)
What is the meaning if this? How did it come out to this?
In Racket, the output is
'(#<procedure:last-elem> (1 2 3 4 5 6) 1 2 3 4 5)
which is a little clearer.
A reference to a function is always stored with its referencing environment, a.k.a. as a closure, and your Scheme implementation chooses to display it that way.
(list last-elem x)
doesn't call the function last-elem. It simply returns a list of two elements: the value of the variable last-elem (which is a procedure) and the value of the argument x. You want:
(list (last-elem x))
But there's no reason to make a list in the first place. Try:
(define (last-to-first x)
(cons (last-elem x) (all-but-last x)))
In Scheme, all identifiers denote either a syntactic keyword (bound to a 'transformer') or a variable (bound to a value). In your code last-elem denotes a variable bound to a function, which you defined. When you write:
(list last-elem x)
the interpreter/compiler produces a list with the value of last-elem and x. Thus, the result of #<Closure> in the list.

What is the output from this short string of cdr/car commands?

I am trying to understand how multiple calls of car and cdr work together. For example, the following example seems simple enough:
(car (cdr '(car (cdr (1 2 3))))
My DrRacket compiler outputs '(cdr (1 2 3)) when it is run, but I don't see how. Shouldn't cdr of (1 2 3) be taken first? What about the first two car and cdr?
No, the quote operator will quote all forms and sub forms that follow it. Only the first car and cdr of the list are executed; first (cdr '(car (cdr (1 2 3))) -> '((cdr (1 2 3)), and then (car '((cdr (1 2 3))) -> '(cdr (1 2 3)).
The problem here is that "quote" is much more powerful than you think it is. In particular, the quote is an instruction to the "reader"--the very first piece of code to examine your program--to rewrite your program from
(car (cdr '(car (cdr (1 2 3))))
...into
(car (cdr (list (quote car) (list (quote cdr) (list 1 2 3))))
That is, quote trickles down and changes every left paren into a new list creation, and every identifier into a quoted symbol.
Applying quote to things other than identifiers (e.g., 'abc) is a fairly slippery concept, and usually makes more sense after you have lots of experience with lists, and are looking for a nice way to abbreviate them.

Resources