天天看點

初識LISP(1)——基本的結構、文法與資料類型

       既然下定決心學習LISP,我計劃學習LISP的過程都以部落格的形式做總結。當然是需要參考學習網上的教程,網上的教程講解的比較詳細。而我打算以自己的了解來做盡可能簡潔的總結,一方面将自己的學習過程做一個回顧,另一方面,如果日後忘記了什麼知識點,也友善查詢。

一、LISP—程式結構

      首先lisp很獨特的一點就是圓括号,程式自始至終都是圓括号,例如函數、表達式……這一特色的功能與Java的花括号“{}”和Python的縮進功能類似。LISP的字首表示方法類似于棧的概念,即a+b,寫作(+ a b),下面第一句就是實作(3+5)/2,值得注意的是運算符和數字之間必須以空格間隔開,這是最基本的文法要求。

(print (/ (+ 3 5) 2))
(format t "~%");列印一個換行符
(write-line "Hello World!");最經典的,列印“Hello World!”
           

二、LISP—基本文法

       這裡需要記住的是LISP的三個基本塊:原子、清單和字元串。原子可以了解成編譯器視角下的單一進制素,可以由數字、字母和特殊字元組成。而清單是包含原子與子清單的序列。字元串是由雙引号括起的字元。

      需要注意的是1.LISP語言不區分大小寫;

                              2.過去調用函數的方式為f(x),而在LISP的世界一切都是平等的,寫作(f  x);

                              3.隻有三種類型的元素是常數,傳回的是自己的值:數字;字母t,代表邏輯真;nil,代表邏輯假,還有一個空的清單。

     LISP允許名字裡包含數字,但是也别過分到都是數字,這樣編譯器隻能認為這是數字了好吧。之前說原子裡可以包含特殊字元,比如什麼雙引号、冒号什麼的,那麼也需要有轉義字元的,轉義字元是()。

     最後值得一提的,先看代碼:

(write (* 2 3));這行代碼會列印出乘法結果6,而如果要列印出(* 2 3),也就是不進行求值,那可以通過以下代碼實作

