Types 序言类型错误

Types 序言类型错误,types,prolog,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,

我正在研究一种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相当于integer(expr),它将数据类型舍入并转换为整数。我还尝试用truncate(expr)和integer(expr)替换round,但收到了相同的错误。有人能解释一下我做错了什么吗?

round
不是一个函数,而是一个谓词。我还没有看过代码的其余部分,但那一行应该是

round(Length/2, R), trim(L, R, A)
编辑:顺便说一句,你想得太多了

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

round
不是一个函数,而是一个谓词。我还没有看过代码的其余部分,但那一行应该是

round(Length/2, R), trim(L, R, A)
编辑:顺便说一句,你想得太多了

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

Prolog不执行内联表达式求值。因此,诸如
trim(L2,Length/2,B)
trim(L,round(Length/2),A)
之类的调用将不会像您期望的那样工作。只有在使用某些运算符(如
is/2
、算术比较或它们的CLP(FD)对应项)时,才会对表达式进行特定计算。这些表达式需要按如下方式执行:
L是长度//2,trim(L2,L,B)
R是圆形(长度/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
    ).

Prolog不执行内联表达式求值。因此,诸如
trim(L2,Length/2,B)
trim(L,round(Length/2),A)
之类的调用将不会像您期望的那样工作。只有在使用某些运算符(如
is/2
、算术比较或它们的CLP(FD)对应项)时,才会对表达式进行特定计算。这些表达式需要按如下方式执行:
L是长度//2,trim(L2,L,B)
R是圆形(长度/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
    ).
惯用的解决方案:

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).
编辑

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

从Prolog一开始,我们就提供了一个独特的关系和功能(递归)工具的混合,这对新手来说没有什么意义。至少,这仍然让我感到惊讶。。。我喜欢这个事实

例如,现在,函数逻辑编程试图通过“缩小”来解决问题。从链接页面:

缩小范围很有用,因为它允许将函数视为关系:它的值可以“在两个方向”计算

现在,当它是一个简单的方法来解决同样的问题。实际上,swap/2被描述为一种功能,但可以作为一种关系来实现吗

@错误的建议,添加相同长度(L,S)作为第一个目标,修复了交换(-,+)模式,但在交换(-,)上循环。该方法基于_u1/1报告连接无法接地的时间

编辑

除了终止问题,我对目标顺序的选择真的是无效的。暗示着这个答案,我突然想到,将约束放在第一位可以获得巨大的效率增益(至少对于模式交换(+,-):

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)
惯用的解决方案:

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).
编辑

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

从Prolog一开始,我们就提供了一个独特的关系和功能(递归)工具的混合,这对新手来说没有什么意义。至少,这仍然让我感到惊讶。。。我喜欢这个事实

例如,现在,函数逻辑编程试图通过“缩小”来解决问题。从链接页面:

缩小范围很有用,因为它允许将函数视为关系:它的值可以“在两个方向”计算

现在,当它是一个简单的方法来解决同样的问题。实际上,swap/2被描述为一种功能,但可以作为一种关系来实现吗

@错误的建议,添加相同长度(L,S)作为第一个目标,修复了交换(-,+)模式,但在交换(-,)上循环。该方法基于_u1/1报告连接无法接地的时间

编辑

除了终止问题,我对目标顺序的选择真的是无效的。暗示着这个答案,我突然想到,将约束放在第一位可以获得巨大的效率增益(至少对于模式交换(+,-):

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)

下面是另一个解决方案,它基于对的修改,用于将列表拆分为两个等长的列表。我所做的修改通过将0或1个元素的“中间”列表作为参数,使谓词能够成功使用奇数长度列表。它还使用
same_length
约束参数,以避免某些参数出现终止问题