Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Question of the day, to self or not to self?

75 views
Skip to first unread message

j4n bur53

unread,
Jan 15, 2016, 4:00:20 PM1/15/16
to
Hi,

Assume we have a Prolog system with object orientation
or an object based system. Should we be able to write
an instance method as follows:

Variant 1:
test :- write(hello), nl.

Or as follows:

Variant 2:
test(This) :- write(hello), nl.

(Remark:
The latter variant would allow us
to freely use either This, Self, or
something else. So we could also write:

test(Self) :- write(hello), nl.

But because of some singleton test, we
would be probably forced to write:

test(_) :- write(hello), nl.)

Proponents so far:

Java: Variant 1
(Since it has a type system, which includes a modifier static
for a method, it can decide at compile time whether a method
has a self or not)

Python: Variant 2
(See for example here:
http://neopythonic.blogspot.ch/2008/10/why-explicit-self-has-to-stay.html)

What would be the best for Prolog, a typeless language?

Markus Triska

unread,
Jan 16, 2016, 3:43:08 AM1/16/16
to
j4n bur53 <janb...@fastmail.fm> writes:

> Assume we have a Prolog system with object orientation
> or an object based system. Should we be able to write
> an instance method as follows:

Is variant 3 an option?

test :- self(Self), ... .

--
comp.lang.prolog FAQ: http://www.logic.at/prolog/faq/

Jan Burse

unread,
Jan 17, 2016, 7:55:47 AM1/17/16
to
Markus Triska schrieb:
> j4n bur53<janb...@fastmail.fm> writes:
>
>> >Assume we have a Prolog system with object orientation
>> >or an object based system. Should we be able to write
>> >an instance method as follows:
> Is variant 3 an option?
>
> test :- self(Self), ... .

Yes, thats for example found in Logtalk. But I
am not sure whether Logtalk can distinguish between
static and non-static methods inside a class

(this is all Java terminology, but the Python link I
gave as a third distinction, via decorators or explicitly
via code, class methods where the class itself is
passed around as a parameter, but this can be totally
differently modelled, and is out of scope of the
discussion here, just lift the class to an object,
as Java is doing it, and then there are only two
distinctions).

The advantage of an explicit parameter would be,
assuming a term object class "foo" with possibly
more parameters or not:

/* the non-static method */
test(Self) :- ...

/* the static method */
test :-

This can be paired with corresponding invokation
operators (::)/2 and (:)/2, things that are already found
in Logtalk and in the ISO module standard. For
example:

/* invoking the non-static method, aka instance method */
?- ..., Foo::test, ...

/* invoking the static method, aka class method, also
no confusion with possible term object class instances,
it is clear that we mean the class foo statically */
?- ..., foo:test, ...

I am currently experimenting with a separated (::)/2
operator, so that the (:)/2 operator doesn't have the
burden to distinguish between static and non-static.
What is a little fascinating are the meta-predicate
declarations of these operators:

I got:

:- meta_predicate :(?,0)
:- meta_predicate ::(?,1)

Why is that. Well its a little bit a stretch of meta-predicate
declaration, since a Prolog system will anyway have the
burden to handle (:)/2 and (::)/2 as a special case in
cross referencers etc.. But still it expresses some
truth if we recall the Pythonesk self rewriting.

The creator of Python mentions the following equivalence,
which is of mere theoretical interest, using a Prolog
rephrasing:

Foo::meth(Arg1,..,Argn) == class:meth(Foo, Arg1, .., Argn)

http://neopythonic.blogspot.ch/2008/10/why-explicit-self-has-to-stay.html

So we see what happens in the Pythonesk modelling of an
object oriented Prolog system. The (::)/2 operator indeed
could prepend an argument to the given message and then
delegate to (:)/2 as a goal. That the (::)/2 prepends an
argument is indicated by the closure index 1:

:- meta_predicate ::(?,1)
^^^ here

So I ambandoned my intial try to mixup (:)/2 and (::)/2 into
a single operator, and now have two operators (:)/2 and
(::)/2 in the cooking. I was hesitant to use (::)/2 since
it involves additional typing. But I noticed since its
the same character colon (:) on the same keyboard cap twice,
its not so much work typing it twice.

Here are already some example runs:

?- 'System':err(X), X::println('abc').
/* output goes somewhere else */

?- current_error(X), X::write('abc'), X::nl.
abc

Or debugging the involved rewriting:

?- use_module(library(inspection/provable)).

?- 'System':err(X), sys_callable_colon(
Expanded, X::println('abc')).
Expanded = 'java.io.PrintStream%println'(0r2bdc4bbe,abc)

?- current_error(X), sys_callable_colon(
Expanded, X::write('abc')).
Expanded =
'jekdev.reference.system.ConnectionWriterTrace%write'(0r175a9882,abc)

?- current_error(X), sys_callable_colon(
Expanded, X::nl).
Expanded = 'jekdev.reference.system.ConnectionWriterTrace%nl'(0r175a9882)

We see an additional advantage of the Pythonesk approach,
maybe implicitly somewhere found in the blog text or other
resources of the creator of Python. Namely we might fallback
to ordinary Prolog clauses.

This happens in the current_error/1 example above. Although
we send a message write('abc') or nl to the object, we fall
back to the ordinary ISO predicates write/2 and nl/1.

The fallback has to do with an intricacy of the ISO prolog
module system. The intricacy is implemented by many Prolog
systems, for example by SWI-Prolog. It is seen here:

Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.12)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam

