common Lisp学习笔记(十二)
?
- 12 Structure and The Type Syetem
- 12.2 typep, type-of
- 12.3 defining structures
- 12.5 accessing, modifying structs
- 12.6 kwargs to constructor functions
- 12.7 修改結(jié)構(gòu)體定義
- 12.8 print func for structs
- 12.9 equality of structs
- 12.10 inheritance
12 Structure and The Type Syetem
總結(jié)一下前面學(xué)習(xí)過的lisp的基本類型,有number, symbol, cons, string, function, stream等,這些都是最基本的 數(shù)據(jù)類型. structures結(jié)構(gòu)體是用戶定義的數(shù)據(jù)類型,與其他語言類似
12.2 typep, type-of
(typep 3 'number) -> t (typep 3 'integer) -> t (typep 'foo 'symbol) -> t(type-of 'foo) -> symbol (type-of '3.5) -> short-floattypep, type-of的用法都很簡(jiǎn)單。在lisp中,有以下規(guī)則
- 所有的對(duì)象都繼承于t,即都是t的子類型
- NULL類型只包含符號(hào)nil
- list類型包含cons和null, null是symbol和list的子類型
12.3 defining structures
defstruct macro定義新的結(jié)構(gòu)體的名字和變量的默認(rèn)值
(defstruct starship(name nil)(speed 0)(condition 'green)(shields 'down)starship是結(jié)構(gòu)體的名字,里面有4個(gè)成員變量,每個(gè)成員變量和初始值放在一個(gè)小括號(hào)中
使用defstruct定義好結(jié)構(gòu)體之后,會(huì)自動(dòng)定義一個(gè)make函數(shù)可以用來構(gòu)造一個(gè)結(jié)構(gòu)體,如make-starship
> (setf s1 (make-starship)) #S(starship name nilspeed 0condition greenshields down)輸出的結(jié)構(gòu)體前面有#S表示,也可以直接用#S結(jié)構(gòu)體對(duì)變量進(jìn)行賦值
> (setf s2 '#s(starship speed (warp 3))) #S(starship ...)defstruct之后還會(huì)自動(dòng)生成starship-p這個(gè)predicate,可以判斷對(duì)象是否是這個(gè)類型
12.5 accessing, modifying structs
定義結(jié)構(gòu)體之后,使用structname-member可以訪問成員變量,如(starship-speed s2) -> (warp 3)
對(duì)structname-member可以使用setf賦值
12.6 kwargs to constructor functions
defstruct里面定義的是成員變量的默認(rèn)值,我們?cè)跇?gòu)造一個(gè)新對(duì)象的時(shí)候可以使用關(guān)鍵字參數(shù)來設(shè)置成員變量的初始 值,回顧前面使用關(guān)鍵字參數(shù)要在前面加上冒號(hào)
> (setf s3 (make-starship :name "Jack":shields 'damaged)) #S(starship name "Jack"...)12.7 修改結(jié)構(gòu)體定義
使用defstruct定義好結(jié)構(gòu)體之后,如果再次定義同名的結(jié)構(gòu)體,會(huì)對(duì)之前已經(jīng)創(chuàng)建好的實(shí)例造成無法預(yù)測(cè)的影響 可以重新使用make-structname構(gòu)造函數(shù)來修改實(shí)例的值
ex 12.4
(defstruct node (name)(question)(yes-case)(no-case))(setf *node-list* nil)(defun init () (setf *node-list* nil))(defun add-node (name question yes-case no-case) (push (make-node :name name :question question :yes-case yes-case :no-case no-case) *node-list*)name)(defun find-node (name)(find-if #'(lambda (e) (equal name (node-name e))) *node-list*))(add-node 'start"Does the engine turn over?"'engine-turns-over'engine-wont-turn-over) (add-node 'engine-turns-over"Will the engine run for any period of time?"'engine-will-run-briefly'engine-wont-run) (add-node 'engine-wont-run"Is there gas in the tank?"'gas-in-tank"Fill the tank and try starting the engine again.") (add-node 'engine-wont-turn-over"Do you hear any sound when you turn the key?"'sound-when-turn-key'no-sound-when-turn-key) (add-node 'no-sound-when-turn-key"Is the battery voltage low?""Replace the battery"'battery-voltage-ok) (add-node 'battery-voltage-ok"Are the battery cables dirty or loose?""Clean the cables and tighten the connections."'battery-cables-good)(defun process-node (name)(let ((node-exist (find-node name)))(if node-exist (if (y-or-n-p "~&~A " (node-question node-exist))(node-yes-case node-exist)(node-no-case node-exist))(format t "~&node ~S not yet defined." name))))(defun run ()(do ((current-node 'start (process-node current-node)))((null current-node) nil)(when (stringp current-node) (format t "~&~S" current-node) (return nil)))))(defun prompt-for (s)(format t "~&~A~%" s)(read))(defun interactive-add ()(let* ((name (prompt-for "node name?"))(question (prompt-for "question?"))(yes-action (prompt-for "if yes?"))(no-action (prompt-for "if no?")))(add-node name question yes-action no-action)))12.8 print func for structs
默認(rèn)輸出一個(gè)結(jié)構(gòu)體的時(shí)候,會(huì)把整個(gè)結(jié)構(gòu)體的所有成員都輸出,但是有時(shí)我們只需要其中一些信息,因此可以通過修改結(jié)構(gòu)體的輸出函數(shù)來實(shí)現(xiàn)
clisp中一個(gè)簡(jiǎn)化輸出的結(jié)構(gòu)體習(xí)慣用"#<...>"來表示,如#<starship enterprise>
下面重新定義輸出的函數(shù),里面要有三個(gè)參數(shù),要輸出的結(jié)構(gòu)體,輸出的stream,還有輸出的深度限制。輸出到屏幕則stream為t,深度暫時(shí)不做討論。如只需要輸出starship的name
(defun print-starship (x stream depth)(format stream "#<starship ~A>" (starship-name x)))重新定義結(jié)構(gòu)體,使用:print-function參數(shù)
(defstruct (starship (:print-function print-starship))(captain nil)(name nil)(shields 'down)(condition 'green)(speed 0))> (setf s4 (make-starship :name "hello")) #<starship hello>注意上面的括號(hào),starship左邊的括號(hào)在print-starship之后已經(jīng)閉合,后面參數(shù)還是一樣
重新定義輸出還有一個(gè)作用,比如一些結(jié)構(gòu)體中包含另一個(gè)結(jié)構(gòu)體,而另一個(gè)結(jié)構(gòu)體也反過來包含這個(gè)結(jié)構(gòu)體,比如一個(gè)船長(zhǎng)擁有一艘船,一艘船則屬于一個(gè)船長(zhǎng),類似于一些數(shù)據(jù)庫,這種情況下普通的輸出會(huì)形成無限的循環(huán)。
ex 12.5
(defstruct starship (captain nil) (name nil) (speed 0) (condition 'green) (shields 'down))(defstruct (captain (:print-function print-captain))nameageship) (defun print-captain (x stream depth) (format t "#<captain ~A>" (captain-name x)))(setf s1 (make-starship :name "Enterprise")) (setf c1 (make-captain :name "James T.Kirk" :age 35 :ship s1)) (setf (starship-captain s1) c1)12.9 equality of structs
之前equal函數(shù)只要兩個(gè)對(duì)象的值相等就會(huì)返回t,但是對(duì)于結(jié)構(gòu)體比較特殊,即使兩個(gè)結(jié)構(gòu)體的成員的值完全相同,equal函數(shù)也會(huì)返回nil,只有比較同一個(gè)結(jié)構(gòu)體對(duì)象的時(shí)候,才會(huì)返回t
如果要比較兩個(gè)結(jié)構(gòu)體的值相等,可以使用equalp,eg
(setf s1 (make-starship)) (setf s2 (make-starship))> (equalp s1 s2) tequalp函數(shù)還有一點(diǎn)與equal不同,就是比較兩個(gè)字符串的時(shí)候是忽略大小寫的
(equal "hello" "Hello") -> nil (equalp "hello" "Hello") -> t12.10 inheritance
lisp的結(jié)構(gòu)體和其他語言一樣,也可以繼承于基類,繼承時(shí)加上關(guān)鍵字:include,類似于重定義輸出函數(shù)的用法
(defstruct ship(name nil)(captain nil)(crew-size nil))(defstruct (starship (:include ship))(weapons nil)(shields nil))(defstruct (supply-ship (:include ship))(cargo nil))在子類中可以用同樣的方法來反問基類的成員變量
轉(zhuǎn)載于:https://www.cnblogs.com/jolin123/p/4531467.html
總結(jié)
以上是生活随笔為你收集整理的common Lisp学习笔记(十二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转】Ubuntu 修改hosts
- 下一篇: 经典语句,看看让心灵宁静