我正在尝试通过 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 (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))))
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))))
这样的事情呢?
(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)))))
我使用以下代码完成了它,它使用了内置的min
、max
和square
过程。它们很简单,仅使用到目前为止在文本中介绍的内容即可实现。
(define (sum-of-highest-squares x y z)
(+ (square (max x y))
(square (max (min x y) z))))
仅使用本文之前介绍的概念,我认为这是相当重要的,这里有一个不同的解决方案:
(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 (f a b c)
(if (= a (min a b c))
(+ (* b b) (* c c))
(f b c a)))
对我来说看起来不错,您有什么具体要改进的地方吗?
您可以执行以下操作:
(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)可以很容易地转换为处理任意数量的参数。
(define (sum-sqr x y)
(+ (square x) (square y)))
(define (sum-squares-2-of-3 x y z)
(cond ((and (<= x y) (<= x z)) (sum-sqr y z))
((and (<= y x) (<= y z)) (sum-sqr x z))
((and (<= z x) (<= z y)) (sum-sqr x y))))
在 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))))
(+ (square b) (square c)))))
您还可以对列表进行排序并添加排序列表的第一个和第二个元素的平方:
(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))))
这是另一种方法:
#!/usr/bin/env mzscheme #lang 方案/加载 (模块 ex-1.3 方案/基础 (定义(ex-1.3 abc) (let* ((square (lambda (x) (* xx))) (p (lambda (abc) (+ (square a) (square (if (> bc) bc)))))) (如果 (> ab) (pabc) (pbac)))) (需要方案/合同) (提供/合同 [ex-1.3 (-> number?number?number?number?)])) ;; 测试 (模块 ex-1.3/test scheme/base (需要(行星“test.ss”(“原理图”“schemeunit.plt”2)) (行星“text-ui.ss”(“原理图”“schemeunit.plt”2))) (需要'ex-1.3) (测试/文本-ui (测试套件 “前 1.3” (测试等于?“1 2 3”(ex-1.3 1 2 3)13) (测试等于?“2 1 3”(ex-1.3 2 1 3)13) (测试等于?“2 1. 3.5”(ex-1.3 2 1. 3.5)16.25) (测试等于?“-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))) (测试相等?“全部相等”(ex-1.3 3 3 3)18)))) (需要'ex-1.3/test)
例子:
$ mzscheme ex-1.3.ss 6 成功 0 失败 0 错误 6 测试运行 0
很高兴看到其他人如何解决这个问题。这是我的解决方案:
(define (isGreater? x y z)
(if (and (> x z) (> y z))
(+ (square x) (square y))
0))
(define (sumLarger x y z)
(if (= (isGreater? x y z) 0)
(sumLarger y z x)
(isGreater? x y z)))
我通过迭代解决了它,但我更喜欢 ashitaka 和 (+ (square (max xy)) (square (max (min xy) z))) 解决方案,因为在我的版本中,如果 z 是最小的数字,isGreater? 被调用两次,创建了一个不必要的缓慢和迂回的过程。
(define (sum a b) (+ a b))
(define (square a) (* a a))
(define (greater a b )
( if (< a b) b a))
(define (smaller a b )
( if (< a b) a b))
(define (sumOfSquare a b)
(sum (square a) (square b)))
(define (sumOfSquareOfGreaterNumbers a b c)
(sumOfSquare (greater a b) (greater (smaller a b) c)))
我试过了:
(define (procedure a b c)
(let ((y (sort (list a b c) >)) (square (lambda (x) (* x x))))
(+ (square (first y)) (square(second y)))))
;exercise 1.3
(define (sum-square-of-max a b c)
(+ (if (> a b) (* a a) (* b b))
(if (> b c) (* b b) (* c c))))
我认为这是最小和最有效的方法:
(define (square-sum-larger a b c)
(+
(square (max a b))
(square (max (min a b) c))))
下面是我想出的解决方案。我发现将代码分解为小函数时更容易推理出解决方案。
; Exercise 1.3
(define (sum-square-largest a b c)
(+ (square (greatest a b))
(square (greatest (least a b) c))))
(define (greatest a b)
(cond (( > a b) a)
(( < a b) b)))
(define (least a b)
(cond ((> a b) b)
((< a b) a)))
(define (square a)
(* a a))