Ошибка в Лиспе: спецификация привязки LET искажена - PullRequest
0 голосов
/ 24 октября 2018

Я действительно новичок в обычном Лиспе и испытываю некоторые трудности.Я работаю над функцией, которая дает x , y и массив с индексом для вертикального значения возвращает NIL , если естьдиагональ элемента от (xy).

(defun diagonal? (x y array)
    (loop for line from 0 to 19 do
        (let (col (aref array line)) (
            (if (= col -1) (return-from diagonal? t))
            (let (diag (= (abs (- x line)) (abs (- y col)))) (
                if (= diag T) (return-from diagonal? NIL))
            )
    )))
    return T
)

Когда я пробую эту функцию, я получаю следующую ошибку:

; caught ERROR:
;   The LET binding spec (AREF ARRAY LINE) is malformed.

;     (SB-INT:NAMED-LAMBDA DIAGONAL?
;         (X Y ARRAY)
;       (BLOCK DIAGONAL?
;         (LOOP FOR LINE FROM 0 TO 19
;               DO (LET (COL #)
;                    (# #)))
;         RETURN
;         T))

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Первое и чрезвычайно важное: используйте автоматический отступ.

(defun diagonal? (x y array)
  (loop for line from 0 to 19 do
        (let (col (aref array line)) (
                                      (if (= col -1) (return-from diagonal? t))
                                      (let (diag (= (abs (- x line)) (abs (- y col)))) (
                                                                                        if (= diag T) (return-from diagonal? NIL))
                                        )
                                      )))
  return T
  )

Тогда ваш код выглядит странно с длинными строками: никогда не ставьте круглые скобки на своей собственной строке и никогда не заканчивайте строку открытыми скобками.

Улучшено:

(defun diagonal? (x y array)
  (loop for line from 0 to 19 do
        (let (col (aref array line))
          ((if (= col -1)
               (return-from diagonal? t))
           (let (diag (= (abs (- x line))
                         (abs (- y col))))
             (if (= diag T)
                 (return-from diagonal? NIL))))))
  return T)

Второе: LET ожидает список привязок.Одиночная привязка - это переменная или (variable value):

(defun diagonal? (x y array)
  (loop for line from 0 to 19 do
        (let ((col (aref array line)))
          ((if (= col -1)
               (return-from diagonal? t))
           (let ((diag (= (abs (- x line))
                          (abs (- y col)))))
             (if (= diag T)
                 (return-from diagonal? NIL))))))
  return T)

Третье: LET ожидает тело форм Lisp.Это ноль или более форм Lisp:

(defun diagonal? (x y array)
  (loop for line from 0 to 19 do
        (let ((col (aref array line)))
          (if (= col -1)
               (return-from diagonal? t))
          (let ((diag (= (abs (- x line))
                         (abs (- y col)))))
            (if (= diag T)
                (return-from diagonal? NIL)))))
  return T)

Четвертый: = ожидает числа в качестве аргументов.T это не число.= уже возвращает T или NIL, которые мы можем проверить.

(defun diagonal? (x y array)
  (loop for line from 0 to 19 do
        (let ((col (aref array line)))
          (if (= col -1)
              (return-from diagonal? t))
          (if (= (abs (- x line))
                 (abs (- y col)))
              (return-from diagonal? NIL))))
  return T)

Пятый: return T не является допустимой формой Лисп.Мы можем просто вернуть T напрямую.

(defun diagonal? (x y array)
  (loop for line from 0 to 19 do
        (let ((col (aref array line)))
          (if (= col -1)
              (return-from diagonal? t))
          (if (= (abs (- x line))
                 (abs (- y col)))
              (return-from diagonal? NIL))))
  T)

Шестое: нам не нужно LET для col, мы можем заменить его на FOR в LOOP.

(defun diagonal? (x y array)
  (loop for line from 0 to 19
        for col = (aref array line)
        do
        (if (= col -1)
            (return-from diagonal? t))
        (if (= (abs (- x line))
               (abs (- y col)))
            (return-from diagonal? NIL))))
  T)

Седьмое: кратное IF может быть записано как одно COND.

(defun diagonal? (x y array)
  (loop for line from 0 to 19
        for col = (aref array line)
        do (cond ((= col -1)
                  (return-from diagonal? t))
                 ((= (abs (- x line))
                     (abs (- y col)))
                  (return-from diagonal? nil))))
  t)

Восьмое: for from 0 to n можно заменить на below (+ n 1) или upto n

(defun diagonal? (x y array)
  (loop for line below 20
        for col = (aref array line)
        do (cond ((= col -1)
                  (return-from diagonal? t))
                 ((= (abs (- x line))
                     (abs (- y col)))
                  (return-from diagonal? nil))))
  t)

Девятое: поскольку (RETURN-FROM ... T) возвращается из функции, которая по умолчанию возвращает T, мы можем заменить ее на предложение UNTIL в цикле:

(defun diagonal? (x y array)
  (loop for line below 20
        for col = (aref array line)
        until (= col -1)
        when (= (abs (- x line))
                (abs (- y col)))
        do (return-from diagonal? nil))
  t)

Десятое: поскольку col - это просто итерация значений массива:

(defun diagonal? (x y array)
  (loop for line below 20
        for col across array
        until (= col -1)
        when (= (abs (- x line))
                (abs (- y col)))
        do (return-from diagonal? nil))
  t)

Одиннадцатое: предложение @Coredump, используйте NEVER.По умолчанию возвращаемое значение LOOP теперь равно T.Возврат только тогда nil, когда предложение never не выполнено.

(defun diagonal? (x y array)
  (loop for line below 20
        for col across array
        until (= col -1)
        never (= (abs (- x line))
                 (abs (- y col)))))
0 голосов
/ 24 октября 2018

Согласно CLHS a let имеет следующую структуру:

(let (var  (var2 expression))
  body ...)

Здесь первая привязка не имеет значения, но она совпадает с записью:

(let ((var nil) (var2 expression))
  body ...)

Ваши привязки выглядят так:

(let (col                  ; col initialized to nil OK
     (aref array line))    ; variable aref initialized to?
 ...)

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

(let ((col (aref array line)))
  ...)

Также я заметил, что у вас есть ( в той же строке, как если бы вы делали блок.Это не сработает, поскольку ((if ....)) не является допустимым кодом Common Lisp.Вы получаете ошибку, что оператор должен быть именованной функцией или лямбда-выражением.let является блоком, поэтому начало (let ...) создает блок, так что вы можете иметь множество выражений внутри без лишних скобок.

...