?- lists:member(X, [1,2,3]).
X = 1 ;
X = 2 ;
X = 3.

?- lists:write(hello), lists:nl.
hello
true.

So for a static call, along the possibly empty reexport/1
chain, we might fall back to user: predicates, assuming
the user: qualification accounts for globally defined unqualified
predicates such as write/1, write/2 or nl/1, nl/0.

One can try the above also with write/2 and nl/1, the
lists module will also fallback to the unqualified
predicates, which is somehow unavoidable.

Bye

Jan Burse

unread,
Jan 17, 2016, 8:02:44 AM1/17/16
to
Jan Burse schrieb:
>
> So we see what happens in the Pythonesk modelling of an
> object oriented Prolog system. The (::)/2 operator indeed
> could prepend an argument to the given message and then
> delegate to (:)/2 as a goal. That the (::)/2 prepends an
> argument is indicated by the closure index 1:
>
> :- meta_predicate ::(?,1)
> ^^^ here

Which is an abuse of closure indexes, since they append
and not prepend. So some advanced term expansion, that
can also expand meta predicates, wouldn't work here anyway.

Jan Burse

unread,
Jan 17, 2016, 8:25:51 AM1/17/16
to
Markus Triska schrieb:
> Is variant 3 an option?
>
> test :- self(Self), ... .

Just recall also that demoting Logtalk could be just
a consequence of doing science.

"Logically, no number of positive outcomes at the level of
experimental testing can confirm a scientific theory, but a single
counterexample is logically decisive: it shows the theory, from which
the implication is derived, to be false."

https://en.wikipedia.org/wiki/Karl_Popper#Falsifiability.2Fproblem_of_demarcation

So Logtalk, besides beeing rather an experiment, than
a real implementation, might still have corners that
could demand different solutions.

Bye

Jan Burse

unread,
Jan 17, 2016, 8:27:29 AM1/17/16
to
Jan Burse schrieb:
> So Logtalk, besides beeing rather an experiment, than
> a real implementation, might still have corners that
> could demand different solutions.

Besides having different scientific goals as well,
my current goal is a for a less bloathed OO-LP. It
should be darn simple, just on top of the ISO
Prolog module system.

Bye

Jan Burse

unread,
Jan 17, 2016, 8:42:49 AM1/17/16
to
Jan Burse schrieb:
>
> Besides having different scientific goals as well,
> my current goal is a for a less bloathed OO-LP. It
> should be darn simple, just on top of the ISO
> Prolog module system.

Example of less bloat, why the heck needs an
OO-LP before and after hooks in the message sending.
Why the heck do we mix aspect oriented programming
into an OO-LP?

This is the task of a debugger, to instrument
code. And a traditional debugger can also instrument
OO code. I don't see much problem here. For example
if I try my current (::)/2 with the debugger I see:

