SICP练习1.3征求意见
时间:2020-03-06 15:01:08 来源:igfitidea点击:
我正在尝试通过SICP学习方案。练习1.3的内容如下:定义一个以三个数字为参数并返回两个较大数字的平方和的过程。请评论如何改善我的解决方案。
(define (big x y)
(if (> x y) x y))
(define (p a b c)
(cond ((> a b) (+ (square a) (square (big b c))))
(else (+ (square b) (square (big a c))))))
解决方案
对我来说还好,我们有什么要改进的地方吗?
我们可以执行以下操作:
(define (max2 . l)
(lambda ()
(let ((a (apply max l)))
(values a (apply max (remv a l))))))
(define (q a b c)
(call-with-values (max2 a b c)
(lambda (a b)
(+ (* a a) (* b b)))))
(define (skip-min . l)
(lambda ()
(apply values (remv (apply min l) l))))
(define (p a b c)
(call-with-values (skip-min a b c)
(lambda (a b)
(+ (* a a) (* b b)))))
而且此(proc p)可以轻松转换为处理任意数量的参数。
" big"称为" max"。使用标准库功能。
我的方法是不同的。无需进行大量测试,我只需将所有三个的平方相加,然后减去最小的平方。
(define (exercise1.3 a b c)
(let ((smallest (min a b c))
(square (lambda (x) (* x x))))
(+ (square a) (square b) (square c) (- (square smallest)))))
当然,我们是否喜欢这种方法还是一堆if测试都取决于我们。
使用SRFI 95的替代实施:
(define (exercise1.3 . args)
(let ((sorted (sort! args >))
(square (lambda (x) (* x x))))
(+ (square (car sorted)) (square (cadr sorted)))))
如上,但是作为一个单行(感谢synx @ freenode #scheme);还需要SRFI 1和SRFI 26:
(define (exercise1.3 . args) (apply + (map! (cut expt <> 2) (take! (sort! args >) 2))))
我们还可以对列表进行排序,并添加已排序列表的第一个和第二个元素的平方:
(require (lib "list.ss")) ;; I use PLT Scheme
(define (exercise-1-3 a b c)
(let* [(sorted-list (sort (list a b c) >))
(x (first sorted-list))
(y (second sorted-list))]
(+ (* x x) (* y y))))
那这样的东西呢?
(define (p a b c)
(if (> a b)
(if (> b c)
(+ (square a) (square b))
(+ (square a) (square c)))
(if (> a c)
(+ (square a) (square b))
(+ (square b) (square c)))))
这是另一种方法:
#!/usr/bin/env mzscheme
#lang scheme/load
(module ex-1.3 scheme/base
(define (ex-1.3 a b c)
(let* ((square (lambda (x) (* x x)))
(p (lambda (a b c) (+ (square a) (square (if (> b c) b c))))))
(if (> a b) (p a b c) (p b a c))))
(require scheme/contract)
(provide/contract [ex-1.3 (-> number? number? number? number?)]))
;; tests
(module ex-1.3/test scheme/base
(require (planet "test.ss" ("schematics" "schemeunit.plt" 2))
(planet "text-ui.ss" ("schematics" "schemeunit.plt" 2)))
(require 'ex-1.3)
(test/text-ui
(test-suite
"ex-1.3"
(test-equal? "1 2 3" (ex-1.3 1 2 3) 13)
(test-equal? "2 1 3" (ex-1.3 2 1 3) 13)
(test-equal? "2 1. 3.5" (ex-1.3 2 1. 3.5) 16.25)
(test-equal? "-2 -10. 3.5" (ex-1.3 -2 -10. 3.5) 16.25)
(test-exn "2+1i 0 0" exn:fail:contract? (lambda () (ex-1.3 2+1i 0 0)))
(test-equal? "all equal" (ex-1.3 3 3 3) 18))))
(require 'ex-1.3/test)
例子:
$ mzscheme ex-1.3.ss 6 success(es) 0 failure(s) 0 error(s) 6 test(s) run 0
我认为仅使用文字介绍之前介绍的概念是很重要的,这里有一个不同的解决方案:
(define (smallest-of-three a b c)
(if (< a b)
(if (< a c) a c)
(if (< b c) b c)))
(define (square a)
(* a a))
(define (sum-of-squares-largest a b c)
(+ (square a)
(square b)
(square c)
(- (square (smallest-of-three a b c)))))
我只使用书中介绍的概念,就可以做到这一点:
(define (square x) (* x x)) (define (sum-of-squares x y) (+ (square x) (square y))) (define (min x y) (if (< x y) x y)) (define (max x y) (if (> x y) x y)) (define (sum-squares-2-biggest x y z) (sum-of-squares (max x y) (max z (min x y))))
我使用下面的代码来做到这一点,该代码使用内置的min,max和square过程。它们非常简单,仅需使用到目前为止所介绍的内容即可实现。
(define (sum-of-highest-squares x y z)
(+ (square (max x y))
(square (max (min x y) z))))
在斯科特·霍夫曼(Scott Hoffman)和一些irc帮助的帮助下,我更正了错误的代码,这是
(define (p a b c)
(cond ((> a b)
(cond ((> b c)
(+ (square a) (square b)))
(else (+ (square a) (square c)))))
(else
(cond ((> a c)
(+ (square b) (square a)))
(else (+ (square b) (square c))))))
我已经去了:
(define (procedure a b c)
(let ((y (sort (list a b c) >)) (square (lambda (x) (* x x))))
(+ (square (first y)) (square(second y)))))

