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? - racket

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))

Related

Introducing new symbols into Common-Lisp Function/Macro

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)

How can I write a MEMBER function using the DO macro in Common Lisp?

I am trying to make a function which works like MEMBER function in Common Lisp.
So, I want to make this function work like this :
(my-member 2 '(1 4 5 5 3 2 5 6 9))
=> (2 5 6 9)
This is exactly same as how MEMBER function works.;
(member 2 '(1 4 5 5 3 2 5 6 9))
=> (2 5 6 9)
The condition is that I should use 'DO' macro to make this function.
This is my code that I have written to make this function :
(defun my-member (item x)
"This function works like MEMBER function."
(do ((z x (rest z))
(e (first x) (first z)))
(:when (equal item (first z))
(return z))))
But it doesn't work..
(my-member 2 '(3 4 5 2 1 1))
-> (3 4 5 2 1 1)
What should I do to solve this problem?
Here is the correct way to use do:
(do ((var 0 (1+ var))
(lst '() (cons var lst)))
((= var 5) lst)))
; ==> (4 3 2 1 0)
So both var and lst are variables initialised to 0 and () and after each iteration the variable is set to (1+ var) and (cons var lst).
What determines when it should stop is (= var 5) becoming not nil and when that happens the result of the whole do form is lst. This is the second part of the do and the last this has since I do not supply a body.
You can make an equivalent of the member function with using only one variable and a second part with an end condition and what should be the result of the do. Good luck!

cons two elements outputs the wrong result

#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 . ()))))

Find and remove a list item based on the item's third element

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.

how to test whether one list is a member of another

Lets say I have two lists, ((1 2 3)) and (((1 2 3)) ((4 5))). I want to be able to tell if the first list is a member of the second list. I have tried to use subsetp, but it does not return true for this query. How can I accomplish this?
As Rainer Joswig mentioned in the comments, you're not checking for subsets, but for members, which you can do using the aptly named member function. Member returns a generalized boolean, i.e., nil for false, and something, not necessarily t, non-nil for true. Specifically, if an element is a member of the list, member returns the tail of the list whose first element is the element.
CL-USER> (member 3 '(1 2 3 4 5))
(3 4 5)
CL-USER> (member 7 '(1 2 3 4 5))
NIL
Of course, when checking membership in a list, there's a question of how to compare the given item with the elements of the list. Member's default comparison is eql, which works on things like numbers, as shown in the example above. For your case, however, you probably want to test with equal, since ((1 2 3)) might not be the same object as the first element of (((1 2 3)) ((4 5))):
CL-USER> (member '((1 2 3)) '(((1 2 3)) ((4 5))))
NIL
CL-USER> (member '((1 2 3)) '(((1 2 3)) ((4 5))) :test 'equal)
(((1 2 3)) ((4 5)))
CL-USER> (member '((4 5)) '(((1 2 3)) ((4 5))) :test 'equal)
(((4 5)))
CL-USER> (member '((1 2 4)) '(((1 2 3)) ((4 5))) :test 'equal)
NIL
If you want to have lists as elements of your sets for subsetp, you have to change the value of the :test keyword.
CL-USER 1 > (subsetp '(1 2 3) '(1 2 3 4 5))
T
CL-USER 2 > (subsetp '((1) (2) (3)) '((1) (2) (3) (4) (5)))
NIL
The first one gives T, the second one gives NIL. Why? Because equality is checked with #'eql which works for identical objects or numbers of the same value and of same type. Since two lists must not be identical objects, (eql '(1) '(1)) gives NIL. (That may depend on your CL implementation.) If you want to compare a tree of conses, tree-equal can help you.
CL-USER 3 > (subsetp '((1) (2) (3)) '((1) (2) (3) (4) (5)) :test #'tree-equal)
T
I don't understand the structure of the sets you gave as example completely, but I hope this helps.

Categories