For portray/1, which is a multifile predicate, there are existing predicates of portray(cr(A))
.
Can some specific predicates be disabled?
Details
When parsing with DCGs
One module has portray/1 predicates for terminals. (rfc5234_base_types).
Another module for the non-terminals uses the portray/1 predicates from the module for terminals. (rfc5234_structures)
A listing of portray(cr(_))
shows other portray/1 predicates for cr(_) that are not desired.
?- listing(portray(cr(_))).
:- multifile rfc5234_base_types:portray/1.
rfc5234_base_types:portray(cr(String)) :-
write(String).
:- multifile rfc5234_structures:portray/1.
:- dynamic portray/1.
:- multifile portray/1.
portray(cr(A)) :-
pce_portray:
( cr(A)= @(Ref),
object(cr(A)),
!,
( send(cr(A), '_instance_of'(var))
-> get(cr(A), '_value', Value),
format('@~w(= ~p)', [Ref, Value])
; get(cr(A), '_class_name', CN),
format('@~w/~w', [Ref, CN])
)
).
portray(cr(A)) :-
portray_text:
( do_portray_text(true),
'$skip_list'(Length, cr(A), Tail),
portray_text_option(min_length, MinLen),
Length>=MinLen,
all_ascii(cr(A)),
portray_text_option(ellipsis, IfLonger),
put_char('"'),
( Length>IfLonger
-> First is IfLonger+ -5,
Skip is Length+ -5,
skip_first(Skip, cr(A), Rest),
put_n_codes(First, cr(A)),
format(..., [])
; Rest=cr(A)
),
( var_or_numbered(Tail)
-> put_var_codes(Rest)
; format('~s', [Rest])
),
put_char('"')
).
true.
EDIT
For now I will call this a workaround because I believe there is a better solution, I just don’t know it.
Instead of trying to disable or exclude certain predicates, the desired predicates are called specifically using the module name, e.g.
in rfc5234_structures.pl
portray(crlf(CR,LF)) :-
rfc5234_base_types:portray(CR),
rfc5234_base_types:portray(LF).
This is defeating the purpose of multifile but it works.
Personal Notes - click to expand
As noted by Jan W.
This is the result of a dubious property of listing/1 (bug). If you look at the code you’ll see it uses a plain variable rather than
cr(A)
.
pce_portray is a module found in GitHub - SWI-Prolog - packages-xpce/prolog/boot/pce_portray.pl
(ref)
user:portray(Obj) :-
Obj = @Ref,
object(Obj),
!,
( send(Obj, '_instance_of', var)
-> get(Obj, '_value', Value),
format('@~w(= ~p)', [Ref, Value])
; get(Obj, '_class_name', CN),
format('@~w/~w', [Ref, CN])
).
portray_text is a module found in GitHub - SWI-Prolog - swipl-devel/library/portray_test.pl
(ref)
:- multifile
user:portray/1.
:- dynamic
user:portray/1.
user:portray(Codes) :-
do_portray_text(true),
'$skip_list'(Length, Codes, Tail),
portray_text_option(min_length, MinLen),
Length >= MinLen,
all_ascii(Codes),
portray_text_option(ellipsis, IfLonger),
put_char('"'),
( Length > IfLonger
-> First is IfLonger - 5,
Skip is Length - 5,
skip_first(Skip, Codes, Rest),
put_n_codes(First, Codes),
format('...', [])
; Rest = Codes
),
( var_or_numbered(Tail)
-> put_var_codes(Rest)
; format('~s', [Rest])
),
put_char('"').
When first reading the note by Jan W. it seemed the variable causing the bug was in the use of _
in listing(portray(cr(_))).
. In inspecting the listed predicates it is obvious that their use of a variable is the reason the extra predicates show up, e.g.
user:portray(Obj)
and
user:portray(Codes)
is unifying with portray(cr(_))
and resulting in them being listed.
The extra predicates show up after executing gtrace/0
, e.g.
Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.4-11-g1db629e24)
?- listing(portray(cr(_))).
:- dynamic portray/1.
:- multifile portray/1.
true.
?- gtrace.
% The graphical front-end will be used for subsequent tracing
true.
[trace] ?- nodebug.
true.
?- listing(portray(cr(_))).
:- dynamic portray/1.
:- multifile portray/1.
portray(cr(A)) :-
pce_portray:
( cr(A)= @(Ref),
object(cr(A)),
!,
( send(cr(A), '_instance_of'(var))
-> get(cr(A), '_value', Value),
format('@~w(= ~p)', [Ref, Value])
; get(cr(A), '_class_name', CN),
format('@~w/~w', [Ref, CN])
)
).
portray(cr(A)) :-
portray_text:
( do_portray_text(true),
'$skip_list'(Length, cr(A), Tail),
portray_text_option(min_length, MinLen),
Length>=MinLen,
all_ascii(cr(A)),
portray_text_option(ellipsis, IfLonger),
put_char('"'),
( Length>IfLonger
-> First is IfLonger+ -5,
Skip is Length+ -5,
skip_first(Skip, cr(A), Rest),
put_n_codes(First, cr(A)),
format(..., [])
; Rest=cr(A)
),
( var_or_numbered(Tail)
-> put_var_codes(Rest)
; format('~s', [Rest])
),
put_char('"')
).
true.
As a further example after gtrace/0 is run, listing(portray(dummy(_))).
will also list the predicates using a variable name instead of a functor.
By Jan W.
Defining a hook without using the thing that is hooked can’t be right.
This is referring to the calling of portray/1 directly. It is not meant to be called directly and if not for having the property multifile
, it would probably not be accessible.
?- predicate_property(portray(_),P).
P = interpreted ;
P = visible ;
P = (dynamic) ;
P = (multifile) ;
P = number_of_clauses(0) ;
P = number_of_rules(0) ;
P = last_modified_generation(0) ;
P = defined ;
P = size(112).
If one reads the documentation for portray/1 it notes
A dynamic predicate, which can be defined by the user to change the behaviour of print/1 on (sub)terms. For each subterm encountered that is not a variable print/1 first calls portray/1 using the term as argument. For lists, only the list as a whole is given to portray/1. If portray/1 succeeds print/1 assumes the term has been written.
So portray/1 is only to be used via print/1 and not called directly.
EDIT
For an example of converting a structure back into text, look at how callgraph generated the dot file in dot.pl