Closed domel closed 1 year ago
@domel Could you give an example of where N3 collections would be insufficient?
@william-vw This concept was introduced in the old N3 spec. I guess the intention was related to the characteristics of the sets compared to lists. That is, no duplicates and no order. For example
:n3cg a :CommunityGroup ;
:member {$ :alice, :bob, :carol $} .
is not the same as
:n3cg a :CommunityGroup ;
:member ( :alice :bob :carol ) .
In the first listing, the order is not important, all members are equal. There is no information that :alice
is the first one and :carol
is the last one. In the second listing, :alice
is first so there are a few interpretations of that order, e.g. she become a member as a first person.
Moreless similar examples are the authors of a scientific publication. If you want to emphasize the order, e.g. contribution to publications, you will probably choose the list. If you do not want to indicate more important and less important authors, you will probably choose the set.
I can also imagine that the uniqueness of the members of such a collection can also be useful. For example, if we generate the forms using n3, it is not possible to handle the situation where the user enters the same value twice.
How does it differ from:
:n3cg a :CommunityGroup ;
:member :alice, :bob, :carol .
? Is this expected to use something like rdf:Bag
?
@gkellogg rdf:Bag
can have duplicates. The second thing is that rdf:Bag
and other RDF containers do not have semantics and they are defined as non-normative.
The :member :alice, :bob, :carol .
and :member {$ :alice, :bob, :carol $} .
are different, I guess, In the context of graph structure preservation.
@domel
I can also imagine that the uniqueness of the members of such a collection can also be useful. For example, if we generate the forms using n3, it is not possible to handle the situation where the user enters the same value twice.
Note that you can use list:in
to check whether a subject element is contained in an object collection; i.e., it would handle your use case. See here for an example.
Also, note that :member :alice, :bob, :carol .
does not allow duplicates either. E.g.:
:n3cg a :member :alice, :bob, :alice .
Is a shorthand for statements
:n3cg :member :alice .
:n3cg :member :bob .
:n3cg :member :alice .
RDF statements in and of themselves constitute a set - i.e., no order and no duplicates. (In practice, this is also how RDF stores treat statements internally.)
@william-vw Agree. RDF triples is seen as unordered set in different implementations. But it is slightly different level, my examples was about serialization and graph structure level. In other words, let's ask how many members are defined in your example. And the same question how many members do we have in example with a set notation. In you case it's 3 in my case it's 2. Re in:list, yes you can simulate sets in list but it's only simulation because you haven't got any constraints e.g., uniqnes.
Sets as first-class citizens are supported in Cwm and also again in Eye.
Here is a simple test:
$ cat test_sets.n3
@prefix log: <http://www.w3.org/2000/10/swap/log#>.
@prefix : <http://example.org/ns#>.
{($ 2 1 2 3 2 3 1 $) log:equalTo ($ 1 2 3 2 $)} => {:test1 :is :OK}.
$ cwm test_sets.n3 --think --data
#Processed by Id
# using base file:///home/jdroo/temp/test_sets.n3
@prefix : <http://example.org/ns#> .
:test1 :is :OK .
$ eye --quiet --nope test_sets.n3 --pass 2>/dev/null
@prefix log: <http://www.w3.org/2000/10/swap/log#>.
@prefix : <http://example.org/ns#>.
:test1 :is :OK.
About the difference between
#ex1
:g1 :members {$ :alice :bob :charlie $}.
and
#ex2
:g1 :member :alice, :bob, :charlie.
Ex1 tells you that the group g1 has at most 3 members (not exactly, because it is still possible that :alice owl:sameAs :bob
, for example), while ex2 does not tell you anything about how many members there are (there could be additional members that we don't know about).
IIRC, the first/rest ladders were introduced exactly for that reason: to ensure that we had the complete list of elements, even under the open world assumption -- a feature that the historical rdf:Seq, rdf:Bag and rdf:Alt did not provide.
@josd excellent!
@pchampin Agree. On the other hand, OWA does not conflict with sets (and lists). As you rightly noticed, both examples are not equivalent.
In other words, let's ask how many members are defined in your example. And the same question how many members do we have in example with a set notation. In you case it's 3 in my case it's 2. Re in:list, yes you can simulate sets in list but it's only simulation because you haven't got any constraints e.g., uniqnes.
Sorry if this was unclear in my post. In both cases one would only have 2 members, since an RDF graph similarly represents a set of statements.
Re in:list, yes you can simulate sets in list but it's only simulation because you haven't got any constraints e.g., uniqnes.
I was addressing your use case re:
For example, if we generate the forms using n3, it is not possible to handle the situation where the user enters the same value twice.
This would be handled better by list:in
since it explicitly checks whether the same value is entered twice; if the value already exists, a warning can be raised, for instance. A set would quietly ignore the duplicate value. (Of course, there could be an equivalent set:in
builtin, but I think that's besides the point here).
About the difference between
#ex1 :g1 :members {$ :alice :bob :charlie $}.
and
#ex2 :g1 :member :alice, :bob, :charlie.
Ex1 tells you that the group g1 has at most 3 members (not exactly, because it is still possible that
:alice owl:sameAs :bob
, for example), while ex2 does not tell you anything about how many members there are (there could be additional members that we don't know about).
You are right and I remember a lengthy discussion about this on the semweb mailing list a while back. I guess the most suitable representation depends on the use case. As you say, using sets here (or collections, for that matter) means the list of elements is immutable - one can infer a new set / collection in a rule (using list:append
) but this would constitute a new element list and both would co-exist at that point.
So, is a Set a new first-class citizen in N3, similar to how Lists are treated? As opposed to RDF, where a List is represented using a first/rest ladder. What are the N3 triples that result from parsing an example with a Set?
IMHO they are first-class citizens, so
$ cat sets.n3
@prefix : <http://example.org/ns#>.
:s :p ($ 2 1 2 3 2 3 1 $).
would be 1 triple
$ eye --quiet --nope sets.n3 --pass 2>/dev/null
@prefix : <http://example.org/ns#>.
:s :p ($ 1 2 3 $).
Years ago when sets were proposed I thought it would be fine to use <http://www.w3.org/2002/07/owl#oneOf>
but then the above example gives 2 triples. This is actually still how Cwm outputs them
$ cwm sets.n3
#Processed by Id
# using base file:///tmp/sets.n3
@prefix : <http://example.org/ns#> .
:s :p [
<http://www.w3.org/2002/07/owl#oneOf> (
1
2
3 ) ] .
If we want to keep sets of first class citizens, I would like to have a "plain RDF" representation of sets, just like there is one for lists. The owl:oneOf
trick does the job, IMO.
Right and a plain RDF representation was actually the reason why I proposed the owl:oneOf thing in 2005
The topic is very interesting from a scientific point of view, since there is a Datalog-extension with sets (Datalog(S)) and some recent studies how to best implement that, how to get termination, etc. I would be curious how that can be connected and I am sure the Datalog people would like to see use cases from our side.
As discussed in the N3 CG meeting today the latest EYE now supports the list:setEqualTo
and list:setNotEqualTo
built-ins and the tests below all succeed:
@prefix list: <http://www.w3.org/2000/10/swap/list#>.
@prefix : <http://example.org/test#>.
{(:alice :bob :charlie) list:setEqualTo (:bob :charlie :alice)} => {:test1 a :OK}.
{(:alice :bob :charlie) list:setEqualTo (:alice :bob :charlie :alice)} => {:test2 a :OK}.
{(:alice :bob :charlie ?X) list:setEqualTo (:alice ?Y :bob :charlie)} => {:test3 a :OK}.
{(:alice :bob :charlie :dan) list:setNotEqualTo (:eve :bob :charlie :alice)} => {:test4 a :OK}.
{(:alice :bob :charlie ?X) list:setNotEqualTo (:alice ?Y :bob :charlie ?Z)} => {:test5 a :OK}.
is that tested at the symbol level (or UNA)? what about
:dan = :eve .
{(:alice :bob :charlie :dan) list:setEqualTo (:eve :bob :charlie :alice)}
?
@josd -- Please edit your latest comment, and put triple-backtick code fences before/above and after/below both your explicit rules and your result. This is particularly important because your text includes @Prefix
which (when not code fenced) tags an active GitHub user who is probably not interested in our conversations.
That doesn't help. I tried it half a day ago and again 5 minutes ago. It says "Email replies do not support Markdown" which is how the original reply was done.
@josd -- Ah, that's unfortunate. There is another option, which will solve this post.
That is, instead of starting those lines with @Prefix
and ending with a .
, start them with PREFIX
and remove the trailing .
To be clear, those lines would become --
PREFIX list: <http://www.w3.org/2000/10/swap/list#>
PREFIX log: <http://www.w3.org/2000/10/swap/log#>
PREFIX : <http://example.org/test#>
(Another option would be to delete that comment, and repost it [with the code fences] through the website instead of by email.)
is that tested at the symbol level (or UNA)? what about
:dan = :eve . {(:alice :bob :charlie :dan) list:setEqualTo (:eve :bob :charlie :alice)}
?
It is tested at the symbol level and I would do your example with explicit rules:
@prefix list: <http://www.w3.org/2000/10/swap/list#>.
@prefix log: <http://www.w3.org/2000/10/swap/log#>.
@prefix : <http://example.org/test#>.
:dan = :eve .
{?Name :isTheNameUsedFor ?A} <= {?Name = ?A}.
{?Name :isTheNameUsedFor ?Name} <= {(?Any {?Any = ?Name} ()) log:collectAllIn ?Scope}.
{ (?Name {(:alice :bob :charlie :dan) list:member ?M. ?Name :isTheNameUsedFor ?M} ?List1) log:collectAllIn ?Scope.
(?Name {(:eve :bob :charlie :alice) list:member ?M. ?Name :isTheNameUsedFor ?M} ?List2) log:collectAllIn ?Scope.
?List1 list:setEqualTo ?List2.
} => {
:test4 a :OK.
}.
which gives
:test4 a :OK.
Do we need to support the sets? The sets appeared once, but as far as I know, they were never implemented.
{$ 1, 2, <a> $}