View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        jan@swi-prolog.org
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  1985-2021, University of Amsterdam,
    7                              VU University Amsterdam
    8                              SWI-Prolog Solutions b.v.
    9    All rights reserved.
   10
   11    Redistribution and use in source and binary forms, with or without
   12    modification, are permitted provided that the following conditions
   13    are met:
   14
   15    1. Redistributions of source code must retain the above copyright
   16       notice, this list of conditions and the following disclaimer.
   17
   18    2. Redistributions in binary form must reproduce the above copyright
   19       notice, this list of conditions and the following disclaimer in
   20       the documentation and/or other materials provided with the
   21       distribution.
   22
   23    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   24    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   25    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   26    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   27    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   28    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   29    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   30    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   31    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   33    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   34    POSSIBILITY OF SUCH DAMAGE.
   35*/
   36
   37:- module(prolog_explain,
   38          [ explain/1,
   39            explain/2
   40          ]).   41:- autoload(library(apply),[maplist/2,maplist/3]).   42:- autoload(library(lists),[flatten/2]).   43:- autoload(library(prolog_code), [pi_head/2]).   44
   45:- if(exists_source(library(pldoc/man_index))).   46:- autoload(library(pldoc/man_index), [man_object_property/2]).   47:- endif.

Describe Prolog Terms

The library(explain) describes prolog-terms. The most useful functionality is its cross-referencing function.

?- explain(subset(_,_)).
"subset(_, _)" is a compound term
    from 2-th clause of lists:subset/2
    Referenced from 46-th clause of prolog_xref:imported/3
    Referenced from 68-th clause of prolog_xref:imported/3
lists:subset/2 is a predicate defined in
    /staff/jan/lib/pl-5.6.17/library/lists.pl:307
    Referenced from 2-th clause of lists:subset/2
    Possibly referenced from 2-th clause of lists:subset/2

Note that PceEmacs can jump to definitions and gxref/0 can be used for an overview of dependencies. */

 explain(@Term) is det
Give an explanation on Term. The argument may be any Prolog data object. If the argument is an atom, a term of the form Name/Arity or a term of the form Module:Name/Arity, explain/1 describes the predicate as well as possible references to it. See also gxref/0.
   77explain(Item) :-
   78    explain(Item, Explanation),
   79    writeln(Explanation),
   80    fail.
   81explain(_).
   82
   83                /********************************
   84                *           BASIC TYPES         *
   85                *********************************/
 explain(@Term, -Explanation) is nondet
True when Explanation is an explanation of Term.
   91explain(Var, Explanation) :-
   92    var(Var),
   93    !,
   94    utter(Explanation, '"~w" is an unbound variable', [Var]).
   95explain(I, Explanation) :-
   96    integer(I),
   97    !,
   98    utter(Explanation, '"~w" is an integer', [I]).
   99explain(F, Explanation) :-
  100    float(F),
  101    !,
  102    utter(Explanation, '"~w" is a floating point number', [F]).
  103explain(S, Explanation) :-
  104    string(S),
  105    !,
  106    utter(Explanation, '"~w" is a string', S).
  107explain([], Explanation) :-
  108    !,
  109    utter(Explanation, '"[]" is a special constant denoting an empty list', []).
  110explain(A, Explanation) :-
  111    atom(A),
  112    utter(Explanation, '"~w" is an atom', [A]).
  113explain(A, Explanation) :-
  114    atom(A),
  115    current_op(Pri, F, A),
  116    op_type(F, Type),
  117    utter(Explanation, '"~w" is a ~w (~w) operator of priority ~d',
  118          [A, Type, F, Pri]).
  119explain(A, Explanation) :-
  120    atom(A),
  121    !,
  122    explain_atom(A, Explanation).
  123explain([H|T], Explanation) :-
  124    is_list(T),
  125    !,
  126    List = [H|T],
  127    length(List, L),
  128    (   utter(Explanation, '"~p" is a proper list with ~d elements',
  129              [List, L])
  130    ;   maplist(printable, List),
  131        utter(Explanation, '~t~4|Text is "~s"',  [List])
  132    ).
  133explain([H|T], Explanation) :-
  134    !,
  135    length([H|T], L),
  136    !,
  137    utter(Explanation, '"~p" is a not-closed list with ~d elements',
  138          [[H|T], L]).
  139explain(Name/Arity, Explanation) :-
  140    atom(Name),
  141    integer(Arity),
  142    !,
  143    functor(Head, Name, Arity),
  144    known_predicate(Module:Head),
  145    (   Module == system
  146    ->  true
  147    ;   \+ predicate_property(Module:Head, imported_from(_))
  148    ),
  149    explain_predicate(Module:Head, Explanation).
  150explain(Module:Name/Arity, Explanation) :-
  151    atom(Module), atom(Name), integer(Arity),
  152    !,
  153    functor(Head, Name, Arity),
  154    explain_predicate(Module:Head, Explanation).
  155explain(Module:Head, Explanation) :-
  156    callable(Head),
  157    !,
  158    explain_predicate(Module:Head, Explanation).
  159explain(Dict, Explanation) :-
  160    is_dict(Dict, Tag),
  161    !,
  162    utter(Explanation, '"~W" is a dict with tag ~q',
  163          [Dict, [quoted(true), numbervars(true)], Tag]).
  164explain(Term, Explanation) :-
  165    numbervars(Term, 0, _, [singletons(true)]),
  166    utter(Explanation, '"~W" is a compound term',
  167          [Term, [quoted(true), numbervars(true)]]).
  168explain(Term, Explanation) :-
  169    explain_functor(Term, Explanation).
 known_predicate(:Head)
