我在做一個Prolog程序,它可以找到一組列表的一個子集。這個子集必須符合一些特定的條件,其中一個方面是子集的列表不能相同。什麼是困惑我的是,當我試圖找到變量匹配,X,如果我把它們插入到查詢到位X的例如生成返回錯誤結果:爲什麼Prolog會將變量與直接插入的結果匹配失敗?
?- containsSet(2, [[3],[7],[7]], X).
X = [[3], [7]] ;
X = [[3], [7]] ;
X = [[7], [7]] ;
false.
?- containsSet(2, [[3],[7],[7]], [[7],[7]]).
false.
怎麼可能呢如果在直接插入時返回false,可能會將X與[[7],[7]]匹配。
containsSet的思想是找到在匹配位置中沒有匹配元素的長度爲N的子集(在本例中爲2)(即,子集中沒有兩個列表具有相同的第一個元素,或者相同第二元素等)。在上面的例子中,[7]和[7]中的第一個(也是唯一)元素匹配,所以它返回false。
非常好的觀察!這顯然違反了連接的交換性,因此違背了我們對純邏輯關係的期望。很可能,您在代碼中使用非單調和不純的結構,如'(\ +)/ 1','!/ 0'或if-then-else。你應該使用'dif/2'這樣的限制來消除這些雜質,以表示這兩個術語是不同的。這會讓你的程序變得純粹,並且可以在更多方向上使用。參見[tag:prolog-dif]和[tag:logical-purity]。另外,'please_use_more_readable_names''insteadOfNamesNoOneCanReadProperly'。 – mat
啊!我在set_is_compatible(SET)行中使用'(\ +)/ 1'幾次: - \ +(select(X,SET,R),\ + list_compatible_with_set(X,R))''。我會試着弄清楚如何重寫這個。謝謝! – vestlen
是的,我強烈推薦使用'dif/2'這樣的純謂詞來代替。 '(\ +)/ 1'版本將爲您創建無盡的聲明性問題。考慮如下:'?\ \ + select(X,[a,b,c],Rest),X = d.',產生'false',**但**,如果我們只交換這兩個目標合意!)交合的交換性,我們得到:'X = d'。如果它的論證是基礎的,那麼「(\ +)/ 1」是合理的,但是總的來說,你不能依賴這種非單調謂詞來獲得真正的一般的和陳述性的解決方案。您最好留在Prolog的純粹和單調子集中以保留這些好的屬性。 – mat