【发布时间】:2022-08-14 22:38:35
【问题描述】:
我正在学习 prolog 并在 exercism.io 上解决一些练习。我被困住了。我不想在互联网上搜索解决方案,因此我只会在练习部分提供一点帮助,因为我不明白我的错误在哪里,也不知道如何调试它。
练习是创建一个合法的chain of dominos。为此,我想编写一个简单的检查器。
[(1,2), (2,3), (3,4), (4,1)] 以及 [(1,1)] 或 [] 是合法的。 [(1,2)]、[(1,2), (3,1)] 或 [(1,2),(2,3)] 是非法的。我可以用我的is_chain 检查它:
is_loop([]).
is_loop([(X,X)]).
is_loop([(L,_)|Xs]) :-
last(Xs, (_, L)).
is_chain_no_loop([]).
is_chain_no_loop([(_, _)]).
is_chain_no_loop([(_,L), (L,Y)|Xs]) :-
is_chain_no_loop([(L,Y)|Xs]).
is_chain(X) :-
is_loop(X), is_chain_no_loop(X).
我把它分成两部分。 is_loop 检查第一个和最后一个元素是否兼容,is_chain_no_loop 检查内链。
这是我的困惑开始的地方。
我可以问序言,什么样的列表是有效的:
is_chain(R).
我得到以下信息:
R = []
R = [(_1370,_1370)]
R = [(_1370,_1372), (_1372,_1370)]
R = [(_1370,_1372), (_1372,_1384), (_1384,_1370)]
R = [(_1370,_1372), (_1372,_1384), (_1384,_1396), (_1396,_1370)]
R = [(_1370,_1372), (_1372,_1384), (_1384,_1396), (_1396,_1408), (_1408,_1370)]
R = [(_1370,_1372), (_1372,_1384), (_1384,_1396), (_1396,_1408), (_1408,_1420), (_552,_502)]
除了最后一个,我都明白了。我正在使用在线 SWI-Prolog SWISH。
为什么R的最后一张骨牌错了? _1420 与 _552 不匹配,_502 与第一个 _1370 不匹配。
最重要的是,(因为我假设is_chain 工作正常,但显然不是)我开始实现chain,得到了Pile 的多米诺骨牌,我可以得到正确的Chain (如果有的话)。
chain([], Chain) :- is_chain(Chain).
chain([P, Pile], []) :- chain(Pile, [P]).
现在,这还不完整,但我也不明白这里的东西。
给定一个Chain,它是一个有效的链,如果它是is_chain。简单的。
如果我没有Chain,那么我只需从 Pile 中选择一个P 并从它开始。
除了chain([(1,1)], R) 是false。但是is_chain([(1,1)]) 是true。
考虑到一切,似乎有一些深刻的东西,我不了解序言或其执行(或它的搜索)。很抱歉,我无法将其分解为更简单的示例。
编辑:
经过更多思考,我意识到is_chain 可以通过“吃掉”多米诺骨牌的递归更简单地实现:
is_chain([]).
is_chain([(X,X)]).
is_chain([(X,Y), (Y, Z)|Ls]) :-
is_chain([(X,Z)|Ls]).
但是,这会导致相同的解决方案...
-
我也担心我的问题不值得 StackOverflow。这可能更适合 Reddit 或某些 IRC ......我仍然希望有人能将我推向正确的方向。
-
我怀疑它正在工作,并且您的代码中没有错误。尝试
is_chain(Dominos), Dominos = [First-_|_Rest]并看到它在链变长时将First保持在开始和结束位置。我不知道发生了什么;我的怀疑是来自is_loop的开始变量和来自is_chain_no_loop([(_, _)])的结束变量使它们不同的变量只要它们统一,而在链内部,它们都来自is_chain([(X,Y), (Y, Z)|Ls]) :-,其中Y是同一个变量在两个地方。不过,这主要是猜测,并不是一个可靠的答案。 -
了解如何调试 Prolog,以便您可以看到正在发生的事情,而不是感到困惑和卡住 - swi-prolog.org/pldoc/man?section=debugoverview 及其子页面。
-
避免使用“逗号列表”,它们很容易混淆 - swi-prolog.discourse.group/t/… - 可以使用例如
d(X, Y)是一个正常的术语。 -
啊;在我的评论中,我的意思是
is_chain(Dominos), Dominos = [(First,_)|_Rest],我在玩多米诺骨牌时已将代码更改为使用X-Y而不是(X,Y),但忘记将我的示例改回来。
标签: prolog