?- trace.
Yes
?- current_error(X), X::write('abc'), X::nl.
0 Call current_error(X) ?
0 Exit current_error(0r11f9ab5f) ?
0 Call
jekdev/reference/system/'ConnectionWriterTrace':write(0r11f9ab5f, abc) ?
1 Call integer32(abc) ?
1 Fail integer32(abc) ?
1 Call integer32(abc) ?
1 Fail integer32(abc) ?
1 Call java/io/'Writer':write(0r11f9ab5f, abc) ?
2 Call integer32(abc) ?
2 Fail integer32(abc) ?
2 Call write_var1(0r11f9ab5f, abc) ?
2 Exit write_var1(0r11f9ab5f, abc) ?
1 Exit java/io/'Writer':write(0r11f9ab5f, abc) ?
0 Exit
jekdev/reference/system/'ConnectionWriterTrace':write(0r11f9ab5f, abc) ?
0 Call
jekdev/reference/system/'ConnectionWriterTrace':nl(0r11f9ab5f) ?
abc
0 Exit
jekdev/reference/system/'ConnectionWriterTrace':nl(0r11f9ab5f) ?
X = 0r11f9ab5f

What we even seen in the above, how the code runs along the
the branching code for the reexport/1 chain of the auto loader.
Showing some super calls as well.

Interestingly my claim that write/2 is falling back to the
global write/2 is false. Only the nl/1 falls back. The write/2
is of course handled by the java/io/'Writer':write/2.

Bye

P.S.: The ConnectionWriterTrace class overrides
the write/2 from Writer, and uses both delegation
and super calls to write a protocoll, to take care
of the protocol/1 debugger directive.

Its open source, and its in Java. My Prolog debugger
currently cannot show the Java super call, or any
execution in the Java, it is not integrated into the
Java itself:

http://www.jekejeke.ch/idatab/doclet/blog/en/docs/10_dev/02_reference/system/ConnectionWriterTrace.html

You would need the Java debugger in parallel, and set
some breack points there or some such. But using in
parallel works.

P.P.S.: When listing the auto loaded classes we
get the following (excerpts):

?- system/automatic:generated.
% Closeable.class
[...]
% FilterWriter.class
[...]
:- public override virtual write/2.
write(B, A) :-
integer32(A), !,
write_var0(B, A).
write(A, B) :-
'java.io.Writer%write'(A, B).
% Flushable.class
[...]
% Writer.class
[...]
% Appendable.class
[...]
% Object.class
[...]

One might see here another form of "bloat". But somehow
I am used to it that Java has so many classes and interfaces.
Atleast this is not a "bloat" that affects my own classes,
if I build them from scratch.

And if I am not building classes from scratch, it gives
me some choice on the domain level. So I am not talking
of the "bloat" that could result when somebody is applying
an OO-LP. I am talking about "bloat" in the OO-LP itself.









Jan Burse

unread,
Jan 17, 2016, 8:51:44 AM1/17/16
to
Jan Burse schrieb:
> % Writer.class
> [...]

Oops. This one would be relevant for the above trace.

Jan Burse

unread,
Feb 3, 2016, 5:42:15 PM2/3/16
to
Markus Triska schrieb:
> j4n bur53<janb...@fastmail.fm> writes:
>
>> >Assume we have a Prolog system with object orientation
>> >or an object based system. Should we be able to write
>> >an instance method as follows:
> Is variant 3 an option?
>
> test :- self(Self), ... .

A Pythonesk definition in the root class (primordial class,
in Java it is Object) of all classes would be,

but since the ISO module system anway falls back to
non-module predicates just a non-module predicate:

self(This, This).

But you would need some magic that self application doesn't
need some extra syntax, since you do:

test :- self(Self), ...

Which would be a short hand to:

test(This) :- This::self(Self), ...

So its defineable either way.

Bye

j4n bur53

unread,
Feb 4, 2016, 3:02:16 AM2/4/16
to
Jan Burse schrieb:
> but since the ISO module system anway falls back to
> non-module predicates just a non-module predicate:
>
> self(This, This).

Or if you model object context via DCG, as you did
in the SSL/NNTP show case,

