2016-11-16 100 views
0

這是事實:如何對Prolog事實施加約束?

address(host1, '10.0.0.1'). 
address(host2, '10.0.0.2'). 

而且我可以查詢一個事實:

?- address(host1, X). 
X = '10.0.0.1'. 

我是新來的Prolog,但我習慣了關係數據庫。在SQL數據庫中,我對數據施加了限制以防止出錯。如果我要確保,所有地址都是A類網絡10.0.0.0/8的,我可以把表列一個約束:

create table hosts (
    name text, 
    address text check (address like '10.%') 
); 

我怎麼會做同樣的序言中,以防止錯誤的事實?

回答

6

你寫的事實等同於以下規則

 
address(host1, '10.0.0.1') :- true. 
address(host2, '10.0.0.2') :- true. 

true/0最一般的目標:它總是成功

約束條款更強烈,您可以添加更多目標。在Prolog中,每個目標在回答上充當約束。 @ coder的答案是現貨:你可以簡單地編寫規則來添加這些檢查,它們與你的數據庫約束相似(並且比表達更強)。

例如,你可以寫:

 
host_ip(host1, IP) :- IP = '10.0.0.1', good_ip(IP). 
host_ip(host2, IP) :- IP = '10.0.0.2', good_ip(IP). 

注意謂語命名約定:要明確每個參數是什麼,我使用host_ip/2而不是簡單地address/2

good_ip/1一個可能的定義是:

 
good_ip(IP) :- atom_concat('10.', _, IP). 

這是真的當且僅當IP開始與10.

在這一點上,問題出現在您是否選擇了IP  地址的最合適的表示

如果您經常需要分析的組件,例如考慮表示:

ip(A,B,C,D)

在此表示,我們可以這樣寫:

 
host_ip(host1, IP) :- IP = ip(10,0,0,1), good_ip(IP). 
host_ip(host2, IP) :- IP = ip(10,0,0,2), good_ip(IP). 

good_ip(ip(10,_,_,_)). 

編輯:正如你在正確的評論指出,這只是阻止錯誤  IP地址,而不是斷言加入錯誤事實或條款。

,使它們成爲可能,考慮@lurker介紹的方法:你可以簡單地定義如下規則:從添加錯誤的IP地址到數據庫

 
add_host_ip(Host, IP) :- 
    good_ip(IP), 
    assertz(host_ip(Host,IP)). 

這可以防止你的,假設你一直使用這個接口謂詞。

還請注意,如果給出了錯誤的IP,則將此與投擲例外相結合。例如:

 
good_ip(ip(First,_,_,_)) :- 
    dif(First, 10), 
    throw(wrong_subnet(First)). 
good_ip(ip(10,_,_,_)). 

實施例的會話:

 
?- add_host_ip(host3, ip(11,0,0,0)). 
ERROR: Unhandled exception: wrong_subnet(11) 

?- add_host_ip(host4, ip(10,0,0,1)). 
true. 

?- host_ip(host3, IP). 
false. 

?- host_ip(host4, IP). 
IP = ip(10, 0, 0, 1). 

這說明無效的IP現在既沒有存儲也不返回的答案。

+0

但在你的例子中,仍然可以定義一個無效地址'host'_ip(host3,IP): - IP = ip(1,2,3,4),good_ip(IP) 。效果就是,它不能被發現了。但事實數據庫仍然是腐敗的,因爲儘管'host3'的地址已經被定義了,但是它缺失了。 – ceving

+0

沒錯,我添加了代碼,顯示如何防止這種情況。 – mat

1

你可以寫:

find_address(X,Y):- 
      address(X,Y), 
      atom_chars(Y,Y1), 
      consecutive_member('1','0',Y1). 

consecutive_member(X,Y,[X,Y|_]). 
consecutive_member(X,Y,[H1,H2|T]):- 
        dif(H1,1),dif(H2,0), 
        consecutive_member(X,Y,T). 

和查詢find_address(主機1,X)。其成功僅當有以「10」的地址,主機1:

?- find_address(host1,X). 
X = '10.0.0.1' ; 
false. 
+0

我的意圖不是要忽略一個錯誤定義的IP地址,而是爲了防止定義。 – ceving

+0

那麼你如何將事實加載到prolog數據庫? – coder

+0

我沒有偏好。我應該怎麼做?從我閱讀到現在,似乎通常將它們放在一個擴展名爲「.pl」的文件中。 – ceving