Succeeds if we know anything about this predicate. Undefined predicates are considered `known' for this purpose, so we can provide referenced messages on them.
  177known_predicate(M:Head) :-
  178    var(M),
  179    current_predicate(_, M2:Head),
  180    (   predicate_property(M2:Head, imported_from(M))
  181    ->  true
  182    ;   M = M2
  183    ),
  184    !.
  185known_predicate(Pred) :-
  186    predicate_property(Pred, undefined).
  187known_predicate(_:Head) :-
  188    functor(Head, Name, Arity),
  189    '$in_library'(Name, Arity, _Path).
  190
  191op_type(X, prefix) :-
  192    atom_chars(X, [f, _]).
  193op_type(X, infix) :-
  194    atom_chars(X, [_, f, _]).
  195op_type(X, postfix) :-
  196    atom_chars(X, [_, f]).
  197
  198printable(C) :-
  199    integer(C),
  200    code_type(C, graph).
  201
  202
  203                /********************************
  204                *             ATOMS             *
  205                *********************************/
  206
  207explain_atom(A, Explanation) :-
  208    referenced(A, Explanation).
  209explain_atom(A, Explanation) :-
  210    current_predicate(A, Module:Head),
  211    (   Module == system
  212    ->  true
  213    ;   \+ predicate_property(Module:Head, imported_from(_))
  214    ),
  215    explain_predicate(Module:Head, Explanation).
  216explain_atom(A, Explanation) :-
  217    predicate_property(Module:Head, undefined),
  218    functor(Head, A, _),
  219    explain_predicate(Module:Head, Explanation).
  220
  221
  222                /********************************
  223                *            FUNCTOR             *
  224                *********************************/
  225
  226explain_functor(Head, Explanation) :-
  227    referenced(Head, Explanation).
  228explain_functor(Head, Explanation) :-
  229    current_predicate(_, Module:Head),
  230    \+ predicate_property(Module:Head, imported_from(_)),
  231    explain_predicate(Module:Head, Explanation).
  232explain_functor(Head, Explanation) :-
  233    predicate_property(M:Head, undefined),
  234    (   functor(Head, N, A),
  235        utter(Explanation,
  236              '~w:~w/~d is an undefined predicate', [M,N,A])
  237    ;   referenced(M:Head, Explanation)
  238    ).
  239
  240
  241                /********************************
  242                *           PREDICATE           *
  243                *********************************/
  244
  245lproperty(built_in,     ' built-in', []).
  246lproperty(dynamic,      ' dynamic', []).
  247lproperty(multifile,    ' multifile', []).
  248lproperty(transparent,  ' meta', []).
  249
  250tproperty(imported_from(Module), ' imported from module ~w', [Module]).
  251tproperty(file(File),           ' defined in~n~t~4|~w', [File]).
  252tproperty(line_count(Number),   ':~d', [Number]).
  253tproperty(autoload,             ' that can be autoloaded', []).
  254
  255combine_utterances(Pairs, Explanation) :-
  256    maplist(first, Pairs, Fmts),
  257    atomic_list_concat(Fmts, Format),
  258    maplist(second, Pairs, ArgList),
  259    flatten(ArgList, Args),
  260    utter(Explanation, Format, Args).
  261
  262first(A-_B, A).
  263second(_A-B, B).
 explain_predicate(:Head, -Explanation) is det
  267explain_predicate(Pred, Explanation) :-
  268    Pred = Module:Head,
  269    functor(Head, Name, Arity),
  270
  271    (   predicate_property(Pred, undefined)
  272    ->  utter(Explanation,
  273              '~w:~w/~d is an undefined predicate', [Module,Name,Arity])
  274    ;   (   var(Module)
  275        ->  U0 = '~w/~d is a' - [Name, Arity]
  276        ;   U0 = '~w:~w/~d is a' - [Module, Name, Arity]
  277        ),
  278        findall(Fmt-Arg, (lproperty(Prop, Fmt, Arg),
  279                          predicate_property(Pred, Prop)),
  280                U1),
  281        U2 = ' predicate' - [],
  282        findall(Fmt-Arg, (tproperty(Prop, Fmt, Arg),
  283                          predicate_property(Pred, Prop)),
  284                U3),
  285        flatten([U0, U1, U2, U3], Utters),
  286        combine_utterances(Utters, Explanation)
  287    ).
  288:- if(current_predicate(man_object_property/2)).  289explain_predicate(Pred, Explanation) :-
  290    Pred = _Module:Head,
  291    functor(Head, Name, Arity),
  292    man_object_property(Name/Arity, summary(Summary)),
  293    source_file(Pred, File),
  294    current_prolog_flag(home, Home),
  295    sub_atom(File, 0, _, _, Home),
  296    utter(Explanation, '~t~4|Summary: ``~w''''', [Summary]).
  297:- endif.  298explain_predicate(Pred, Explanation) :-
  299    referenced(Pred, Explanation).
  300
  301                /********************************
  302                *          REFERENCES           *
  303                *********************************/
  304
  305referenced(Term, Explanation) :-
  306    current_predicate(_, Module:Head),
  307    (   predicate_property(Module:Head, built_in)
  308    ->  current_prolog_flag(access_level, system)
  309    ;   true
  310    ),
  311    \+ predicate_property(Module:Head, imported_from(_)),
  312    Module:Head \= help_index:predicate(_,_,_,_,_),
  313    nth_clause(Module:Head, N, Ref),
  314    '$xr_member'(Ref, Term),
  315    utter_referenced(Module:Head, N, Ref,
  316                     'Referenced', Explanation).
  317referenced(_:Head, Explanation) :-
  318    current_predicate(_, Module:Head),
  319    (   predicate_property(Module:Head, built_in)
  320    ->  current_prolog_flag(access_level, system)
  321    ;   true
  322    ),
  323    \+ predicate_property(Module:Head, imported_from(_)),
  324    nth_clause(Module:Head, N, Ref),
  325    '$xr_member'(Ref, Head),
  326    utter_referenced(Module:Head, N, Ref,
  327                     'Possibly referenced', Explanation).
  328
  329utter_referenced(_Module:class(_,_,_,_,_,_), _, _, _, _) :-
  330    current_prolog_flag(xpce, true),
  331    !,
  332    fail.
  333utter_referenced(_Module:lazy_send_method(_,_,_), _, _, _, _) :-
  334    current_prolog_flag(xpce, true),
  335    !,
  336    fail.
  337utter_referenced(_Module:lazy_get_method(_,_,_), _, _, _, _) :-
  338    current_prolog_flag(xpce, true),
  339    !,
  340    fail.
  341utter_referenced(From, _, _, _, _) :-
  342    hide_reference(From),
  343    !,
  344    fail.
  345utter_referenced(pce_xref:defined(_,_,_), _, _, _, _) :-
  346    !,
  347    fail.
  348utter_referenced(pce_xref:called(_,_,_), _, _, _, _) :-
  349    !,
  350    fail.
  351utter_referenced(pce_principal:send_implementation(_, _, _),
  352                 _, Ref, Text, Explanation) :-
  353    current_prolog_flag(xpce, true),
  354    !,
  355    xpce_method_id(Ref, Id),
  356    utter(Explanation, '~t~4|~w from ~w', [Text, Id]).
  357utter_referenced(pce_principal:get_implementation(Id, _, _, _),
  358                 _, Ref, Text, Explanation) :-
  359    current_prolog_flag(xpce, true),
  360    !,
  361    xpce_method_id(Ref, Id),
  362    utter(Explanation, '~t~4|~w from ~w', [Text, Id]).
  363utter_referenced(Head, N, Ref, Text, Explanation) :-
  364    clause_property(Ref, file(File)),
  365    clause_property(Ref, line_count(Line)),
  366    !,
  367    pi_head(PI, Head),
  368    utter(Explanation,
  369          '~t~4|~w from ~d-th clause of ~q at ~w:~d',
  370          [Text, N, PI, File, Line]).
  371utter_referenced(Head, N, _Ref, Text, Explanation) :-
  372    pi_head(PI, Head),
  373    utter(Explanation,
  374          '~t~4|~w from ~d-th clause of ~q',
  375          [Text, N, PI]).
  376
  377xpce_method_id(Ref, Id) :-
  378    clause(Head, _Body, Ref),
  379    strip_module(Head, _, H),
  380    arg(1, H, Id).
  381
  382hide_reference(pce_xref:exported(_,_)).
  383hide_reference(pce_xref:defined(_,_,_)).
  384hide_reference(pce_xref:called(_,_,_)).
  385hide_reference(prolog_xref:pred_mode(_,_,_)).
  386hide_reference(prolog_xref:exported(_,_)).
  387hide_reference(prolog_xref:dynamic(_,_,_)).
  388hide_reference(prolog_xref:imported(_,_,_)).
  389hide_reference(prolog_xref:pred_comment(_,_,_,_)).
  390hide_reference(_:'$mode'(_,_)).
  391
  392
  393                /********************************
  394                *             UTTER            *
  395                *********************************/
  396
  397utter(Explanation, Fmt, Args) :-
  398    format(string(Explanation), Fmt, Args)