I'm having a tough time figuring out why my function buildList-aux does not return the correct contents of the list Z.
When I run debug mode, and pause on the if statement above return Z, I can see that the value in racket is correct and as expected, however the actual contents that gets returned and printed have some sort of error (overflow? or something) and prints (shared ((-1- (list 'abc))) (list -1- -1-)).
I'm running DrRacket 6.11, Advanced Student language.
(define buildList-aux
(lambda (E Z count)
(if (<= count 0)
Z
(if (not (list? E))
(buildList-aux E (append (list E) Z) (- count 1))
(buildList-aux E (cons E Z) (- count 1))))))
(define buildList
(lambda (N E)
(buildList-aux E '() N)))
(buildList 5 '())
(buildList 3 'A)
(buildList 2 '(abc))
(buildList 3 '(A))
Expected Output:
(list '() '() '() '() '())
(list 'A 'A 'A)
(list (list 'abc) (list 'abc))
(list (list 'A) (list 'A) (list 'A))
Actual Output:
(list '() '() '() '() '())
(list 'A 'A 'A)
(shared ((-1- (list 'abc))) (list -1- -1-))
(shared ((-1- (list 'A))) (list -1- -1- -1-))
Your code is correct, it's just the way a list gets displayed in "Advanced Student". To see the correct output, do as #JohnClements suggests and go to "Language Details", and uncheck "Show Sharing in Values" box. Alternatively, switch to "Detect language from source" and specify #lang racket at the top of the file. Either way, the output will be as expected:
'(() () () () ())
'(A A A)
'((abc) (abc))
'((A) (A) (A))
But let's take a look at that weird output:
(shared ((-1- (list 'abc))) (list -1- -1-))
The above is stating that the result is:
(list -1- -1-)
Think of the -1- as a "variable" representing shared data, with a value of (list 'abc). If we substitute the "variable" with its value we get the more familiar:
(list (list 'abc) (list 'abc))
Related
Here is my code about postfix in scheme:
(define (stackupdate e s)
(if (number? e)
(cons e s)
(cons (eval '(e (car s) (cadr s))) (cddr s))))
(define (postfixhelper lst s)
(if (null? lst)
(car s)
(postfixhelper (cdr lst) (stackupdate (car lst) s))))
(define (postfix list)
(postfixhelper list '()))
(postfix '(1 2 +))
But when I tried to run it, the compiler said it takes wrong. I tried to check it, but still can't find why it is wrong. Does anyone can help me? Thanks so much!
And this is what the compiler said:
e: unbound identifier;
also, no #%app syntax transformer is bound in: e
eval never has any information about variables that some how are defined in the same scope as it is used. Thus e and s does not exist. Usually eval is the wrong solution, but if you are to use eval try doing it as as little as you can:
;; Use eval to get the global procedure
;; from the host scheme
(define (symbol->proc sym)
(eval sym))
Now instead of (eval '(e (car s) (cadr s))) you do ((symbol->proc e) (car s) (cadr s)). Now you should try (postfix '(1 2 pair?))
I've made many interpreters and none of them used eval. Here is what I would have done most of the time:
;; Usually you know what operators are supported
;; so you can map their symbol with a procedure
(define (symbol->proc sym)
(case sym
[(+) +]
[(hyp) (lambda (k1 k2) (sqrt (+ (* k1 k1) (* k2 k2))))]
[else (error "No such operation" sym)]))
This fixes the (postfix '(1 2 pair?)) problem. A thing that I see in your code is that you always assume two arguments. But how would you do a double? eg something that just doubles the one argument. In this case symbol->proc could return more information:
(define (symbol->op sym)
(case sym
[(+) (cons + 2)]
[(double) (cons (lambda (v) (* v v)) 1)]
[else (error "No such operation" sym)]))
(define op-proc car)
(define op-arity cdr)
And in your code you could do this if it's not a number:
(let* ([op (symbol->op e)]
[proc (op-proc op)]
[arity (op-arity op)])
(cons (apply proc (take s arity)
(drop s arity)))
take and drop are not R5RS, but they are simple to create.
I want to be able to make my list go one step to the right. Here's my example code that makes it go one step to the left.
(define (rotate-L lst) (append (cdr lst) (list (car lst))))
(rotate-L '(a b c))
(b c a)
I'm having trouble understanding why when I make it backward, i get an error
(define (rotate-L lst) (append (car lst) (list (cdr lst))))
(rotate-L '(a b c))
SchemeError: argument 0 of append has wrong type (string)
Current Eval Stack:
0: (rotate-L (quote (a b c)))
(define rotr
(lambda (l)
(if (null? l)
l
((lambda (s) (s s l cons))
(lambda (s l c)
(if (null? (cdr l))
(c (car l) '())
(s s (cdr l)
(lambda (f r)
(c f (cons (car l) r))))))))))
(define rotl
(lambda (l0)
(if (null? l0)
l0
((lambda (s) (s s (cdr l0) (lambda (r) r)))
(lambda (s l c)
(if (null? l)
(c (list (car l0)))
(s s (cdr l)
(lambda (r)
(c (cons (car l) r))))))))))
Here is a test:
(rotr '())
(rotr '(a))
(rotr '(a b))
(rotr '(a b c))
(rotl '())
(rotl '(a))
(rotl '(a b))
(rotl '(a b c))
whose output is so:
1 ]=> (rotr '())
;Value: ()
1 ]=> (rotr '(a))
;Value: (a)
1 ]=> (rotr '(a b))
;Value: (b a)
1 ]=> (rotr '(a b c))
;Value: (c a b)
1 ]=> (rotl '())
;Value: ()
1 ]=> (rotl '(a))
;Value: (a)
1 ]=> (rotl '(a b))
;Value: (b a)
1 ]=> (rotl '(a b c))
;Value: (b c a)
It's worth remembering what lists look like as structures made of conses:
(1 2 3 4) looks like this, for instance
So pretty obviously (car '(1 2 3 4)) is a number, not a list, and so (append (car '(1 2 3 4)) ...) is not going to work, because append wants its arguments to be lists. But even if you fix this to be correct, you're not doing what you think:
(define (not-rotating lst)
(append (list (car lst)) (cdr lst)))
This simply takes the first element of the list, makes a single-element list from it, and appends the rest of the list to it. Well, you could write this more easily:
(define (not-rotating lst)
(cons (car lst) (cdr list)))
and it should be clear that this is doing nothing at all useful.
To rotate the list 'right' you need to:
find the last element of the list;
construct a list which is all of the original list except for that element;
and glue the last element onto the start of that list.
The only way to find the last element of the list is to walk along the list until you get to it. And you also need to make a copy of all the elements of the list but the last one, which also means walking down the list. It is natural to do these two operations at the same time:
walk down the list, building up a copy of it;
when you get to the last element, attach it to the start of the copy.
Here is a terrible way of doing this:
(define (rotate-r/terrible lst)
(let rrl ((tail lst)
(building '()))
(if (null? (cdr tail))
;; we've got to the end
(cons (car tail) building)
(rrl (cdr tail)
(append building (list (car tail)))))))
This is terrible because at each step it appends the current element to the end of the list it is building. That's terrible for not one but two reasons:
appending two lists takes time proportional to the length of the first list;
appending two lists requires a complete copy of the first list to be made.
That makes this both quadratic in the length of the list, which is terrible, and also very 'consy' – it allocates lots of ephemeral storage. But it does work.
So: there is, not surprisingly a better way of doing this: a way which is both linear and makes no more than two copies of the list. I'm not going to give it here, but it's surprisingly close to the above terrible solution. Two hints:
what is the natural way to accumulate elements into a list? is it at the start, or at the end of a list?
how do you turn the list you accumulated like that into the list you want?
I am trying to write by myself the cons function in scheme. I have written this code:
(define (car. z)
(z (lambda (p q) p)))
and I am trying to run :
(car. '(1 2 3))
I expect to get the number 1, but it does not work properly.
When you implement language data structures you need to supply constructors and accessors that conform to the contract:
(car (cons 1 2)) ; ==> 1
(cdr (cons 1 2)) ; ==> 2
(pair? (cons 1 2)) ; ==> 2
Here is an example:
(define (cons a d)
(vector a d))
(define (car p)
(vector-ref p 0))
(define (cdr p)
(vector-ref p 1))
Now if you make an implementation you would implement read to be conformant to this way of doing pairs so that '(1 2 3) would create the correct data structure the simple rules above is still the same.
From looking at car I imagine cons looks like this:
(define (cons a d)
(lambda (p) (p a d)))
It works with closures. Now A stack machine implementation of Scheme would analyze the code for free variables living passed their scope and thus create them as boxes. Closures containing a, and d aren't much different than vectors.
I urge you to implement a minimalistic Scheme interpreter. First in Scheme since you can use the host language, then a different than a lisp language. You can even do it in an esoteric language, but it is very time consuming.
Sylwester's answer is great. Here's another possible implementation of null, null?, cons, car, cdr -
(define null 'null)
(define (null? xs)
(eq? null xs))
(define (cons a b)
(define (dispatch message)
(match message
('car a)
('cdr b)
(_ (error 'cons "unsupported message" message))
dispatch)
(define (car xs)
(if (null? xs)
(error 'car "cannot call car on an empty pair")
(xs 'car)))
(define (cdr xs)
(if (null? xs)
(error 'cdr "cannot call cdr on an empty pair")
(xs 'cdr)))
It works like this -
(define xs (cons 'a (cons 'b (cons 'c null))))
(printf "~a -> ~a -> ~a\n"
(car xs)
(car (cdr xs))
(car (cdr (cdr xs))))
;; a -> b -> c
It raises errors in these scenarios -
(cdr null)
; car: cannot call car on an empty pair
(cdr null)
; cdr: cannot call cdr on an empty pair
((cons 'a 'b) 'foo)
;; cons: unsupported dispatch: foo
define/match adds a little sugar, if you like sweet things -
(define (cons a b)
(define/match (dispatch msg)
(('car) a)
(('cdr) b)
(('pair?) #t)
((_) (error 'cons "unsupported dispatch: ~a" msg)))
dispatch)
((cons 1 2) 'car) ;; 1
((cons 1 2) 'cdr) ;; 2
((cons 1 2) 'pair?) ;; #t
((cons 1 2) 'foo) ;; cons: unsupported dispatch: foo
I have found a recursive problem in one page that says the following:
If a person enter a string with two consecutive letters that are the same, it should put a 5 between them. For example if I enter "hello"
it should print "hel5lo"
I have done the following program in Scheme:
(define (function listT)
(if (empty? listT)
'()
(begin
(if (eq? (car listT) (car (cdr listT)))
(display 5)
(display (car listT))
)))
(function (cdr listT)))
and tested with:
(function'( 'h 'e 'l 'l 'o))
and the problem I got is
car: contract violation
expected: pair?
given: ()
I suppose that is because at one moment (car (cdr listT)) will face an empty list, have tried with a conditional before, but still with some issues.
Is it possible to do it only using recursion over the list of characters with cdr and car? I mean not with new variables, strings, using reverse or loops?
Any help?
Thanks
This happens when there is only one character left in the list; (cdr listT) will be the empty list '() and the car of the empty list is undefined.
So you either need to check that the cdr isn't empty, for example:
(define (f str)
(let loop ((lst (string->list str)) (res '()))
(if (null? lst)
(list->string (reverse res))
(let ((c (car lst)))
(loop (cdr lst)
(cons c
(if (and (not (null? res)) (char=? c (car res)))
(cons #\5 res)
res)))))))
or, instead of looking one character ahead, turn around your logic and keep track of the last character, which is initialised to some value that will be different in every case (not as elegant as the first solution though IMO):
(define (f str)
(list->string
(let loop ((prev #f) (lst (string->list str)))
(if (null? lst)
'()
(let ((c (car lst)))
(if (equal? c prev)
(cons #\5 (cons c (loop c (cdr lst))))
(cons c (loop c (cdr lst)))))))))
[EDIT alternatively, with an explicit inner procedure:
(define (f str)
(define (inner prev lst)
(if (null? lst)
'()
(let ((c (car lst)))
(if (equal? c prev)
(cons #\5 (cons c (inner c (cdr lst))))
(cons c (inner c (cdr lst)))))))
(list->string (inner #f (string->list str))))
]
Testing:
> (f "hello")
"hel5lo"
> (f "helo")
"helo"
> (f "heloo")
"helo5o"
Side note: don't double quote:
> '('h 'e 'l 'l 'o)
'('h 'e 'l 'l 'o)
> (car '('h 'e 'l 'l 'o))
''h
This is probably not what you expected. Instead:
> '(h e l l o)
'(h e l l o)
> (car '(h e l l o))
'h
or
> (list 'h 'e 'l 'l 'o)
'(h e l l o)
> (car (list 'h 'e 'l 'l 'o))
'h
Also note that these are symbols, whereas, since you start from a string, you want characters:
> (string->list "hello")
'(#\h #\e #\l #\l #\o)
EDIT 2
I see you are still struggling with my answer. Here's a solution that should be as minimal as you requested, I hope this is it:
(define (f lst (prev #f))
(unless (null? lst)
(when (equal? (car lst) prev) (display "5"))
(display (car lst))
(f (cdr lst) (car lst))))
or even
(define (f lst)
(unless (null? lst)
(display (car lst))
(when (and (not (null? (cdr lst))) (equal? (car lst) (cadr lst)))
(display "5"))
(f (cdr lst))))
Testing:
> (f '(h e l l o))
hel5lo
> (f '(h e l o))
helo
> (f '(h e l o o))
helo5o
I have found a solution:
(define (func lisT)
(if (empty? (cdr lisT))
(display (car lisT))
(begin
(if (eq? (car lisT) (car (cdr lisT)))
(begin
(display (car lisT))
(display 5)
)
(display (car lisT))
)
(func (cdr lisT))
)
))
Here's a solution including just one, top-level recursive function:
(define (insert list item)
(if (< (length list) 2) ;; not enough elements to compare?
list ;; then just return the input
(let ((first (car list)) ;; capture the first element,
(second (cadr list)) ;; the second element,
(rest (insert (cdr list) item))) ;; and the recursively processed tail
(cons first ;; construct a list with the first element
(if (eq? first second) ;; compare the first two and return either
(cons item rest) ;; the item before the rest
rest))))) ;; or just the rest
It takes as input a list and an item to be inserted between each two consecutive identical elements. It does not display anything, but rather returns another list with the result of the insertion. For example,
(insert '(1 2 2 3 3 3 2 2 1) 0)
results in
(1 2 0 2 3 0 3 0 3 2 0 2 1)
This hopefully solves your problem and seeds further experimentation.
Here is a straightforward function from a list to a list:
(define (add5s s)
(cond ((null? s) s)
((null? (cdr s)) s)
((equal? (car s) (cadr s)) (cons (car s) (cons 5 (add5s (cdr s)))))
(else (cons (car s) (add5s (cdr s))))
)
)
A list either:
is null
has one element
begins with two equal elements
begins with two unequal elements
A list with a 5 put between consecutive equal elements is respectively:
the list
the list
the first element followed by a 5 followed by the rest of it with a 5 put between consecutive equal elements
the first element followed by the rest of it with a 5 put between consecutive equal elements
A Scheme string is not a list of characters or a list of symbols. If you want to input and output strings then you should use the corresponding string operators. Or write a function that defines this one, calls it with string->list of an input string and outputs list->string of this one's result list. Or a function like this one but that branches on string->list of its input string and outputs list->string of what this one returns.
(It is really not clear what code is to be written. You say "enters a string", but your "tested" code is a function that takes a list as argument, rather than reading from a port. And you say "put a 5" but you print argument list elements or a 5 via display to a port, rather than returning a value of the type of the argument. And you give an example passing an argument that is a list of quoted symbols rather than just symbols let alone characters. (If you want to pass a list of symbols then use '(h e l l o) or (list 'h 'e 'l 'l 'o).) Say exactly what is to be produced, eg, a function with what arguments, return value and effect on ports.)
I have the following items
(define itemslist
(list 'a1 'b2 'c3 (list 'z1 'z2) 'd5 'e6))
My method to find items is below
(define find-item
(lambda (item itemslist)
(cond ((null? itemslist) #f)
((list? (car itemslist))
(cond ((null? itemslist) #f)
(else (find-item item (car itemslist)))))
((equal? stn (car itemslist)) (display "found"))
(else (find-stn stn (cdr itemslist)))
)
)
)
With my method above I can find a1, b2, c3, z1, z2. But when I want to find d5 onwards, it returns nothing. It seems to have skip the stack. Btw, I am just starting to learn Scheme so simple explanation would be better.
One more qns, how about if I have this
(list 'a1 'b2 'c3 (list 'z1 (list 'y1 'y2) 'z2) 'd5 'e6)
does this works as well? Thanks!
Yes, you skip lists.
Example:
'(1 '(2 3) 4)
If (list? '(2 3)) is true, the else part (outer cond) wont be evaluated so 4 is skipped.
So, either you place the else part inside list? block or you redesign your code.
If the itemlist is a list/pair you can pass it right away in a recursive call so
you can avoid writing code like (car itemslist) inside predicates thus make the code simple.
Here is a redesigned (simplified) version:
(define (find-item item l)
(cond ((equal? item l) #t)
((pair? l) (or (find-item item (car l)) (find-item item (cdr l))))
(else #f)))
Tip: you can also can write lists with '(...) notation instead of (list ...), ie
(find-item 'z2 '('a1 'b2 'c3 '('z1 '('y1 'y2) 'z2) 'd5 'e6))
#t
(find-item 'e6 '('a1 'b2 'c3 '('z1 '('y1 'y2) 'z2) 'd5 'e6))
#t
To write more for the sake of writing more... This is usually called a "tree-walk" because a nested list like that is really a binary tree. Lists are really made up of binary pairs, so when you have a pair (l . r), l is the left branch of the tree and r is the right branch of the tree.
For example, '(1 (2 3) 4) is short for '(1 . ((2 . (3 . ())) . (4 . ()))) which can be drawn as
.
/ \
1 .
/ \
/ .
/ / \
. 4 ()
/ \
2 .
/ \
3 ()
and at any pair (l . r), car gets you the left tree and cdr gets you the right. So, when you write (pair? ls), you're really asking if you're at a branch in the tree, at which point you should recur on both the left branch (car) and the right branch (cdr). Hope that helps you understand lists.
Even though you got your [specific] answer, here's something that might help you with similar questions.
(define describe
(lambda (e)
(cond #;((list? e)
`(list ,#(map describe e)))
((pair? e)
`(cons ,(describe (car e))
,(describe (cdr e))))
((vector? e)
`(vector ,#(map describe (vector->list e))))
((or (null? e) (symbol? e)) `',e)
(else e))))
This procedure prints the code that generates a given sexpr. For example:
> (describe '(a 2 b 3))
(cons 'a (cons 2 (cons 'b (cons 3 '()))))
It will also place the quotes where needed, so it places them before symbols or () but not before numbers. When you are comfortable with nested pairs, you may want to remove the #; on the third line, to generate more compact output:
> (describe '(a 2 b 3))
(list 'a 2 'b 3)
This code can teach you many things about quote. For example:
> (describe ''''a)
(list 'quote (list 'quote (list 'quote 'a)))