跳至內容

Lisp 入門/第十章 小例子

維基教科書,自由的教學讀本

從一到八章,我們講解了許多函數,有好多不是公理,我們來一一實現它們(以及一些新的函數)。

這些函數系統都有提供,我們重新發明一遍輪子。這些輪子的簡單程度可以說是令人髮指。

NULL函數

[編輯]

NULL函數用於檢測表是否為空,或者元素是否為nil。

(defun null2 (x) (cond ((equal x nil) t) (t nil))))

解釋:如果參數x與nil相等,就返回t,否則返回nil。這和邏輯學上的not函數是一致的(但null函數的應用範圍更廣,因為它可以應用於表)。

And函數

[編輯]
>(defun and2 (x y) (cond ((equal x nil) nil) ((not (equal y nil)) t) (t nil)))

Or函數

[編輯]
>(defun or2 (x y) (cond ((equal x t) t) ((equal y t) t)))

Last 函數的表示

[編輯]
>(defun last2 (x) (cond ((equal (cdr x) nil) x) (t (last2 (cdr x)))))

Length函數的表示

[編輯]

下面講如何計算一個表x的長(即元素個數)度。

>(defun len (x) (cond ((null x) 0) (t (+ (len (cdr x)) 1))))

遞歸式是(len (cdr x)) ,終結條件是(null x)為真。

Append函數的表示

[編輯]

設參數形式是x和y。很容易分析出來,遞歸式是(cons (car x) (append2 (cdr x) y)),終結條件是當x為NIL時,返回y。

>(defun append2 (x y) (cond ((eq x nil) y) (t (cons (car x) (append2 (cdr x) y)))))

Equal函數的表示

[編輯]

設參數形式是x和y。很容易分析出來,遞歸式是(equal (cdr x) (cdr y)),遞歸條件是(equal (car x) (car y)),終止條件是(equal (cdr x) nil)或者(equal (cdr y) nil)或者((atom x) (equal x y))

(defun equal2 (x y) 
  (cond 
    ((null x) (not y))
    ((null y) (not x))
    ((atom x) (eq x y))
    ((atom y) (eq x y))
    ((not (equal2  (car x) (car y))) nil)
    (t (equal2 (cdr x) (cdr y)))
  )
)

代碼解釋:

   ((null x) (not y))

首先,如果x為空,說明遇到了x列表的末尾,這時檢測y列表是否也到了,如果到了(此時我們知道之前的元素都相等),那麼返回真,否則返回假。

   ((null y) (not x))

如果y到了末尾,一樣處理。

   ((atom x) (eq x y))

如果x是一個原子,說明函數是從(equal2 (car x) (car y))字句進入的,且(car x)的結果為原子。這時函數就可以結束了,返回x=y的結果。

   ((atom y) (eq x y))

如果y是一個原子,說明函數是從(equal2 (car x) (car y))字句進入的,且(car y)的結果為原子。這時函數就可以結束了,返回x=y的結果。

   (t (equal2 (cdr x) (cdr y)))

否則的情況,我們就遞歸。

總結,大家可以發現,其實這個函數的遞歸路徑有兩個。

If函數的表示

[編輯]

用cond可以實現if函數。實際上,在類c語言中,if語句強調的是程序的走向,但在Lisp中,程序的走向可以忽略(從某種意義上),而強調的是返回值。

>(defun if2 (p e1 e2)
 (cond (p e1) (t e2))
 )

IF2

--需要一個while實現的例子。