How does the map function implemented in racket and why, recursion or iteration.
Maybe some implementation example
How to implement map
The map function walks a list (or multiple lists), and applies a given function to every value of a list. For example mappiing add1 to a list results in:
> (map add1 '(1 2 3 4))
'(2 3 4 5)
As such, you can implement map as a recursive function:
(define (map func lst)
(if (empty? lst)
'()
(cons (func (first lst)) (map func (rest lst)))))
Of course, map can accept any number of arguments, with each element passed to the given prop. For example, you can zip two lists together using map list:
> (map list '(1 2 3) '(a b c))
'((1 a) (2 b) (3 c))
To implement this variable arity map, we need to make use of the apply function:
(define (map proc lst . lst*)
(if (empty? lst)
'()
(cons (apply proc (first lst) (map first lst*))
(apply map proc (rest lst) (map rest lst*)))))
Now, this does assume all of the given lists have the same length, otherwise you will get some unexpected behavior. To do that right you would want to run empty? on all lists, not just the first one. But...when you use it, you get:
> (map list '(a b c) '(1 2 3))
'((a 1) (b 2) (c 3))
Note that map here calls itself recursively 3 times. A faster implementation might do some unrolling to run faster. A better implementation would also do proper error checking, which I have elided for this example.
How Racket's map is implemented
If you open up DrRacket (using the latest Racket 7 nightly) and make the following file:
#lang racket
map
You can now right click on map and select Open Defining File. From here, you can see that map is renamed from the definition map2. The definition of which is:
(define map2
(let ([map
(case-lambda
[(f l)
(if (or-unsafe (and (procedure? f)
(procedure-arity-includes? f 1)
(list? l)))
(let loop ([l l])
(cond
[(null? l) null]
[else
(let ([r (cdr l)]) ; so `l` is not necessarily retained during `f`
(cons (f (car l)) (loop r)))]))
(gen-map f (list l)))]
[(f l1 l2)
(if (or-unsafe
(and (procedure? f)
(procedure-arity-includes? f 2)
(list? l1)
(list? l2)
(= (length l1) (length l2))))
(let loop ([l1 l1] [l2 l2])
(cond
[(null? l1) null]
[else
(let ([r1 (cdr l1)]
[r2 (cdr l2)])
(cons (f (car l1) (car l2))
(loop r1 r2)))]))
(gen-map f (list l1 l2)))]
[(f l . args) (gen-map f (cons l args))])])
map))
Related
I'm trying to make a function that takes in two lists of atoms as a parameter and returns them as a list of pairs.
Example Input
(combine '(1 2 3 4 5) '(a b c d e))
Example Output
'((1 a) (2 b) (3 c) (4 d) (5 e))
However, I'm new to Racket and can't seem to figure out the specific syntax to do so. Here is the program that I have so far:
(define connect
(lambda (a b)
(cond [(> (length(list a)) (length(list b))) (error 'connect"first list too long")]
[(< (length(list a)) (length(list b))) (error 'connect"first list too short")]
[else (cons (cons (car a) (car b)) (connect(cdr a) (cdr b)))]
)))
When I run it, it gives me the error:
car: contract violation
expected: pair?
given: '()
Along with that, I don't believe the error checking here works either, because the program gives me the same error in the else statement when I use lists of different lengths.
Can someone please help? The syntax of cons doesn't make sense to me, and the documentation for Racket didn't help me solve this issue.
When you're new to Scheme, you have to learn to write code in the way recommended for the language. You'll learn this through books, tutorials, etc. In particular, most of the time you want to use built-in procedures; as mentioned in the comments this is how you'd solve the problem in "real life":
(define (zip a b)
(apply map list (list a b)))
Having said that, if you want to solve the problem by explicitly traversing the lists, there are a couple of things to have in mind when coding in Scheme:
We traverse lists using recursion. A recursive procedure needs at least one base case and one or more recursive cases.
A recursive step involves calling the procedure itself, something that's not happening in your solution.
If we needed them, we create new helper procedures.
We never use length to test if we have processed all the elements in the list.
We build new lists using cons, be sure to understand how it works, because we'll recursively call cons to build the output list in our solution.
The syntax of cons is very simple: (cons 'x 'y) just sticks together two things, for example the symbols 'x and 'y. By convention, a list is just a series of nested cons calls where the last element is the empty list. For example: (cons 'x (cons 'y '())) produces the two-element list '(x y)
Following the above recommendations, this is how to write the solution to the problem at hand:
(define (zip a b)
; do all the error checking here before calling the real procedure
(cond
[(> (length a) (length b)) (error 'zip "first list too long")]
[(< (length a) (length b)) (error 'zip "first list too short")]
[else (combine a b)])) ; both lists have the same length
(define (combine a b)
(cond
; base case: we've reached the end of the lists
[(null? a) '()]
; recursive case
[else (cons (list (car a) (car b)) ; zip together one element from each list
(combine (cdr a) (cdr b)))])) ; advance the recursion
It works as expected:
(zip '(1 2 3 4 5) '(a b c d e))
=> '((1 a) (2 b) (3 c) (4 d) (5 e))
The reason your error handling doesn't work is because you are converting your lists to a list with a single element. (list '(1 2 3 4 5)) gives '((1 2 3 4 5)) which length is 1. You need to remove the list.
This post is a good explanation of cons. You can use cons to build a list recursively in your case.
(define connect
(lambda (a b)
(cond [(> (length a) (length b)) (error 'zip "first list too long")]
[(< (length a) (length b)) (error 'zip "first list too short")]
[(empty? a) '()]
[else (cons (list (car a) (car b)) (connect (cdr a) (cdr b)))]
)))
However, I would prefer Sylwester's solution
(define (unzip . lists) (apply map list lists))
which uses Racket's useful apply function.
#lang racket
(define (combine lst1 lst2)
(map list lst1 lst2))
;;; TEST
(combine '() '())
(combine (range 10) (range 10))
(combine (range 9) (range 10))
map have buildin check mechanism. We don't need to write check again.
#lang racket
(define (combine lst1 lst2)
(local [(define L1 (length lst1))
(define L2 (length lst2))]
(cond
[(> L1 L2)
(error 'combine "first list too long")]
[(< L1 L2)
(error 'combine "second list too long")]
[else (map list lst1 lst2)])))
This is trivial implement of course, but I feel there is certainly something built in to Racket that does this. Am I correct in that intuition, and if so, what is the function?
Strangely, there isn't a built-in procedure in Racket for finding the 0-based index of an element in a list (the opposite procedure does exist, it's called list-ref). However, it's not hard to implement efficiently:
(define (index-of lst ele)
(let loop ((lst lst)
(idx 0))
(cond ((empty? lst) #f)
((equal? (first lst) ele) idx)
(else (loop (rest lst) (add1 idx))))))
But there is a similar procedure in srfi/1, it's called list-index and you can get the desired effect by passing the right parameters:
(require srfi/1)
(list-index (curry equal? 3) '(1 2 3 4 5))
=> 2
(list-index (curry equal? 6) '(1 2 3 4 5))
=> #f
UPDATE
As of Racket 6.7, index-of is now part of the standard library. Enjoy!
Here's a very simple implementation:
(define (index-of l x)
(for/or ([y l] [i (in-naturals)] #:when (equal? x y)) i))
And yes, something like this should be added to the standard library, but it's just a little tricky to do so nobody got there yet.
Note, however, that it's a feature that is very rarely useful -- since lists are usually taken as a sequence that is deconstructed using only the first/rest idiom rather than directly accessing elements. More than that, if you have a use for it and you're a newbie, then my first guess will be that you're misusing lists. Given that, the addition of such a function is likely to trip such newbies by making it more accessible. (But it will still be added, eventually.)
One can also use a built-in function 'member' which gives a sublist starting with the required item or #f if item does not exist in the list. Following compares the lengths of original list and the sublist returned by member:
(define (indexof n l)
(define sl (member n l))
(if sl
(- (length l)
(length sl))
#f))
For many situations, one may want indexes of all occurrences of item in the list. One can get a list of all indexes as follows:
(define (indexes_of1 x l)
(let loop ((l l)
(ol '())
(idx 0))
(cond
[(empty? l) (reverse ol)]
[(equal? (first l) x)
(loop (rest l)
(cons idx ol)
(add1 idx))]
[else
(loop (rest l)
ol
(add1 idx))])))
For/list can also be used for this:
(define (indexes_of2 x l)
(for/list ((i l)
(n (in-naturals))
#:when (equal? i x))
n))
Testing:
(indexes_of1 'a '(a b c a d e a f g))
(indexes_of2 'a '(a b c a d e a f g))
Output:
'(0 3 6)
'(0 3 6)
I would like to write a function that reverses the elements of a list, but it should happen in place (that is, don't create a new reversed list).
Something like:
>> (setq l ' (a b c d))
((a b c d)
>> (rev l)
(d c b a)
>> l
(d c b a)
What flags should I follow to achieve this?
Have a look at nreverse which will modify the list in place (see HyperSpec).
As per the comments, do note the comments that #Barmar made and this bit from the spec:
For nreverse, sequence might be destroyed and re-used to produce the result. The result might or might not be identical to sequence. Specifically, when sequence is a list, nreverse is permitted to setf any part, car or cdr, of any cons that is part of the list structure of sequence.
It's not difficult to implement this (ignoring fault cases). The keys are to use (setf cdr) to reuse a given cons cell and not to lose the reference to the prior cdr.
(defun nreverse2 (list)
(recurse reving ((list list) (rslt '()))
(if (not (consp list))
rslt
(let ((rest (cdr list)))
(setf (cdr list) rslt)
(reving rest list)))))
(defmacro recurse (name args &rest body)
`(labels ((,name ,(mapcar #'car args) ,#body))
(,name ,#(mapcar #'cadr args))))
[edit] As mentioned in a comment, to do this truly in-place (and w/o regard to consing):
(defun reverse-in-place (l)
(let ((result l))
(recurse reving ((l l) (r (reverse l))
(cond ((not (consp l)) result)
(else (setf (car l) (car r))
(reving (cdr l) (cdr r)))))))
> (defvar l '(1 2 3))
> (reverse-in-place l))
(3 2 1)
> l
(3 2 1)
Please, help me with one simple exercise on the Scheme.
Write function, that return count of atoms on the each level in the
list. For example:
(a (b (c (d e (f) k 1 5) e))) –> ((1 1) (2 1) (3 2) (4 5) (5 1))
My Solution:
(define (atom? x)
(and (not (pair? x)) (not (null? x))))
(define (count L)
(cond ((null? L) 0)
((pair? (car L))
(count (cdr L)))
(else
(+ 1 (count (cdr L))))))
(define (fun L level)
(cons
(list level (count L))
(ololo L level)))
(define (ololo L level)
(if (null? L)
'()
(if (atom? (car L))
(ololo (cdr L) level)
(fun (car L) (+ level 1)))))
(fun '(a (b (c (d e (f) k 1 5) e))) 1)
It's work fine, but give not correctly answer for this list:
(a (b (c (d e (f) (k) 1 5) e)))
is:
((1 1) (2 1) (3 2) (4 4) (5 1))
But we assume that 'f' and 'k' on the one level, and answer must be:
((1 1) (2 1) (3 2) (4 4) (5 2))
How should I edit the code to make it work right?
UPD (29.10.12):
My final solution:
(define A '(a (b (c (d e (f) k 1 5) e))))
(define (atom? x)
(and (not (pair? x)) (not (null? x))))
(define (unite L res)
(if (null? L) (reverse res)
(unite (cdr L) (cons (car L) res))))
(define (count-atoms L answ)
(cond ((null? L) answ)
((pair? (car L))
(count-atoms (cdr L) answ))
(else
(count-atoms (cdr L) (+ answ 1)))))
(define (del-atoms L answ)
(cond ((null? L) answ)
((list? (car L))
(begin
(del-atoms (cdr L) (unite (car L) answ))))
(else
(del-atoms (cdr L) answ))))
(define (count L)
(define (countme L level answ)
(if (null? L) (reverse answ)
(countme (del-atoms L '()) (+ level 1) (cons (cons level (cons (count-atoms L 0) '())) answ))))
(countme L 1 '()))
(count A)
What can you say about this?
Do you know what you get if you run this?
(fun '(a (b (c (d e (f) k 1 5) e)) (a (b (c)))) 1)
You get this:
((1 1) (2 1) (3 2) (4 5) (5 1))
The whole extra nested structure that I added on the right has been ignored. Here is why...
Each recursion of your function does two things:
Count all the atoms at the current "level"
Move down the level till you find an s-expression that is a pair (well, not an atom)
Once it finds a nested pair, it calls itself on that. And so on
What happens in oLoLo when fun returns from the first nested pair? Why, it returns! It does not keep going down the list to find another.
Your function will never find more than the first list at any level. And if it did, what would you to do add the count from the first list at that level to the second? You need to think carefully about how you recur completely through a list containing multiple nested lists and about how you could preserve information at each level. There's more than one way to do it, but you haven't hit on any of them yet.
Note that depending on your implementation, the library used here may need to be imported in some other way. It might be painstakingly difficult to find the way it has to be imported and what are the exact names of the functions you want to use. Some would have it as filter and reduce-left instead. require-extension may or may not be Guile-specific, I don't really know.
(require-extension (srfi 1))
(define (count-atoms source-list)
(define (%atom? x) (not (or (pair? x) (null? x))))
(define (%count-atoms source-list level)
(if (not (null? source-list))
(cons (list level (count %atom? source-list))
(%count-atoms (reduce append '()
(filter-map
(lambda (x) (if (%atom? x) '() x))
source-list)) (1+ level))) '()))
(%count-atoms source-list 1))
And, of course, as I mentioned before, it would be best to do this with hash-tables. Doing it with lists may have some didactic effect. But I have a very strong opposition to didactic effects that make you write essentially bad code.
I'm writing a function that takes a list and returns a list of permutations of the argument.
I know how to do it by using a function that removes an element and then recursively use that function to generate all permutations. I now have a problem where I want to use the following function:
(define (insert-everywhere item lst)
(define (helper item L1 L2)
(if (null? L2) (cons (append L1 (cons item '())) '())
(cons (append L1 (cons item L2))
(helper item (append L1 (cons (car L2) '())) (cdr L2)))))
(helper item '() lst))
This function will insert the item into every possible location of the list, like the following:
(insert-everywhere 1 '(a b))
will get:
'((1 a b) (a 1 b) (a b 1))
How would I use this function to get all permutations of a list?
I now have:
(define (permutations lst)
(if (null? lst)
'()
(insert-helper (car lst) (permutations (cdr lst)))))
(define (insert-helper item lst)
(cond ((null? lst) '())
(else (append (insert-everywhere item (car lst))
(insert-helper item (cdr lst))))))
but doing (permutations '(1 2 3)) just returns the empty list '().
First, construct a family of related examples:
(permutations '()) = ???
(permutations '(z)) = ???
(permutations '(y z)) = ???
(permutations '(x y z)) = ???
Figure out how each answer is related to the one before it. That is, how can you calculate each answer given the previous answer (for the tail of the list) and the new element at the head of the list?
Here is a function, that generates all permutations of numbers with size 'size' , that it consisted of the elements in the list 'items'
(define (generate-permutations items size)
(if (zero? size)
'(())
(for/list ([tail (in-list (generate-permutations items (- size 1)))]
#:when #t
[i (in-list items)]
#:unless (member i tail))
(cons i tail))))