首页 > 解决方案 > 使用 Prolog 查找列表的回文:- Ivan Btrako 的练习 3.5“人工智能的 Prolog 编程”

问题描述

在过去的 3 年里,我一直在用 java 编程,而我刚刚开始学习 Prolog。我下载了 SWI-Prolog 来运行我的代码并进行跟踪,但我在这个特定问题上遇到了麻烦。

/*concatinates 2 Lists together*/
 conc([],L,L).
 conc([X|T],L2,[X|T1]):-
     conc(T,L2,T1).

/*Finds the reverse a List*/    
reverse([],[]).
reverse([H|T],ReversedList):-
    reverse(T,Reverse),
    conc(Reverse,[H],ReversedList).

palindrome(L):-
    reverse(L,L1),
    L is L1.

例如,如果我输入

palindrome([m,a,d,a,m]). 

L 是 [m,a,d,a,m] & L1 应该是从反向谓词返回的 [m,a,d,a,m]。

L = L1并且输出应该是真的。但是打印了一个我不明白的错误

ERROR: Type error: `[]' expected, found `[m,a,d,a,m]' (a list) ("x" must hold one character)
ERROR: In:
ERROR:    [9] [m,a|...]is[m,a|...]
ERROR:    [8] palindrome([m,a|...]) at c:/users/d/desktop/trial.pl:97
ERROR:    [7] <user>

我的代码只有在我将谓词更改为:

palindrome(L):-
    reverse(L,L).

我不明白为什么因为逻辑是相同的......L = L1与调用 L1, L 开始时相同。

此外,这是不使用 reverse 函数的谓词代码。我无法理解为什么我们有 palidrome1([_]) 基本情况以及为什么如果我没有在 conc 函数的 [First] 周围放置一个括号,它会返回 false。

palindromel( [] ).
palindromel( [_] ).
palindromel( [First | Rest]) :-
    conc( Middle, [First], Rest), /*Do I have to put First in a list bracket?*/
    palindromel( Middle).

任何帮助,将不胜感激。

标签: prolog

解决方案


但是打印了一个我不明白的错误。

导致该行的错误是

L is L1

是/2说:

-Number is +Expr

True when Number is the value to which Expr evaluates. 
Typically, is/2 should be used with unbound left operand. 
If equality is to be tested, =:=/2 should be used.

由于左边不是数字,右边不是表达式 is/2 ,所以不能使用。


我不明白为什么,因为逻辑是一样的。

其实逻辑不一样。is/2不等于统一,=/2

原因

palindrome(L):-
    reverse(L,L).

有效,因为 . 的两个参数只有一个变量reverse/2。因此输入reverse/2和结果reverse/2必须统一。在这种情况下,由于输入和输出是相同的,如果它们是回文,它们可以统一。

另一种看待这一点的方法是使用这种变化

palindrome(L1):-
    reverse(L1,L2),
    L1 = L2.

这次我使用了两个不同的变量,reverse/2但随后将统一作为一个单独的步骤进行。第一种方式

palindrome(L):-
    reverse(L,L).

与此变体相同,但在第一种方式中,统一是通过使用reverse(L,L).


我无法理解为什么我们有 palidrome1([_]) 基本案例。

当我开始编写代码来解决问题时,我会在脑海中或在纸上手动解决问题。我从最简单的案例开始,然后朝着更复杂的方向努力。对于回文,最简单的情况是没有字母的单词。

因此,如果输入是一个空列表[],则回文是一个空列表[]

palindromel( [] ).

下一个更难的情况是一个带有一个字母的单词[_]

palindromel( [_] ).

下一个更难的情况是一个有两个字母的单词[A,A]

palindromel( [A,A] ).

等等

 palindromel( [A,B,A] ).
 palindromel( [A,B,B,A] ).
 palindromel( [A,B,C,B,A] ).
 palindromel( [A,B,C,C,B,A] ).

为了避免不得不创建无穷无尽的子句列表,使用了递归。然而,对于回文,两个简单的案例成为递归的基本案例,其余的都是使用带有递归子句的基本案例来完成的。

如果我没有在 conc 函数的 [First] 周围放置一个括号,它会返回 false。

我问 Bratko 的“人工智能的 Prolog 编程”的原因是,在他的书中,他让学生创建conc/3,但没有注意到它真的是append/3。如果您正在使用这本书,请帮自己一个忙并改用append/3它,因为它没有错误,而且很可能conc/3会失败,而append/3会起作用。

append/3附加两个列表以创建第三个列表。如果您不放置[]单个字符,那么它不是一个列表而是一个字符,并且append/3conc/3将失败。


推荐阅读