【问题标题】:Prolog check if list contains even number of an elementProlog检查列表是否包含偶数个元素
【发布时间】:2018-11-17 20:20:06
【问题描述】:

我必须检查一个列表是否包含偶数个没有内置的元素。

例子:

containsEvenNumber([a,b,c,a,a], a).

返回假

containsEvenNumber([a,b,c,a], a).

返回真

当前状态:

not(A) :-
    A, !,
    fail.
not(_).
equal([E|_], E).
containsEvenNumber([], _).
containsEvenNumber([E|Tail], E) :-
    unevenCount(Tail, E).

containsEvenNumber([Head|Tail], E) :-
    not(equal([Head|Tail], E)),
    evenCount(Tail, E).

evenCount([], _).
evenCount([E|Tail], E) :-
    unevenCount(Tail, E).

evenCount([Head, Tail], E) :-
    not(equal([Head|Tail], E)),
    unevenCount(Tail, E).

unevenCount([], _) :-
    fail.
unevenCount([E, Tail], E) :-
    evenCount(Tail, E).

unevenCount([Head, Tail], E) :-
    not(equal([Head|Tail], E)),
    unevenCount(Tail, E).

我尝试在元素出现时在状态之间切换。 它不起作用,因为我从不进入头部不是元素的状态,或者更确切地说,我也进入状态并在头部是元素时返回 false。

我怎样才能让它工作/修复它?

【问题讨论】:

  • 是的,在 Prolog 中是可能的。没有内置插件?由于 Prolog 的所有基本功能都是“内置的”,我会说不是。你都尝试了些什么?你有更具体的问题吗?您是否查看过 Prolog 文档并检查过它的运算符集?
  • 是的,我应该编写以下谓词:containsEvenNumberOfTheElement(L,E).,没有任何内置函数。 L 是一个列表。
  • 那个也是可能的。您需要展示您的尝试并提出具体问题。
  • 我现在编辑了这个,希望你能帮助我:)
  • “状态之间的切换”其实是解决这个问题的好办法,但是你有几个问题:(1)你不需要定义not/1。它已经在 SWI Prolog 中定义,ISO prolog 有\+(这不是错误,只是注释); (2)[Head, Tail]应该是[Head | Tail][E, Tail]应该是[E|Tail]; (3) 您对unevenCount/2 的基本情况(我假设您的意思是oddCount?)不正确。应该是unevenCount([X], X). 使用失败子句作为基本情况会导致谓词失败。

标签: list recursion prolog tail head


【解决方案1】:

“状态之间的切换”其实是解决这个问题的好办法。逻辑应该遵循这些简单的规则:

  1. 如果Xs 中有奇数个X 元素,则[X|Xs] 中有偶数个X 元素。

  2. 如果XY不同,则[Y|Xs]中有偶数个X元素,Xs中有偶数个X元素。

  3. 如果Xs 中有偶数个X 元素,则[X|Xs] 中有奇数个X 元素。

  4. 如果XY 不同,则[Y|Xs] 中有奇数个X 元素,而Xs 中有奇数个X 元素。

那么你就有了基本情况:

[] 中有偶数个任意元素。

[X] 中有奇数个X

您只需将这些规则编写为 Prolog。但是,您的实现存在一些问题。

在少数情况下,您将列表写为[Head, Tail] 而不是[Head|Tail][Head, Tail] 是正好包含两个元素的列表。此外,unevenCount/2 的基本情况(我假设您的意思是奇数)不正确。如果您有一个始终失败的基本案例,那么您的谓词将始终失败。除了少数例外,您应该编写谓词从句以成功,而不是失败。无法成功时会自动失败。

让我们试着写出上面的规则。 ISO Prologs 已经有\+,所以你不需要定义not/1。另外,写equal([E|_], E). 是不必要的。您可以直接在代码中简单地执行此操作。

evenCount(_, []).          % base case for even
evenCount(X, [X|Xs]) :-    % rule #1
    oddCount(X, Xs).
evenCount(X, [Y|Xs]) :-    % rule #2
    dif(X, Y),
    evenCount(X, Xs).

oddCount(X, [X]).          % base case for odd
oddCount(X, [X|Xs]) :-     % rule #3
    evenCount(X, Xs).
oddCount(X, [Y|Xs]) :-     % rule #4
    dif(X, Y),
    oddCount(X, Xs).

SWI Prolog 定义了dif/2。您也可以使用\==,但它不是像dif/2 那样纯粹定义(因此行为不一样)。

【讨论】:

  • 非常感谢您的回答。不过我有些担心。我认为这种方法也会失败,同时输入两个谓词(如果我说得对的话)。例如:evenCount(1, [1|2,3]) 将输入 evenCount(X, [X|Xs])evenCount(X, [Y|Xs]),第二个将在 dif(1,1) 失败。另外我猜dif 是内置的,因此不幸的是不适合。如果我错了,请纠正我。
  • @beefsausage 您应该尝试我提供的代码来验证您的担忧。 evenCount(1, [1,2,3])(与evenCount(1, [1|[2,3]])) 相同,将调用oddCount(1, [2,3]),然后最终失败,因为1 没有均匀地包含在[1,2,3] 中。而且,是的,evenCount(X, [Y|Xs]) 子句也失败了,因为dif(1,1)失败,也根据需要。请注意,当您有多个谓词子句时,您只需要一个成功即可使查询成功。它们彼此之间具有“OR”关系。
  • 就内置函数而言,我已经提到您可以使用 \== 代替 dif/2
  • 非常感谢!它奏效了,但我花了一点时间才明白这一点!你太棒了,我非常感谢你的解释和解决方案!你拯救了我的一天:)
  • @beefsausage 不用担心。我希望这很清楚。如果您对此有任何疑问,请告诉我。我建议所有 Prolog 初学者:忘记你认为你知道的关于编程的一切。 Prolog 不像其他语言那样工作,这些语言大多是命令式的。可以将其视为定义一组规则:“如果这是真的,那是真的,等等。”这个想法是定义规则是准确的、完整的和不重叠的(以避免重复的解决方案)。
猜你喜欢
  • 1970-01-01
  • 2014-07-31
  • 2022-09-23
  • 1970-01-01
  • 1970-01-01
  • 2021-06-24
  • 2017-11-20
  • 2014-04-30
相关资源
最近更新 更多