1

我是 Prolog 的新手,并试图实现一种深度平方谓词,它将列表和子列表中的所有数字平方。我写了一些工作代码,但它没有给我我期望的输出。

代码:

dsquare([],S).
dsquare([H|T],[R|S]):- number(H), dsquare(T,S), R is H*H, !.
dsquare([H|T],S):- isList(H), dsquare(H,S).
dsquare([H|T],[R|S]) :- dsquare(T,S), R = H, !.

电流输出:

2?- dsquare([[2],4,a],X).

X = [4| _VDHV] ;

X = [[2], 16, a| _VDNM] ;

fail.

预期输出:

X = [[4], 16, a]

我还想知道为什么我的输出中会出现那些“_VDHV”和“_VDNM”。任何帮助将非常感激。

编辑: 好的,所以我将代码更新为:

dsquare([],[]).
dsquare([H|T],[R|S]):- number(H), R is H*H, dsquare(T,S).
dsquare([H|T],[R|S]):- isList(H), dsquare(H,R), dsquare(T,S).
dsquare([H|T],[R|S]) :- R=H, dsquare(T,S).

但我得到的输出是:

13?- dsquare([a,3,[[2]],b,4],X).

X = [a, 9, [[4]], b, 16] ;

X = [a, 9, [[4]], b, 4] ;

X = [a, 9, [[2]], b, 16] ;

X = [a, 9, [[2]], b, 4] ;

X = [a, 9, [[2]], b, 16] ;

X = [a, 9, [[2]], b, 4] ;

X = [a, 9, [[2]], b, 16] ;

X = [a, 9, [[2]], b, 4] ;

X = [a, 3, [[4]], b, 16] ;

X = [a, 3, [[4]], b, 4] ;

X = [a, 3, [[2]], b, 16] ;

X = [a, 3, [[2]], b, 4] ;

X = [a, 3, [[2]], b, 16] ;

X = [a, 3, [[2]], b, 4] ;

X = [a, 3, [[2]], b, 16] ;

X = [a, 3, [[2]], b, 4] ;

fail.

我不知道它是如何得到这么多结果的。

最后编辑 工作解决方案是

dsquare([],[]).
dsquare([H|T],[R|S]) :- number(H), !, R is H*H, dsquare(T,S).
dsquare([H|T],[R|S]) :- isList(H), !, dsquare(H,R), dsquare(T,S).
dsquare([H|T],[H|S]) :- dsquare(T,S).
4

2 回答 2

1

你的 Prolog 应该在你的第一条和第三条规则中警告你一个“单例”。

尝试

dsquare([],[]).
...
dsquare([H|T],[S|R]):- isList(H), dsquare(H,S), dsquare(T,R).

OT 不会在没有动机的情况下进行裁员。

编辑你会得到更多结果,因为最后一条规则在回溯时被触发。现在可能是时候在需要的地方放置剪辑了(即在代码进入由条件保护的分支之后):

dsquare([],[]).
dsquare([H|T],[R|S]) :- number(H), !, R is H*H, dsquare(T,S).
dsquare([H|T],[R|S]) :- isList(H), !, dsquare(H,R), dsquare(T,S).
dsquare([H|T],[R|S]) :- R=H, dsquare(T,S).

或考虑进行重构以解决重复代码:

dsquare([],[]).
dsquare([H|T],[R|S]) :-
  (  number(H)
  -> R is H*H
  ;  isList(H)
  -> dsquare(H,R)
  ;  R=H
  ),
  dsquare(T,S).

编辑上面的定义(我用'if/then/else'测试过)似乎很好:

1 ?- dsquare([[2],4,a],X).
X = [[4], 16, a].

2 ?- dsquare([a,[3],[[[5]]],[2],a],X).
X = [a, [9], [[[25]]], [4], a].
于 2013-11-01T23:08:04.767 回答
0

这些_Vxxx位是 prolog 对结果中未绑定变量的表示。基本上,它是符号表中的键或地址。

  • 在你的第一条规则中,

    dsquare([],S).
    

    你永远不会将任何东西绑定到第二个参数。这意味着如果您调用它 as dsquare([],X), X 将保持未绑定。如果调用为dsquare([1,2,3],X)(假设其他一切正常,则生成的列表结构将被破坏并且X类似于[1,2,3|_VD3DC],因为最后一项既不是原子[](空列表)也不./2是非空的结构列表。

  • 在你的第二条规则中,

    dsquare([H|T],[R|S]):- number(H), dsquare(T,S), R is H*H, !.
    
    • 剪切 ( !) 是不必要的
    • 您的运算符顺序不正确。先平方 H,然后向下递归。这完成了两件事:它 (A) 提前失败(如果结果是绑定的),并且 (B) 允许应用尾递归优化。
  • 在你的第三条规则中,

    dsquare([H|T],S):- isList(H), dsquare(H,S).
    

    您正在递归作为源列表头部的子列表,但根本不评估源列表的尾部,而是简单地丢弃它。

  • 在你的第四条规则中,

    dsquare([H|T],[R|S]) :- dsquare(T,S), R = H, !.
    

    再次,就像您的第二条规则一样,不需要切割并且操作顺序颠倒。

我会这样写:

deep_square( []     , []     )    % squaring an empty list produces an empty list
  .
deep_square( [X|Xs] , [Y|Ys] ) :- % otherwise...
  number(X) ,                     % if the head is a number,
  Y is X*X  ,                     % square it
  deep_square(Xs,Ys)              % and recurse down
  .                               %
deep_square( [X|Xs] , [Y|Ys] ) :- % otherwise...
  nonvar(X) ,                     % if the head is bound,
  X = [_|_] ,                     % and is a non-empty list.
  deep_square( X , Y ) ,          % deep square the head
  deep_square( Xs , Ys )          % and then recurse down
  .
deep_square( [X|Xs] , [X|Ys] ) :- % otherwise the head is unbound or something other than a number or a non-empty list...
  deep_square( Xs , Ys )          % recurse down.
  .                               % Easy!

你会注意到在序言谓词的子句的头部有很多统一魔法等等。

于 2013-11-02T01:24:59.560 回答