Prolog类型错误

时间:2016-04-21 01:17:33

标签: types prolog

我正在研究一种能在列表上执行“交换”的prolog算法。

示例:

输入:[1,2,3,4] - >产出:[3,4,1,2]  输入:[1,2,3,4,5] - >输出:[4,5,3,1,2]

列表的前半部分和后半部分交换位置,如果有奇数,则中心元素保留其位置。我想出了一个算法,但是我收到了一个错误:

?- swap([1,2,3,4],L).
ERROR: length/2: Type error: `integer' expected, found `round(4/2)'

我的代码如下:

swap(L, S) :-
    length(L, Length),
    reverse(L, L2),
    mixing(L, Length, A),
    trim(L2, Length/2 , B),
    append(A,B,S).

trim(L,N,S) :-
    length(P,N),
    append(P,S,L).

mixing(L, Length, A) :-
    (  mod(Length, 2) == 0
    -> trim(L, round(Length/2), A)
    ;  trim(L, round(Length/2), A)
    ).

问题在于,在调用trim(L,round(Length / 2),A)时'混合',类型不是整数?我知道Length / 2不是一个整数(很可能是一个浮点数),我认为round等于整数(expr),它将数据类型舍入并转换为整数。我也尝试用truncate(expr)和integer(expr)替换round,但是我收到了同样的错误。有人可以解释我做错了吗?

4 个答案:

答案 0 :(得分:2)

Prolog不进行内联表达式评估。因此,trim(L2, Length/2 , B)trim(L, round(Length/2), A)等来电不会像预期的那样发挥作用。表达式仅在使用某些运算符(如is/2,算术比较或其CLP(FD)对应项)时进行特定评估。这些表达式需要完成:L is Length // 2, trim(L2, L, B)R is round(Length/2), trim(L, R, A)如果按字面意思完成。

然而,您的解决方案可能会被压缩,如下所示。

swap(L, S) :-
    same_length(L, S),               % L and S are necessarily the same length
    length(L, N),
    M is N // 2,   % integer divide ; half the original list length
    length(Left, M),                 % Left is a list of half the length of L
                                     %   or half minus one if the length is odd
    (   (N mod 2) =:= 1              % If the original length is odd...
    ->  append(Left, [H|Right], L),  % then L is Left + [H|Right]
        append(Right, [H|Left], S)   %   So, S is Right + [H|Left]
    ;   append(Left, Right, L),      % otherwise, L is Left + Right
        append(Right, Left, S)       %   So, S is Right + Left
    ).

答案 1 :(得分:1)

round不是函数,它是谓词。我没有查看其余的代码,但该行应该是

round(Length/2, R), trim(L, R, A)

编辑:顺便说一下,你是在思考它。

swap([], []).
swap([X], [X]).
swap([X, Y | A], [Y, X | B]) :- swap(A, B).

<击>

答案 2 :(得分:0)

惯用解决方案:

swap(L,S) :-
    %maplist(when_, [
    append([X,C,Y],L), (C=[];C=[_]), same_length(X,Y),
    reverse(X,U), reverse(Y,V), append([U,C,V],S)
    %])
    .

?- swap([1,2,3,4,5],S).
S = [2, 1, 3, 5, 4] ;
false.

这不是真正的关系,因为如果在模式swap(-,+)中调用它会挂起,但在取消注释包围后它会表现得更好,并提供此代码段:

:- meta_predicate when_(0).
when_(P) :-
    strip_module(P,_,Q), Q =.. [_|As],
    or_list(As, Exp), display(Exp),
    when(Exp, P).

or_list([A], ground(A)) :- !.
or_list([A|As], (ground(A);Exp)) :- or_list(As, Exp).

修改

在@false'评论之后,我试图解释这个答案的动机。请求的swap / 2'函数'似乎是展示Prolog数据模型特性的理想候选者,虽然请求的解释(关于应用于列表的整数算法的正确语法用法)在这里甚至没有暗示。

从Prolog的一开始,我们就可以使用关系功能(递归)工具的独特组合,这对新手来说毫无意义。至少,它仍然让我感到惊讶......我喜欢这个事实。

现在,功能逻辑编程(例如Curry)通过“缩小”尝试解决方案。从链接页面:

  

缩小很有用,因为它允许将函数视为关系:它的值可以“双向”计算

现在,when_ / 1这是一个解决同一问题的简单方法。在脚踏实地的情况下,swap / 2被描述为一个函数,但可以 实现作为关系?

@false建议,添加same_length(L,S)作为第一个目标,修复交换( - ,+)模式,但循环交换( - , - )。基于when_ / 1的方法代替报告无法将连接点接地。

修改

终止问题,我选择的目标订单实际上是无效的。向another question暗示这个答案,我发现可以获得一个很大的效率增益(至少对于模式交换(+, - ))可以先得到约束:

3 ?- numlist(1,100,L), time((append([X,C,Y],L), (C=[];C=[_]), same_length(X,Y), append([Y,C,X], S))). 
% 328,899 inferences, 0.125 CPU in 0.125 seconds (100% CPU, 2634422 Lips)
L = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
X = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
C = [],
Y = [51, 52, 53, 54, 55, 56, 57, 58, 59|...],
S = [51, 52, 53, 54, 55, 56, 57, 58, 59|...] 
.

4 ?- numlist(1,100,L), time(((C=[];C=[_]), same_length(X,Y), append([X,C,Y],L), append([Y,C,X], S))). 
% 3,273 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 3210999 Lips)

答案 3 :(得分:0)

这是另一种解决方案,它基于对a predicate posted by @joel76的修改,将列表拆分为两个相等长度的列表。我做的修改使谓词通过包含&#34;中间&#34;成功使用奇数长度列表。 0或1个元素的列表作为参数。它还使用same_length约束参数以避免某些参数的终止问题。我包含了same_length/2的简单实现,并非所有Prolog都有(它包含在SWI Prolog中)。

swap(L, S) :-
    same_length(L, S),
    div(L, Front, Middle, Back),     % L is divided into two halfs & middle
    append(Back, Middle, NewFront),  % S is Back + Middle + Front
    append(NewFront, Front, S).

% List L consists of Left + Middle + Right where Left and Right are equal length
%   and Middle has maximum length of 1
%
div(L, Left, Middle, Right) :-
    split(L, L, Left, Middle, Right).

split(L, [], [], [], L).
split([H|T], [_], [], [H], T).
split([H|T], [_, _|T1], [H|T2], M, Right) :-
    split(T, T1, T2, M, Right).

% same_length/2 is pre-defined in SWI Prolog and succeeds if the arguments
% are lists of equal length
%
same_length([], []).
same_length([_|Xs], [_|Ys]) :- same_length(Xs, Ys).