(write ' (* 2 3));沒錯,就是加一個單引号在前面~~其實想實作這個功能還有一種辦法的

(format t "(* 2 3)");最傳統的列印字元串的好吧,其實也就是列印原子或清單的字面結果。
           

三、LISP—資料類型

   類型說明符是資料類型的系統定義的符号。

array fixnum package simple-string
atom float pathname simple-vector
bignum function random-state single-float
bit hash-table ratio standard-char
bit-vector integer rational stream
character keyword readtable string
[common] list sequence [string-char]
compiled-function long-float short-float symbol
complex nill signed-byte t
cons null simple-array unsigned-byte
double-float number simple-bit-vector vector

      沒有什麼可說的,類型說明符也隻能等以後遇見什麼再聊吧。先看幾行代碼吧:

(setq a 10)

(print a);前一句可以了解成a是10的變量引用,這裡列印了a

(setq b 20)

(print (type-of b));
           

輸出結果為

(INTEGER 0 281474976710655) 
      

       很顯然這裡輸出的b的類型,而後面的兩個數代表的是b的值在這個範圍内,後面那個數肯定是有背景的,換算成十六進制即為FFFF FFFF FFFF ,可以嘗試一下當輸入為

(setq x 281474976710656)  ;建構一個符号指定一個值
(setq x 281474976710657)
(print (type-of x));分别運作上面的代碼,得到的都是  (INTEGER (281474976710655))  ,即是變量的值大于這個臨界值。
           

四、LISP—宏

       我覺得這裡的宏完全可以當做函數對待,宏的定義是使用defmacro來實作的。

;宏定義

(defmacro setTo10(num)
  (setq num 10)
  (print num))
(setq x 25)
(print x)
(setTo10 x)
           

五、LISP—變量

       全局變量是通過defvar來定義的,而局部變量有三種結構可以建立:setq、let和prog

(defvar x 123)
;(print x)
(write x)

(setq x 10)
(setq y 20)
(format t "x = ~2d y = ~2d ~%" x y);類似于C語言的形式,大概了解是令t指向總字元串
(format t "x = ~2d y = ~2d " x y);“~%”是換行作用,~2d是兩位整型數
           
;局部變量的使用,分别定義的x、y和z之間不互相沖突

(let ((x ' a)
     (y ' b)
     (z ' c))
(format t "x = ~a ~% y = ~a ~% z = ~a ~%" x y z))

(prog ((x ' (a b c))
      (y ' (1 2 3))
      (z ' (p q 10)))
(format t "x = ~a ~% y = ~a ~% z = ~a" x y z));~b是輸出二進制編碼,~a是輸出字元
           

六、LISP—常量

        常量通過defconstant聲明得到,defun即是定義函數。

;聲明圓周率為全局常量,定義一個得到圓面積的函數
(defconstant PI 3.141592)
(defun area-cirlce(rad)
    (terpri)
    (format t "Radius = ~5f" rad)
    (format t "~%Area = ~10f" (* PI rad rad)))
(area-cirlce 10)
           

七、LISP—運算符

      運算符是一個符号,它告訴編譯器執行特定的數學或邏輯操作。其中對資料的運算操作歸類為四種:算術運算、比較操作、邏輯運算和位運算。

算術運算:

運算符 描述 Example
+ 增加了兩個操作數 (+ A B) = 30
- 從第一數減去第二個操作數 (- A B)= -10
* 乘兩個操作數 (* A B) = 200
/ 通過取消分子除以分子 (/ B A) = 2
mod,rem 模運算符和其餘整數除法後 (mod B A ) = 0
incf 遞增運算符,所指定的第二個參數增加整數值 (incf A 3) = 13
decf 遞減操作符,通過指定的第二個參數減小整數值 (decf A 4) = 9

比較操作:

Operator 描述 Example
= 檢查如果操作數的值都相等與否,如果是的話那麼條件為真。 (= A B)= true.
/= 檢查如果操作數的值都不同,或沒有,如果值不相等,則條件為真。 (/= A B) =true.
> 檢查如果操作數的值單調遞減。 (> A B) !=true.
< 檢查如果操作數的值單調遞增。 (< A B) = true.
>= 如有左操作數的值大于或等于下一個右操作數的值,如果是則條件檢查為真。 (>= A B) !=true.
<= 如有左操作數的值小于或等于其右操作數的值,如果是,則條件檢查為真。 (<= A B) = true.
max 它比較兩個或多個參數,并傳回最大值。 (max A B) 傳回20
min 它比較兩個或多個參數,并傳回最小值。 (min A B) 傳回 20

布爾值邏輯操作:

運算符 描述 示例
and 這需要任意數量的參數。該參數是從左向右計算。如果所有參數的計算結果為非零,那麼最後一個參數的值傳回。否則就傳回nil。 (and A B) = NIL.
or 這需要任意數量的參數。該參數是從左向右計算的,直到一個計算結果為非零,則此情況下傳回參數值,否則傳回nil。 (or A B) = 5.
not 它接受一個參數,并傳回t,如果參數的計算結果為nil。 (not A) = T.

對數位運算操作:

操作符 描述 Example
logand 這将傳回位邏輯的參數和。如果沒有給出參數,則結果為-1,這是該操作的辨別。 (logand a b)) = 12
logior 這将傳回位邏輯包括它的參數或。如果沒有給出參數,那麼結果是零,這是該操作的辨別。 (logior a b) = 61
logxor 這将傳回其參數的按位邏輯異或。如果沒有給出參數,那麼結果是零,這是該操作的辨別。 (logxor a b) = 49
lognor 這不傳回的逐位它的參數。如果沒有給出參數,則結果為-1,這是該操作的辨別。 (lognor a b) = -62,
logeqv 這将傳回其參數的逐位邏輯相等(也稱為異或非)。如果沒有給出參數,則結果為-1,這是該操作的辨別。 (logeqv a b) = -50

        這裡就隻給出算術運算和比較運算的代碼,其中對數位運算就是以二進制數之間進行與、或、異或等操作,然後運算的結果以十進制的形式輸出。

;運算符,算術運算
(setq a 10)
(setq b 20)
(format t "~%和:~d" (+ a b))
(format t "~%差:~d" (- a b))
(format t "~%積:~d" (* a b))
(format t "~%商:~d" (/ a b))
(format t "~%取餘:~d" (mod a b))
(format t "~%取餘2:~d" (rem a b))
(format t "~%加的和:~d" (incf a 3))
(format t "~%減的差:~d" (decf a 5))
;比較運算
(format t "~%是否相等? ~a" (= a b))
(format t "~%是否不等? ~a" (/= a b))
(format t "~%是否小于? ~a" (< a b))
(format t "~%是否大于? ~a" (> a b))
(format t "~%是否大于等于? ~a" (>= a b))
(format t "~%是否小于等于? ~a" (<= a b))
(format t "~%最大值? ~a" (max a b 15 30))
(format t "~%最小值? ~a" (min a b 15 30))
           

繼續閱讀