基本概念
列表
列表由括號括起來揭朝,元素由空格分開队贱。
'(rose violet daisy buttercup)
在LISP中,數(shù)據(jù)和程序都以同樣的方式表示潭袱。都是由空格分隔的柱嫌、由括號括起來的單詞、數(shù)字或者其他列表的列表屯换。列表是LISP的基礎(chǔ)编丘。
原子
原子是LISP里面不可分割的部分。在一個列表中彤悔,原子是由空格意義分割的嘉抓,原子可以緊接著括號。
LISP的一個列表有三中可能的組成方式:
- 括號和括號中由空格分割的原子
- 括號和括號中的其他列表
- 括號和括號中的其他列表及原子
一個沒有任何原子的列表就像這樣()
晕窑,它被稱為空列表抑片,可以把它同時看做既是一個原子,也是一個列表杨赤。
在LISP的日常使用習(xí)慣中敞斋,“原子”一詞不太常用,LISP編程幾乎都是關(guān)于列表中的符號的疾牲。另外植捎,在LISP中,所有用雙引號括起來的文本阳柔,包括標(biāo)點符號和空格焰枢,都是單個原子盔沫。這種原子被稱為string医咨。
求值
當(dāng)LISP解釋器處理一個表達(dá)式時,這個動作被稱為“求值”架诞。我們稱拟淮,解釋器計算表達(dá)式的值。
對一個內(nèi)部列表求值
如果對一個嵌套在另一個列表中的列表求值很泊,對外部列表求值時可以使用受限對內(nèi)部列表求值所得的結(jié)果沾谓。這解釋了為什么內(nèi)存列表總是首先被求值的:因為它們的返回值被首先用于外部表達(dá)式。
(+ 2 (+ 3 3))
數(shù)字8
就會顯示在回顯區(qū)昏兆。
變量
LISP中妇穴,可以降一個值賦給一個符號爬虱,就像降一個函數(shù)定義賦給一個符號那樣隶债。但兩者含義不同。
- 函數(shù)定義時一組指令跑筝,這組指令是由計算機(jī)執(zhí)行的死讹。
- 一個符號的值可以是LISP中的任意表達(dá)式,如一個符號曲梗、一個數(shù)字赞警、一個列表或者一個字符串。幼稚的一個符號被稱為一個變量虏两。
- 一個符號可以同時具有一個函數(shù)定義和一個值愧旦。
LISP風(fēng)格“Hello World"
讓REPL打印“Hello World”再簡單不過。
CL-USER> "hello world"
"hello world"
其工作原理是碘举,因為字符串和數(shù)字一樣忘瓦,帶有LISP讀取器可以理解的字面語法并且是自求值對象;LISP讀取雙引號里的字符串引颈,求值的時候在內(nèi)存里簡歷一個可以對自身求值的字符串對象,然后再以相同的語法打印出來境蜕。雙引號本身不是在內(nèi)存中的字符串對象的一部分——它們只是語法蝙场,用來告訴讀取器讀入一個字符串。而打印器之所以在打印字符串時帶上它們粱年,則是因為其試圖以奕宗讀取器可以理解的相同語法來打印對象售滤。
函數(shù)
函數(shù)是LISP的基本程序構(gòu)造單元,可以用類似下面的defun
表達(dá)式來定義:
CL-USER> (defun hello-world () (format t "hello world"))
HELLO-WORLD
defun
后面的hello-world
是這個函數(shù)的名字台诗。像hello-world
這種用連字符而不是下劃線或是內(nèi)部大寫來形成復(fù)合詞的方法完箩,是標(biāo)準(zhǔn)的LISP風(fēng)格。
表面上看拉队,這個表達(dá)式和你目前見到的所有其他表達(dá)式一樣弊知,只是另一個被REPL
讀取、求值和打印的表達(dá)式粱快。這里返回值是你所定義的函數(shù)名秩彤。但是和format
表達(dá)式一樣,這個表達(dá)式的副作用比返回值更有用事哭。但與format
表達(dá)式所不同的是漫雷,它的副作用是不可見的:當(dāng)這個表達(dá)式被求值時,一個不帶參數(shù)且函數(shù)體為(format t "hello world")
的新函數(shù)會被創(chuàng)建出來并被命名為HELLO-WORLD
鳍咱。
一旦定義了這個函數(shù)降盹,你就可以像這樣來調(diào)用它:
CL-USER> (hello-world)
hello world
NIL
保存工作結(jié)果
在Emacs中可以通過輸入C-x C-f
來創(chuàng)建一個新文件,然后根據(jù)Emacs的提示輸入文件的名字谤辜。文件存放的位置并不重要蓄坏。Common Lisp源文件習(xí)慣上帶有.lisp
擴(kuò)展名仅胞,盡管有些人用.cl
來代替。
一旦創(chuàng)建了文件剑辫,就可以向其中寫入之前在REPL里面輸入過的定義干旧。需要注意的是,在輸入了開括號和defun
以后妹蔽,在Emacs窗口的底端椎眯,slime將會提示它所期待的參數(shù)。**具體形式取決于具體Common Lisp實現(xiàn)胳岂,但其形式可能如下所示编整。
(defun name varlist &rest body)
在文件中輸入以下內(nèi)容:
(defun hello-world ()
(format t "hello world"))
可用集中方式將這個定義輸入到LISP環(huán)境中,最簡單的是當(dāng)光標(biāo)位于defun
定義內(nèi)部的任何位置時乳丰,輸入C-c C-c
掌测,這將啟動slime-compile-defun
命令,將當(dāng)前定義發(fā)給LISP進(jìn)行求值并編譯产园。
輸入C-c C-z
切換到REPL中可以嘗試調(diào)用新函數(shù)汞斧。
CL-USER> (hello-world)
hello world
NIL
輸入C-x C-s
可以啟動Emacs命令save-buffer
。
嘗試從源文件加載這個函數(shù)什燕,著需要退出并重啟LISP環(huán)境粘勒。
執(zhí)行退出操作可以使用一個slime快捷鍵:在REPL中輸入一個逗號。然后在Emacs窗口底部將提示你輸入命令屎即,輸入
quit
庙睡,然后按回車。這將退出LISP并且關(guān)閉所有slime創(chuàng)建的緩沖區(qū)技俐。
現(xiàn)在重啟slime乘陪,使用M-x slime
。
這里有幾種方式讓LISP知道hello-world
的定義雕擂。
- 使用
C-x b
,在其提示時輸入hello.lisp
以切換回含有那個文件的緩沖區(qū)啡邑,然后像之前那樣重新編譯定義。 - 加載整個文件捂刺。
CL-USER> (load "hello.lisp")
T