2008-10-02 6 views
18

Я пытаюсь изучить схему через SICP. Упражнение 1.3 читается следующим образом: Определите процедуру, которая принимает три числа в качестве аргументов и возвращает сумму квадратов двух больших чисел. Прошу прокомментировать, как я могу улучшить свое решение.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)))))) 
+2

FWIW, я думаю, ваше решение лучше, чем любой из предоставленных ответов (если вы переименуете большой в max, как было предложено). – 2011-06-19 19:33:11

+0

Хорошее решение самостоятельно! – 2013-11-04 13:23:30

ответ

3

Выглядит нормально, есть ли что-то конкретное, что вы хотите улучшить?

Вы могли бы сделать что-то вроде:

(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 р) может быть легко преобразован в обрабатывать любое количество аргументов.

+0

Я считаю, что OP просил высказать замечания по стилю, и в этом отделе есть некоторые вещи, о которых можно было бы поговорить, например, что у меня на посту. :-) – 2008-10-02 10:29:14

+0

P.S. Я вижу вас на #схеме (хотя вы, похоже, продолжаете выходить из системы)! Маленький мир! – 2008-10-02 11:11:42

+0

Да, кажется, мой ISP сильно влияет на движение на некоторых портах. Забавно, что я могу отправить данные, это просто требует времени, чтобы получить что-либо :(Это говорит о том, что я не знал, что в мире было более 100 пользователей Scheme! Hehe – leppie 2008-10-02 11:31:40

12

bigmax. Используйте стандартную библиотечную функциональность, когда она есть.

Мой подход отличается. Вместо множества тестов я просто добавляю квадраты всех трех, а затем вычитаю квадрат самого маленького.

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

Я думаю, что квадрат стоит дороже, чем несколько дополнительных тестов. Но это только я :) – leppie 2008-10-02 10:31:34

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

А что-то вроде этого?

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

Вот еще один способ сделать это:

 
#!/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 
2

Используя только понятие, введенное до этого момента текста, который я думаю, достаточно важное значение, это другое решение:

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

Используя только концепции, представленные в этой точке книги, я хотел бы сделать это:

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

Я сделал это с помощью следующего кода, который использует встроенный в min, max, и square процедур. Они достаточно просты, чтобы реализовать, используя только то, что было введено в тексте до этого момента.

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

С Скотт Хоффман и некоторые 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)))))) 
0

Я был пойти:

(define (procedure a b c) 
    (let ((y (sort (list a b c) >)) (square (lambda (x) (* x x)))) 
     (+ (square (first y)) (square(second y))))) 
0
;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)))) 
2
(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)))) 
0
(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))) 
0

Я думаю, что это самый маленький и самый эффективный способ:

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

Ниже решение, которое я придумал. Мне легче рассуждать о решении, когда код разлагается на небольшие функции.

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