check / 3谓词从列表中获取备用元素

时间:2014-10-29 16:00:34

标签: prolog

我有一个谓词check/3,例如check(A,B,C)。所有三个参数都是列表:

  • C是主列表
  • A包含具有奇数索引的项目
  • B包含具有偶数索引的项目

例如,

check([1,3],[2,4],[1,2,3,4]) % is true
check([1,2],[3,4],[1,2,3,4]) % is false

我试图检查并且不创建具有偶数和奇数奇偶校验的两个列表。这是我写的程序:

check( [] , [] , []      ).
check( O  , C  , [O,_|C] ) :- check(O,C,A).

我试图通过从第三个列表中删除备用元素并将其放在第一个列表中,同时将其余元素放在第二个列表中来解决它。但是我觉得如果比较它们就足够了。但我无法在没有任何算术或内置谓词的情况下了解如何实现它。

2 个答案:

答案 0 :(得分:3)

要根据列表中元素的序号位置(其*索引)将列表C划分为奇数和偶数元素列表,如果计算第一项中的第一项,这应该是技巧。列表为奇数(索引为1):

check( []     , []     , []       ) .  % the empty list has neither an even nor an odd element.
check( [O]    , []     , [O]      ) .  % a list of length 1 has only an odd element
check( [O|Os] , [E|Es] , [O,E|Xs] ) :- % a list of length > 1 has both an even and an odd element
  check(Os,Es,Xs) .                    % - park them on the respective lists and recurse down.

另一方面,如果你想把第一项计算为偶数(索引为0),那就差别不大了:

check( []     , []     , []       ) .  % the empty list has neither an even nor an odd element.
check( []     , [E]    , [E]      ) .  % a list of length 1 has only an even element
check( [O|Os] , [E|Es] , [E,O|Xs] ) :- % a list of length > 1 has both an even and an odd element
  check(Os,Es,Xs) .                    % - park them on the respective lists and recurse down.

你也可以通过使用一个带有标志的辅助谓词来完成同样的事情,该标志可以切换以指示状态:

check( Os , Es , Xs ) :-        % to partition list C into odd and even components...
  check( odd , Os , Es , Xs ) . % - just invoke the helper with an appropriate seed value.

check( _    , []     , []     , []     ) .  % we're done when we hit the end of the list.
check( odd  , [X|Os] , Es     , [X|Xs] ) :- % otherwise, place the head of the source list on the odd result list
  check( even , Os , Es ,Xs ) .             % - and recurse down, toggling state to even.
check( even , Os     , [X|Es] , [X|Xs] ) :- % otherwise, place the head of the source list on the even result list
  check( odd  , Os , Es ,Xs ) .             % - and recurse down toggling state to odd.

你会注意到在上面的例子中,我们已经用odd给助手播种,表明第一个元素有一个奇数位置(1个相对)。如果您希望第一个元素具有偶数位置(0-相对),只需将种子值切换为even

然而...... 有一种更简单的方法:在每次递归时,只需切换两个结果列表的位置:

check( []     , [] , []     ) .
check( [X|As] , Bs , [X|Cs] ) :- check( Bs , As , Cs ) .

甜!

答案 1 :(得分:1)

你真的非常接近。你的第二个条款应该是:

check([O|Os], [E|Es], [O,E|Rest]) :- check(Os, Es, Rest).

请注意,这并不保证奇怪或均匀的任何内容,只是第三个列表将由前两个列表中的交替项组成。 生成。如果您无法使用算术运算,那么显然无法以任何方式保证列表项的算术属性。但这可能不是这里真正想要的。这将满足您的示例查询。

在我看来,这个条款显示了对Prolog最难理解的事情之一:通过该条款的信息流。你可以想象每个变量被重用为类似箭头的东西:你有一个箭头从第一个参数的第一个项目到第三个参数的第一个项目,另一个箭头从第二个参数的第一个项目到第三个项目的第二个项目,然后从所有列表剩余的箭头到身体,基本上说"证明这种关系,证明它递归地保持在列表的尾部。"这很奇怪,我想你要么挂在这个上,要么在头上的模式匹配上。我的变量名称可能不完美,但我怀疑他们会比O和C更有助于看到这种关系。

我敢打赌,如果你看着它并看着你自己,你会自己看到问题,但在这里它们是:

  • check(O, C, ...)在类型上感到困惑。 OC需要在这里列出,但是条款正文中的列表项(好吧,C不会,但那里也存在问题)。
  • check(..., [O,_|C])表示列表的第一项是O,然后是未指定的内容,然后C就是列表的尾部。
  • A是身体中的单身人士,这意味着它并没有真正做任何事情。每当你收到一个单例警告时,用一个下划线替换变量,看看它是否仍然有意义。如果没有,你就会产生误解,可能需要对你的条款进行修改。

要查看列表构造函数,[X | Xs]表示X是第一个项目,列表的其余部分是Xs。 |运算符从列表尾部划分项目。因此,如果你正在处理一个扁平(单调)列表,左边的所有内容都应该是项目,而右边的内容则是另一个列表。你也可以在右边只有一个东西,但你可以在它之前用逗号分隔几个项目(就像你一样)。

希望这有帮助!