在 lisp 中创建卡方函数。 [初学者]

Creating a chi square function in lisp. [beginner]

首先,对于这样一个新手问题,我深表歉意。 我的目标不仅仅是创建卡方函数,而是了解如何避免我遇到的一般问题。

我的代码如下所示:

(defun chi-square (expected-list observed-list)
(cond ((not (= (length expected-list) (length observed-list))) (print "Lists do not match in length.~%"))
    ((and (null expected-list) (null observed-list)) 0)
    (+ (/ (square (- (car observed-list) (car expected-list))) (car expected-list)) 
       (chi-square (cdr expected-list) (cdr observed-list)))
)
)

我认为第三个条件工作正常,除非它在 ​​nil 和 nil 上调用卡方时输出只是读取 0。我理解为什么会发生这种情况(因为第二个条件),但我不知道如何避免它。例如,如果我给它一个 (100 50) 的预期列表和一个 (90 60) 的观察列表,我希望它输出 (+ 1 (+ 2 0)) = 3。我怎样才能给出 (chi-square nil nil) 值 0 而不是立即结束函数?

免责声明:我相信有更好的方法可以做到这一点,也许已经有一些功能可以做到这一点。我写这个函数只是为了学习目的。

第三种cond情况出错:求和前少了t

(defun chi-square (expected-list observed-list)
  (cond ((not (= (length expected-list) (length observed-list)))
         (print "Lists do not match in length.~%"))
        ((and (null expected-list) (null observed-list)) 0)
        (t (+ (/ (square (- (car observed-list) (car expected-list))) (car expected-list))
              (chi-square (cdr expected-list) (cdr observed-list))))))

您可以在 specification.

中找到 cond 宏的语法

通常,您希望避免在递归同一列表的过程中调用类似 length 的内容。那是因为 length 的 运行 时间与你给它的列表的长度成正比,你最终会得到一个 O(N^2) 算法,因为你在原始列表。如果您的列表总是很短,那也没关系。最好在例程开始时只测试一次列表长度,或者在列表中的一个是 null 而另一个不是时在最后退出。不管怎样,这里有一些其他的方法来编写这个函数:

;using built-in recursion combinators (mapcar & reduce)
(defun χ² (expected observed)
  (reduce #'+ (mapcar (lambda (e o) (/ (square (- o e)) e)) expected observed)))

;using loop
(defun chi-sqr (expected observed)
  (loop
     for e in expected
     for o in observed
     summing (/ (square (- o e)) e)))