I am trying to use the unrestricted lambda in order to apply an arbitrary number of procedures on one argument. My code returns '#procedure' rather than a value (I was expecting ((compose-many add1 add1 add1) 3) => 6). Please clarify my mistake. Thank you.
(define compose-many
(lambda args
(lambda (x)
(cond
((null? args)
x)
((null? (cdr args))
(car args) x)
(else (car args) (compose-many (cdr args)))))))
((compose-many add1 add1 add1) 3)
In your code, when you call the recursion you're expected to again pass values to the parameters in (lambda args (lambda (x) ...)), when the correct would be to just iterate over the args. Also, you forgot to actually apply the procedures! An expression like this: ((null? (cdr args)) (car args) x) ignores the result of (car args) and just returns x.
To see this more clearly, let's see how the solution should look for a case in particular, say - we only have to compose three procedures. Notice that we return a single lambda and how the procedures are applied:
(define (compose f g h)
(lambda (x)
(f (g (h x)))))
We should approach the problem differently: we must return the (lambda (x) ...) only once, and a "loop" should process the args list before returning it. Something like this, perhaps?
(define compose-many
(lambda args
; we return (lambda (x) ...) only once, is not part of the recursion
(lambda (x)
; here we loop over the args list
(define (helper args)
(if (null? args)
x
; notice the "((" here we apply the procedure!
((car args) (helper (cdr args)))))
; call the helper a single time and we're done!
(helper args))))
((compose-many add1 add1 add1) 3)
=> 6
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.
In "The Scheme Programming Language 4th Edition" section 3.3 Continuations the following example is given:
(define product
(lambda (ls)
(call/cc
(lambda (break)
(let f ([ls ls])
(cond
[(null? ls) 1]
[(= (car ls) 0) (break 0)]
[else (* (car ls) (f (cdr ls)))]))))))
I can confirm it works in chezscheme as written:
> (product '(1 2 3 4 5))
120
What is 'f' in the above let? Why is the given ls being assigned to itself? It doesn't seem to match what I understand about (let ...) as described in 4.4 local binding:
syntax: (let ((var expr) ...) body1 body2 ...)
If 'f' is being defined here I would expect it inside parenthesis/square brackets:
(let ([f some-value]) ...)
This is 'named let', and it's a syntactic convenience.
(let f ([x y] ...)
...
(f ...)
...)
is more-or-less equivalent to
(letrec ([f (λ (x ...)
...
(f ...)
...)])
(f y ...))
or, in suitable contexts, to a local define followed by a call:
(define (outer ...)
(let inner ([x y] ...)
...
(inner ...)
...))
is more-or-less equivalent to
(define (outer ...)
(define (inner x ...)
...
(inner ...)
...)
(inner y ...))
The nice thing about named let is that it puts the definition and the initial call of the local function in the same place.
Cavemen like me who use CL sometimes use macros like binding, below, to implement this (note this is not production code: all its error messages are obscure jokes):
(defmacro binding (name/bindings &body bindings/decls/forms)
;; let / named let
(typecase name/bindings
(list
`(let ,name/bindings ,#bindings/decls/forms))
(symbol
(unless (not (null bindings/decls/forms))
(error "a syntax"))
(destructuring-bind (bindings . decls/forms) bindings/decls/forms
(unless (listp bindings)
(error "another syntax"))
(unless (listp decls/forms)
(error "yet another syntax"))
(multiple-value-bind (args inits)
(loop for binding in bindings
do (unless (and (listp binding)
(= (length binding) 2)
(symbolp (first binding)))
(error "a more subtle syntax"))
collect (first binding) into args
collect (second binding) into inits
finally (return (values args inits)))
`(labels ((,name/bindings ,args
,#decls/forms))
(,name/bindings ,#inits)))))
(t
(error "yet a different syntax"))))
f is bound to a procedure that has the body of let as a body and ls as a parameter.
http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_sec_11.16
Think of this procedure:
(define (sum lst)
(define (helper lst acc)
(if (null? lst)
acc
(helper (cdr lst)
(+ (car lst) acc))))
(helper lst 0))
(sum '(1 2 3)) ; ==> 6
We can use named let instead of defining a local procedure and then use it like this:
(define (sum lst-arg)
(let helper ((lst lst-arg) (acc 0))
(if (null? lst)
acc
(helper (cdr lst)
(+ (car lst) acc)))))
Those are the exact same code with the exception of some duplicate naming situations. lst-arg can have the same name lst and it is never the same as lst inside the let.
Named let is easy to grasp. call/ccusually takes some maturing. I didn't get call/cc before I started creating my own implementations.
I want to write a function which for n arguments will create n lists and each contains n-th element for every argument, for example:
(aux '(1 2) '(3 4)) = `((1 3) (2 4))
I wrote such a function:
(define (aux . args)
(if (null? args)
'()
(cons (map car args)
(aux (map cdr args)))))
but when I try to evalute (aux '(1 2) '(3 4)) the REPL does not show any output.
My question is what should I change because I don't see any syntax errors.
Chris is correct. In the event you want to use rest arguments and then use it in recursion you should consider wrapping it in a named let or make a local helper procedure.
(define (zip . args)
(let aux ((args args))
(if (ormap null? args)
'()
(cons (map car args)
(aux (map cdr args))))))
I also do this when there are arguments that don't change. eg. a map implementation for only one list I don't pass the procedure at each iteration:
(define (map1 proc lst)
(let aux ((lst lst))
(if (null? lst)
'()
(cons (proc (car lst))
(aux (cdr lst))))))
Of course what actually will happen is up to the implementation so don't think of any of these as optimizations. It's mostly for code clarity.
You forgot to write an apply in your function. Don't worry, I make this mistake all the time, which was why I spotted it instantly. ;-)
Basically, you need to use (apply aux (map cdr args)). Otherwise, your aux is being recursed into with one argument only.
Oh, and you also need to use (ormap null? args) instead of just (null? args), since the base case is that all your given lists are exhausted, not that you have no given lists.
I'm fairly new to Scheme programming and was wondering how I can add some error checkers in this program. I would like it to check if the user types in more than one parameter and if the user does I would like it to say that its an error.
(define (thirds lst)
(cond ((or (null? lst) (null? (cdr lst))) lst)
((null? (cddr lst)) (list (car lst)))
(else (cons (car lst)
(thirds (cdddr lst))))))
The Scheme interpreter should check this automatically. You only need to do your own checking of the number of arguments if you define the procedure to take spread arguments, i.e.
(define (thirds . args)
...)
You would normally only do this if the procedure takes a variable number of arguments. For procedures with static arguments, just list them in the definition and let the interpreter do the checking for you.
If you really want to detect this yourself, you can do:
(define (thirds . args)
(if (= (length args) 1)
(let ((lst (car args)))
(cond ... ; all the rest of your code
))
(display "Oh that's an error")))
So, using your definition of thirds in #!racket (the language) and trying to use it like this:
(thirds '(a b c) '(d e f))
thirds: arity mismatch;
the expected number of arguments does not match the given number
expected: 1
given: 2
arguments...:
'(a b c)
'(d e f)
context...:
/usr/share/racket/collects/racket/private/misc.rkt:87:7
As you can see all computation stops since I have given a one argument procedure two arguments. It's a contract violation and it throws an exception.
It's perfectly possible to make handlers:
(with-handlers ([exn:fail:contract?
(λ (e) (displayln "got a contract error"))])
(thirds '(1 2 3) '(4 5 6)))
; prints "got a contract error"
I have the following scheme function:
(define get-ivars
(λ (ivars num)
(cond ((null? ivars) '())
(else
(append (list (car ivars) `(nth args ,num)) (list (get-ivars (cdr ivars) (+ num 1))))))))
That returns the following in a specific instance:
(x (nth args 1) (y (nth args 2) ()))
The problem is, I need it to return:
((x (nth args1)) (y (nth args 2)) ())
-the two closing parenthesis at the end should be after the (nth statements.
How would I go about getting this to work properly?
get-ivars caller:
(define gen-classes
(λ (classes)
(cond ((null? classes) '())
(else
(let* ((class (car classes)))
(eval
`(define ,(cadr class)
(λ (args)
(let (
,(get-ivars (cdr (cadddr class)) 1)
)
(eval
(let* ,(cdar (cddddr class))
(λ (method . args)
,(get-methods (cdadr (cddddr class)))
))))))))))))
That second (list ...) in your else clause is what's screwing you up. It's nesting each successive call deeper and deeper. The recursion will naturally create the list; you don't need to wrap it again.
Try:
(define get-ivars
(λ (ivars num)
(if (null? ivars) '()
(cons (list (car ivars) `(nth args ,num))
(get-ivars (cdr ivars) (+ num 1))))))
Regarding the get-ivars caller code, the parentheses surrounding the unquoted call to get-ivars are what's giving you the trouble you mention in the comments. With them, this code:
`(define ClassName
(lambda (args)
(let (,(get-ivars '(iVar1 iVar2 iVar3) 1))
;; your method-getting code
)))
Gives you this:
(define ClassName
(lambda (args)
(let (((iVar1 (nth args 1))
(iVar2 (nth args 2))
(iVar3 (nth args 3))))
;; method-getting code
)))
Which, as you can see, gives you an extra set of parentheses around the assignments in the let.
So you want to do this:
`(define ClassName
(lambda (args)
(let ,(get-ivars '(iVar1 iVar2 iVar3) 1)
;; your method-getting code
)))
get-ivars is returning a list of lists, which is exactly what you want for the assignments in the let, so you don't need to wrap or (as I had it earlier) splice it. Just use the unquote on its own, and the result is:
(define ClassName
(lambda (args)
(let ((iVar1 (nth args 1))
(iVar2 (nth args 2))
(iVar3 (nth args 3)))
;; method-getting code
)))
Which should do the trick.
Incidentally, I found it helpful to leave off the eval when I was playing around with this; one can then visually inspect the result to make sure its syntax is okay.
I haven't tried this, but I think this would work:
(define (get-ivars ivars num)
(if (null? ivars)
'()
(list (list (car ivars) `(nth args ,num))
(get-ivars (cdr ivars) (1+ num)))))