Являются ли функции Scheme одним вкладышем? - PullRequest
3 голосов
/ 02 февраля 2009

Я следую Структура и интерпретация компьютерных программ и, пытаясь решить пример 1.3, я получил следующий код в качестве моей первой попытки:

(define (sumsq a b c)(
(define highest (if (> (if (> a b) a b) (if (> a c) a c)) (if (> a b) a b) (if (> a c) a c)))
(define second_h (if (> (if (> a b) b a) (if (> a c) c a)) (if (> a b) b a) (if (> a c) c a)))
(+ (* highest highest) (* second_h second_h)))

Это не сработало, и я посмотрел решение и нашел их на SICP Wiki

;; ex 1.3
;; implemented using only techniques covered to this point

(define (square x) (* x x))

(define (sum-of-squares x y)
  (+ (square x) (square y)))

(define (largest-two-of-three x y z)
  (if (>= x y)
      (sum-of-squares x (if (>= y z) y z))
      (sum-of-squares y (if (>= x z) x z))))

Разница заключалась в том, что я использовал несколько операторов для определения переменных, а затем суммировал квадраты, тогда как правильный способ - определить каждую из моих строк как функции.

Являются ли функции в Схеме 1 вкладышами? Или я все это пропустил?

Ответы [ 5 ]

6 голосов
/ 02 февраля 2009

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

(define (sumsq a b c)
  ((define highest 
     (if (> (if (> a b) a b)
            (if (> a c) a c))
         (if (> a b) a b)
         (if (> a c) a c)))
   (define second-h
     (if (> (if (> a b) b a)
            (if (> a c) c a))
         (if (> a b) b a)
         (if (> a c) c a)))
   (+ (* highest highest)
      (* second-h second-h)))

Первое, на что нужно обратить внимание: круглые скобки не совпадают; есть еще один открытый, чем закрытый. Тщательный осмотр показывает, что одна открывающая скобка во второй строке неверна. Это, кстати, тот, который каким-то образом болтался в конце вашей первой строки. Я рискнул бы предположить, что когда вы попытались оценить это, ничего не произошло, так как читатель ждал конца утверждения.

Правильный отступ довольно важен. Я думаю, что SICP не объясняет это явно, хотя примеры обычно делаются таким образом. Я нашел руководство по стилю здесь .

Второе замечание: ты много повторяешься. Во всех этих вложенных if утверждениях я не совсем уверен, действительно ли вы получили правильные значения. Посмотрите на решение, которое вы нашли, чтобы увидеть, как это можно значительно упростить.

Вы пытались разбить сложность, дав имена подрезультатов. Разбивать сложность - это хорошо, но обычно лучше назвать не результаты, а концепции. Подумайте, что вы делаете, а затем назовите эти действия. Это функции, и они составляют язык, на котором вы, наконец, почти тривиально решаете свою проблему.

5 голосов
/ 02 февраля 2009

То, что вы написали (минус один дополнительный парень):

(define (sumsq a b c)
  (define highest
    (if (> (if (> a b) a b)
           (if (> a c) a c))
      (if (> a b) a b)
      (if (> a c) a c)))
  (define second_h
    (if (> (if (> a b) b a)
           (if (> a c) c a))
      (if (> a b) b a)
      (if (> a c) c a)))
  (+ (* highest highest) (* second_h second_h)))

Их решение делит квадраты и суммы квадратов на отдельные функции, но я не думаю, что это важно. Если вы не напишите (+ (* a a) (* b b)) , то лишит вас необходимости называть два вычисляемых значения, что позволит вам написать функцию в виде одного большого выражения в конце, но теперь есть о чем беспокоиться. .

Думаю, проблема в том, что ваши (если ...) выражения слишком велики, чтобы их было легко понять. Обратите внимание, что есть два шаблона, которые появляются много раз: (if (> a b) a b) и (if (> a b) b a). Это функции max и min, поэтому полезно определить их так:

(define (min a b) (if (< a b) a b))
(define (max a b) (if (< a b) b a))

Таким образом, вы можете переписать ваше решение как:

(define (sumsq a b c)
  (define highest
    (if (> (max a b) (max a c))
      (max a b)
      (max a c)))
  (define second_h
    (if (> (min a b) (min a c))
      (min a b)
      (min a c)))
  (+ (* highest highest) (* second_h second_h)))

Упрощение снова дает:

(define (sumsq a b c)
  (define highest
    (max (max a b) (max a c)))
  (define second_h
    (max (min a b) (min a c)))
  (+ (* highest highest) (* second_h second_h)))

Обратите внимание, что этот текст гораздо проще рассуждать, (max (max a b) (max a c)), очевидно, является максимумом a b и c и может быть переписан как (max (max a b) c). Глядя на second_h, не очевидно, что это правильно. Что произойдет, если a является наименьшим из трех значений?

Хитрость, которую они используют в своем решении, - сначала сравнить x и y. если x < y, то вы знаете, что y не является наименьшим из трех, поэтому он является либо самым высоким, либо вторым по величине. Другое число, которое вы захотите использовать, является более высоким из x и z, поскольку меньшее из этих двух будет самым маленьким из трех, которые вы хотите игнорировать. Аналогичная логика применяется, когда y < x.

4 голосов
/ 02 февраля 2009

Ваше решение имело такую ​​форму: (define (func param) (define ...) (define ...))

Но определить нужно эту форму: (определить (func param) тело)

Тело - это реализация функции ... что она делает, что возвращает. Ваше тело было просто больше определений, никогда ничего не делая. Это объясняет, почему ваше решение не было принято интерпретатором Схемы.

Чтобы ответить на вопрос "являются ли функции схемы однострочными?" вам нужно исследовать форму «начало», которая выглядит следующим образом: (начало (+ 1 1) (+ 2 2)) => 4

В приведенном выше примере результат (+ 1 1) просто отбрасывается, поэтому вы можете видеть, что начало действительно имеет смысл, только если внутри него есть побочные эффекты.

Вы должны знать, что некоторые части Схемы (в частности, let и лямбда) имеют неявное начало вокруг их тела. Так что это действительно:

  (let ((x 1))
    (+ 1 1)
    (+ 2 2))

даже без начала. Это облегчает написание кода.

Наконец, продолжая изучать Схему, всегда старайтесь найти способ сделать что-то без начала и без побочных эффектов. Особенно в первых нескольких главах большинства книг по Схемам, если вы думаете: «Я хочу установить эту переменную, затем я хочу сделать это, а затем это ...», вы, вероятно, оказались в ловушке своего старого способа программирования и не делаете Это Схема пути. Нет ничего плохого в побочных эффектах, но их интенсивное использование означает, что вы на самом деле не программируете Scheme так, как он работает лучше.

4 голосов
/ 02 февраля 2009

Одной из идей схемы является bottom-up programming, где вы создаете функцию для каждой концептуальной операции. Это рекомендуемый подход во многих функциональных языках программирования.

При таком подходе вы получите множество небольших функций, реализующих одну логическую операцию над аргументами. Таким образом, ваш код становится намного более модульным и чистым.

1 голос
/ 18 января 2011

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

(define (square x)
   (* x x))

(define (max x y)
   (if (> x y) x y))

(define (min x y)
   (if (< x y) x y))

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

Процедура sum-of-highest-squares работает путем сложения квадрата максимума x и y (максимум этих двух исключается из наименьшего из трех) и квадрата максимума оставшихся двух (минимум x и y, которые будут в зависимости от того, какое значение было оставлено с первого шага), и z.

Примечание. Это из моего блога Упражнения SICP 1.1 - 1.5 . Там есть ссылки, которые приведут вас ко многим другим решениям SICP.

...