"Life is all about sharing. If we are good at something, pass it on." - Mary Berry

### SICP Exercise 2.77: expected a procedure that can be applied to arguments, given #f

2023-07-13

Categories:

2.5.1 Generic Arithmetic Operations

Louis Reasoner tries to evaluate the expression (magnitude z) where z is the object shown in figure 2.24. To his surprise, instead of the answer 5 he gets an error message from `apply-generic`, saying there is no method for the operation `magnitude` on the types `(complex)`.

To simplify the `install-complex-package` procedure, I made the following changes:

``` 1(define (install-complex-package)
2  (define (make-from-real-imag x y)
3		((get 'make-from-real-imag 'rectangular) x y))
4	(define (tag z) (attach-tag 'complex z))
5	(put 'make-from-real-imag 'complex
6		(lambda (x y) (tag (make-from-real-imag x y))))
7
8(install-complex-package)
9
10(trace-define (make-complex-from-real-imag x y)
11	((get 'make-from-real-imag 'complex) x y))
12
13(magnitude (make-complex-from-real-imag 3 4))
```

However, upon running the code, instead of the expected error from `apply-generic`, a different error occurred:

```1\$ racket 2.77-apply-generic-magnitude.rkt
2'done
3>(make-complex-from-real-imag 3 4)
4application: not a procedure;
5 expected a procedure that can be applied to arguments
6  given: #f
```

I wondered why it returned `#f` when `'make-from-real-imag 'complex` had already been `put` into the dispatch table:

```1\$ racket --repl
2Welcome to Racket v8.9 [cs].
3> (require "2.77-apply-generic-magnitude.rkt")
4> (get 'make-from-real-imag 'complex)
5#<procedure:...neric-magnitude.rkt:75:16>
```

To debug the issue, I utilized the racket/trace library:

``` 1\$ racket --repl
2Welcome to Racket v8.9 [cs].
3> (require "2.77-apply-generic-magnitude.rkt")
4>(install-complex-package)
5> (put 'make-from-real-imag 'complex #<procedure:...neric-magnitude.rkt:75:16>)
6< #<void>
7<'done
8'done
9> (make-complex-from-real-imag 3 4)
10>(make-complex-from-real-imag 3 4)
11> (get 'make-from-real-imag 'complex)
12< #<procedure:...neric-magnitude.rkt:75:16>
13> (make-from-real-imag 3 4)
14> >(get 'make-from-real-imag 'rectangular)
15< <#f
16application: not a procedure;
17 expected a procedure that can be applied to arguments
18  given: #f
19 [,bt for context]
```

As a result, it became evident that when we called `(make-complex-from-real-imag 3 4)`, it was actually invoking `make-from-real-imag 3 4`, which, in turn, called `(get 'make-from-real-imag 'rectangular)` and this returned `#f`.

To address this issue, we need to add the `install-rectangular-package` procedure mentioned in 2.4.3 Data-Directed Programming and Additivity to get the expected error:

``` 1>(make-complex-from-real-imag 3 4)
2> (get 'make-from-real-imag 'complex)
3< #<procedure:...neric-magnitude.rkt:75:16>
4> (make-from-real-imag 3 4)
5> >(get 'make-from-real-imag 'rectangular)
6< <#<procedure:...neric-magnitude.rkt:65:16>
7> (attach-tag 'rectangular '(3 . 4))
8< '(rectangular 3 . 4)
9>(tag '(rectangular 3 . 4))
10>(attach-tag 'complex '(rectangular 3 . 4))
11<'(complex rectangular 3 . 4)
12>(get 'magnitude '(complex))
13<#f
14No method for these types: APPLY-GENERIC '(magnitude (complex))
```

Tags:

Related Posts: