2015-06-12 99 views
1

是否可以使用lisp的宏來進行字符串插值?反引號字符串插值

舉例來說,我可以做這樣的宏:

(defmacro test (a) `",a") 

所以這(測試ABC)返回 「ABC」 作爲一個字符串?我可以通過引用它並將該引號轉換爲字符串來作弊,但這對於「9:00」(不帶雙引號)的參數不起作用。

+0

嘗試['(符號名「一)'](http://clhs.lisp.se/Body/f_symb_2.htm)。 – Dan

+0

@Dan:這對我的例子不起作用。 '9:00試圖尋找一個名爲「9」的包,它不存在。 – iHuman

+1

@iHuman你需要逃避它。例如。 9:00或9:00。 – Sylwester

回答

3

Lisp的宏在參數上操作該已經被lisp的讀者讀過。因爲宏不能改變它讀取參數的方式,並且如果你傳遞一個參數,當你嘗試讀取它時會報錯,例如9:00(test 9:00)中,讀取器在宏開始運行之前發出錯誤信號。

閱讀器也是可定製的。不能以一種直接的方式讀取9:00作爲"9:00",但例如,您可以編寫一個簡短的讀取器宏,其讀取@9:00"9:00"或作爲日期對象。

編輯:事情是這樣的:

(defvar *arguments-rt* (copy-readtable())) 

(defun timestring-reader (stream char &optional count) 
    (declare (ignore char count)) 
    (with-output-to-string (s) 
    (loop repeat 4 do (write-char (read-char stream) s)))) 

(set-macro-character #\@ #'timestring-reader() *arguments-rt*) 

(let ((*readtable* *arguments-rt*)) 
    (let ((args "dinner @9:00")) 
    (with-input-from-string (stream args) 
     (loop for arg = (read stream()()) 
      while arg collect arg)))) 

-> (DINNER "9:00") 
+0

謝謝。之所以我試圖通過箍環來使它成爲一個字符串,是因爲我在命令行參數的連接版本上使用了從字符串中讀取字符串。這導致使用雙引號是一種痛苦,因爲bash沒有通過引號來判別。 '@'在bash中沒有什麼特別之處,所以我會去看你的想法。 – iHuman

+0

@iHuman我添加了一個快速示例。在新的readtable中設置閱讀器宏(用'copy-readtable'創建)並綁定'* readtable *'在本地防止更改在遠處的代碼中產生意外效果。 –

+2

如果您只想以結構化的形式獲取命令行參數,請查看所有命令行解析器(或僅使用它們)。 – Svante

2

對於字符串插值,請參見format。例如。 (format nil "~a" a)做你想做的。在Practical Common Lisp有一些format recipes

quasiquote和unquote只適用於列表,而不是其他序列。

宏是代碼的轉換。它不是運行時發生的事情。例如。當你有像(my-macro x)這樣的代碼,其中x在運行時將是一個字符串,宏只能看到該符號。它不知道在擴展時它是什麼類型。

3

Backquoting,無論是在宏觀還是不行,不會做到這一點:

[1]> (defmacro test (a) `",a") 
TEST 
[2]> (test oh-no) 
",a" 

你可以做的是使用format,如下:

[3]> (defun interp (name) (format nil "Hi, my name is ~A" name)) 
INTERP 
[4]> (interp "Steve") 
"Hi, my name is Steve" 
+0

所以我不得不使用一個字符串? – iHuman

+0

對於'9:00',是的。您不需要使用其他符號,但對這類數據使用字符串通常是一個好主意。請參閱m-n的迴應以更好地解釋爲什麼會這樣。 – zck

+0

你的問題是「是否有可能使用lisp的宏做字符串插值?」是的,您必須使用字符串進行字符串插值。如果幻想語法'',一個「'工作,這將是一種字符串操作的形式。 – Kaz