Схема неправильной формы - PullRequest
2 голосов
/ 27 января 2012

Я очень новичок в Scheme и получаю сообщение об ошибке "неправильно сформированная специальная форма", когда пытаюсь использовать эту функцию. Я хочу, чтобы функция возвращала left , если длина original равна 0. В противном случае я хочу, чтобы она выполняла вызовы на добавление и рекурсивный вызов. Я полагаю, я сделал что-то действительно глупое, что вызывает это. Любая помощь?

(define (partition left right original)
(if (= (length original) 0) left
    (append left (car original))
        (append right (car (reverse original)))
              (partition left right (reverse original))))

Ответы [ 2 ]

2 голосов
/ 27 января 2012

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

Вы сталкиваетесь с тем, что многие новички в Схеме сталкиваются с другими языками:

if в Лиспе (включая схему) на самом деле является троичным оператором, а не if блоком из C-подобного мира.

Ваш код пытается представить if более чем тремя формами, поэтому он терпит неудачу. Наивно, что вы могли бы сделать, это использовать блочную конструкцию begin (progn в Common Lisp), чтобы убедиться, что одна ветвь условного содержит только одну форму.

(define (partition left right original)
  (if (= (length original) 0)
      left
      (begin 
        (append left (car original))
        (append right (car (reverse original)))
        (partition left right (reverse original))))) 

Теперь у меня возникает ощущение, что это тоже не будет работать, потому что append работает (то есть возвращает результат без изменения аргументов). Другими словами, ни один из ваших звонков на append ничего не сделает, и original никогда не станет короче. То, что вы на самом деле хотите здесь, это что-то вроде

(define (partition left right original)
  (if (= (length original) 0)
      left
      (partition (cons (car original) left)
                 (cons (last original) right)
                 (cdr (take original (- (length original) 1))))))
2 голосов
/ 27 января 2012

Форма if состоит из 4 частей:

  1. Слово if.
  2. Условие.
  3. Тогдашняя ветвь.
  4. Другая ветвь.

Ваша if -форма, однако, состоит из 6 частей.(= (length original) 0) это условие.left - это ветвь then, а (append left (car original)) - ветвь else.Но какими должны быть две другие?Для читателя очевидно, что они все еще должны быть частью else-ветви, но компилятор не может этого знать.Насколько знает компилятор, вы с таким же успехом могли и для left и (append left ...) перейти в ветвь then, а для двух других - в ветвь else.

Если выЕсли вы хотите выполнить несколько выражений внутри if, вам нужен какой-то способ сгруппировать выражения, принадлежащие одной ветви.Вы делаете это, используя begin следующим образом:

(if condition
  (begin
    (do-something-in-the-then-branch)
    (do-something-else-in-the-then-branch))
  (begin
    (do-something-in-the-else-branch)
    (do-something-else-in-the-else-branch)))

Однако в вашем случае это не поможет, потому что append не работает на месте.Т.е. если вы сделаете (append left (car original)), значение left фактически не изменится.Вместо этого append вернет новый список, содержащий содержимое left и (car original) без фактического изменения любого из списков.Таким образом, чтобы использовать результат append, вам нужно использовать его возвращаемое значение.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...