I am writing a Scheme function that detects if a word is in a list of words. My code uses an if statement and memq to return either #t or #f. However, something is causing the first parameter to return the error that the object is not applicable.
(define in?
(lambda (y xs)
((if (memq( y xs )) #t #f))))
Parentheses matter:
(define in?
(lambda (y xs)
(if (memq y xs) #t #f)))
so
you have double parentheses before if
you put memq parameters between parentheses
BTW, you can also express this as
(define in?
(lambda (y xs)
(and (memq y xs) #t)))
Related
Can someone explain me what's happening with the two lambda statements in the following code?
(define (remove x ls)
(if (null? ls)
'()
(let ((h (car ls)))
((if (eqv? x h)
(lambda (y) y)
(lambda (y) (cons h y)))
(remove x (cdr ls))))))
What is the 'y' in the above code?
Depending on the if's condition, we're returning one or the other lambda and then immediately applying it (notice the double opening parentheses to the left of the if). The first lambda returns the result of calling the recursion, the second lambda conses an element to the result of calling the recursion, either way the recursion gets called. The y is just the parameter name for the lambdas, which gets bound to the value of (remove x (cdr ls)). The whole thing is equivalent to this, and in fact it should be written like this, not in its current, overly complicated form:
(define (remove x ls)
(if (null? ls)
'()
(let ((h (car ls)))
(if (eqv? x h) ; using `equal?` would be a better idea
(remove x (cdr ls))
(cons h (remove x (cdr ls)))))))
could someone help me with clarification to one of the possible solution to exercise 3.19. the procedure mystery is infinite loop in case list cycle is given as argument. nevertheless when we use procedure eq? to check if list contains the cycle, it works and provides true value.
(define (last-pair x)
(if (null? (cdr x))
x
(last-pair (cdr x))
)
)
(define (make-cycle x)
(set-cdr! (last-pair x) x)
)
(define (mystery x)
(define (loop x y)
(if (null? x)
y
(let ((temp (cdr x)))
(set-cdr! x y)
(loop temp x)
)
)
)
(loop x '())
)
(define t (list 1 2 3))
(define w (make-cycle t))
(eq? (mystery t) t)
it looks like magic. I would appreciate for any help.
mystery reverses an array "in-place" by repeatedly snipping off the cdr of each entry and replacing that with the cdr of the previous x.
If this list has no loop, then it will end up reversed by the time you get back to the original '(). If there is a loop, you'll have the original array's pointer.
This is definitely a tricky to understand issue. If you make a box-and-pointer diagram it will definitely help and you'll only need to draw 3 diagrams.
Automatically Generating Diagrams of Lists
In the process of doing SICP myself, I found myself wanting a way to visualize list mutation (and to skip the numerous "draw a list diagram of..." exercises). I wrote a small function for doing so and I thought you might find it helpful if I shared it.
These diagrams are an example of this function being run on x each time loop (within the mystery function) is ran.
The following code is what I used for generating these diagrams. I wrote this code as a Scheme novice, but it's very simple to use: the function (list->graphviz) accepts a parameter lst which is the list you'd like a diagram of, as well as an optional argument graph-name which gives the graph a special name.
(define* (list->graphviz lst #:optional graph-name)
"""Convert a list into a set of Graphviz instructions
`lst' is the list you'd like a diagram of
`graph-name` is an optional parameter indicating the name you'd like to give the graph."""
(define number 0)
(define result "")
(define ordinals '())
(define (result-append! str)
(set! result (string-append result str)))
(define* (nodename n #:optional cell)
(format #f "cons~a~a" n (if cell (string-append ":" cell) "")))
(define* (build-connector from to #:optional from-cell)
(format #f "\t~a -> ~a;~%" (nodename from from-cell) (nodename to)))
(define (build-shape elt)
(define (build-label cell)
(cond ((null? cell) "/");; "∅") ; null character
((pair? cell) "*");; "•") ; bullet dot character
(else (format #f "~a" cell))))
(set! number (+ number 1))
(format #f "\t~a [shape=record,label=\"<car> ~a | <cdr> ~a\"];~%"
(nodename number)
(build-label (car elt))
(build-label (cdr elt))))
(define* (search xs #:optional from-id from-cell)
(let ((existing (assq xs ordinals)))
(cond
;; if we're not dealing with a pair, don't bother making a shape
((not (pair? xs)) (result-append! "\tnothing [shape=polygon, label=\"not a pair\"]\n"))
((pair? existing)
(result-append! (build-connector from-id (cdr existing) from-cell)))
(else
(begin
(result-append! (build-shape xs))
(set! ordinals (assq-set! ordinals xs number))
(let ((parent-id number))
;; make a X->Y connector
(if (number? from-id)
(result-append! (build-connector from-id parent-id from-cell)))
;; recurse
(if (pair? (car xs)) (search (car xs) parent-id "car"))
(if (pair? (cdr xs)) (search (cdr xs) parent-id "cdr"))))))))
(search lst)
(string-append "digraph " graph-name " {\n" result "}\n"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;; Here is where `mystery' begins ;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define t '(1 2 3))
(set-cdr! (cddr t) t)
(define (mystery x)
(define (loop x y graph-num)
(display (list->graphviz x (format #f "graph~a" graph-num)))
(if (null? x)
y
(let ((temp (cdr x)))
(set-cdr! x y)
(loop temp x (+ 1 graph-num)))))
(loop x '() 0))
(mystery t)
The code above code generates Graphviz graph description statements, which must then be processed by dot (Graphviz) to be rendered to a graphical format.
For example, you can run the code above and pipe it into dot:
$ scheme generate_box_ptr.scm | dot -o ptrs.ps -Tps
This command generates a postscript file which has the advantage of separating each list into it's own page if you've run list->graphviz more than once. dot can also output PNGs, PDFs and many other file formats as the manpage describes.
I have created a function that can determine if a character is in a list. While it works fine by itself, it does not work properly when called by another function which is suppose to compare the elements of a list to several key words. I have also tried using the functions memq, memv, and member, but they fail as well. I would like to know what it is that is causing my program to not return #t and where I went wrong.
(define in?
(lambda (y xs)
(if (memq y xs) #t #f)))
(define det?
(lambda (xs)
(if (in? 'a xs) #t)
(if (in? 'an xs) #t)
(if (in? 'the xs) #t #f)))
There's no such thing (*1) as an explicit return statement in Scheme; a procedure just returns the value of the last expression. Chris has shown you alternatives with cond and correct, 2-armed ifs.
If you find yourself with conditionals returning #t and #f there's usually a more elegant alternative using boolean logic, in this case:
(define det?
(lambda (xs)
(or (in? 'a xs)
(in? 'an xs)
(in? 'the xs))))
and in? could be expressed as
(define in?
(lambda (y xs)
(and (memq y xs) #t)))
(*1) I was lying, of course. You can have this effet using call/cc or any variation thereof. It's an advanced subject and not appropriate for your situiation, but to give you a glimpse of what it would like:
(define det?
(lambda (xs)
(call/cc
(lambda (return)
(when (in? 'a xs) (return #t))
(when (in? 'an xs) (return #t))
(when (in? 'the xs) (return #t))
#f))))
Note that I use when, not if, since they are still one-armed conditions.
Your use of if is incorrect; only the last if actually does anything. (To help prevent these kinds of errors, Racket bans the use of one-armed if expressions.) Perhaps you would like to use cond instead?
(define (det? xs)
(cond ((in? 'a xs) #t)
((in? 'an xs) #t)
((in? 'the xs) #t)
(else #f)))
This macro-expands to the following ifs:
(if (in? 'a xs)
#t
(if (in? 'an xs)
#t
(if (in? 'the xs)
#t
#f)))
Notice how that's different from your series of if expressions.
I have three functions for a practice exam that I am struggling on.
A function that takes a predicate "pred" and a set "x" and returns whether or not the predicate is true for all elements in the set.
What I was trying:
(define (all? pred x)
(lambda (t)
(equal? (pred t) x)))
Since pred t returns the subset of x where the predicate is true, I was trying to compare it to the original set... Which obviously isn't the way to do it.
A function that takes an operation "op" and a set "x" and returns a new set where basically the op function has been mapped to the entire set. Basically the equivalent of map, so you'd think I shouldn't be asking for help on this...
What I am trying:
(define (map op x)
(lambda (t)
(map (op t))))
I must be missing some basic aspect of currying because I feel like these operations should be simple..
So you're trying to do something like andmap
You could define a function that evaluates a list to see wether all their elements are #t values.
(define full-true?
(λ (lst)
(if (empty? lst) #t
(if (car lst) (full-true? (cdr lst))
(car lst)))
))
Then, your main function would be:
(define for-all?
(lambda
(pred lst-of-items)
(full-true? (map (lambda (x) (pred x)) lst-of-items))
))
So, I am trying to see how functions that can accept any number of arguments work?
I tried this
(define (plus x . xs)
(if
(null? xs) x
(plus (+ x (car xs)) . (cdr xs))))
(plus 1 2 3 4)
But is seemed that it wasn't actually applying cdr to xs, but passing ( (2 3 4)) in when I stepped through it in the debugger. So I tried this
(define (plus* x . xs)
(if
(null? xs) x
(let ((h (car xs))
(t (crd xs)))
(plus* (+ x h) . t))))
Thinking: "ha, I'd like to see you pass cdr in now", but I get an error: "application: bad syntax (illegal use of `.') in: (plus* (+ x h) . t)"
What is going on?
(I can get a version of addition to work, either by
(define (add . xs)
(foldl + 0 xs))
Or even
(define (plus x . xs)
(if
(null? xs) x
(apply plus (cons (+ x (car xs)) (cdr xs)))))
so, the addition is not the problem, how dotted things work is.)
Your last version is the correct way to pass a list of numbers as inputs to plus -- you must use apply to do this. (Well, either that, or avoid the whole thing as you did with foldl.) Using a dot in the application is not doing what you think it should -- it makes the program read differently.