Матрица Добавить Лисп - PullRequest
1 голос
/ 27 мая 2010
    (defun (matrix-add m1 m2)

  (defun (matrix-add-row r1 r2 res-row)
    (if (and (not (null? r1)) (not (null? r2)))
    (matrix-add-row (cdr r1) (cdr r2)
            (cons (+ (car r1) (car r2)) res-row))
    (reverse res-row)))

  (defun (matrix-add-each m1 m2 res)
    (if (and (not (null? m1)) (not (null? m2)))
    (let ((res-row (matrix-add-row (car m1) (car m2) ())))
      (matrix-add-each (cdr m1) (cdr m2) (cons res-row res)))
    (reverse res)))
  (matrix-add-each m1 m2 ()))

Привет, я добавляю матрицу на листе бумаги, но теперь она работает, когда я печатаю в lisp .. Что не так?

1 Ответ

8 голосов
/ 27 мая 2010

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

В синтаксисе Common-Lisp это работает как ожидалось:

(defun matrix-add (m1 m2)
  (labels 
    ((matrix-add-row (r1 r2 res-row)
      (if (and (not (null r1)) (not (null r2)))
        (matrix-add-row (cdr r1) (cdr r2)
          (cons (+ (car r1) (car r2)) res-row))
        (reverse res-row)))

    (matrix-add-each (m1 m2 res)
      (if (and (not (null m1)) (not (null m2)))
        (let ((res-row (matrix-add-row (car m1) (car m2) ())))
          (matrix-add-each (cdr m1) (cdr m2) (cons res-row res)))
        (reverse res))))

    (matrix-add-each m1 m2 ())))

> (matrix-add `((1 2) (3 4)) `((10 20) (30 40)))
((11 22) (33 44))

Несколько вещей более многословны, чем здесь требуется.

Во-первых, в общем lisp nil равен false, а and возвращает последний аргумент, который не равен false.

> (and () `(1))
NIL
> (and `(1) `(1))
(1)
> (and `(1) `(3))
(3)
> (and `(1) ())
NIL

так что в вашем случае, в общем случае, вам не нужны все ненулевые тесты.

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

  (defun matrix-add-row (r1 r2)
    (if (and r1 r2)
      (cons (+ (car r1) (car r2)) (matrix-add-row (cdr r1) (cdr r2)))
      ()))

> (matrix-add-row `(1 2 3 4) `(10 20 30 40))
(11 22 33 44)

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

Таким образом, вы будете склонны использовать функции карты для работы с простыми списками, а не писать свои собственные. Макрос считывателя #' (сокращение от function) извлекает функцию из символа, поэтому для применения функции + к элементам двух списков можно использовать mapcar:

> (mapcar #'+ `(1 2 3 4) `(10 20 30 40))
(11 22 33 44)

Это устраняет сложность написания контрольной панели для рекурсивного применения, может быть более эффективным и выражает намерение более высокого уровня.

Поскольку вам больше не нужен аккумулятор, вам не нужно определять matrix-add-each, а вместо этого можно просто вернуть результат применения функции add-row к каждой строке в матрице:

(defun matrix-add (m1 m2) 
  (flet ((matrix-add-row (r1 r2) (mapcar #'+ r1 r2)))
    (mapcar #'matrix-add-row m1 m2)))

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

(defun matrix-add (m1 m2)
  (mapcar (lambda (r1 r2) (mapcar #'+ r1 r2)) m1 m2))

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

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

Как отмечалось в комментариях, defun создает глобальную привязку функции, flet и labels в локальной области видимости.

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