I would call this modelling object-based and not
object-oriented since I don't see how you would
allow generalization and specialization, for example
in the form of inheritance and overriding,

anyway, so if you use DCG, you could define
self//1 as follows:

self(This), [This] --> [This]

You could then define the read_write//2 as
follows:

read_write(Read, Write) --> self(Read-Write).

Or you could inline the read_write//2 directly
and for example use self//1 as follows:

connect(HostPort) -->
self(Read-Write),
{ ssl(HostPort, Read, Write) }.

Or a little bit more OO-ish, define getters
respective they are also declarative setters,
since the connect will instantiate this state:

read(Read) --> self(Read-_).
write(Write) --> self(_-Write).

And then for example do:

send(Format, Args) -->
write(Write),
{ format(codes(Codes), Format, Args),
silent_authinfo(Codes),
format(Write, "~s", [Codes]),
flush_output(Write) }.

And:

slurp(File) -->
read(Read),
{ setup_call_cleanup(open(File, write, Out),
slurp_into(Read, Out),
close(Out)) }.




j4n bur53

unread,
Feb 4, 2016, 3:06:35 AM2/4/16
to
Hi,

j4n bur53 schrieb:
> And then for example do:
>
> send(Format, Args) -->
> write(Write),
> { format(codes(Codes), Format, Args),
> silent_authinfo(Codes),
> format(Write, "~s", [Codes]),
> flush_output(Write) }.
>
> And:
>
> slurp(File) -->
> read(Read),
> { setup_call_cleanup(open(File, write, Out),
> slurp_into(Read, Out),
> close(Out)) }.

The setter/getter, strongly opposed by ROK some
years ago on the Erlang mailing list, he called
this Java la la Land stuff, has some advantage,

you could extend the state easily afterwards, so
if you think you need more state in the object,

for example some additional state foo, you would
only need to change the setters/getters, for
example into:

read(Read) --> self(Read-_-_).
write(Write) --> self(_-Write-_).
foo(Foo) --> self(_-_-Foo).

Bye

Markus Triska

unread,
Feb 5, 2016, 12:45:06 PM2/5/16
to
j4n bur53 <janb...@fastmail.fm> writes:

> for example some additional state foo, you would
> only need to change the setters/getters, for
> example into:
>
> read(Read) --> self(Read-_-_).
> write(Write) --> self(_-Write-_).
> foo(Foo) --> self(_-_-Foo).

I tend to use s/N terms in such cases, for example:

read(Read) --> self(s(Read,_,_)).
write(Write) --> self(s(_,Write,_)).
foo(Foo) --> self(s(_,_,Foo)).

"s" stands for "state".

Using such s/N terms has a few advantages, for example:

?- write_canonical(a-b-c).
%@ -(-(a,b),c)
%@ true.

vs.:

?- write_canonical(s(a,b,c)).
%@ s(a,b,c)
%@ true.

I leave figuring out other advantages as an easy exercise.

All the best,
Markus

j4n bur53

unread,
Feb 7, 2016, 12:36:27 PM2/7/16
to
This leads to no where if you want to have
real objects, namely objects that are based
on generalization and specialization of their
classes, and where the classes somehow define
the state of the object instances.

I was mentioning the setter/getter for this
reason. If you interchange A-B-C with s(A,B,C)
you might spare some unification. But if for
example a fourth property appreas, lets say
bar, you have to rewrite all four setters/
getters:

read(Read) --> self(s(Read,_,_,_)).
write(Write) --> self(s(_,Write,_,_)).
foo(Foo) --> self(s(_,_,Foo,_)).
bar(Bar) --> self(s(_,_,_,Bar)).

But what if the read and write setter/getter
was not defined by you but by someone else
in another module which is sealed, i.e. you
cannot modify. You can still hope that you
are allowed to override read and write. But
this is also not guaranteed.

So basically, if you can assure that the state
is only subject to single inheritance you
might want to meet an old fried, namely the
arg/3 predicate. Just use:

read(Read) --> self(Self), arg(1, Self, Read).
write(Write) --> self(Self), arg(2, Self, Write).

You can then freely add:

