Prolog List Squaring,修改List中的元素

时间:2014-05-30 18:57:01

标签: prolog

我正在尝试编写一个简短的Prolog程序,该程序会获取一个数字列表并返回一个列表,其中所有数字都已被平方。

即:[2,4,5] => [4,16,25]

到目前为止我的代码:

list_of_squares([X], L) :-
    L is X^2.
list_of_squares([X|XS], [X^2|M]) :-
    list_of_squares(XS, M).

出于某种原因,尽管Prolog并不喜欢我在将X添加到列表时对X进行平方...对于我如何做到这一点的任何想法?

3 个答案:

答案 0 :(得分:3)

你不是那么遥远,但是你犯了两个小错误:

首先,您将元素X与列表L混合。你的第一个条款应该是:

list_of_squares([X], [Y]):-
  Y is X ^ 2.

其次,您不能以列表表示法执行算术功能。 您的第二个条款应如下:

list_of_squares([X|Xs], [Y|Ys]):-
  Y is X ^ 2,
  list_of_squares(Xs, Ys).

第三,存在一个更基本的问题。使用前两个修复程序,您的代码可以正常工作,但基本情况(即第一个子句)并没有很好地选择。 (一)代码无法处理空列表。 (B)对于单例列表,代码是不必要的不​​确定性,因为这两个条款都适用。这可以通过明智地选择基本案例来解决:

squares([], []).
squares([X|Xs], [Y|Ys]):-
  Y is X ^ 2,
  squares(Xs, Ys).

答案 1 :(得分:1)

以下是一般方法,您可以如何本地化此类错误。首先,让我们从你的例子开始:

?- list_of_squares([2,4,5],[4,16,25]).
false.

哦不!它失败!在这种情况下,有一种非常通用的方法:

概括查询

所以我们用一个新的,新鲜的(啊,真正的新鲜!)变量替换[4,16,25]

?- list_of_squares([2,4,5],L).
L = [2^2, 4^2|25] ;
false.

这样更好:现在你知道有一个“结果”,但结果并不是你所期望的。

接下来,

最小化查询

列表太长了,所以我会砍掉一些元素。说,前两个:

?- list_of_squares([5],L).
L = 25 ;
false.

再次,错误,但更小。现在,错误在哪里?得到它

专攻您的计划

list_of_squares([X], L) :-
    L is X^2.
list_of_squares([X|XS], [X^2|M]) :- false,
    list_of_squares(XS, M).

该程序再次给出了同样错误的答案!所以在可见部分有一个错误。我们期待的是

?- list_of_squares([5],[25]).
false.
这是成功的。但错误在哪里?再次:

概括查询

?- list_of_squares([5],[X]).
false.

HET!

现在,您应该意识到该规则可能是:

list_of_squares([X], [Y]):-
  Y is X ^ 2.

在递归规则中应该使用相同的(is)/2。而且,为什么不接受[]

我个人宁愿使用library(lambda)写一下:

list_of_squares(Xs, Ys) :-
   maplist(\X^XX^(XX is X^2), Xs, Ys).

或者,甚至更好,使用library(clpfd)

list_of_squares(Xs, Ys) :-
   maplist(\X^XX^(XX #= X^2), Xs, Ys).

答案 2 :(得分:0)

Prolog没有'功能'思维模式,但是一些标准的内置谓词可以帮助处理列表。在这种情况下

list_of_squares(L,S) :- findall(Sq,(member(E,L),Sq is E*E),S).

?- list_of_squares([2,4,5], R).
R = [4, 16, 25].

在这种情况下,member / 2扮演类似于lambda表达式的角色,为L. findall / 3中的每个元素E提供一个“名称”,计算其目标,(member(E,L),Sq is E*E),的所有解,并收集结果( '模板'表达式,即Sq)。