newLISP 簡介/基礎
安裝說明可在 newlisp.org 找到。
安裝 newLISP 後,有各種方法可以執行它。有關詳細資訊,請參閱 newLISP 文件。最直接的方法是透過在控制檯或終端視窗中鍵入 newlisp 命令來從命令列執行 newLISP 直譯器。
$ newlisp newLISP v.x on OSX IPv4 UTF-8, execute 'newlisp -h' for more info. >
這對於嘗試簡短的表示式、測試想法和除錯非常有用。您可以在此環境中編寫多行程式碼,方法是在 [cmd] 和 [/cmd] 之間包含這些行。在新版本中,您只需在空白行上使用回車鍵即可開始和結束多行塊。
>[cmd]
(define (fibonacci n)
(if (< n 2)
1
(+ (fibonacci (- n 1))
(fibonacci (- n 2)))))
[/cmd]
>(fibonacci 10)
89
>
newLISP 的視覺化介面 newLISP-GS 為 newLISP 應用程式提供了圖形工具包,它還為您提供了用於編寫和測試程式碼的開發環境:newLISP 編輯器。在 Windows 上,它以桌面圖示和程式開始選單中的資料夾的形式安裝。在 MacOS X 上,應用程式包和圖示安裝在應用程式資料夾中。newLISP-GS 編輯器為您提供多個帶標籤的視窗、語法著色以及一個用於檢視執行程式碼結果的監視區域。
您還可以從命令列執行 newLISP-GS 編輯器:您可以在 C:/Program Files/newlisp/newlisp-edit(Windows)或 /usr/bin/newlisp-edit(在 Unix 上)找到該檔案。(這是一個 newLISP 原始檔,因此您也可以檢視程式碼。)
您可以在自己喜歡的文字編輯器中編輯 newLISP 指令碼。在 MacOS X 上,您可以使用 BBEdit、TextWrangler 或 TextMate 執行 newLISP 指令碼,或者您可以使用預安裝的 Unix 文字編輯器,例如 vim 或 emacs。在 Windows 上,您可以使用 UltraEdit、EditPlus 或 NotePad++,僅舉幾例。如果您使用 Linux,您比我更瞭解文字編輯器,您可能已經有自己的偏好。
newLISP 網站在 http://newlisp.org/index.cgi?Code_Contributions 主持多個流行編輯器的配置檔案。
在 Unix 上,newLISP 指令碼的第一行應該是
#!/usr/local/bin/newlisp
或者
#!/usr/bin/env newlisp
如果您更喜歡在外部文字編輯器中執行 newLISP,則必須使用更多 println 函式來檢視每個函式或表示式返回的值。
通常,您使用 exit 函式結束 newLISP 指令碼或控制檯會話
(exit)
您只需要學習三個基本規則來使用 newLISP 進行程式設計。以下是第一個規則
列表是被括號括起來的元素序列
(1 2 3 4 5) ; a list of integers
("the" "cat" "sat") ; a list of strings
(x y z foo bar) ; a list of symbol names
(sin cos tan atan) ; a list of newLISP functions
(1 2 "stitch" x sin) ; a mixed list
(1 2 (1 2 3) 3 4 ) ; a list with a list inside it
((1 2) (3 4) (5 6)) ; a list of lists
列表是 newLISP 中的基本資料結構,也是您編寫程式程式碼的方式。但現在還不要輸入這些示例——還有兩個規則要學習!
當 newLISP 看到一個列表時,它會將第一個元素視為一個函式,然後嘗試使用其餘元素作為該函式所需的資訊。
(+ 2 2)
這是一個包含三個元素的列表:名為 + 的函式,後面跟著兩個數字。當 newLISP 看到這個列表時,它會對其進行評估並返回 4(當然)的值。請注意,第一個元素被 newLISP 視為一個函式,而其餘元素被解釋為該函式的引數——函式期望的數字。
以下是一些更進一步的示例,說明了這兩個基本規則
(+ 1 2 3 4 5 6 7 8 9)
返回 45。+ 函式將列表中的所有數字加起來。
(max 1 1.2 12.1 12.2 1.3 1.2 12.3)
返回 12.3,即列表中最大的數字。同樣,列表的長度沒有(合理的)限制:如果一個函式樂於接受 137 個專案(max 和 + 都可以),那麼您可以傳遞 137 個專案。
(print "the sun has put his hat on")
"the sun has put his hat on"
列印字元字串 the sun has put his hat on。(它還會返回字串,這就是為什麼當您在控制檯中工作時,有時會看到事物重複出現兩次。)print 函式可以列印單個字元字串,或者您可以提供要列印的元素序列
(print 1 2 "buckle" "my" "shoe")
12bucklemyshoe
它會列印兩個數字和三個字串(雖然格式不太好,因為您還沒有接觸到 format 函式)。
directory 函式
(directory "/")
生成指定目錄(在本例中為根目錄 "/")的列表
("." ".." ".DS_Store" ".hotfiles.btree" ".Spotlight-V100"
".Trashes"".vol" ".VolumeIcon.icns" "Applications"
"automount" "bin" "cores" "Desktop DB" "Desktop DF"
"Desktop Folder" "dev""Developer" "etc" "Library"
"mach" "mach.sym" "mach_kernel" "Network" "private"
"sbin" "System" "System Folder" "TheVolumeSettingsFolder"
"tmp" "User Guides And Information" "Users" "usr"
"var" "Volumes")
如果您沒有指定目錄,它會列出當前目錄
(directory)
("." ".." "2008-calendar.lsp" "allelements.lsp" "ansi.lsp"
"binary-clock.lsp" ... )
有一個 read-file 函式可以讀取文字檔案的內容
(read-file "/usr/share/newlisp/modules/stat.lsp")
這裡,該函式需要一個引數——檔名——並將檔案的內容以字串形式返回給您。
這些是 newLISP 程式碼構建塊的典型示例——包含函式呼叫的列表,後面可能還有該函式需要的任何額外資訊。newLISP 有 380 多個函式,您可以參考出色的 newLISP 參考手冊以瞭解所有函式的詳細資訊以及如何使用它們。
您可以嘗試這些示例。如果您在終端中使用 newLISP,只需輸入它們即可。如果您將這些行輸入文字編輯器並將其作為指令碼執行,除非您將表示式包含在 println 函式中,否則您可能不會看到函式呼叫的結果。例如,鍵入
(println (read-file "/usr/share/newlisp/modules/stat.lsp"))
以列印 read-file 函式的結果。
每個 newLISP 表示式都會返回一個值。即使是 println 函式也會返回一個值。您可以說,列印操作實際上只是一個副作用,其主要任務是返回一個值。您可能會注意到,當您在控制檯視窗中以互動方式使用 println 時,您會看到返回值出現兩次:一次是列印時,一次是返回值返回到呼叫函式(在本例中為頂層)時。
在您學習第三條規則之前,還有一件有用的事情需要檢視。
您已經發現一個列表巢狀在另一個列表中。以下是一個示例
(* (+ 1 2) (+ 3 4))
當 newLISP 看到這個時,它會思考如下
嗯。讓我們從那些內部列表中的第一個開始。我可以輕鬆地做到
(+ 1 2)
它的值是 3。我也可以輕鬆地做到第二個列表
(+ 3 4)
足夠簡單。它評估為 7。
因此,如果我將這兩個內部列表替換為這些值,我將得到
(* 3 7)
這真的很容易。我將為這個表示式返回 21 的值。
(* (+ 1 2) (+ 3 4))
(* 3 (+ 3 4))
(* 3 7)
21
看到第一行末尾的兩個右括號嗎?它們都是必要的:第一個括號結束 (+ 3 4 列表,第二個括號結束以 (* 開頭的乘法運算。當您開始編寫更復雜的程式碼時,您會發現自己將列表放入列表中,再放入列表中,再放入列表中,並且您可能會以六個右括號來結束一些更復雜的定義。一個好的編輯器會幫助您跟蹤它們。
但是您不必擔心空格、行終止符、各種標點符號或強制縮排。並且由於所有資料和程式碼都以相同的方式(在列表中)儲存,因此您可以自由地混合它們。稍後會詳細介紹。
有些人第一次看到 LISP 程式碼時會擔心括號氾濫。其他人稱它們為指甲碎片,或者說 LISP 代表大量的令人討厭的愚蠢括號。但我更喜歡將括號視為包圍 newLISP 思想的小把手
當您在好的編輯器中編輯 newLISP 程式碼時,您可以透過抓住其控制代碼輕鬆地移動或編輯一個想法,並使用“平衡括號”命令輕鬆地選擇一個想法。您很快就會發現括號比您最初認為的更有用!
現在您可以使用 newLISP 瞭解程式設計的第三條規則
要停止 newLISP 評估某個內容,請引用它。
比較這兩行
(+ 2 2)
'(+ 2 2)
第一行是一個列表,包含一個函式和兩個數字。在第二行中,該列表被引用 - 在前面有一個單引號或撇號 (')。您不需要在結束括號後新增另一個引號,因為一個就足夠了。
> (+ 2 2)
4
> '(+ 2 2)
(+ 2 2)
>
對於第一個表示式,newLISP 照常執行其工作,並熱心地評估該列表,返回數字 4。但對於第二個表示式,newLISP 一看到引號,就不會考慮透過新增數字來評估該列表;它只返回該列表,不進行評估。
此引號在 newLISP 中的作用與書面英語中的開閉引號相同 - 它們告訴讀者該單詞或短語不要按通常方式解釋,而要以某種特殊方式對待:非標準或諷刺的含義,也許是另一個人說的話,或者是不應該照字面理解的東西。
那麼,為什麼您要阻止 newLISP 評估事物呢?您很快就會遇到一些示例,其中您引用事物以防止 newLISP 認為列表中的第一個專案是一個函式。例如,當您將資訊儲存在列表中時,您不希望 newLISP 以通常的方式評估它們
(2006 1 12) ; today's year/month/date
("Arthur" "J" "Chopin") ; someone's full name
您不希望 newLISP 尋找名為2006或"Arthur"的函式。此外,2006不是有效的函式名,因為它以數字開頭,函式名不能以雙引號開頭,因此在任何情況下您的程式都會停止並出現錯誤。因此,您需要引用列表以阻止其第一個元素用作函式而不是資料
'(2006 1 12) ; evaluates to (2006 1 12)
'("Arthur" "J" "Chopin") ; evaluates to ("Arthur" "J" "Chopin")
newLISP 將表示式視為資料 - 以及將資料視為表示式 - 的能力將在後面詳細討論。
使用垂直撇號(ASCII 碼 39)來引用列表和符號。有時,文字編輯器或其他程式會將這些簡單的垂直撇號更改為花括號。它們的作用不同,因此您必須將所有智慧引號更改為垂直撇號。
符號是帶有名稱的 newLISP事物。您在程式碼中定義了一些東西併為其分配一個名稱。然後,您可以在以後使用該名稱而不是內容來引用該東西。例如,在鍵入以下內容後
(set 'alphabet "abcdefghijklmnopqrstuvwxyz")
現在有一個名為alphabet的新符號,其值為一個字串,該字串包含字母表的 26 個字母。set函式將從 a 到 z 的字元字串儲存在alphabet符號中。現在,此符號可以在其他地方使用,並在使用時始終評估為字母表。每當您想要使用字母表的 26 個字母時,您都會使用此符號,而不會引用它。例如,以下是upper-case函式
(upper-case alphabet)
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
我使用該符號而不引用它,因為我想要 newLISP 使用該符號的值,而不是其名稱。我實際上對將單詞alphabet轉換為大寫不感興趣,而是對字母表本身感興趣。在本例中,newLISP 沒有永久更改符號的值,因為upper-case始終建立並返回一個新字串,使儲存在符號中的字串保持不變。
符號對應於其他程式語言中的變數。實際上,newLISP 使用符號的頻率並不像其他語言使用變數那樣高。這部分是因為值會不斷地由表示式返回並直接饋送到其他表示式,而無需儲存。例如,在以下程式碼中,每個函式都會將其結果直接傳遞給下一個包含函式
(println (first (upper-case alphabet)))
"A"
upper-case將其返回值直接傳遞給first,first將其返回值直接傳遞給println,println既列印它,也為您提供它列印的字串作為返回值。因此,沒有必要臨時儲存值。但還有很多其他地方您確實需要符號。
以下是符號引用的另外兩個示例
(define x (+ 2 2 ))
(define y '(+ 2 2))
在第一個示例中,我沒有引用(+ 2 2)列表 - newLISP 將其評估為 4,然後將 4 分配給符號x,它評估為 4
x
;-> 4
在第二個示例中,我引用了該列表。這意味著符號y現在儲存的是一個列表,而不是一個數字。每當 newLISP 看到符號y時,它都會返回該列表,而不是 4。(當然,除非您也先引用y!)
y
;-> (+ 2 2)
'y
;-> y
順便說一下,在本文件中
; the semicolon is the comment character
;-> that ";->" is my way of saying "the value is"
以及 newLISP 直譯器列印的輸出通常顯示為
like this
建立和設定符號值的方法有很多。您可以使用define或set,如下所示
(set 'x (+ 2 2))
;-> 4
(define y (+ 2 2))
;-> 4
set期望後面跟著一個符號,但首先會評估其第一個引數。因此,您應該引用一個符號以防止它被評估(因為它可能評估為除符號以外的其他東西),或者提供一個評估為符號的表示式。define不期望引數被引用。
您還可以使用setf和setq來設定符號的值。這些期望第一個引數為符號或符號引用,因此您不必引用它。
(setf y (+ 2 2))
;-> 4
(setq y (+ 2 2))
;-> 4
這兩個函式(它們具有相同的操作)可以設定符號(變數)、列表、陣列或字串的內容。一個約定是在設定符號時使用setq,在設定列表或陣列的元素時使用setf。
define還用於定義函式。參見建立您自己的函式.
一些 newLISP 函式會修改它們操作的符號的值,而另一些則會建立值的副本並返回該副本。從技術上講,修改符號內容的函式被稱為破壞性函式 - 儘管您通常會使用它們來建立新資料。在本檔案中,我將描述諸如push和replace之類的函式為破壞性函式。這僅僅意味著它們會改變某個東西的值,而不是返回一個修改後的副本。

