#lang racket
I need to create a pair from an element and a list
however when I do (cons 2 (list 1 2 3)) I get (2 (1 2 3)), I want to get (2 . (1 2 3))
how do I get the dot in ?
Since (cons a b) is the same as (a . b) we get that (2 . (1 2 3)) is the same as (cons 2 (list 1 2 3) which is the same as (list 2 1 2 3). To confirm:
> (cons 2 (list 1 2 3))
'(2 1 2 3)
> '(2 . (1 2 3))
'(2 1 2 3)
Note that the printer prints (2 1 2 3) and not (2 . (1 2 3)). The printer attempts to use the dot only when absolutely needed.
There is a difference between the syntax that explains the structure, how it's stored and how display would represent it.
For a list of two elements there are two ways you can represent it (1) and (1 . ()). When this list is displayed it will always prefer the one with the least parentheses. Thus '(2 . (1 2 3)) will always be printed as (2 1 2 3) by display. If you don't want that you can make yourself a cons-write like:
;; displays cons always as dotted
(define (cons-write x)
(if (pair? x)
(begin
(display "(")
(cons-write (car x))
(display " . ") ; spaces are important
(cons-write (cdr x))
(display ")"))
(write x)))
(cons-write '(1 2 3 4)) ; prints (1 . (2 . (3 . (4 . ()))))
Related
How would I write a function in Dr. Racket which consumes a list of list of integers and produces a new list of list of integers with a transformation (sqr) applied to each element.
Note: There is an equal number of elements in each list.
Here are two examples to show what I am saying:
Example 1:
(list (list 1 2) (list 3 -2))
Should produce:
(list (list 1 4) (list 9 4))
Example 2:
(list (list 3 4 5) (list 2 1 3) (list 2 3 7) (list 0 -3 2))
Should produce:
(list (list 9 16 25) (list 4 1 9) (list 4 9 49) (list 0 9 4))
Here is my code so far:
(define (transform-to-sqr b)
(map sqr b))
If I type in:
(transform-to-sqr (list (list 1 2) (list 3 -2)))
I get an error message saying:
sqr: expected a number; given (list 1 2).
Why is this happening. Can someone please tell me what I am doing wrong.
Thanks for your help.
The map higher-order procedure applies a procedure over the elements of a list, but in this case the elements are lists themselves. To operate on the nested elements, we need to nest calls to map:
(define (transform-to-sqr matrix)
(map (λ (row) (map sqr row))
matrix))
It works as expected:
(transform-to-sqr '((1 2) (3 -2)))
=> '((1 4) (9 4))
(transform-to-sqr '((3 4 5) (2 1 3) (2 3 7) (0 -3 2)))
=> '((9 16 25) (4 1 9) (4 9 49) (0 9 4))
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.
I need to find and return the first item in a list when that item's third element matches a value passed into the function. I then need that item to be permanently removed from the list.
I have written this function to do it and am wondering if there are any built-in functions that might accomplish the same without this fairly messy implementation:
(defun find-remove-third (x)
(let ((item (first (member x *test-list* :key #'third))))
(setf *test-list* (remove item *test-list* :test #'equal))
item))
Operation:
CL-USER> *test-list*
((1 2 3) (2 3 4) (3 4 5) (4 4 4) (5 4 3) (6 5 4) (2 2 2))
CL-USER> (find-remove-third 4)
(2 3 4)
CL-USER> *test-list*
((1 2 3) (3 4 5) (4 4 4) (5 4 3) (6 5 4) (2 2 2))
CL-USER> (find-remove-third 4)
(4 4 4)
CL-USER> *test-list*
((1 2 3) (3 4 5) (5 4 3) (6 5 4) (2 2 2))
For example pop mutates and returns from a list, though is more limited, but I'm wondering if anything more elegant than my function above might be possible, or if this implementation is normal and idiomatic?
Your implementation scans the list twice, so it is suboptimal.
I don't think you can write what you need without an explicit loop (or, equivalently, recursion):
(defun pop-from-list (object list &key (key #'identity) (test #'eql) kept)
"Like `remove', but return the object removed as the second value."
(let ((1st (car list)))
(if (funcall test object 1st)
(values (revappend kept (rest list))
1st)
(pop-from-list object (rest list) :key key :test test
:kept (cons 1st kept)))))
Now you can define your function like this:
(defun find-remove-third (x)
(multiple-value-bind (list object)
(pop-from-list x *test-list* :key #'third)
(setq *test-list* list)
object))
Edit - Deleting this doesn't seem right so I'll leave it up, but as noted by #sds and #WillNess in the comments, this has serious issues.
Here's a destructive version which only scans the list once. It has the potential benefit that you don't have to hardcode the name of the list you're operating on.
CL-USER> (defun find&remove (list obj &key (key #'identity) (test #'eql))
(loop with last = nil
for cons on list
when (funcall test obj (funcall key (first cons))) do
(progn (setf (rest last) (rest cons))
(return (first cons)))
do (setf last cons)))
CL-USER> (defvar test-list (list (list 1 2 3)
(list 3 4 5)
(list 5 6 7)
(list 8 9 10)))
CL-USER> (find&remove test-list 5 :key #'third)
(3 4 5)
CL-USER> test-list
((1 2 3) (5 6 7) (8 9 10))
CL-USER> (find&remove test-list 7 :key #'third)
(5 6 7)
CL-USER> test-list
((1 2 3) (8 9 10))
The key is to traverse the list by cons cell rather than by item (loop for ... on rather than loop for ... in) and keep a pointer to the parts of the list we've already looked at (last). Then, when we find what we're looking for, we connect the cdr of what we'd already seen to the next cons (so now the list omits the "hit") and finally return the result.
The length of
(length (car '('(0)'(1 2 3)'(6 7))))
is being show 2 while the same
(length (car '((0)(1 2 3)(6 7))))
is correctly shown 1. so what does the the first expression actually represent?
The quote character ' is a reader macro. 'anything expands into (quote anything). So the first expression is shorthand for:
(length (car (quote ((quote (0))
(quote (1 2 3))
(quote (6 7)))
The first quote causes the parameter to be treated literally. That means that the quote expressions inside it are just lists that happen to begin with the symbol quote.
So the CAR of that list is the sub-list (quote (0)). It contains 2 elements: the symbol quote and the list (0).
CL-USER 8 > '((0)(1 2 3)(6 7))
((0)
(1 2 3)
(6 7))
CL-USER 9 > '('(0)'(1 2 3)'(6 7))
((QUOTE (0))
(QUOTE (1 2 3))
(QUOTE (6 7)))
Let's say I have the following macro in R5RS Scheme:
(define-syntax pair-test
(syntax-rules ()
((_ (a b . c))
(quote (a b . c)))))
The macro transforms an input pair to an output pair, as one would expect:
(pair-test (1 2 . 3))
==> (1 2 . 3)
I can also pass a list to the macro, as allowed by the spec. However, the output is a list instead of a pair:
(pair-test (1 2 3))
==> (1 2 3)
What exactly is going on here? Why is the output a list instead of a pair?
Could c be (3 . ()) in the second case? I'm not positive but that would make sense to me. And then quoting (a b . c) would be (1 2 . (3 . ())) which is (1 2 . (3)) and (3) is a proper list, so (1 2 3)?
To see what's happening here, you need to know that a list in Scheme is a recursive chain of pairs of elements and other lists. Any data that follows the form of a list will always be printed as a list. Once you know how basic lists are constructed, you'll be able to see what's happening inside your macro.
Pairs in Scheme can be created using the . operator, or using the cons function. Here's a simple pair of numbers:
(quote (1 . 2))
==> '(1 . 2)
(cons 1 2)
==> '(1 . 2)
To create a list of 1 in Scheme, you can make a pair out of something and the empty list:
(quote (1 . ()))
==> '(1)
(cons 1 (list))
==> '(1)
A list of 2 is a pair of something of something on the left side, and a list of 1 on the right side. Likewise, a list of 3 is one element paired with a list of 2:
(quote (1 . (2 . (3 . ()))))
==> '(1 2 3)
(cons 1 (cons 2 (cons 3 (list))))
==> '(1 2 3)
To see what your macro is doing, you can rearrange the (quote (a b . c)) to be more explicit:
(quote (a . (b . c)))
(cons (quote a) (cons (quote b) (quote c)))
Now you can see that this form looks very similar to when you're constructing a list. If (quote c) results in a list, then the whole expression will be a list. In the case of (pair-test (1 2 3)), c becomes (3 . ()):
(quote (a . (b . c)))
==> (quote (1 . (2 . (3 . ()))))
==> '(1 2 3)
(cons (quote a) (cons (quote b) (quote c)))
==> (cons '1 (cons '2 '(3 . ())))
==> '(1 2 3)
This value is printed by the REPL as a list because it is a "proper list". Each right side (cdr) is a list, all the way up to the empty list at the end, so this value perfectly follows list form. The REPL assumes you'd like to see the result as a list, so it gets printed without a . present.
You'd see '(1 2 . 3) for (pair-test (1 2 . 3)), because this is how the REPL prints "improper lists". If the last element in the chain of pairs is not the empty list, the value is considered an "improper list", and will be printed differently:
(quote (1 . (2 . 3)))
==> '(1 2 . 3)
(cons 1 (cons 2 3))
==> '(1 2 . 3)