Closed kenbowen closed 5 years ago
Are the examples added in 55cd00b4397cee9fc97d0702afc1fb033acb68c6 appealing enough?
Yes. I thought I said so. Sorry. —Ken
On Jul 11, 2019, at 5:46 AM, Chuck Houpt notifications@github.com wrote:
Are the examples added in 55cd00b appealing enough?
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.
Roger. I was just asking if the issue could be closed. I've closed it.
Develop an appealing example for the use of %p in printf. It should show how %p can do something which is more difficult to achieve without it. As a devil’s advocate approach, note that this example
?- sprintf(X, 'Answer: %p', [S^write(S,42)]). X="Answer: 42"
is easily achieved with
?- sprintf(X, 'Answer: %t', [42]). X="Answer: 42"
So to me, the problem is coming up with something relatively natural where S^Goal uses the fact that it has S in hand to compose some output which might be difficult to extract from a version of Goal not containing S and also difficult to compose out of multiple %t placeholders and constant characters. The following is artificial, but it tries to move in what might be the right direction. (However, it does show that there is a module-related problem in the implementation so far.)
Load the following predicate:
b(S,K) :- Goal = (write(S, 'h('), write(S, foo),put(S, 0',), write(S,K), put(S,0')) ), Goal.
Then:
?- sprintf(X, 'Answer: %p', [S^b(S,bar)]). Error: Operation attempted on object of type procedure which does not exist. Operation attempted on: builtins: b( stream_descriptor('\b',open,string,string(_A),[noinput|output],false, 43,[],[],0,0,true,0,wt_opts(78,400,flat),[],wait,text,eof_code, true,0), bar).
Adding a module qualifier lets it work:
?- sprintf(X, 'Answer: %p', [S^(user:b(S,bar))]).
X="Answer: h(foo,bar)" S=stream_descriptor('',closed,string,string("Answer: h(foo,bar)"), [noinput|output],false,44,"Answer: h(foo,bar)",")",0,0,true,0, wt_opts(78,400,flat),[],wait,text,eof_code,true,0)
Note: related emails are included below.
6/12/19: Chuck -> Ken
The old and new doc and examples for %p don't quite capture how %p is intended for use (assuming my understanding is correct). The most important thing to convey is that the S in S^Goal is a mechanism for printf to pass the output stream down to the Goal. Prolog doesn't have first-class anonymous functions (lambdas), so S^Goal is the pseudo-equivalent of "function(S) { Goal }" in Javascript.
I think the following is a good example that gets to the heart of %p. Because it uses sprintf, it makes it clear that the output stream is ephemeral and unknown (created by sprintf on the fly). Note how S must be unbound -- arguable passing a bound S for %p should result in a domain-error:
?- sprintf(X, 'Answer: %p', [S^write(S,42)]). X="Answer: 42" S=stream_descriptor(...)
[ Note, it seems like a bug that S gets bound to a stream as a result. ]
Also, I don't understand the utility of allowing a plain Goal for %p. For example, one gets non-sensical results like:
?- sprintf(X, 'Answer: %p', [write(42)]). 42 X="Answer: "
Is there any case where the plain Goal form is useful (specifically excluding "accidental" usefulness of outputting to user_output)?
Chuck
6/12/19: Ken -> Chuck
First:
?- open(string(Y), write, S), printf(S, 'Answer: %p', [S^write(S,42)]),close(S).
Y="Answer: 42" S=stream_descriptor('',closed,string,string("Answer: 42"),[noinput|output], false,45,"Answer: 42","2",0,0,true,0,wt_opts(78,400,flat),[],wait,text, eof_code,true,0)
yes.
And
?- current_output(S), printf(S, 'Answer: %p', [S^write(S,42)]). Answer: 42 S=stream_descriptor('\002',open,console,'standard output',[noinput|output], false,-2,0,0,0,0,true,0,wt_opts(78,400,flat),[],wait,text,eof_code,true,0)
yes.
Second, the relevant clause in blt_io.pro (line 102ff) is:
%%%% %p -- call print procedure as argument printf0([0'%,0'p |Format], Stream, [PrintGoal|ArgList],Options) :-!, (PrintGoal = Stream^PrintGoal0 -> call(PrintGoal0) ; (PrintGoal = [Stream,Options]^PrintGoal0 -> call(PrintGoal0) ; call(PrintGoal) )
Note that the Stream in Stream^PrintGoal0 must unify with the toplevel Stream argument in printf0.
Third, the following line (after the pseudo-code for %p, just before sprintf/3) says that the Stream occurring in Stream^PrintGoal0 should be the same as the output stream of print/3,4:
It is important that
Stream
above is the stream argument toprint/3
orprintf/4
.I do think this is saying what you said with
S in S^Goal is a mechanism for printf to pass the output stream down to the Goal.