Prolog:如何执行“检查(a++b++c++d 等于 d++a++ ;c++b) ->是的”
让我们定义自定义运算符 - 让它为 ++
、equals
:- op(900, yfx, equals).
:- op(800, xfy, ++).
事实上:
check(A equals A).
我尝试创建谓词,让它为 check/1
,即在以下所有情况下将返回 true:
check( a ++ b ++ c ++ d equals c ++ d ++ b ++ a ),
check( a ++ b ++ c ++ d equals d ++ a ++ c ++ b),
check( a ++ b ++ c ++ d equals d ++ b ++ c ++ a ),
% and all permutations... of any amount of atoms
check( a ++ ( b ++ c ) equals (c ++ a) ++ b),
% be resistant to any type of parentheses
return
yes
如何在 Prolog 中实现此功能? (代码片段,请问。可能吗?我错过了什么吗?)
Gnu-Prolog 是首选,但 SWI-Prolog 是也可以接受。
PS 请将代码视为草稿“伪代码”,并且不要关心小的语法问题。
PPS“++”才刚刚开始。我想添加更多运算符。这就是为什么我担心将东西放入列表可能不是一个好的解决方案。
另外
,如果可以进行查询,那就太好了(但是,这部分不是必需的,如果您能够回答第一部分,那就太好了)
check( a ++ (b ++ X) equals (c ++ Y) ++ b) )
可能的结果之一(感谢@用于向其他人展示的垫子)
X=c, Y=a
我主要寻找问题第一部分的解决方案 - “是/否”检查。
第二部分 X,Y 将是很好的补充。其中X,Y应该是简单原子。对于上面的示例,X、Y 的域被指定为:domain(X,[a,b,c]),domain(Y,[a,b,c])
。
Let's define custom operators - let it be ++
,equals
:- op(900, yfx, equals).
:- op(800, xfy, ++).
And fact:
check(A equals A).
I try to make predicate, let it be check/1
, that will return true in all following situations:
check( a ++ b ++ c ++ d equals c ++ d ++ b ++ a ),
check( a ++ b ++ c ++ d equals d ++ a ++ c ++ b),
check( a ++ b ++ c ++ d equals d ++ b ++ c ++ a ),
% and all permutations... of any amount of atoms
check( a ++ ( b ++ c ) equals (c ++ a) ++ b),
% be resistant to any type of parentheses
return
yes
How to implement this in Prolog? (Code snippet, please. Is it possible? Am I missing something?)
Gnu-Prolog is preferred, but SWI-Prolog is acceptable as well.
P.S. Please treat code, as draft "pseudocode", and don't care for small syntax issues.
P.P.S '++' is just beginning. I'd like to add more operators. That's why I'm afraid that putting stuff into list might be not good solution.
Additionally
Additionally, would be nice, if queries would be possible (but, this part is not required, if you are able to answer to first part, it's great and enough)
check( a ++ (b ++ X) equals (c ++ Y) ++ b) )
one of possible results (thanks @mat for showing others)
X=c, Y=a
I am looking mostly for solution for first part of question - "yes/no" checking.
Second part with X,Y would be nice addition. In it X,Y should be simple atoms. For above example domains for X,Y are specified: domain(X,[a,b,c]),domain(Y,[a,b,c])
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的表示称为“defaulty”:为了处理这种形式的表达式,您需要一个“default”情况,或者显式检查atom/1(这不是单调的) - 您不能直接使用模式匹配来处理所有情况。因此,再次考虑您的情况:
您说这应该回答
X=c, Y=a
。但是,它也可以回答X = (c ++ d), Y = (a ++ d)
。这个解决方案也应该出现吗?如果不是,它就不会是单调的,从而使程序的声明式调试和推理变得非常复杂。在您的情况下,将此类表达式表示为列表有意义吗?例如,[a,b,c,d] 等于 [c,d,b,a]?然后,您可以简单地使用库谓词 permutation/2 来检查此类“表达式”是否相等。当然也可以使用默认表示,并且在许多情况下,它们可能对用户更方便(想想 Prolog 源代码本身及其目标的默认表示法,或 Prolog 算术表达式)。您可以使用非单调谓词(如 var/1 和atom/1)以及术语检查谓词(如 functor/3 和 (=..)/2)来系统地处理所有情况,但它们通常会阻止或至少阻碍良好的声明性解决方案可以在各个方向上使用它来测试并生成所有案例。
Your representation is called "defaulty": In order to handle expressions of this form, you need a "default" case, or explicitly check for atom/1 (which is not monotonic) - you cannot use pattern matching directly to handle all cases. As a consequence, consider again your case:
You say this should answer
X=c, Y=a
. However, it could also answerX = (c ++ d), Y = (a ++ d)
. Should this solution also occur? If not, it would not be monotonic and thus significantly complicate declarative debugging and reasoning about your program. In your case, would it make sense to represent such expressions as lists? For example, [a,b,c,d] equals [c,d,b,a]? You could then simply use the library predicate permutation/2 to check for equality of such "expressions".It is of course also possible to work with defaulty representations, and for many cases they might be more convenient for users (think of Prolog source code itself with its defaulty notation for goals, or Prolog arithmetic expressions). You can use non-monotonic predicates like var/1 and atom/1, and also term inspection predicates like functor/3 and (=..)/2 to systematically handle all cases, but they usually prevent or at least impede nice declarative solutions that can be used in all directions to test and also generate all cases.
这个问题相当老了,但无论如何我都会发布我的解决方案。我在业余时间学习 prolog,发现这是一个相当具有挑战性的问题。
我学到了很多关于 DCG 和差异列表的知识。恐怕我没有想出一个不使用列表的解决方案。就像 mat 所建议的那样,它将术语转换为平面列表以处理括号,并使用
permutation/2
来匹配列表,考虑到 ++ 运算符的交换性质......这就是我的结果补充:
sum_pp/3 谓词是主力,它接受一个术语并将其转换为一个简单的被加数列表,返回(或检查)长度,同时不受括号的影响。它与 DCG 规则(使用差异列表)非常相似,但它被编写为常规谓词,因为它使用长度来帮助打破左递归,否则会导致无限递归(我花了很长时间才击败它) 。
它可以检查基本项:
它还生成解决方案:
equ/2
运算符“统一”两个项,并且还可以在存在变量时提供解决方案:在 equ/2 规则中
,第一次调用 sum_pp生成一个长度,而第二次调用将长度作为约束。剪切是必要的,因为第一个调用可能会继续生成不断增长的列表,这些列表将永远不会再次与第二个列表匹配,从而导致无限递归。我还没有找到更好的解决方案...
感谢您发布如此有趣的问题!
/Peter
编辑:sum_pp_写为DCG规则:
更新:
我将sum_pp分成两个变体。第一个是精简版本,用于检查基本术语并且是确定性的。第二个变体调用
length/2
来执行某种迭代加深,以防止左递归在右递归有机会产生某些东西之前逃跑。与每个递归调用之前的长度检查一起,这现在是比以前更多情况下的无限递归证明。特别是以下查询现在可以工作:
This question is rather old, but I'll post my solution anyways. I'm learning prolog in my spare time, and found this quite a challenging problem.
I learned a lot about DCG and difference lists. I'm afraid, I didn't come up with a solution that does not use lists. Like mat suggested, it transforms terms into flat lists to cope with the parentheses, and uses
permutation/2
to match the lists, accounting for the commutative nature of the ++ operator...Here's what I came up with:
The
sum_pp/3
predicate is the workhorse which takes a term and transforms it into a flat list of summands, returning (or checking) the length, while being immune to parentheses. It is very similar to a DCG rule (using difference lists), but it is written as a regular predicate because it uses the length to help break the left recursion which would otherwise lead to infinite recursion (took me quite a while to beat it).It can check ground terms:
It also generates solutions:
The
equ/2
operator "unifies" two terms, and can also provide solutions if there are variables:In the equ/2 rule
the first call to sum_pp generates a length, while the second call takes the length as a constraint. The cut is necessary, because the first call may continue to generate ever growing lists that will never again match with the second list, leading to infinite recursion. I haven't found a better solution yet...
Thanks for posting such an interesting problem!
/Peter
edit: sum_pp_ written as DCG rules:
update:
I split sum_pp into two variants. The first is a slim version that checks ground terms and is deterministic. The second variant calls
length/2
to perform some kind of iterative deepening, to prevent the left-recursion from running away before the right recurson gets a chance to produce something. Together with the length checks before each recursive call, this is now infinite recursion proof for many more cases than before.In particular the following queries now work: