2016-04-15 35 views
4

append/3是一個非常強大的謂詞。假設我想要一個和SWI-Prolog的字符串一樣的謂詞。SWI-Prolog中的可逆謂詞和字符串

我看到的最簡單的方法是將這些字符串轉換爲與​​列表,然後應用append/3,然後使用​​回來。這種方法的一個大問題是如果兩個變量都不統一,​​不起作用。

這是一個極其醜陋的解決方案,我想出了,檢查哪些字符串是統一適用​​需要的時候:

append_strings(S1, S2, S3) :- 
    nonvar(S1), 
    nonvar(S2),!, 
    string_codes(S1, A), 
    string_codes(S2, B), 
    append(A,B,C), 
    string_codes(S3, C). 

append_strings(S1, S2, S3) :- 
    nonvar(S1), 
    nonvar(S3),!, 
    string_codes(S1, A), 
    string_codes(S3, C), 
    append(A,B,C), 
    string_codes(S2, B). 

append_strings(S1, S2, S3) :- 
    nonvar(S2), 
    nonvar(S3),!, 
    string_codes(S2, B), 
    string_codes(S3, C), 
    append(A,B,C), 
    string_codes(S1, A). 

append_strings(S1, S2, S3) :- 
    nonvar(S3), 
    string_codes(S3, C), 
    append(A,B,C), 
    string_codes(S1, A), 
    string_codes(S2, B). 

這將產生以下情況下,正確的結果:

?- append_strings("test","auie","testauie"). 
true. 

?- append_strings("test",A,"testauie"). 
A = "auie". 

?- append_strings(A,"auie","testauie"). 
A = "test" ; 
false. 

?- append_strings(A,B,"testauie"). 
A = "", 
B = "testauie" ; 
A = "t", 
B = "estauie" ; 
A = "te", 
B = "stauie" ; 
A = "tes", 
B = "tauie" ; 
A = "test", 
B = "auie" ; 
A = "testa", 
B = "uie" ; 
A = "testau", 
B = "ie" ; 
A = "testaui", 
B = "e" ; 
A = "testauie", 
B = "" ; 
false. 

真的沒有辦法讓事情比這更簡單嗎?假設我想製作一大堆使用字符串的謂詞,就像使用列表一樣:我顯然不想寫出我爲它們所做的所有append/3。但我也不想使用代碼字符串,因爲我無法知道我是在操縱一個普通列表還是一個字符串。

+1

最簡單的方法是不直接使用字符串。相反[使用'chars'](http://stackoverflow.com/a/36645725/772868)。 – false

+1

你的定義失敗了'append_strings(Xs,Ys,Zs)'。它應該產生一個實例化錯誤。 – false

+0

@false但是,我不能區分列表和字符串。假設我想要一個謂詞轉置,它轉換一個列表,但對於一個根據換行符轉換的字符串。有了字符清單,我無法知道我是否在使用字符串。 – Fatalize

回答

3

只要使用string_concat/3即可。像ISO atom_concat/3一樣,它可以在許多模式下使用,包括( - , - ,+)。

1

出現了similar question前一段時間,我會告訴我的建議,修訂

:- meta_predicate when_(0). 
when_(P) :- 
    strip_module(P,_,Q), Q =.. [_|As], 
    or_list(As, Exp), % hurry debugging :-) display(Exp), 
    when(Exp, P). 

or_list([A], ground(A)) :- !. 
or_list([A|As], (ground(A);Exp)) :- or_list(As, Exp). 

append_strings(S1, S2, S3) :- 
    maplist(when_, [string_codes(S1, A), string_codes(S2, B), append(A,B,C), string_codes(S3, C)]). 

如果你有興趣,我可以添加一個操作者隱藏的語法細節,要達到這樣的

append_strings(S1, S2, S3) -:- 
    string_codes(S1, A), string_codes(S2, B), append(A,B,C), string_codes(S3, C). 
1

這是更緊湊的定義:

append_strings(S1, S2, S3):- 
    append_strings1(S1, L1, [1]-[], N1), 
    append_strings1(S2, L2, [1|N1]-N1, N2), 
    append_strings1(S3, L3, [1,1|N2]-N2, N3), 
    (N3\=[_,_|_] ->instantiation_error(append_strings/3); true), 
    append(L1, L2, L3), 
    (ground(S1)->true;string_codes(S1, L1)), 
    (ground(S2)->true;string_codes(S2, L2)), 
    (ground(S3)->true;string_codes(S3, L3)). 

append_strings1(S, L, G-NG, N):- 
    (ground(S) -> (string_codes(S, L), N=G) ; N=NG). 

它檢查是否每個參數都是基礎並嘗試轉換爲代碼,然後檢查第三個參數是否爲地面或其他兩個參數,並在條件不滿足時引發實例化錯誤。

追加後,它將轉換回字符串參數,其中不地面。

4

由於謂詞在列表上工作,因此使用DCG似乎很誘人。首先,讓我們看到,在Prolog的字符串是真正的字符代碼列表:

?- X="test". 
X = [116,101,115,116] 

當然,這不是很可讀,讓我們這一翻譯看文字本身的代碼:

?- set_prolog_flag(double_quotes,chars). 
yes 
    ?- X="test". 
X = [t,e,s,t] 

這是更好的。考慮謂詞應描述的關係,我選擇了一個描述性名稱,如list_list_appended/3。這個謂詞有一個目標:DCG規則,我們稱之爲list_list // 2,使用另一DCG,讓我們把它列出// 2,實際編寫的列表:

list_list_appended(L1,L2,L3) :- 
    phrase(list_list(L1,L2),L3). % L3 is L1+L2 

list([]) -->      % if the list is empty ... 
    [].       % ... there's nothing in the list 
list([X|Xs]) -->     % if there's a head element ... 
    [X],       % ... it's in the list 
    list(Xs).      % the tail is also a list 

list_list(L1,L2) -->    % the list consists of ... 
    list(L1),      % ... L1 followed by ... 
    list(L2).      % L2 

您查詢示例:

?- list_list_appended("test","auie","testauie"). 
yes 
    ?- list_list_appended(L1,"auie","testauie"). 
L1 = [t,e,s,t] ? ; 
no 
    ?- list_list_appended("test",L2,"testauie"). 
L2 = [a,u,i,e] ? ; 
no 
    ?- list_list_appended("test","auie",L3). 
L3 = [t,e,s,t,a,u,i,e] 
    ?- list_list_appended(L1,L2,"testauie"). 
L1 = [], 
L2 = [t,e,s,t,a,u,i,e] ? ; 
L1 = [t], 
L2 = [e,s,t,a,u,i,e] ? ; 
L1 = [t,e], 
L2 = [s,t,a,u,i,e] ? ; 
L1 = [t,e,s], 
L2 = [t,a,u,i,e] ? ; 
L1 = [t,e,s,t], 
L2 = [a,u,i,e] ? ; 
L1 = [t,e,s,t,a], 
L2 = [u,i,e] ? ; 
L1 = [t,e,s,t,a,u], 
L2 = [i,e] ? ; 
L1 = [t,e,s,t,a,u,i], 
L2 = [e] ? ; 
L1 = [t,e,s,t,a,u,i,e], 
L2 = [] ? ; 
no 

作爲SWI用戶,您還可以使用this libraryset_prolog_flag(double_quotes,chars).組合來獲得所需形式的輸出。詳情請參閱this answer