According to the book, this is what the function definition is,
The function scramble takes a non-empty tuple in which no argument is greater than its own index and returns a tuple of same length. Each number in the argument is treated as a backward index from its own position to a point earlier in tuple. The result at each position is obtained by counting backward from the current position according to this index.
And these are some examples,
; Examples of scramble
(scramble '(1 1 1 3 4 2 1 1 9 2)) ; '(1 1 1 1 1 4 1 1 1 9)
(scramble '(1 2 3 4 5 6 7 8 9)) ; '(1 1 1 1 1 1 1 1 1)
(scramble '(1 2 3 1 2 3 4 1 8 2 10)) ; '(1 1 1 1 1 1 1 1 2 8 2)
Here is the implementation,
(define pick
(λ (i lat)
(cond
((eq? i 1) (car lat))
(else (pick (sub1 i)
(cdr lat))))))
(define scramble-b
(lambda (tup rev-pre)
(cond
((null? tup) '())
(else
(cons (pick (car tup) (cons (car tup) rev-pre))
(scramble-b (cdr tup)
(cons (car tup) rev-pre)))))))
(define scramble
(lambda (tup)
(scramble-b tup '())))
This is a case where using a very minimal version of the language means that the code is verbose enough that understanding the algorithm is not perhaps easy.
One way of dealing with this problem is to write the program in a much richer language, and then work out how the algorithm, which is now obvious, is implemented in the minimal version. Let's pick Racket as the rich language.
Racket has a function (as does Scheme) called list-ref: (list-ref l i) returns the ith element of l, zero-based.
It also has a nice notion of 'sequences' which are pretty much 'things you can iterate over' and a bunch of constructs whose names begin with for for iterating over sequences. There are two functions which make sequences we care about:
in-naturals makes an infinite sequence of the natural numbers, which by default starts from 0, but (in-naturals n) starts from n.
in-list makes a sequence from a list (a list is already a sequence in fact, but in-list makes things clearer and there are rumours also faster).
And the iteration construct we care about is for/list which iterates over some sequences and collects the result from its body into a list.
Given these, then the algorithm is almost trivial: we want to iterate along the list, keeping track of the current index and then do the appropriate subtraction to pick a value further back along the list. The only non-trivial bit is dealing with zero- vs one-based indexing.
(define (scramble l)
(for/list ([index (in-naturals)]
[element (in-list l)])
(list-ref l (+ (- index element) 1))))
And in fact if we cause in-naturals to count from 1 we can avoid the awkward adding-1:
(define (scramble l)
(for/list ([index (in-naturals 1)]
(element (in-list l)))
(list-ref l (- index element))))
Now looking at this code, even if you don't know Racket, the algorithm is very clear, and you can check it gives the answers in the book:
> (scramble '(1 1 1 3 4 2 1 1 9 2))
'(1 1 1 1 1 4 1 1 1 9)
Now it remains to work out how the code in the book implements the same algorithm. That's fiddly, but once you know what the algorithm is it should be straightforward.
If the verbal description looks vague and hard to follow, we can try following the code itself, turning it into a more visual pseudocode as we go:
pick i [x, ...ys] =
case i {
1 --> x ;
pick (i-1) ys }
==>
pick i xs = nth1 i xs
(* 1 <= i <= |xs| *)
scramble xs =
scramble2 xs []
scramble2 xs revPre =
case xs {
[] --> [] ;
[x, ...ys] -->
[ pick x [x, ...revPre],
...scramble2 ys
[x, ...revPre]] }
Thus,
scramble [x,y,z,w, ...]
=
[ nth1 x [x] (*x=1..1*)
, nth1 y [y,x] (*y=1..2*)
, nth1 z [z,y,x] (*z=1..3*)
, nth1 w [w,z,y,x] (*w=1..4*)
, ... ]
Thus each element in the input list is used as an index into the reversed prefix of that list, up to and including that element. In other words, an index into the prefix while counting backwards, i.e. from the element to the left, i.e. towards the list's start.
So we have now visualized what the code is doing, and have also discovered requirements for its input list's elements.
Related
A classic enumeration using unfold:
(unfold-left (lambda (x)
(if (> x 10)
(#;no values)
(+ x 1)))
#;from 0)
===> (0 1 2 3 4 5 6 7 8 9 10))
if limiting the scope is not needed is there any way to just write x without the lambda?
unfold is implemented like this:
(define (unfold p f g seed (tail-gen (λ (_) '())))
(let recur ((seed seed))
(if (p seed)
(tail-gen seed)
(cons (f seed)
(recur (g seed))))))
As you can see p, f, g, and tail-gen are all procedures since they get surrounded by parentheses in the implementation. If they are not procedures you will get an application: not a procedure error.
You are using unfold wrong. you need a procedure that takes the current value and return wether or not you are finished. Second is a procedure that takes the seed and return what value to collect and the third is a procedure to create the next seed. The optional tail-gen takes the seed and creates the tail where the empty list will be used if not provided. Here is how you make a list from 0 to 10:
#lang racket
(require srfi/1)
(require srfi/26)
(unfold (cut > <> 10) identity add1 0)
; ==> (0 1 2 3 4 5 6 7 8 9 10)
And of course, (range 11) gives the same answer.
I could manage following code to replaces items in a list using 2 other lists. Orilist and newlist have original and new terms in order. The replacement is done using orilist and newlist- if orilist items are present in slist, slist is changed to have corresponding new items from newlist:
(define (list-replace-from-lists slist orilist newlist)
(define replaced #f)
(define outl '())
(for ((item slist))
(set! replaced #f)
(for ((ori_ orilist) (i (in-naturals)) #:when (equal? item ori_))
(set! outl (cons (list-ref newlist i) outl))
(set! replaced #t))
(when (not replaced)
(set! outl (cons item outl))))
(reverse outl))
To replace 2 and 5 to 12 and 15, respectively, in (list 1 2 3 4 5 6) :
(list-replace-from-lists (list 1 2 3 4 5 6) (list 2 5) (list 12 15))
Output is:
'(1 12 3 4 15 6)
However, above code does not look functional and has many set! statements. How can this be converted to functional code? Should I use structures or some other data-types for above purpose?
Edit: items may recur in original list, e.g. (list 1 2 3 4 5 2 6)
You can still use lists and keep everything functional. :-) Here's my solution:
(define (replace-all haystack needles new-needles)
(define replace-alist (map cons needles new-needles))
(define (replace-one item)
(cond ((assoc item replace-alist) => cdr)
(else item)))
(map replace-one haystack))
Explanation of the code:
First, we build a replacement association list (alist). This is a list of pairs, of which the keys correspond to the needles and the values correspond to new-needles.
Then we define a replace-one function that takes an item, and sees if it matches any of the keys in the alist. If so, we return the corresponding value; otherwise, we return the original item.
Finally, we map the haystack through replace-one. Yay higher-order functions!
Note that this code is O(m*n) where m is the size of haystack and n is the size of needles, which is the same runtime as your version. If needles is large, you will want to use a hashtable instead of an alist, which will amortise the runtime of the function to O(m).
This is a functional solution that uses hash to keep the associations. That makes this solution O(haystack-length log needle-length) since immutable hashes are implemented with trees.
(define (list-replace-all haystack needles new-values)
;; make a dictionary of elements to be replaced
(define hash
(foldl (λ (needle new-value hash)
(hash-set hash needle new-value))
#hash()
needles
new-values))
;; do the replace. If not in hash the actual key is default
(map (λ (e) (hash-ref hash e e)) haystack))
(list-replace-all '(1 2 3 4 5 6) '(2 5) '(12 15))
; ==> (1 12 3 4 15 6)
write a scheme function workit that takes a predicate and a list of integers as arguments. the function should multiply each item in the list that satisfies the predicate by 2 and adds the results. For example::
(workit even? '(1 2 3 4 5 6)) ==> 4+8+12=24
(workit odd? '(1 2 3 4 5 6)) ==> 2+6+10=18
You may not use map, remove, filter, or any other higher order function.
Could someone at least help me get a head start on this? Decided to learn Scheme for a job that I am interested in applying for.... Any help would be great! Thanks
First define even?
(define (even? x) (= 0 (modulo x 2)))
You can define odd? in terms of not even
(define (odd? x) (not (even? x)))
Your workit function is pretty self-explanatory
(define (workit predicate xs)
(define (iter sum xs)
(cond ((empty? xs) sum)
((predicate (first xs)) (iter (+ sum (* 2 (first xs))) (rest xs)))
(else (iter sum (rest xs)))))
(iter 0 xs))
I defined an inner iter function to step through the list of provided numbers, xs, while keeping track of the output, sum.
If the list we're iterating through is empty?, we're done, so return the sum
Else, if (predicate x) is true, add (* 2 x) to the sum and continue iteration
Otherwise, the predicate is false, do not alter the sum for this iteration
I chose to use the auxiliary iter function in order to achieve proper tail recursion. This allows workit to operate in constant space.
Outputs
(print (workit even? '(1 2 3 4 5 6))) ;; => 24
(print (workit odd? '(1 2 3 4 5 6))) ;; => 18
If there are no elements in the list, the workit of the list is some base
value.
If the first element satisfies some condition, then the workit of the list is the result of some operation involving that first element, and the workit of the remainder of the list.
If the first element does not satisfy the condition, then the workit of the list is simply the workit of the remainder of the list.
Note that each time workit is called recursively (as in the second and third cases) the list is the remainder of the list in the the previous call.
If I have the following list:
(define thelist '(0 1 0 0 7 7 7))
How can I write a function that returns a new list in which the value in the requested cell is replaced.
Example:
(set-cell thelist 2 4)
This would return a new list with the same values, but in cell (2) there will be the value 4 instead of 1:
(0 4 0 0 7 7 7)
HtDP provides a really concrete methodology for solving this kind of problem. For this problem, your job is going to be to write down the template for lists, then to stare at it until you can see what the arguments to the recursive call should be, and what the results will be. I'm hoping that you've solved a bunch of warm-up problems on lists--compute the length of a list, count the number of 6's in the list, etc.
Although you can implement the requested functionality with lists, the natural way to solve that problem is to use a vector, and remember that in Scheme indexes start in 0 (that's why the second argument for vector-set! is a 1 and not a 2):
(define thevector (vector 0 1 0 0 7 7 7))
; thevector is #(0 1 0 0 7 7 7)
(vector-set! thevector 1 4)
; thevector is #(0 4 0 0 7 7 7)
Now, if you definitely need to use a list, something like this would work:
(define (set-cell lst idx val)
(cond ((null? lst) '())
((zero? idx) (cons val (cdr lst)))
(else (cons (car lst)
(set-cell (cdr lst) (sub1 idx) val)))))
And you'd call it like this:
(define thelist '(0 1 0 0 7 7 7))
(set-cell thelist 1 4)
> (0 4 0 0 7 7 7)
Again, I'm using 0-based indexing, as is the convention. Also notice that thelist was not modified, instead, set-cell returns a new list with the modification.
Other people have mentioned the 0-based indexes convention. I'll assume 0-based indexes, then.
The other answers you've gotten are wrong, given how you stated your problem. I'll cite the key point in your question (my emphasis):
This would return a new list with the same values, but in cell (2) there will be the value 4 instead of 1.
The answers you've been given are modifying a list in place, not returning a newly constructed list while leaving the original intact!
Here's a correct (though suboptimal) solution:
(define (set-list index new-value list)
(if (= index 0)
(cons new-value (cdr list))
(cons (car list)
(set-list (- index 1) new-value (cdr list))))))
I didn't bother to put in error checking here (e.g., if somebody passes in the empty list, or a list with too few elements relative to index, or a negative index).
Here is an approach using an auxiliary function that starts the count from 0. On each recursion, the count is incremented, and the list is shortened.
If the desired index is hit, the recursion can stop. If it gets to the end of the list without hitting the index, the original list is returned.
(define (set-cell ls ind val)
(define (aux c ls)
(cond ((null? ls) ls)
((= c ind) (cons val (cdr ls)))
(else (cons (car ls) (aux (+ c 1) (cdr ls))))))
(aux 0 ls))
What a mess above!! Keep it simple: Scheme has list-set! for this.
Example:
(define ls (list 1 2 3 4 5))
(list-set! ls 0 "new")
(list-set! ls 3 "changed")
(list-ref ls 0)
=> "new"
ls
=> '("new" 2 3 "changed" 5)
However, you might want to limit assignments on lists. Vectors are faster for this since you don't need to traverse the previous elements. Use lists whenever you can't specify the length before construction or when the length is continously changed.
I want to take an interval of a vector in Scheme. I know there is a procedure named vector->values, but seems like it returns each element separately, while I want to get the result as a vector. How can I achieve this?
> (vector->values (vector 1 2 3 4 5) 0 3)
1
2
3
while I need:
#(1 2 3)
If you're using PLT, you have a few easy ways to get this:
(define (subvector v start end)
(list->vector (for/list ([i (in-vector v start end)]) i)))
(define (subvector v start end)
(build-vector (- end start) (lambda (i) (vector-ref v (+ i start)))))
(define (subvector v start end)
(define new (make-vector (- end start)))
(vector-copy! new 0 v start end)
new)
The last one is probably going to be the fastest. The reason that there is no such operation that is built-in is that people usually don't do that. When you're dealing with vectors in Scheme, you're usually doing so because you want to optimize something so returning a vector and a range instead of allocating a new one is more common.
(And if you think that this is useful, please suggest it on the PLT mailing list.)
The Scheme R6RS standard has make-vector, vector-ref, vector-set! and vector-length. With that you can write your own function subvector, which does not seem to be part of R6RS (!). Some Scheme implementation have something like subvector already.
You can also switch to Common Lisp, which provides the function SUBSEQ in the standard.
Here is a portable R6RS version using SRFI 43:
#!r6rs
(import (rnrs base)
(prefix (srfi :43) srfi/43:))
(srfi/43:vector-copy (vector 1 2 3 4 5) 0 3)
#lang scheme
(define (my-vector-value v l h c)
(if (and (>= c l) (< c h))
(cons (first v) (my-vector-value (rest v) l h (add1 c)))
empty))
(list->vector (my-vector-value (vector->list (vector 1 2 3 4 5)) 0 3 0))
Ghetto? Yes, very. But it only took two minutes to write and gets the job done.
(I find it's generally easier to play with lists in Scheme)
you want subvector:
(subvector (vector 1 2 3 4 5) 0 3)