(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 ()))
Run Code Online (Sandbox Code Playgroud)
嗨我在一张纸上添加了矩阵,但是当我输入lisp时它现在正在工作..出了什么问题?
首先,语法既不是普通的lisp也不是方案,这两种主要的lisp方言是常用的.
在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))
Run Code Online (Sandbox Code Playgroud)
这里有一些比这里要求的更冗长的东西.
首先,在常见的lisp中,nil为false,并and返回最后一个非false的参数.
> (and () `(1))
NIL
> (and `(1) `(1))
(1)
> (and `(1) `(3))
(3)
> (and `(1) ())
NIL
Run Code Online (Sandbox Code Playgroud)
所以在你的情况下,在常见的lisp中,你不需要所有非null测试.
其次,使用尾递归函数而不是基于累加器的函数是常见的(在方案中比在lisp中更常见),因此在不使用库函数的情况下添加两个列表通常需要两个列表,并返回一个列表,其头部是两个列表的头部之和,其尾部是添加每个列表尾部元素的结果.因此,不是采用三个参数(输入,输入,累加器),而是反转累加器,而是将函数编写为接受两个参数并根据这两个参数返回结果的一部分.
(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)
Run Code Online (Sandbox Code Playgroud)
但是这种将函数应用于列表汽车并将函数应用于列表其余部分的模式非常常见,因此它有一组库函数 - 映射族.
所以你倾向于使用map函数来操作简单的列表而不是自己编写.该#'阅读器的宏(简称function)提取从符号的功能,因此对应用+功能的两个列表,你可以使用的元素mapcar:
> (mapcar #'+ `(1 2 3 4) `(10 20 30 40))
(11 22 33 44)
Run Code Online (Sandbox Code Playgroud)
这消除了必须为递归应用程序编写样板的复杂性,它可能更有效,并表达更高级别的意图.
由于您不再需要累加器,因此您无需定义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)))
Run Code Online (Sandbox Code Playgroud)
或者您甚至可以使用lambda而不是单独定义函数,尽管可能更容易阅读拆分版本以开始:
(defun matrix-add (m1 m2)
(mapcar (lambda (r1 r2) (mapcar #'+ r1 r2)) m1 m2))
Run Code Online (Sandbox Code Playgroud)
虽然对于"真实"函数,您可能需要检查矩阵是否大小相同且行的大小相同,这比单行函数更复杂.但是对于真正的矩阵代码,你可能想要使用数组而不是列表.
一旦你开始考虑列表上的函数和在列表上应用函数的函数,你就会发现你必须做更少的工作才能让lisp做你想做的事情.
正如评论所指出的,defun创建一个全局函数绑定,flet并labels在本地范围内.