Suspicious warning "The predicates below are not defined ','/6"

This is a reduced code of a project:

mi_term( MI_TERM, TERM, DICT_IN, DICT_OUT) :- MI_TERM \\== (*,*), call( MI_TERM, MI_TERM, TERM, DICT_IN, DICT_OUT).

main_001 :- true
, MI_TERM= ( current_input/1, read_string/5)
, mi_term( MI_TERM, TERM, STARTDICT, DICT)
.

I get the warning on make:

(ins)$ ./009.pl
Warning: /home/ox/tmp/2025_10_08_swipl_errormessage_analysis/009.pl:7:
Warning: Singleton variables: [TERM,STARTDICT,DICT]
Welcome to SWI-Prolog (threaded, 64 bits, version 9.3.20-DIRTY)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

(ins)?- make.
Warning: The predicates below are not defined. If these are defined
Warning: at runtime using assert/1, use :- dynamic Name/Arity.
Warning:
Warning: ‘,’/6, which is referenced by
Warning: /home/ox/tmp/2025_10_08_swipl_errormessage_analysis/009.pl:9:11: 1-st clause of main_001/0
true.

I see the relation between the term “MI_TERM= ( current_input/1, read_string/5)” and the call in mi_term/4 but it is not called because I have a guard there. In the actual code I have more than this 1 rule of mi_term/4 so don’t wonder when this snipped makes no sense, it is reduced to this minimum which creates the warning.

How can I get rid of this warning? (Not the singleton warning)

I think I have it. I just define:

:- dynamic ‘,’/6.

Then the message vanishes and whoever reads this line will never understand what it means :slight_smile: .

That is a “comma list” term (which is best avoided), having no explicit functor name - comma_list/2 and functor/3 show:

?- MI_TERM = (current_input/1, read_string/5), MI_TERM =.. L, functor(MI_TERM, Name, Arity), comma_list(MI_TERM, CommaList).
MI_TERM = (current_input/1, read_string/5),
L = [',', current_input/1, read_string/5],
Name = (','),
Arity = 2,
CommaList = [current_input/1, read_string/5].

Easy solution: provide a functor name, e.g. t:

MI_TERM = t(current_input/1, read_string/5)

But yes, the ‘,’/6 warning seems wrong.

No. I see call(MI_TERM, <4 more arguments>). As MI_TERM is ,/2, there are a total of 6 arguments.

And no, there is no reachability check to decide about what may be called. Note that the test is also wrong, as it (a,b) \== (_,_) is always true.

I think the code needs some cleanup at a higher level. Otherwise using dynamic/1 is a reasonable solution.

Is this some editing artifact? I edited your post to use a code block as I suspected the underlying text was (a,b) \== (_,_). Anyway, both are always true.

P.s. SWI-Prolog warns on e.g. A \== _ with “Test is always true: A\==_556”. It should do the same if one of the terms contains a fresh or singleton variable.

1 Like

Yes I am struggling with coding artefacts in this forum by using backslash and underscode. In the rich text editor mode "MI_TERM \== (_,_)" becomes "MI_TERM == (,)" and after switching to markdown mode it becomes "MI_TERM == (*,*)" and after saving all terms become "MI_TERM == (,)" what a mess! I wrote now inside "preformatted text" which fixes that.

In the actual code I don’t have this guard: "MI_TERM \== (_,_)". I wrote it in the example in the hope it would fail. I get by the way no warning that it is always true.

For the example I change the guard to “false” and get still the warning:

mi_term( MI_TERM, TERM, DICT_IN, DICT_OUT) :- false , call( MI_TERM, MI_TERM, TERM, DICT_IN, DICT_OUT).

main_001 :- true
, MI_TERM= ( current_input/1, read_string/5)
, mi_term( MI_TERM, _TERM, _STARTDICT, _DICT)
.

The warning is:

(ins)$ ./009.pl 
Welcome to SWI-Prolog (threaded, 64 bits, version 9.3.20-DIRTY)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

(ins)?- make.
Warning: The predicates below are not defined. If these are defined
Warning: at runtime using assert/1, use :- dynamic Name/Arity.
Warning: 
Warning: ','/6, which is referenced by
Warning: 	/home/ox/tmp/2025_10_08_swipl_errormessage_analysis/009.pl:13:11: 1-st clause of main_001/0
true.

