Cusp,Lisp 的 Eclipse 開發環境
Cusp 是 Common Lisp 編程語言的開發環境。使用 Lisp 可以開發所有類型 的應用程序,包括 Web 應用程序。Lisp 是目前仍在使用的第二種最古老的編程 語言(在 Fortran 之後)並被稱為第一種函數語言。Lisp 的創建開始於二十世 紀五十年代後期,並且於 1958 年由 MIT 人工智能 (AI) 項目首次實現。它的 強大之處在於處理列表:AI 和符號數學。實際上,Lisp 是 “list processor ” 的簡寫,正是出於對列表處理器的需求創建了這種編程語言,您將在稍後的 段落中看到相關說明(有關 Lisp 的歷史信息,請參閱 參考資料)。
您將會發現 Lisp 與其他普通的編程語言根本不同。例如,在大多數普通編 程語言中,執行乘法就像您在紙上作運算一樣:int times = 5 * 5;。
使用 Lisp,將通過代碼 (* 5 5 3) 得到 75。要獲得此列表中的最大值,使 用 (MAX 9 8 7 6 20) 將返回 20。
注意,這裡所說的 “第一種函數語言” 十分貼切,因為一切都基於函數。 每個函數都可以有若干數目不定的參數。使用遞歸和諸如 car 和 cdr 之類的 Lisp 函數處理這些列表是使用 Lisp 處理列表的強大之處。
由於 Lisp 歷史較久,因此您可以找到許多適用於 Lisp 的開發環境,但是 ,也存在舊編程語言固有的問題,工具支持大部分都是基於文本的,並且對於新 手來說不夠直觀。因此,嘗試使用 Cusp 的一個原因是它提供了供新手了解和開 發 Lisp 的直觀 GUI,而不使用基於文本的 “嘗試記住所有這些命令” 類型的 界面。它還比 Eclipse GUI 框架固有的 superb 項目管理功能更具優勢。
繼續之前,您需要從 Eclipse.org 下載最新的 Eclipse 標准包。然後了解 如何安裝和設置 Cusp。
安裝 Cusp
現在應當有一個經過壓縮的 Eclipse 標准包歸檔。請將其解壓縮並運行 eclipse.exe。
要獲得最新版本的 Cusp,請單擊 Help > Software Updates > Find and Install。單擊 Search for new features to install 選項。現在單擊 New Remote Site 按鈕。鍵入名稱 Cusp update site 和 URL http://www.sergeykolos.com/cusp/update,然後單擊 OK(參見圖 1)。
圖 1. 為 Cusp 輸入遠程站點信息
單擊已添加的新遠程站點旁邊的復選框並單擊 Finish(參見圖 2)。
圖 2. 選擇 Cusp Eclipse Update Site
系統將顯示另一個窗口,在該窗口中需要展開 Cusp Eclipse Update Site 並選擇 Cusp,如下所示:
圖 3. 選擇要安裝的功能
單擊 Next。然後閱讀許可證協議並單擊 I accept the terms in the license agreement 接受許可證協議,然後單擊 Next。確保選中所有庫,如下 所示,然後再次單擊 Next。
圖 4. 選擇可選功能
最後一個頁面將顯示要安裝功能的安裝匯總。單擊 Finish。插件及其組件將 下載並安裝。下載後,您將收到一則警告,表明將要安裝一個未簽名的功能。單 擊 Install all。在安裝結束時,系統將詢問您是否要重新啟動 Eclipse;請單 擊 Yes。
您已經安裝了 Eclipse Cusp 插件。接下來,將創建一個 Lisp 項目。
創建 Lisp 項目
在開始進行 Lisp 開發之前,必須先創建一個新的 Lisp 項目。您可以通過 轉到 File > New > Project 來完成此操作。展開 Lisp 文件夾,單擊 Lisp Project,然後單擊 Next。為新項目選擇一個名稱 my_new_lisp_project ,如下所示,然後單擊 Finish。
圖 5. 命名新 Lisp 項目
單擊 Finish 後,將創建新項目並打開 Lisp 透視圖,如下所示:
圖 6. Lisp 透視圖
查看 Lisp 透視圖。Lisp Navigator 窗口顯示打開的項目及其相關文件。 Outline 窗口顯示當前打開文件的概要。位於右上側顯示 main.lisp 的窗口是 Lisp 開發窗口。位於右下側的窗口 REPL 是 Lisp 的命令行 Lisp 解析程序, 您可以在這裡運行 Lisp 命令。
如果關閉並重新打開 Eclipse,則需要裝入項目的 .asd 文件,如下所示:
圖 7. 裝入 ASD 文件
注意,需要在 my_new_lisp_project 文件夾下的 my_new_lisp_project.asd 文件上右鍵單擊,然後選擇 Load asd。這實際上就是在 REPL 窗口中編譯 Lisp 項目,允許您輸入可以使用新代碼的 Lisp 命令。
接下來,將嘗試使用 Cusp 進行一些 Lisp 開發。
使用 Cusp 進行 Lisp 開發
首先,還是定義並測試一個簡單的自定義函數。打開 main.lisp 文件,並使 用 defun(定義函數)命令,然後添加以下內容:
...
(defun first_howdy_function ()
"howdy ho")
保存該文件。要從包中導出函數,請在 defpackage.lisp 中鍵入以下代碼:
...
;; Exported symbols go here
first_howdy_function
))
可以從包的外部使用該函數。要測試新函數,請在 REPL 中位置靠下的窗口 中鍵入以下代碼:(my_new_lisp_project:first_howdy_function)。
注意,在您所處的范圍內,這樣做與輸入 (my_new_lisp_project::first_howdy_function) 等效。如果未在 defpackage.lisp 中導出函數,則這是您必須鍵入的代碼。
單擊 Send,然後查看輸出。輸入上面任意一條命令所得到的輸出都是:
COMMON-LISP-USER>
(my_new_lisp_project:first_howdy_function)
"howdy ho"
您已經得到它了:第一個 Lisp Howdy 函數。
嘗試為 echo 函數提供一個輸入:
...
(defun first_echo_function (echoval)
echoval)
同上一個函數一樣,將其導出到 defpackage.lisp 中。在 REPL 窗口中位置 靠下的部分中鍵入以下代碼 (my_new_lisp_project:first_echo_function '("howd" "y h" "o")) 來測試這個 first_echo_function。注意,'("howd" "y h" "o") 部分是用於定義列表的語法。首先,單引號必須放在括號之前,然後在 括號內定義列表元素。輸出如下所示:
COMMON-LISP-USER>
(my_new_lisp_project:first_echo_function '("howd" "y h" "o"))
("howd" "y h" "o")
您將創建一種分別處理每個列表元素的方法,這是 Lisp 的真正強大之處。 定義如下:
(defmethod concat2 ((str1 string) (str2 string))
(concatenate 'string str1 str2))
注意,以上方法實際上定義了一個類型字符串。到現在為止,您一直在使用 Lisp 作為一種大型的無類型語言。雖然雙引號隱式地把數據類型定義為字符串 ,但是以上方法顯式地把 concat2 函數的輸入和輸出類型定義為字符串。此方 法還使用內置的 concatenate 函數把兩個字符串組合在一起,並將其作為單個 字符串返回。
要測試 concat2,請將其導出,然後鍵入 (my_new_lisp_project:concat2 "howd" "y ho")。輸出如下:
清單 7. 連接兩個字符串的輸出
COMMON-LISP-USER>
(my_new_lisp_project:concat2 "howd" "y ho")
"howdy ho"
完成。字符串 "howd" 和 "y ho" 變成 "howdy ho"。現在您將使用兩個著名 的 Lisp car 和 cdr 函數創建更通用化的 concatenation 函數。
清單 1. 連接列表中的三個元素
(defun concat3 (args_list)
(concat2 (car args_list)
(concat2 (car (cdr args_list))
(car (cdr (cdr args_list))))))
注,此函數仍使用 concat2 函數,但是使用參數列表作為輸入。注意如何從 args_list 檢索連接的各個部分。car 將從列表中獲取第一個元素。cdr 將返回 減去第一個元素的列表。只需對列表調用 car 函數就可以看到如何獲得第一個 元素。獲得第二個元素要求對列表調用 cdr,然後對新列表調用 car。通過對列 表兩次調用 cdr 並對得到的列表調用 car 獲取第三個元素。
導出後以上函數的輸出為:
COMMON-LISP-USER>
(my_new_lisp_project:concat3 '("howd" "y h" "o"))
"howdy ho"
就是這樣。已正確連接了三個字符串來生成 "howdy ho"。接下來,創建遞歸 函數。
使用 Lisp 遞歸
將要創建的最後一個函數要執行一些遞歸操作,這是使用 Lisp 進行列表處 理的真正強大之處。迭代是可能實現的(逐個遍歷所有條目),但是不同於諸如 Java 語言之類的普通語言,遞歸是到現在為止 Lisp 中處理列表的最簡單方法 。在本節的末尾,您將明確了解遞歸的含義。
首先創建遞歸的 concat 函數。
清單 2. 遞歸連接(無限制的參數)
1 (defun concat_recursive (args_list)
2 (if (equal (cdr args_list) nil)
3 (car args_list)
4 (concat2 (car args_list)
5 (concat_recursive (cdr args_list)))))
遞歸是十分難於處理的概念,因此讓我們一起來查看這個概念:
假定將任意參數列表傳遞給上面的函數。
如果列表中只有一個元素(第 2 行中的 (cdr args_list) 部分返回 nil) ,則返回單個元素(第 3 行中的 (car args_list))。
如果列表中有多個元素(意味著第 2 行中的 (cdr args_list) 部分未返回 nil),則返回使用 (cdr args_list) 的結果作為參數(參見第 5 行)連接( 使用 concat2)列表的第一個元素(參見第 4 行)與遞歸調用 concat_recursive 的結果的結果。
當傳遞列表 '("ho" "wd" "y" "h" "o") 作為參數時,下面是遞歸輸出:
第一次執行到第 2 行時,if 語句為 false,並用 "ho" 和 (concat_recursive '("wd" "y" " h" "o")) 調用 concat2。
第二次執行到第 2 行時,if 語句又為 false,並用 "wd" 和 (concat_recursive '("y" " h" "o")) 調用 concat2。
第三次執行到第 2 行時,if 語句又為 false,並用 "y" 和 (concat_recursive '(" h" "o")) 調用 concat2。
第四次執行到第 2 行時,if 語句又為 false,並用 " h" 和 (concat_recursive '("o")) 調用 concat2。
第五次遞歸結束。這是因為這一次,第 2 行中的 if 語句現在為 true,並 且簡單地返回了 "o"。遞歸解開為:
第四次:連接並返回 "h" 和 "o"。
第三次:連接並返回 "y" 和 "ho"。
第二次:連接並返回 "wd" 和 "y ho"。
第一次:連接並返回 "ho" 和 "wdy ho" 作為最終結果。
這時就完成了遞歸 —— "howdy ho" 最終被返回,如下所示:
COMMON-LISP-USER>
(my_new_lisp_project:concat_recursive '("ho" "wd" "y" " h" "o"))
"howdy ho"
已經將遞歸添加到了 Cusp 開發工具庫中。接下來請嘗試調試器。
使用 Cusp 進行調試
考慮輸入條件可能會導致 concat_recursive 失敗,因此調試器可能會派得 上用場。一種情況是可以發送一個混有數字的字符串來查看會發生什麼情況。記 住,使用 concat2 進行連接要求使用兩個字符串,因此數字將導致此函數在遞 歸之間中斷。
鍵入以下命令:(my_new_lisp_project:concat_recursive '("ho" "wd" "y" 55 " h" "o"))。注意沒有用雙引號引起的數字 55 不是字符串並將導致顯示調 試器,如下所示:
圖 8. 觸發調試器
注意,觸發調試器的主要錯誤是無法對列表 (55 " ho") 調用 concat2。另 請注意,在觸發該錯誤之前已經連接了 "h" 和 "o"。
在調試器窗口中,您還可以看到 ==Backtrace==,如圖 8 所示。調試器下部 的每行(本例中為 0 至 19 行)給出了從單擊 Send 到發生錯誤的詳細跟蹤。 在這裡,您還可以查看並跟蹤在觸發了錯誤的數字 55 之前的遞歸。
現在做什麼?遇到上面的情況,您有三種選擇退出調試器並修改和驗證函數 輸入:可以中止命令並返回到正常的 REPL 窗口;可以關閉連接(通過測試發現 ,如果選擇此選項,則需要重新引導 Eclipse 來重新啟動 Lisp 處理器);可 以簡單地中止調試器並返回到正常的 REPL 窗口。退出調試器的最佳選項始終是 中止命令並返回到正常的 REPL 窗口。
就是這樣。您已經在 Lisp 中實現了遞歸函數。
結束語
您已經成功地使用 Cusp Eclipse 插件完成了 Lisp 開發。現在應當知道 Lisp 為什麼如此強大。通過簡單的遞歸語句,可以輕松地推動處理符號和數據 列表。Cusp 為 Lisp 的功能補充了內置 Cusp 調試器、擁有項目管理功能的可 靠 GUI、交互式 Lisp 編輯器以及可以輸入命令和測試代碼的 Lisp 處理器命令 行接口。
本文配套源碼