How to find “not a procedure” error

2019-03-07 03:14发布

问题:

(define (comp f g)
  (lambda (x)(f (g x))))

(define (complement f) (cond ((equal? (comp f (lambda (g) g)) #t) #f)
                             ((equal? (comp f (lambda (g) g)) #f) #t)))

((complement odd?)2)

It keeps saying that ((complement odd?)2) is not a procedure. I'm not sure how to fix it.

回答1:

When you run this code you'll see that ((complement odd?) 2) is red in the definitions and you get the following error:

application: not a procedure;
 expected a procedure that can be applied to arguments
  given: #<void>

So that would mean (complement odd?) doesn't return a procedure but the value #<void>. Lets try that:

(complement odd?)
; ==> nothing (aka #<void>)

If you really want to see it use it somewhere:

(list (complement odd?))
; ==> (#<void>) now you see it

That means you are not handling all your possible checks in the cond in complement and I see why.. Have you tried comp?

(comp f (lambda (g) g)) ; ==> #<procedure>

Surely enough the use of comp becomes a procedure. Not strange since the body has one lambda form that indicates the return would be a procedure. It will never be #t or #f When you don't have an else (default) term for when neither of your predicates became true cond returns an implementation specific defauls value. In Racket this is #<void> which is supressed by the REPL, but in other implementations it can be banana or whatever the implementers want it to be so you should always have a else clause. If you don't think you need it then do (else (error "should never happen")) and you're good to go. (try it)

The consequences in your cond are #t and #f. That means that if your code sould have worked you would have got this error message instead:

application: not a procedure;
 expected a procedure that can be applied to arguments
  given: #t

For each place your return smething that is not a procedure that would be an error since you are using the result as a procedure. You need to change your implementation such that it returns a procedure always.

So, this is the answer to how to find “not a procedure” error. It's not the answer to how to fix your procedure but since this is the simplest procedure in the world I'll add it. You have a procedure comp that takes two procedures and return the composition of the two. eg. if you want add2 you can (define add2 (comp add1 add1)). The complement must be that the false value #f turns #t while all the true values turn #f. not does this so the composition of not and odd? would become the procedure that works the same as even?:

(define (complement f)
  (comp not f)) ; comp returns a procedure always

(define my-even? (complement odd?))
(my-even? 2) ; ==> #t

Since we don't mutate anything you can use substitution method to check what this does:

(my-even? 2)                      ; ==>
((comp not odd?) 2)               ; ==>
(((lambda (x) (not (odd? x))) 2)  ; ==>
(not (odd? 2))                    ; ==>
(not #f)                          ; ==>
#t 


标签: scheme racket