foo(Foo) --> self(Self), arg(3, Self, Foo).
bar(Bar) --> self(Self), arg(4, Self, Bar).

The only problem here, is that arg/3 doesn't work
when Self is not yet a compound. So you would need
to be more careful when you created the Self object
the first time, and for example have a new method,
in the class where only read and write is defined,
the new method would do:

new --> functor(Self, s, 2), self(Self).

In the class where also foo and bar are defined,
the class would override the new method, and define
it as follows, whereas I don't see yet how DCG
could model overriding:

new --> functor(Self, s, 4), self(Self).

I think for Prolog, since it doesn't have an institutionalized
OO system, the above are just programming patterns. So
that the following paper does a right discussion:

Programming Patterns for Logtalk Parametric Objects,
Paulo Moura, 2011
http://cracs.fc.up.pt/sites/default/files/c2011_pm_inap.pdf

The problem with an OO institutionalization is then that
there is quite a design space, and decisions that might
have been taken 10-20 years ago or so, might not be optimal.
In as far as DCG will persist here, I am not yet clear about.

For OO you would need to have generalization and specialization
as well. This goes into the calling mechanism of object sending.
In DCG the calling mechanism of a non-terminal is simply
extending it by the two input and output parameters. So
calling a non-terminal is primarily independent of the
given input and output parameters.

The input and output parameters only add to the arity but
the predicate name is the same as already seen in the DCG
phrase. But for object sending, a solution to the generalization
and specialization problem, is a form of late binding. I
don't know how complicated the mechanism is in Logtalk at
the moment.

My current proposable from Jekejeke is stupid simple, just
use the ISO module system to resolve the actual predicate name.
So the (::)/2 operator is simply defined as follows:

Receiver::Message :-
Message =.. [MessageName|Args],
functor(Receiver, Class, _),
Goal =.. [MessageName,Reciever|Args],
Class:Goal.

This is the pythonesk approach and the lua approach, and under
the hood also used in Java. In Java when a method is resolved
you get a method handle which has a method name and a declaring
class. The Class:Goal will resolve MessageName in the same
way and execute the Goal in the declaring class.

So following the rexport chain the find the declaring class,
every Prolog module system that implements the ISO module
standard should be able to do that. So no need for a bloathed
Logtalk OO system, we can directly work on top of the ISO
module system. Nevertheless there is a lot of work ahead:

- The (::)/2 is only the beginning, it is the head start
for the OO system
- We still need to find solutions that ease the definition
of method heads and method bodies, should we adopt
Logtalks {}/1 and Logtalks ^^/1 and Logtalks ::/1
or are there other solutions possible.
- We still need to find solutions that ease the definition
of properties should we adopt Logtalks parametric
objects or are there orther solutions possible.

All these decisions will lead to an institutionalization
of OO programming patterns, that are already available in
pure Prolog with an ISO module system. Everything that is done
is mapped to pure Prolog in some way or another, an example
beeing (::)/2 which has a pure Prolog definition.

But most likely the resulting language will be much more
dynamic than Logtalk. For example the head start (::)/2
already shows that anything dynamic is delegate to the ISO
module system. If the ISO module system can reload modules
at runtime, fine, the OO system will also be able to reload
classes at runtime.

Similarly there is no need to have a OO-system in the form
of a kind of compiler, that transforms Prolog texts. The
solutions to the methods and properties problems, can mostlikely
easily solved with term expansion. So that the OO-system will
be highly dynamic, no need for some clumsy command line control.
Just use your ordinary Prolog as usually, plus the definition
of (::)/2 and the other definitions.

Bye


Markus Triska schrieb:

j4n bur53

unread,
Feb 7, 2016, 12:51:30 PM2/7/16
to
j4n bur53 schrieb:
> So that the OO-system will
> be highly dynamic, no need for some clumsy command line control.
> Just use your ordinary Prolog as usually, plus the definition
> of (::)/2 and the other definitions.

Prolog systems that allow this:

?- [user].
foo:bar :- write(hello), nl.
^D

?- foo:bar.
hello
Yes

Will also allow to dynamically create classes at runtime.

Bye


j4n bur53

