如何使这个功能优雅

时间:2015-02-22 01:48:34

标签: scheme sicp

响应 SICP 的以下练习,

  

练习1.3。定义一个以三个数字作为参数的过程   并返回两个较大数字的平方和。

我写了以下(正确的)函数:

(define (square-sum-larger a b c)
  (cond ((or (and (> a b) (> b c)) (and (> b a) (> a c))) (+ (* a a) (* b b)))
        ((or (and (> a c) (> c b)) (and (> c a) (> a b))) (+ (* a a) (* c c)))
        ((or (and (> b c) (> c a)) (and (> c b) (> b a))) (+ (* b b) (* c c)))))

不幸的是,这是我生命中写过的最丑陋的功能之一。我如何

(a)优雅,

(b)让它适用于任意数量的输入?

4 个答案:

答案 0 :(得分:4)

我找到了一个优雅的解决方案(尽管它仅适用于3个输入):

(define (square-sum-larger a b c)
 (+ 
  (square (max a b))
  (square (max (min a b) c))))

答案 1 :(得分:1)

如果您愿意使用图书馆的sort功能,这将变得轻松而优雅。

(define (square-sum-larger . nums)
  (define sorted (sort nums >))
  (let ((a (car sorted))
        (b (cadr sorted)))
    (+ (* a a) (* b b))))

在上述功能中,nums是"休息"参数,包含传递给函数的所有参数的列表。我们只是使用>按降序对该列表进行排序,然后对结果的前两个元素进行平方。

答案 2 :(得分:1)

我不知道它是否足够优雅,但对于3参数版本,您可以使用过程抽象来减少重复:

(define (square-sum-larger a b c)
  (define (square x)
    (* x x))

  (define (max x y)
    (if (< x y) y x))

  (if (< a b)
      (+ (square b) (square (max a c)))
      (+ (square a) (square (max b c)))))

使其适用于任意数量的输入。

(define (square-sum-larger a b . rest)
  (let loop ((a (if (> a b) a b)) ;; a becomes largest of a and b
             (b (if (> a b) b a)) ;; b becomes smallest of a and b
             (rest rest))
    (cond ((null? rest) (+ (* a a) (* b b)))
          ((> (car rest) a) (loop (car rest) a (cdr rest)))
          ((> (car rest) b) (loop a (car rest) (cdr rest)))
          (else (loop a b (cdr rest))))))

使用sorttake的R6RS版本:

#!r6rs
(import (rnrs)
        (only (srfi :1) take))

(define (square-sum-larger . rest)
  (apply + 
         (map (lambda (x) (* x x))
              (take (list-sort > rest) 2))))

答案 3 :(得分:1)

你不需要打扰你只需要找到最好的两个。

(define (max-fold L)
  (if (null? L)
      #f 
      (reduce (lambda (x y) 
                 (if (> x y) x y))
              (car L)
              L)))

(define (remove-num-once x L)
 (cond ((null? L) #f)
       ((= x (car L)) (cdr L))
       (else (cons (car L) (remove-once x (cdr L))))))

(define (square-sum-larger . nums) 
   (let ((max (max-fold nums)))
     (+ (square max) 
        (square (max-fold (remove-num-once max nums)))))) 

(square-sum-larger 1 8 7 4 5 6 9 2)

;Value: 145