【问题标题】:SICP Exercise 1.3 request for commentsSICP 练习 1.3 征求意见
【发布时间】:2008-10-02 10:23:31
【问题描述】:

我正在尝试通过 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))))))

【问题讨论】:

  • FWIW,我认为您的解决方案比提供的任何答案都好(如果您按照建议将 big 重命名为 max)。
  • 你自己的好解决方案!

标签: scheme sicp


【解决方案1】:

仅使用本书当时提出的概念,我会这样做:

(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))))

【讨论】:

    【解决方案2】:

    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 1SRFI 26

    (define (exercise1.3 . args)
      (apply + (map! (cut expt <> 2) (take! (sort! args >) 2))))
    

    【讨论】:

    • 我认为做 square 比一些额外的测试更昂贵。但这只是我:)
    • 我认为代码应该首先优化清晰度,其次是性能。但是,我愿意接受理性的人可以对此持不同意见。 :-)
    • 这是一个非常有趣的解决方案。给猫剥皮的方法不止一种。
    • min、let、lambda、sort!、map!、cut car、cadr、take! 和 apply 在文中尚未介绍。
    • @Shawn:我的解决方案并不打算成为人们在第一次阅读时就会实施的解决方案,而是考虑到一定数量的 Scheme 经验,他们可能希望实施的解决方案。此外,喜欢冒险的第一批读者可能会使用这样的解决方案作为学习本书未涵盖的部分 Scheme(和 SRFI)的基础。
    【解决方案3】:

    这样的事情呢?

    (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)))))
    

    【讨论】:

    • 投了赞成票,因为我在这方面苦苦挣扎,而我的代码也在类似的行上。我只是在学习,还不知道其他示例中更大的构造。使用您的代码,我纠正了我的错误代码。由于我无法在此处添加 html 代码,因此我将我的代码放在下面的单独回复中。
    【解决方案4】:

    我使用以下代码完成了它,它使用了内置的minmaxsquare 过程。它们很简单,只需使用到目前为止在文本中介绍的内容即可实现。

    (define (sum-of-highest-squares x y z)
       (+ (square (max x y))
          (square (max (min x y) z))))
    

    【讨论】:

      【解决方案5】:

      仅使用本文之前介绍的概念,我认为这是相当重要的,这是一个不同的解决方案:

      (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)))))
      

      【讨论】:

        【解决方案6】:
        (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))))
        

        【讨论】:

          【解决方案7】:
          (define (f a b c) 
            (if (= a (min a b c)) 
                (+ (* b b) (* c c)) 
                (f b c a)))
          

          【讨论】:

            【解决方案8】:

            在我看来还可以,您有什么具体要改进的地方吗?

            你可以这样做:

            (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) 可以很容易地转换为处理任意数量的参数。

            【讨论】:

            • 我相信 OP 是在要求 cmets 讨论风格,在那个部门有一些可以讨论的事情,比如我的帖子中的内容。 :-)
            • P.S.我在#scheme 上看到你(尽管你似乎一直被注销)!小世界!
            • 是的,看来我的 ISP 正在严重影响某些端口上的流量。有趣的是,我可以发送数据,接收任何东西都需要很长时间:(也就是说,我不知道世界上有超过 100 个 Scheme 用户!呵呵
            • 对您的 ISP 感到失望。是的,很高兴知道互联网上有很多计划者...... :-)
            • 我完全是新手,所以很高兴看到您的替代解决方案(这超出了我的想象)。
            【解决方案9】:

            在 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)))))
            

            【讨论】:

              【解决方案10】:

              还可以对列表进行排序,将排序后的列表的第一个和第二个元素的平方相加:

              (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))))
              

              【讨论】:

              • Sébastien,我还没有学会如何使用列表;但又是一个有趣的解决方案。我正在使用 PLT 方案。这需要 PLT 方案的工作吗?
              【解决方案11】:

              这里还有另一种方法:

              #!/usr/bin/env mzscheme #lang 方案/加载 (模块 ex-1.3 方案/基础 (定义(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))))))) (如果 (> a b) (p a b c) (p b a c)))) (需要方案/合同) (提供/合同 [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

              【讨论】:

              • NB - MzScheme 现在是 Racket。
              【解决方案12】:

              很高兴看到其他人如何解决这个问题。这是我的解决方案:

              (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 x y)) (square (max (min x y) z))) 解决方案,因为在我的版本中,如果 z 是最小的数字, 更伟大?被调用两次,创建了一个不必要的缓慢和迂回的过程。

              【讨论】:

                【解决方案13】:
                (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)))
                

                【讨论】:

                  【解决方案14】:

                  我试过了:

                  (define (procedure a b c)
                      (let ((y (sort (list a b c) >)) (square (lambda (x) (* x x))))
                          (+ (square (first y)) (square(second y)))))
                  

                  【讨论】:

                    【解决方案15】:
                    ;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))))
                    

                    【讨论】:

                    • 如果 A 大于 C 但小于 B 怎么办?
                    【解决方案16】:

                    我认为这是最小且最有效的方式:

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

                    【讨论】:

                      【解决方案17】:

                      以下是我想出的解决方案。我发现将代码分解为小函数时更容易推理出解决方案。

                                  ; 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))
                      

                      【讨论】:

                      • 这个问题没有要求代码来完成这个练习,它要求 cmets 如何改进他们的解决方案。 OP 的代码有什么好处或坏处?你的方式有什么好处?如果没有 cmets,这不能回答所提出的问题。
                      • @ChrisH - 你是对的。这里有很多很好的解决方案。我正在通过 SICP 工作,并在查看人们提出的其他解决方案时发现了这篇文章。由于我的与其他人略有不同,因此我决定将其作为另一个示例。以后一定会离开cmets。
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-07-05
                      • 2011-11-05
                      • 2017-02-03
                      • 2010-12-26
                      • 2012-12-15
                      • 2021-05-23
                      • 1970-01-01
                      相关资源
                      最近更新 更多