unread,
Feb 10, 2016, 6:56:51 PM2/10/16
to
j4n bur53 schrieb:
> So following the rexport chain the find the declaring class,
> every Prolog module system that implements the ISO module
> standard should be able to do that. So no need for a bloathed
> Logtalk OO system, we can directly work on top of the ISO
> module system. Nevertheless there is a lot of work ahead:
>
> - The (::)/2 is only the beginning, it is the head start
> for the OO system
> - We still need to find solutions that ease the definition
> of method heads and method bodies, should we adopt
> Logtalks {}/1 and Logtalks ^^/1 and Logtalks ::/1
> or are there other solutions possible.
> - We still need to find solutions that ease the definition
> of properties should we adopt Logtalks parametric
> objects or are there orther solutions possible.

It seems that the future of the method bodies is already
quite foreseeable. I guess {}/1 will survive, but the
^^/1 and ::/1 not.

But an interesting question, which I didn't consider yet,
is how one would deal with call/n and lambdas in a
non-static context?

So this is also on the todo list now. Logtalk has already
some years experience here:
http://blog.logtalk.org/2009/12/lambda-expressions-in-logtalk/

But there is a plethora of problems, to get a glimps of it
see for example here:
http://stackoverflow.com/questions/9460835/logtalk-metamap-lambda-expression-and-access-to-private-method

Interestingly Java, and other languages around, typically
processs lambda expression, and allow a quite rich outside
access inside them.

Bye

Jan Burse

unread,
Feb 15, 2016, 7:53:44 AM2/15/16
to
In a wider context, it is interesting to see
how Logtalk(*) already pioneered the handling of (::)/2
together with call/n. The idea is very simple. The
basic call/n is defined as follows:

ISO core, corrigendum II:
call(p(X1,..,Xn),Y1,..,Ym) --> p(X1,..,Xn,Y1,..,Ym)

Now we extend this to modules and the module
invokation operator (:)/2:

Case I: ??Standard??
call(m:p(X1,..,Xn),Y1,..,Ym) --> m:p(X1,..,Xn,Y1,..,Ym)

Then there is a further extension, we also allow
the late binding operator (::)/2 in call/n:

Case II: ??Standard??
call(m::p(X1,..,Xn),Y1,..,Ym) --> m::p(X1,..,Xn,Y1,..,Ym)

What I was working on now, was a development of a
meta specifizier, so that we can model what is going
on. I had already a usage for the closure indexes that
many Prolog systems feature in their meta_predicate
declaration. The definitions for Case I are simply:

:- meta_predicate :(?,0).
:- meta_predicate :(?,1,?).
:- meta_predicate :(?,2,?,?).
Etc..

Using exactly the same closure index doesn't work for
the (::)/2 operator. Since in the Pythonesk setting,
the (::)/2 operator prepends (add to the left) a single
parameter, but the closure index appends (add to the right)
multiple paramters. So we invented the new notation ::(<spec>).
The definitions for Case II are simply:

:- meta_predicate ::(?,::(0)).
:- meta_predicate ::(?,::(1),?).
:- meta_predicate ::(?,::(2),?,?).
Etc..

A prototype(**) for the upcoming release 1.1.2 of Jekejeke
is already running. We be out in 1-2 months.

Bye

(*)
http://logtalk.org/manuals/refman/methods/call_N.html
(**)
https://plus.google.com/+JekejekeCh/posts/8ufss43LZB1

Jan Burse schrieb:

Jan Burse

unread,
Feb 15, 2016, 8:10:34 AM2/15/16
to
Hi,

But still refactoring doesn't work for Prolog. The
problem is not late binding in itself, i.e. (::)/2.
Since in late binding, when there is a goal:

Obj::method(Arg1,..,Argn)

if Obj is not instantiated, we don't know really know
which method will be invoked. So we can also not refactor,
assuming in refactoring a particular method is attacked.

But this problem is already persistent for a module
system, when the code makes use of the following:

Module:predicate(Arg1,..,Argn)

if Module is not instantiated, we also don't really
which predicate will be invoked. We only know the name
of the predicate but not the module.

But the new meta spezifier might nevertheless give
some support for refactoring:
- if refactoring attacks method/predicates based on
the name and arity with irrelevant class/module
- if some additional type annotation is there, so that
more specific refactoring can be served

