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))))))
Ответы
Ответ 1
Выглядит хорошо, есть ли что-то конкретное, что вы хотите улучшить?
Вы можете сделать что-то вроде:
(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) может быть легко преобразовано для обработки любого количества аргументов.
Ответ 2
Используя только концепции, представленные в этой части книги, я бы сделал это:
(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))))
Ответ 3
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))))
Ответ 4
Как насчет чего-то подобного?
(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)))))
Ответ 5
Я сделал это со следующим кодом, который использует встроенные процедуры min
, max
и square
. Они достаточно просты для реализации, используя только то, что было введено в тексте до этой точки.
(define (sum-of-highest-squares x y z)
(+ (square (max x y))
(square (max (min x y) z))))
Ответ 6
Использование только понятий, вносимых в эту точку текста, что, по моему мнению, весьма важно, вот другое решение:
(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)))))
Ответ 7
(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))))
Ответ 8
(define (f a b c)
(if (= a (min a b c))
(+ (* b b) (* c c))
(f b c a)))
Ответ 9
С помощью Скотта Хоффмана и некоторой помощи 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))))
Ответ 11
Вот еще один способ сделать это:
#!/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
Ответ 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)))
Я решил это путем итерации, но мне больше нравится ашитака и решения (+ (square (max xy)) (square (max (min xy) z))), так как в моей версии, если z - наименьшее число, isGreater? вызывается дважды, создавая излишне медленную и обходную процедуру.
Ответ 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))))
Ответ 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))
Ответ 18
Боже, я так чертовски глуп
'(define 2-3sums (lambda ( x y z)
(+ ( (lambda (a) ( * a a))
(cond ((and (> x y) (> x z)) x )
((and (> y x) (> y z)) y)
((and (> z y) (> z x)) z)
))
((lambda (b) (* b b))
(cond ((or (and(> x y) (< x z))(and(< x y)(> x z)))x)
((or(and(> y x) (< y z))(and(< y x)(> y z ))) y)
((or(and(> z x)(< z y))(and(< z x)(> z y)))z)
)))))'