2011-11-29 51 views
2

我一直在閱讀一些lisp代碼並且遇到這一節,並不完全理解它具體做了什麼,儘管整個函數應該計算出-z中的字母出現在輸入文字。lisp代碼摘錄

(do ((i #.(char-code #\a) (1+ i))) 
    ((> i #.(char-code #\z))) 

任何人都可以一步一步解釋發生了什麼?我知道這是以某種方式計算字母,但不知道如何。

回答

9

這Lisp代碼是略不尋常的,因爲它使用讀出時間的評價。#.expr表示表達式將只計算一次,在此期間讀出的時間。

在這種情況下一個聰明的編譯器可能已經猜到,一個給定字符的字符代碼是已知並且可能已經從中刪除了字符代碼的計算循環。該代碼的作者選擇在編譯器看到它之前通過評估表達式來實現這一點。

源看起來像這樣:

(do ((i #.(char-code #\a) (1+ i))) 
    ((> i #.(char-code #\z))) 
    ...) 

當Lisp的在s表達讀取,我們得到這一新的代碼作爲結果(假設字符的通常的編碼):

(do ((i 97 (1+ i))) 
    ((> i 122)) 
    ...) 

所以這是一個循環,它將變量i從97增加到122.

1

Lisp代碼編寫爲S-Expression。在典型的S表達式中,任何S表達式的第一個元素都被視爲運算符,其餘的則作爲操作數。操作數可以是一個原子或另一個S表達式。請注意,原子是單個數據對象。牢記這一點

char-code

(char-code #\a) - returns the ascii representation of a character here its 'a'. 

在做語法在你的例子看起來類似於下面

(do ((var1 init1 step1) 
    (var2 init2 step2) 
    ...) 
    (end-test result) 
statement1 
    ...) 

所以做的

(do ((i #.(char-code #\a) (1+ i))) 
    ((> i #.(char-code #\z))) 
    ) 

第一個S-expression操作數是循環初始化,第二個s表達式操作數是結束測試。 因此,這意味着你只是遍歷「A」到「Z」增加i 1。

在C++(不知道你的其他語言的舒適程度,你可以寫

for(i='a';i<='z';i++); 
+0

這裏的讀取時間評估也相對重要。 – Vatine

0

你所顯示的代碼的訣竅是糟糕的形式。我知道這一點,因爲我全部都是 的時間。該代碼假定編譯器將知道每個字符的當前修訂號 。 #。(char-code#\ a)eq [(或者如果你這麼傾向於eql的話)無符號小整數或無符號8位字符,返回值爲正數。

#是一個讀者宏(我相當肯定你知道這:)。使用兩個閱讀器宏是 不是一個好主意,但編譯器知道數據類型時它很快。

我有另一個例子。需要在二進制流搜索ASCII:

(defmacro code-char= (byte1 byte2) 
    (flet ((maybe-char-code (x) (if characterp x) (char-code x) x))) 
     `(the fixnum (= (the fixnum ,(maybe-char-code byte1) 
         (the fixnum ,(maybe-char-code byte2))))) 
)) 

聲明中SBCL返回類型可能會侮辱編譯器,但我把它作爲一個全面的檢查(4我不是U)。

(代碼炭=#\ $#X36) => 噸

。至少我是這麼認爲的。但不知何故,我認爲你可能知道你的方式圍繞一些宏...嗯...我應該打開機器...

如果你真的感興趣,有一些彙編程序爲286(8/16 bit dos彙編程序),您可以使用跳轉表。它對PC很快,我不得不去查看它...