Bye


Jan Burse schrieb:

Jan Burse

unread,
May 16, 2016, 6:40:52 PM5/16/16
to
Dear All,

Ideas flow best on Pentecost (in Swiss German: "An
Pfingsten gehts am geringsten", which is derived from
from the German: "An Pfingsten sind die Geschenke am
geringsten", which has near opposite meaning.).

So walking around I see a lot of RDF proposals
which also propose Quads. These quads have the
following look sometimes, Prolog style:

Old Proposal:
rdf(<Subj>, <Pred>, <Obj>, <Graph>)

Or Lisp style:

Old Proposal:
(<Subj> <Pred> <Obj> <Graph>)

What would happen if we where to adopt the Pythonesk
approach here. Namely to put the <Graph> as the first
argument. So the way to go for quads would be:

New Proposal:
rdf(<Graph>, <Subj>, <Pred>, <Obj>)

First Thought Experiment: Would it harm indexing in Prolog?
I guess no, it depends on the Prolog system and the
chosen index. But if for example multi-argument indexing
is chosen, you might have grouping along graphs, which
could be beneficial.

Second Though Experiment: What could be further benefits?
If we would see a Prolog system as an integrator of
different RDF sources, we could apply the Pythonek
OO style to model different sources and integrate them.

So a RDF graph would be basically a term object or a
reference object that would respond on the rdf/3 message.
Or in Logtalk lingo we would say parametric object instead
of term object.

Lets see what would happen to a SPARQL query, here is
one from the W3C spec:

PREFIX data: <http://example.org/foaf/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?mbox ?nick ?ppd
FROM NAMED <http://example.org/foaf/aliceFoaf>
FROM NAMED <http://example.org/foaf/bobFoaf>
WHERE
{
GRAPH data:aliceFoaf
{
?alice foaf:mbox <mailto:al...@work.example> ;
foaf:knows ?whom .
?whom foaf:mbox ?mbox ;
rdfs:seeAlso ?ppd .
?ppd a foaf:PersonalProfileDocument .
} .
GRAPH ?ppd
{
?w foaf:mbox ?mbox ;
foaf:nick ?nick
}
}

If we adopt the Pythonesk OO approach, we quickly see
to what such a query amounts to just sequence of message
sending of the messsage rdf/3 to two graph handles H1
and H2:

H1::rdf(...),
...
H1::rdf(...),
...
H2::rdf(...),
...
H2::rdf(...)

Additional benefit of OO would be inheritance. I
already explained elsewhere that we even don't need
Logtalk, an ordinary Module system with reexport/1
does the job for an appropriate definition of (::)/2.

So what could be done via inheritance? Well we could
define different base classes for RDF sources. The two
handles H1 and H2 can be instances of different classes.
And these classes can define common behaviour.

Trivial common behaviour could be zero behaviour, meaning
the rdf tripples in the graph are just Prolog facts.
Another common behaviour of a class could be that the
tripples are found in some store. So the rdf/3 message
would not go into facts, but some routine that accesses
the store.

The store can be anything. And different stores can coexist
in the same way that different classes can coexist.
There can be an arbitrary number of store types modelled
by OO classes, and all these store types can be integrated
by the Prolog interpreter when it interprets the SPARQL
query (interpretes such as ClioPatra etc..)

Unfortunately for example SWI-Prolog ClioPatra uses rdf not
the Pythonesk way. But this is anyway only an inspiration
for the future, that one might wish to work on.

Bye

Credits: The idea of organizing quads in objects is not
origin by me. I picked it already up some months ago.
Check for example this book:

Programming the Semantic Web, Page 23
http://www.gise.cse.iitb.ac.in/wiki/images/3/3a/PTSW.pdf

The use of such objects is darn simple. We find statements
such as follows in the Python code:

from simplegraph import SimpleGraph
bg=SimpleGraph()
bg.load('business_triples.csv')

Still I wasnt convinced that it is good idea, until I
saw the SPARQL spec recently, which makes its somehow
evident that the OO approach would also translate to SPARQL
queries.

j4n bur53 schrieb:
0 new messages