在课堂上我们查看了我老师给出的subset_of / 2谓词如下:
subset_of([],[]).
subset_of([X|Xs],Zs):-subset_of(Xs,Ys),maybe_add(X,Ys,Zs).
maybe_add(_,Ys,Ys).
maybe_add(X,Ys,[X|Ys]).
subsets_of(Xs,Xss):-findall(Ys,subset_of(Xs,Ys),Xss).
然后,他要求我们将其更改为仅给出一些长度为K的子集(但不是通过使用长度/ 2,直接找到递归定义)。我的第一次尝试是将subset_of调用分成一个添加额外元素的调用和一个不添加额外元素的调用(而不是使用maybe_add调用)并跟踪传递的列表的长度并在最后检查,但是这根本没有按计划运作。
subset_of(K, 0, [],[]).
subset_of(K, Len, [X|Xs],Zs):-
L1 is Len - 1,
subset_of(K, L1, Xs, Zs),
L1 == K.
subset_of(K, Len, [X|Xs],Zs):-
L1 is Len - 1,
subset_of(K, L1, Xs,Ys),
do_add(X, Ys, Zs),
Len == K.
subsets_of(K,Xs,Xss):-
length(Xs, Len),
findall(Ys,subset_of(K, Len, Xs,Ys),Xss).
我不是要求正确的代码来解决这个问题,而只是向正确的方向推进,所以我可以继续努力解决这个问题。这是我第一次使用声明性的languange而且我很困惑。
答案 0 :(得分:1)
如果你不想直接回答,那么我会说它可以做得更简单。我的解决方案中有3个规则。但是,我不使用这个额外的maybe_add
公式或任何可以重新计算它的公式。如果你真的需要它,可以使用它,然后需要5个参数--3个输入参数和2个输出参数。与原始解决方案一样,这会将subset_of
的规则数量减少到仅2。毕竟它们非常相似。
还要注意重复。我认为subset_of(0, _, [])
正如其他答案所建议的那样,可能会导致重复。然而,可能有一个正确的解决方案,它包含它,我不确定没有。
将其视为正确性的证明。假设你想递归地证明一个集合是另一个集合的K元素子集。你会怎么做呢?看看你使用的含义。你怎么能把它们变成Prolog规则?
答案 1 :(得分:0)
不使用maybe_add
似乎是一个好主意。但是,您不需要两个额外的参数:一个会这样做。你的基础条款是
subset_of(0, _, []).
即,空集是任何东西的零元素子集。在两个递归子句中,一个将查找K-1
- 元素子集,另一个查找K
个大小的子集。