我正在研究一种能在列表上执行“交换”的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,但是我收到了同样的错误。有人可以解释我做错了吗?
答案 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).