<jupyter_start><jupyter_text>SICP 习题 （3.24）解题总结: 表格的处理 SICP 习题 3.24 开始讨论表格。这里的表格对应的是table，就是表，最简单的表就是有行有列，可以通过行列来定位数据。关于表的代码现实在题目上文有完整提到，把代码抄写下来运行测试一下就好。题目具体的要求是要我们实现更广泛的关键字比较，书中原来的比较代码如下：    (define (assoc key records)      (cond ((null? records) f)        ((equal? key (caar records)) (car records))        (else (assoc key (cdr records)))))        这里使用了equal?对两个输入进行了比较。题目提出这种比较有局限性，有些比较是不能直接用equal?来实现的，比如相差不到0.00001的两个数我们也可以认为是相等的，这个时候用equal?就会认为它们不相等。要实现更广泛的关键字比较，我们就需要把比较这件事情从具体代码中抽离出来。通过一个未确定的比较函数来替换equal?，在创建一个表格时可以指定比较函数。这样，比较关键字的代码可以写成这样：    (define (assoc key records same-key?)      (cond ((null? records) f)        ((same-key? key (caar records)) (car records))        (else (assoc key (cdr records) same-key?))))这里把比较函数抽离出来，通过函数的参数传入。这里也充分利用了Lisp里过程就是数据，数据也可以是函数的特性。 完整代码如下：<jupyter_code>(define (assoc key records same-key?)
  (cond ((null? records) #f)
	((same-key? key (caar records)) (car records))
	(else (assoc key (cdr records) same-key?))))

(define (make-table same-key?)
  (let ((local-table (list '*table*)))
    (define (lookup key-1 key-2)
      (let ((subtable (assoc key-1 (cdr local-table) same-key?)))
	(if subtable
	    (let ((record (assoc key-2 (cdr subtable) same-key?)))
	      (if record
		  (cdr record)
		  (begin
		    (display "record not found: ") (display key-2) (newline)
		    #f
		    )))
	    (begin 
	      (display "subtable not found: ") (display key-1)(newline)
	      #f))))
    (define (insert! key-1 key-2 value)
      (let ((subtable (assoc key-1 (cdr local-table) same-key?)))
	(if subtable
	    (let ((record (assoc key-2 (cdr subtable) same-key?)))
	      (if record
		  (set-cdr! record value)
		  (set-cdr! subtable
			    (cons (cons key-2 value)
				  (cdr subtable)))))
	    (set-cdr! local-table
		      (cons (list key-1
				  (cons key-2 value))
			    (cdr local-table)))))
      'ok)
    (define (dispatch m)
      (cond ((eq? m 'lookup-proc) lookup)
	    ((eq? m 'insert-proc!) insert!)
	    (else (error "Unknown operation -- TABLE" m))))
    dispatch))<jupyter_output><empty_output><jupyter_text>然后可以开始测试一下。为了进行基本的测试，我们先看看直接把equal?函数放回去当比较函数是不是可以正常工作：<jupyter_code>(define operation-table (make-table equal?))

(define get (operation-table 'lookup-proc))

(define put (operation-table 'insert-proc!))

(put 'column1 'row1 '11)
(put 'column2 'row1 '21)

(display (get 'column2 'row1))<jupyter_output>21<jupyter_text>确认以上代码是可以工作的，我们再来定义一个close-number函数来判断两个数是不是足够接近：<jupyter_code>(define (close-number? x y)
  (< (abs (- x y)) 0.001))
(close-number? 2 2.00009)<jupyter_output><empty_output><jupyter_text>使用这个新的比较函数就可以创建新的表格了：<jupyter_code>(define operation-table (make-table close-number?))

(define get (operation-table 'lookup-proc))

(define put (operation-table 'insert-proc!))

(put 1 1 '11)
(put 2 1 '21)

(display (get 1.000008 1.00000009))
(put 1 2 100)
(get 1 2)
(get 'column1 'row1)
(put 'column2 'row2 'abc)
(get 'column2 'row2)
(define (start-test-3-24)
  (define operation-table (make-table (lambda (x y) (equal? x y))))

  (define get (operation-table 'lookup-proc))

  (define put (operation-table 'insert-proc!))

  (put 'column1 'row1 '11)
  (put 'column2 'row1 '21)

  (display (get 'column2 'row1)))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15812364088226158, 'fraction_numerical': 0.030444237340789066, 'mean_word_length': 4.235772357723577, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '249600', 'license': 'MIT', 'n_tokens_mistral': 1581, 'n_tokens_neox': 1552, 'n_words': 286, 'path': 'cn/.ipynb_checkpoints/sicp-3-24-checkpoint.ipynb', 'repo_name': 'DamonDeng/sicp_exercise', 'size': '3219'}