I want to re-assemble prolog terms so I think I need comma lists.

I switched back to the old dual markdown editor+preview mode. You can toggle using the icon at the top-left of the editor.

The error vanishes if you run swipl -O file.pl, i.e., switching optimization on. Then you get the code below. Optimization optimizes arithmetic, some tests, removes true, removes the remainder of a conjunction that starts with fail, replaces (if->then;else) by then or else if the condition is always true/false, etc. The price is that the debugger may get confused and may skip calls that are compiled to a lower level :frowning:

101 ?- listing(mi_term).
mi_term(MI_TERM, TERM, DICT_IN, DICT_OUT) :-
    fail.

OK, I will stick to the “:- dynamic ‘,’/6.” solution. The “false” guard was only for presentation of the warning. So the -O compiler option is not the solution in the actual code because I have more complex guards there which don’t get computed in compile time.

The “:- dynamic ‘,’/6.” affects the module which is acceptable. A better solution could be a case wise pragma which affects only this particular situation. The problem which I had was the need to reduce all the code to this 2 predicates because the reason for that was not visible. To produce this warning the compiler has to track the contents of a variable which matches (_,_) and has to follow it to a called predicate which makes then a call on that. The warning don’t show that path so it is really hard to unterstand this message when you have more rules of that “mi_term” predicate.

Is there any option to make this warning more verbose?

What do you have in mind? As it, the fact that mi_term/4 uses call/5 causes the system to derive

:- meta_predicate mi_term(4, ?, ?, ?).

Next, it comes at main_001/0 and sees that ‘,’/2 is passed into mi_term/4. It derives this calls ‘,’/6 which it cannot find.

Note that instead of using the test and dynamic declaration, you could also add a clause

 ','(_,_,_,_,_,_) :- fail.

Then all should work just fine and you can comment this clause explaining why this is needed.

What’s the source of these terms? If they were all comma lists originally, then you can use =../2 to change the functor name to something that’s not confusing, i.e. not a comma.

I’m trying out a new kind of typing.

I define a type database like this;

schema( current_input( inputstream)).
schema( read_string( inputstream, delimiter_chars, padchars, used_delimiter_code, read_string)).

and then I can write code like this:

main_001 :- true
, on_signal( int, _, ignore)
, writeln( '^D for end')
, MI_TERM= ( current_input/1, read_string/5) 
, STARTDICT= #{ delimiter_chars:' \n', padchars: ''}
, mi_term( MI_TERM, TERM, STARTDICT, DICT)
% , writeq( TERM), nl , writeq( DICT), nl
, forall( ( repeat, TERM), ( writeln( DICT.read_string), DICT.used_delimiter_code \== -1))

And it creates a TERM from the MI_TERM which looks like this:

current_input(_4424),read_string(_4424,' \n','',_11860,_11862)

which is then the code,

and the vars are bound to the output dict:

#{delimiter_chars:' \n',inputstream:_4424,padchars:'',read_string:_11862,used_delimiter_code:_11860}

It connects the parameters by the typenames and provides the named parameters by the output dict and alllows parametrisation by the input dict.

mi_term could theoretically be a metainterpreter which executes the given code (after or during transformation) but I decided to create a term which I can use more flexible.

Thats the idea and it works well in this little example.

Perhaps that would be simpler with read_term/2

Ok, I found another solution.

To avoid that swi prolog creates this internal meta_predicate information (which is not visible in predicate_property btw.) I write an enclosing term “meta” for calls which provide meta calls for the language which I am about to parse.

I have several rules

mi_term( meta( MI_TERM), TERM, DICT_IN, DICT_OUT) :- ...
mi_term( MI_TERM, TERM, DICT_IN, DICT_OUT) :- ...
mi_term( MI_TERM, TERM, DICT_IN, DICT_OUT) :- ...
...

And I got in the previous version the same warning about “forall” when I wrote:

main_004 :- true
, on_signal( int, _, ignore)
, writeln( '^D for end')
, MI_TERM= forall(
    ( current_input/1, repeat, read_string/5
     , /* meta */ ( mi_dict_getvars( [read_string,used_delimiter_code], [RS,UDC])))
   , ( writeln(RS), UDC \== -1)  )

