2017-10-26 4 views
0

私は入力ストリームを受け取り、最初の行の内容に応じて異なる処理を行い、さらに入力を読み込むマクロを作成しようとしています。私は入力ストリームを受け取り、そこからいくつかの値を読み込むマクロを持つだけでは問題があります。入力ストリームを取るマクロを定義する

不自然な例:

(defmacro read-and-print (&optional in) 
    `(print 
    ,(if (string= (read-line in) "greet") 
     `(concatenate 'string "hello" (read-line ,in)) 
     `(read-line ,in)))) 

(with-input-from-string (in "greet 
bob") (read-and-print in)) 

それでもそれは次のエラー

There is no applicable method for the generic function 
    #<STANDARD-GENERIC-FUNCTION SB-GRAY:STREAM-READ-LINE (1)> 
when called with arguments 
    (IN). 
    [Condition of type SB-INT:COMPILED-PROGRAM-ERROR] 

本当に私も最初の行のISNのための文字列を取るために機能を変更している不可解だものを生産しています作業中:

(defmacro read-and-print (command &optional in) 
    `(print 
    ,(if (string= command "greet") 
     `(concatenate 'string "hello " (read-line ,in)) 
     `(read-line ,in)))) 

(with-input-from-string (in "greet 
bob") 
    (read-and-print (read-string in) in)) 

これは私に

を与えます
The value 
    (READ-LINE IN) 
is not of type 
    (OR (VECTOR CHARACTER) (VECTOR NIL) BASE-STRING SYMBOL CHARACTER) 
when binding SB-IMPL::STRING1 
    [Condition of type SB-INT:COMPILED-PROGRAM-ERROR] 

これは完全に罰金を実行中:

(with-input-from-string (in "greet 
bob") 
    (read-and-print "greet" in)) 

は私が欠けているwith-input-from-stringマクロについて特別な何かがありますか?私はマクロについて非常に明白な何かを見逃していると思うが、グーグルでは私はどこにもいない。

+3

マクロへの入力はシンボルであり、ストリームではありません。あなたはストリームを受け取り、マクロで(まだ)それを実行しない*コードを生成しています。 – wvxvw

+0

あなたのマクロは狂っています。マクロ展開時にストリーム*オブジェクト*が渡されることを望みます。私たち(ab)が 'eval'を使わない限り、これは起こりません。もしそれが起こるなら、マクロはマクロ展開時にストリームから読み込みたいと思っています。ストリームが特定の文字列を生成する場合、マクロはコード自体にリテラルとして埋め込まれた同じストリームオブジェクトを持つコードを生成したい。 – Kaz

答えて

1

あなたマクロ:inの値は、一般的にマクロ展開時にはストリームではありませんが、以来

(defmacro read-and-print (&optional in) 
    `(print 
    ,(if (string= (read-line in) "greet") 
     `(concatenate 'string "hello" (read-line ,in)) 
     `(read-line ,in)))) 

しかし,(if ... in ...)は、意味をなさないコード(シンボル、 表現、 ...)。あなたのコードは実行されておらず、マクロはソース(そしてまだ実行されていないものの値ではない)を見るので、あなたはそれを行うことができません。あなたはそれを有用に修復することもできません:それはちょうど間違ったアプローチです。代わりに関数を使用してください。

利用機能:使用

CL-USER 17 > (defun read-and-print (&optional in) 
       (if (string= (read-line in) "greet") 
        (concatenate 'string "hello" (read-line in)) 
       (read-line in))) 
READ-AND-PRINT 

CL-USER 18 > (with-input-from-string (in "greet 
foo 
bar") 
       (read-and-print in)) 
"hellofoo" 

マクロ

あなたはまだマクロとしてそれを書くことができますが、その後、あなたはそれが実行時に実行されるようにコードを生成する必要があり、マクロ展開時ではありません。

(defmacro read-and-print (&optional in) 
    `(print 
    (if (string= (read-line ,in) "greet") 
     (concatenate 'string "hello" (read-line ,in)) 
     (read-line ,in)))) 

注:1つのwo uldは実際にはinが複数回評価されないことを処理したいかもしれません。

このマクロは、コードがインライン化されるという利点をもたらします。 このマクロは、コードがインライン化されるという欠点をもたらします。

上記の関数は、コードが通常インライン化されないという利点があります。 上記の関数は、インライン宣言を使用してコンパイラに指示することによって、コードをオプションでインライン化できるという利点があります。

3

お問い合わせ内容

マクロはコード生成ツールです。 彼らはではありません。は引数を評価していません。

with-input-from-stringの例は、文字列が自己評価しているため動作します。文字列リテラルがかなりの場合、エラーが発生します。あなたは

を求めているはずです何

あなたはないがここにマクロが必要です。代わりに関数を使用してください。

機能とマクロの間で決定する、あなたは自問する必要があります。

  • 私は新しい構文を定義していますか?
  • コードでコードが生成されますか?

はいの質問と回答を理解していない限り、関数を使用する必要があります。

も参照してくださいHow does Lisp let you redefine the language itself?

関連する問題