TypeError, the object is not applicable

2019-08-15 03:46发布

I wrote a relatively simple bank account function, however when I try to run it I get an TypeError and I'm not sure to why? It's straight out of SICP so the solution is readily available, I just want to understand why my answer produces that error. Any thoughts? Here is my code:

(define (make-password-account balance password)
    (define (withdraw amount)
        (if (>= balance amount)
            (begin (set! balance (- balance amount))
                balance)
            "Insufficient Funds"))
    (define (deposit amount)
        (set! balance (+ balance amount))
        balance)
    (define (dispatch users-guess-at-password m)
            (if (eq? users-guess-at-password password)
                (cond   ((eq? m 'withdraw) withdraw)
                        ((eq? m 'deposit) deposit)
                        (else (error "Unknown Request --make-account" m)))
               "INVALID PASSWORD"))
dispatch)

Here is the relevant interpreter inputs and outputs from the interpreter:

..loaded function...
>(define acc (make-password-account 100 'secret))
acc
>((acc 's 'withdraw) 2)
;Stack Trace:  
0  TypeError: The object "Invalid Password" is not applicable.  
1  ((acc (quote s) (quote withdraw) 2)

2条回答
对你真心纯属浪费
2楼-- · 2019-08-15 04:32

Since you're passing the wrong password,

(acc 's 'withdraw)

that is,

(dispatch 's 'withdraw)

evaluates to

"INVALID PASSWORD"

and you're attempting to apply that to the number 2, but you can't because it's not a function.

You could use a function instead of a string, similar to the other cases:

(lambda (x) "Invalid password")
查看更多
我只想做你的唯一
3楼-- · 2019-08-15 04:47

Currently your code is doing this:

((acc 's 'withdraw) 2)
((dispatch 's 'withdraw) 2)
("INVALID PASSWORD" 2)
=> TypeError: The object "INVALID PASSWORD" is not applicable.

You have to handle the case where the password entered is wrong. Because you can't do anything useful with the account if the password is incorrect, you should signal an error and stop execution, for instance replacing this line:

"INVALID PASSWORD"

With this:

(error "INVALID PASSWORD")

Now the procedure will return a meaningful error message and stop execution. Alternatively, if signaling an error is too drastic, you could return a string, as suggested by @molbdnilo . Once again replace "INVALID PASSWORD" for the suggested procedure, which no matter what it receives as parameter will return the error string:

(lambda (x) "INVALID PASSWORD")

Now the execution will look like this:

((acc 's 'withdraw) 2)
((dispatch 's 'withdraw) 2)
((lambda (x) "INVALID PASSWORD") 2)
=> "INVALID PASSWORD"
查看更多
登录 后发表回答