, STARTDICT= #{ delimiter_chars:' \n', padchars: ''}
, mi_term( MI_TERM, TERM, STARTDICT, DICT)
, writeq( TERM), nl , writeq( DICT), nl
, TERM
.
(ins)?- make.
Warning: The predicates below are not defined. If these are defined
Warning: at runtime using assert/1, use :- dynamic Name/Arity.
Warning: 
Warning: ','/6, which is referenced by
Warning: 	/home/ox/tmp/2025_10_08_swipl_errormessage_analysis/009.pl:29:11: 1-st clause of main_001/0
Warning: forall/6, which is referenced by
Warning: 	/home/ox/tmp/2025_10_08_swipl_errormessage_analysis/009.pl:46:11: 1-st clause of main_005/0
true.

But when I use this meta(…) notation in the first parameter of mi_term then all this kinds of errormessages disappear.

So there is no longer the need to mask this warning by adventourous metainformation like “dynamic”, etc.

I don’t know how swi prolog handles goals when they are encapsulated in a term like this - there is obviously no meta_predicate notation considered for this - so I have no clue how swi prolog will handle the module sensitivity when it gets relevant in the future - but currently for the prototype all is fine so far.

But the warning itself is still hard to comprehend because when I have an decent amount of rules for mi_term and one of them has this concluded meta_predicate(4,?,?,?) information then this information is hard to figure out. So I think it could make sense to have this additional information about the meta predicate and its roots ( file and linenr. of mi_term) also in the warning.

read_term/2 is actually not a bad idea because it allows also the parsing of various dict statements which I cannot write in a variable as a term.

For instance


(ins)?- A = #{a:1}, B=A.a .
A = #{a:1},
B = 1.

(ins)?- TERM= ( A = #{a:1}, B=A.a )  . 
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR:   [15] throw(error(instantiation_error,_17642))
ERROR:   [13] '.'(_17666,a,_17670) at /usr/local/lib/swipl/boot/dicts.pl:57
ERROR:   [12] '<meta-call>'(user:user: ...) <foreign>
ERROR:   [11] toplevel_call(user:user: ...) at /usr/local/lib/swipl/boot/toplevel.pl:1319
ERROR: 
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
(ins)?- read(TERM).
(ins)|: A = #{a:1}, B=A.a
(ins)|: .

TERM = (_A= #{a:1}, _=_A.a).

But then I loose the ability to bind variables in the middle of a term to the enclosing environment. A solution would be great which can combine both things.

Can add quotes, to make A.a parseable:

?- TERM = (A = #{a:1}, B = 'A.a' ), write_term(TERM, [quoted]).
_19200= #{a:1},_19206='A.a'
TERM = (A= #{a:1}, B='A.a').

But i cannot call this TERM.

(ins)?- TERM= ( A = #{a:1}, B='A.a' ), call(TERM).
TERM = (#{a:1}= #{a:1}, 'A.a'='A.a'),
A = #{a:1},
B = 'A.a'. % is not the intended outcome

(ins)?- TERM_A= ( A = #{a:1}), call(TERM_A), TERM_B=( B=A.a ), call(TERM_B).
TERM_A = (#{a:1}= #{a:1}),
A = #{a:1},
TERM_B = (1=1),
B = 1.

When A holds a dict with the correct key then I can write TERM_B=( B=A.a ). I wish I could delay this check.

Ah OK, can use instead of that dictionary “shorthand” syntax, to be a valid term:

?- TERM = (A = #{a:1}, .(A, a, B)), call(TERM).
TERM = (#{a:1}= #{a:1}, '.'(#{a:1}, a, 1)),
A = #{a:1},
B = 1.

… or:

?- TERM = (A = #{a:1}, get_dict(a, A, B)), call(TERM).
TERM = (#{a:1}= #{a:1}, get_dict(a, #{a:1}, 1)),
A = #{a:1},
B = 1.

… as per SWI-Prolog -- Dicts: structures with named arguments

A last idea so far would be just to disassemble the term and reasemble it before feeding it into call. Thats maybe the best solution. I encountered some crashes during my experiments I guess it has to be with the automated meta_predicate creation for goals. I will maybe reduce the code again and report it in another topic.