Re: pldoc: how to specify predicates with arguments unbound.

Paulo Moura <[email protected]> Tue, 16 Sep 2014 13:54:39 +0100
Newsgroups gmane.comp.ai.prolog.swi
Message-ID <[email protected]>
On 16/09/2014, at 13:34, G=FCnter Kniesel <[email protected]> wrote:

> =

> =

> Am 16.09.2014 12:15, schrieb Paulo Moura:
>> =

>> On 16/09/2014, at 10:51, G=FCnter Kniesel <[email protected]> wrote:
>> =

>>> =

>>> =

>>> Am 16.09.2014 10:58, schrieb Paulo Moura:
>>>> =

>>>> On 16/09/2014, at 08:30, Jan Wielemaker <[email protected]> wrote:
>>>> =

>>>>> Hi Kuniaki,
>>>>> =

>>>>> On 09/16/2014 07:57 AM, Kuniaki Mukai wrote:
>>>>>> =

>>>>>> Hi,
>>>>>> =

>>>>>> Using pldoc, how do we specify a predicate such as follows:
>>>>>> =

>>>>>> 	foo(X, Y) :-  (random(3) =3D:=3D 2, X=3D=3DY;  true).
>>>>>> =

>>>>>> foo is designed so that it returns information on the current state
>>>>>> on unification (constraint)   X=3D=3DY or X\=3D=3DY.  So X, and Y ar=
e always unbound
>>>>>> (var(X), var(Y) are always true).  I often wrote such predicates.
>>>>>> =

>>>>>> Reading pldoc document, the following seems only possible form for f=
oo/2.
>>>>>> =

>>>>>> % foo(-X, -Y)  is det.
>>>>>> =

>>>>>> Is it right ?  Or, is there any other neat form of specification
>>>>>> to tell such intention of programmer of foo above.
>>>>> =

>>>>> Seems close to me. The predicate is `multi` though: it succeeds one or
>>>>> two times (a rarely used qualifier). At some point, I think we need a
>>>>> more advanced mode system, which I think should be:
>>>>> =

>>>>>  --X	X *must* be unbound on input (e.g. the stream argument of open/3=
).
>>>>>        Typically used for output arguments that cannot be predicted by
>>>>> 	the caller and thus providing an instantiated argument will always
>>>>> 	cause failure.
>>>>>   -X   X is output.  It's binding has no impact on the semantics and =
the
>>>>>        predicate behaves as p(NewVar), NewVar =3D X.  I.e., it is ste=
adfast
>>>>>        wrt this argument.  Notably, it does *not* mean X must be unbo=
und.
>>>>>   @X   X is examined, but not altered in any way (e.g., type checks).
>>>>>   ?X	Either -X or +X.  Can be used as a shorthand for listing 2**N
>>>>>        modes (where N is the number of ?X args).  E.g., we do not want
>>>>>        to list 8 modes for append/3.  atom_concat(?,?,?) however is
>>>>>        wrong because at least two of the arguments must be +.
>>>>>   +X   X is input.  It must have a value that is *compatible* with the
>>>>>        type.  I.e., X is a generalization of at least one instance of=
 the
>>>>> 	type.  As far as I'm concerned, this would also mean that
>>>>> 	if the type is `any`, a variable satisfies.
>>>>>  ++X   X is input and bound to an instance of the type.  I.e.,
>>>>> 	sort(++List, -Result) because sort cannot sort partial lists.
>>>>> =

>>>>> If there sufficient consensus to add ++ and -- to PlDoc and add this =
to
>>>>> the documentation? Then we only need a volunteer to go through the
>>>>> manuals ...
>>>>> =

>>>>> I'm afraid this is still not really a good answer to foo/2. --X deman=
ds
>>>>> the right instantiation, but the arguments are never altered, while -=
-X
>>>>> args are typically instantiated by the predicate. That would suggest =
@X,
>>>>> but this allows for nonvar. @X:var could be used,
>>>>> but most LP people claim that var is not a type.
>>> =

>>> Var is indeed not a type but a mode, and var/1 and nonvar/1 are actuall=
y mode testing predicates.
>> =

>> Note that's not how they are described in the official ISO Prolog Core s=
tandard:
>> =

>> 8.3 Type testing
>> =

>> These built-in predicates test the type associated with a term as define=
d in 7.1.
>> ...
>> =

>> There are no reference to "modes" in this section. Interestingly, in sec=
tion "8.1.2.1 Type of an argument", "nonvar" is listed but not "var" (the s=
ection starts with the text "The type of each argument is defined by one of=
 the following types:").
>> =

>>> [Paulo: Calling this type testing is an inaccuracy that was forgivable =
in a language without types.
>> =

>> Nowhere in my previous message I call it "type testing".
> =

> You quoted the standard, which uses this terminology.
> =

>>> But when one is discussing how to add types one should not perpetuate i=
naccurate old terminology.]
>> =

>> I don't necessarily disagree with you here. Just quoting the official IS=
O Prolog Core standard.
> =

> Thanks for clarifying that quoting the standard does not mean suggesting =
the further use of its terminology.
> =

>>> In the case of foo you are actually talking about modes, more precisely=
 the conjunction of two modes
>>> - 'mandatory free' (--) and
>>> - 'readonly' (@)
>>> =

>>> So the logical solution for specifying foo is to write @-- for saying
>>> that a variable must be free and only mode testing will be performed
>>> on it.
>>> =

>>> Which boils down to allowing conjunction of modes in the syntax.
>>> More precisely, to allowing @ (readonly) as conjunction to any other,
>>> since all the others are disjoint cases.
>>> =

>>> Conjunction of @ and any other mode also makes sense because it makes
>>> explicit that we have here two categories of modes:
>>> =

>>> @ talks about how  an argument is used internally by the called predica=
te whereas all the others talk about the value of the argument at call time=
 (However, I'm unsure about - whose difference to -- I don't fully understa=
nd. How can something be output, if it was not free initially?).
>> =

>> The argument can be a variable or a partly instantiated term on input an=
d further instantiated by the call.
> =

> If it is partly instantiated overlaps with +
> =

> Thus + and - are additional candidates for conjunctive use since +-
> would express exactly the partly instantiated terms that will be further =
instantiated. Or how would one express them otherwise?

With a combination with type information, I don't see the need for what you=
 call conjunctive use. For example (again quoting the standard):

clause(+head, ?callable_term)

+head means that its an input argument that can be further instantiated.

?callable_term means that the argument can be either a variable or a (possi=
bly partially) instantiated term on call but that will be instantiated to a=
 callable term on exit =


You could write instead:

clause(+head, -callable_term)
clause(+head, +callable_term)

But I don't see the need for splitting the two cases. For me, "?" clearly e=
xpresses "partly instantiated terms that will be further instantiated". Oth=
erwise we would use "@" instead.

Am I missing something in your argument?

Cheers,

Paulo

-----------------------------------------------------------------
Paulo Moura
Logtalk developer

Email: <mailto:[email protected]>
Web:   <http://logtalk.org/>
-----------------------------------------------------------------