Prolog 中的表述
我目前有以下问题,我想用 Prolog 解决。这是一个简单的例子,用 Java/C/其他语言很容易解决。我的问题是,我认为自己太依赖 Java 的思维,无法利用 Prolog 的逻辑能力来实际地表述问题。
问题是..
我有一组 6 个箭头,要么指向左,要么指向右。让我们假设它们处于以下起始配置中:
->
<-
->
<-
->
<-
现在,只要两个箭头彼此相邻,我就可以切换它们。我的目标是发现哪个操作序列将使箭头的初始配置变成
<-
<-
<-
->
->
->
我最初尝试表述的问题是......
right(arrow_a).
left(arrow_b).
right(arrow_c).
left(arrow_d).
right(arrow_e).
left(arrow_f).
atPosition(1, arrow_a).
atPosition(2, arrow_b).
atPosition(3, arrow_c).
atPosition(4, arrow_d).
atPosition(5, arrow_e).
atPosition(6, arrow_f).
这将告诉 Prolog 箭头的初始配置是什么。但现在我如何在其中插入额外的逻辑呢?例如,如何实现 switchArrows(Index)
?在 Prolog 中这样表述初始条件是否正确?例如,当我尝试设置 arrow_a
位于位置 6、atPosition(6, arrow_a)
时,它不会干扰吗?
I currently have the following problem, that I want to solve with Prolog. It's an easy example, that would be easy to solve in Java/C/whatever. My problem is that I believe to be too tied to Java's thinking to actually formulate the problem in a way that makes useof Prolog's logic power.
The problem is..
I have a set of 6 arrows, either pointing left or right. Let's assume that they are in the following starting configuration:
->
<-
->
<-
->
<-
Now, I can switch two arrows as long as they are next to each other. My goal is to discover which sequence of actions will make the initial configuration of arrows turn into
<-
<-
<-
->
->
->
My initial attempt at formulating the problem is..
right(arrow_a).
left(arrow_b).
right(arrow_c).
left(arrow_d).
right(arrow_e).
left(arrow_f).
atPosition(1, arrow_a).
atPosition(2, arrow_b).
atPosition(3, arrow_c).
atPosition(4, arrow_d).
atPosition(5, arrow_e).
atPosition(6, arrow_f).
This will tell Prolog what the initial configuration of the arrows are. But now how do I insert aditional logic in it? How to implement, for example, switchArrows(Index)
? Is it even correct stating the initial conditions like this, in Prolog? Won't it interfere later when I try to set, for example, that arrow_a
is at position 6, atPosition(6, arrow_a)
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您的问题可以表述为配置之间的一系列转换。首先考虑如何表示单个配置。您可以使用列表来执行此操作,例如 [->,<-,->,<-,->,<-] 来表示初始配置。单个移动可以用关系step/2来描述,该关系用作step(State0, State),并描述通过翻转两个相邻箭头彼此“可达”的两个配置之间的关系。它通常是不确定的。然后,您的主谓词描述了从初始状态到所需目标状态的一系列状态转换。由于您想要描述一个(配置)列表,DCG 是一个很好的选择:
然后使用迭代深化来找到解决方案(如果存在),如下所示:
好处是,一旦给定长度的所有序列都满足,Prolog 就会自动回溯已尝试过,但尚未达到目标状态。您现在只需执行步骤/2 即可完成。
Your problem can be formulated as a sequence of transitions between configurations. First think about how you want to represent a single configuration. You could use a list to do this, for example [->,<-,->,<-,->,<-] to represent the initial configuration. A single move could be described with a relation step/2 that is used as step(State0, State) and describes the relation between two configurations that are "reachable" from each other by flipping two adjacent arrows. It will in general be nondeterministic. Your main predicate then describes a sequence of state transitions that lead to the desired target state from an initial state. Since you want to describe a list (of configurations), DCGs are a good fit:
And then use iterative deepening to find a solution if one exists, as in:
The nice thing is that Prolog automatically backtracks once all sequences of a given length have been tried and the target state could not yet be reached. You only have to implement step/2 now and are done.
由于已经发布了完整的解决方案,这里是我的:
示例查询:
由于使用了迭代加深,我们知道不可能有更短的解决方案(少于 4 个步骤)。
我对你所说的也有一个一般性的评论:
就我个人而言,我认为这个例子已经远远超出了初学者(例如 Java 程序员)的预期。请尝试用 Java/C/其他语言解决这个问题,看看你能走多远。根据我的经验,当学生说他们“太依赖Java的思维”等时,他们也无法解决Java中的问题。 Prolog 是不同的,但并没有那么不同,如果您清楚地知道如何用 Java 解决它,则无法将其直接转换为 Prolog。我的解决方案使用 Prolog 的内置搜索机制,但您不必这样做:您可以像在 Java 中一样自己实现搜索。
Since a complete solution is posted already, here is mine:
Example query:
Since iterative deepening is used, we know that no shorter solution (less than 4 steps) is possible.
I also have a general comment on what you said:
Personally, I think this example is already much more than could be expected from a beginning, say, Java programmer. Please try to solve this problem in Java/C/whatever and see how far you get. In my experience, when students say they are "too tied to Java's thinking" etc., they cannot solve the problem in Java either. Prolog is different, but not that different that, if you had a clear idea of how to solve it in Java, could not translate it quite directly to Prolog. My solution uses the built-in search mechanism of Prolog, but you do not have to: You could implement the search yourself just as you would in Java.
这是我的解决方案:
它只找到所有可能的解决方案,尽管我认为找到的解决方案不是最佳的,而是第一个可行的解决方案。
Here is my solution:
It finds only first solution of all possible, though I suppose the solution found is not optimal, but rather first working one.
设法将 mat 的代码转换为汞:
编译
mmc --infer-all arrows.m
推断签名和决定论
Managed to transform mat's code to mercury:
Compiling with
mmc --infer-all arrows.m
to infer signatures & determinism