在 prolog 中绑定无序列表
Binding unordered lists in prolog
我对 prolog 有点陌生,我想弄清楚如何在顺序无关紧要的情况下实现绑定列表的元素。我在我的代码的最后两行中证明了这一点。这样做似乎微不足道,但它无法绑定。
fh(Hand) :-
is_card(R, _, C1),
is_card(R, _, C2),
is_card(R, _, C3),
C1 \== C2,
C2 \== C3,
C1 \== C3,
is_card(RR, _, D1),
is_card(RR, _, D2),
R \= RR,
D1 \== D2,
is_set(Hand),
list_to_set([C1,C2,C3,D1,D2], Hand).
我希望得到一些提示。 (隐藏谓词名称和功能以防止抄袭)
阅读 library(lists) 中可用的文档,似乎对于您的用例,最好将集合表示为没有重复项的排序列表,使用 sort/2
.
这是我得到的:
?- A = [2,3,1],
B = [1,1,2,3,2,3],
sort(A, S),
sort(B, S).
A = [2, 3, 1],
B = [1, 1, 2, 3, 2, 3],
S = [1, 2, 3].
sort(A, S)
将确保 S 是一个与 A 具有相同元素的有序列表,而 sort(B, S)
将确保如果您从 B 中创建一个集合,则它与 A 相同。
我看到 is_set/1
的实现可能与 length(Set, Lenght), sort(Set, Sorted), length(Sorted, Len).
相同,但我找不到 '$skip_list'
的定义。但是我看到了:
?- '$skip_list'(Len, [2,3,1], Tail).
Len = 3,
Tail = [].
与其他评论者一样,我假设您使用的是 SWI-Prolog 库中的 is_set/1
。在你的代码中你有一个电话
is_set(Hand)
其中 Hand
是一个自由变量。您的目标似乎是将其用作一种生成器或“类型声明”,但这不起作用:
?- is_set(X).
false.
documentation of is_set/1
部分内容如下:
is_set(@Set) [det]
True if Set is a proper list without duplicates.
这里发生了一些事情。根据 SWI's mode documentation,det
表示“在没有选择点的情况下只成功一次”,而 @
表示“参数不会比调用时进一步实例化”。将这两者放在一起,is_set/1
不能 成为生成器,因为它不枚举解决方案:它甚至不将其参数实例化为单个解决方案 (@
),即使成功了,也不会成功多次 (det
)。 (事实上,det
谓词永远不会失败,但 is_set/1
会失败;这似乎是一个文档错误,正确的注释应该是 semidet
。)
因此:您不能将 is_set/1
用作生成器,只能用作类型检查。但即使作为类型检查,它在这里也无济于事,因为自由变量肯定 不是 “适当的列表”。但是,您在这里不需要生成器或类型检查。删除 is_set/1
调用,list_to_set/2
单独应该做你想做的事。
您可以用更严格的条件构建您的手牌,通过对它们下订单而不是仅仅检查它们是否不同来建立独特的元素:
fh(Hand) :-
is_card(R, _, C1),
is_card(R, _, C2),
is_card(R, _, C3),
C1 @< C2,
C2 @< C3,
is_card(RR, _, D1),
is_card(RR, _, D2),
dif(R, RR),
D1 @< D2.
这样,您将使用排序来构建您的手牌,这样您就不会出现任何重复。由于您不关心顺序是什么,因此拥有特定顺序不会干扰需求并提供一种建立唯一性的方法。
我对 prolog 有点陌生,我想弄清楚如何在顺序无关紧要的情况下实现绑定列表的元素。我在我的代码的最后两行中证明了这一点。这样做似乎微不足道,但它无法绑定。
fh(Hand) :-
is_card(R, _, C1),
is_card(R, _, C2),
is_card(R, _, C3),
C1 \== C2,
C2 \== C3,
C1 \== C3,
is_card(RR, _, D1),
is_card(RR, _, D2),
R \= RR,
D1 \== D2,
is_set(Hand),
list_to_set([C1,C2,C3,D1,D2], Hand).
我希望得到一些提示。 (隐藏谓词名称和功能以防止抄袭)
阅读 library(lists) 中可用的文档,似乎对于您的用例,最好将集合表示为没有重复项的排序列表,使用 sort/2
.
这是我得到的:
?- A = [2,3,1],
B = [1,1,2,3,2,3],
sort(A, S),
sort(B, S).
A = [2, 3, 1],
B = [1, 1, 2, 3, 2, 3],
S = [1, 2, 3].
sort(A, S)
将确保 S 是一个与 A 具有相同元素的有序列表,而 sort(B, S)
将确保如果您从 B 中创建一个集合,则它与 A 相同。
我看到 is_set/1
的实现可能与 length(Set, Lenght), sort(Set, Sorted), length(Sorted, Len).
相同,但我找不到 '$skip_list'
的定义。但是我看到了:
?- '$skip_list'(Len, [2,3,1], Tail).
Len = 3,
Tail = [].
与其他评论者一样,我假设您使用的是 SWI-Prolog 库中的 is_set/1
。在你的代码中你有一个电话
is_set(Hand)
其中 Hand
是一个自由变量。您的目标似乎是将其用作一种生成器或“类型声明”,但这不起作用:
?- is_set(X).
false.
documentation of is_set/1
部分内容如下:
is_set(@Set) [det]
True if Set is a proper list without duplicates.
这里发生了一些事情。根据 SWI's mode documentation,det
表示“在没有选择点的情况下只成功一次”,而 @
表示“参数不会比调用时进一步实例化”。将这两者放在一起,is_set/1
不能 成为生成器,因为它不枚举解决方案:它甚至不将其参数实例化为单个解决方案 (@
),即使成功了,也不会成功多次 (det
)。 (事实上,det
谓词永远不会失败,但 is_set/1
会失败;这似乎是一个文档错误,正确的注释应该是 semidet
。)
因此:您不能将 is_set/1
用作生成器,只能用作类型检查。但即使作为类型检查,它在这里也无济于事,因为自由变量肯定 不是 “适当的列表”。但是,您在这里不需要生成器或类型检查。删除 is_set/1
调用,list_to_set/2
单独应该做你想做的事。
您可以用更严格的条件构建您的手牌,通过对它们下订单而不是仅仅检查它们是否不同来建立独特的元素:
fh(Hand) :-
is_card(R, _, C1),
is_card(R, _, C2),
is_card(R, _, C3),
C1 @< C2,
C2 @< C3,
is_card(RR, _, D1),
is_card(RR, _, D2),
dif(R, RR),
D1 @< D2.
这样,您将使用排序来构建您的手牌,这样您就不会出现任何重复。由于您不关心顺序是什么,因此拥有特定顺序不会干扰需求并提供一种建立唯一性的方法。