2009-09-14 55 views

回答

4

使用解析變換可以得到足夠接近的結果。下面的parse_transform會在編譯時查找「atom1 ++ atom2」並將其轉換爲「atom1atom2」。

例如模塊

-module(z). 

-export([z/0]). 

-compile({parse_transform, zt}). 

z() -> concat ++ enate. 

用 'S' 編譯證明它是在編譯時確實級聯:

{function, z, 0, 2}. 
    {label,1}. 
    {func_info,{atom,z},{atom,z},0}. 
    {label,2}. 
    {move,{atom,concatenate},{x,0}}. 
    return. 

按預期方式工作:包含

1> z:z(). 
concatenate 

模塊解析變換:

-module(zt). 

-export([parse_transform/2]). 

parse_transform(AST, _Options) -> 
    [parse(T) || T <- AST]. 

parse({function, _, _, _, _} = T) -> 
    erl_syntax_lib:map(fun hashhash/1, T); 
parse(T) -> T. 

hashhash(Tree) -> 
    erl_syntax:revert(
    case erl_syntax:type(Tree) of 
     infix_expr -> 
     Op = erl_syntax:infix_expr_operator(Tree), 
     Left = erl_syntax:infix_expr_left(Tree), 
     Right = erl_syntax:infix_expr_right(Tree), 
     case {erl_syntax:operator_name(Op), erl_syntax:type(Left), erl_syntax:type(Right)} of 
      {'++', atom, atom} -> 
      erl_syntax:atom(erl_syntax:atom_literal(Left) ++ erl_syntax:atom_literal(Right)); 
      _ -> 
      Tree 
     end; 
     _ -> 
     Tree 
    end 
). 

編輯:編輯爲「超載」中綴++運算符。以前的版本使用'##'功能。

+0

這看起來不錯!我無法通過erlIDE來編譯它:我需要做一些特殊的事情嗎? – jldupont 2009-09-15 15:02:08

+1

erlc在編譯z.erl時需要訪問zt.beam,因此您必須使用-pa標誌將其路徑添加到erlc中,最有可能的是:「erlc -pa。z.erl」。 不知道如何用erlIDE做到這一點。 – Zed 2009-09-15 15:50:53

+0

erlIDE還沒有完整的功能...它不允許指定額外的路徑(例如與-pa開關)。 有沒有辦法做到這一點與編譯指令? – jldupont 2009-09-15 16:35:46

0

我認爲沒有。我認爲,因爲你可以做任何這些東西在運行時沒有副作用

+0

據我所知,編譯器被認爲是非常好的,但怎麼會有沒有副作用(例如消耗的週期)? – jldupont 2009-09-14 18:48:39

+0

你能舉例說明你的意思嗎? – 2009-09-14 21:29:36

1

我不知道我明白你在問什麼,但我會刺傷它。

-define(CATATOM(A, B), list_to_atom(list:concat(atom_to_list(A), atom_to_list(B)))). 
AtomA = atom1. 
AtomB = atom2. 
NewAtom = ?CATATOM(AtomA, AtomB). % NewAtom is atom1atom2 

或者你的意思是?

-define(CATATOM(A, B), AB). 
NewAtom = ?CATATOM(atom1, atom2). % NewAtom is atom1atom2 

雖然我不確定使用新的第二個實際是什麼。因爲只寫atom1atom2而不是宏會更簡單。

第二個將不會產生運行時副作用。第一個會產生運行時副作用,因爲宏的結果是3個函數在運行時運行。

+0

第二個很可能會產生「變量」AB「沒有約束」。 – Zed 2009-09-15 09:44:49

+0

假設它的工作正常,您的建議將導致運行時評估:我正在尋找*編譯時*評估。 – jldupont 2009-09-15 13:40:50

0

有解析變換的概念,這將允許您在編譯時連接原子。

+2

如果不解釋如何使用解析轉換來解決問題,那麼這對你並沒有什麼幫助。 – 2009-09-15 12:07:45

1

你實際上不可能什麼都在一個宏裏面,它只是純粹的文本,很好的標記級別,替換。注:您正在處理源代碼並且未對其進行評估。如果你需要更復雜的替代類型,那麼你需要使用解析轉換。

如果你編寫了一個連接宏,你總是可以使用?? Arg形式來獲取作爲一個字符串的參數。查看在線參考手冊的預處理器部分。

當然,真正有趣的問題是爲什麼你想在編譯時連接兩個原子?我認爲這是另一個宏的輸出,否則就沒有意義了。

+0

我希望能夠「參數化」模塊,例如 -define(APP,app)。 -define(EXT,ext)。 -define(NAME,?APP ++?EXT)。 運算符'++'將在編譯時連接兩個atom()。 – jldupont 2009-09-15 14:18:34

0

你提到的要參數模塊你的答案之一 - 這可以在運行時做...

的學術論文它是here

Mochiweb使用它。

+0

不是我在找什麼,但謝謝。 – jldupont 2009-09-15 19:29:45