- From: Bob MacGregor <macgregor@ISI.EDU>
- Date: Tue, 12 Aug 2003 17:39:38 -0700
- To: Garret Wilson <garret@globalmentor.com>, www-rdf-interest@w3.org
- Message-Id: <5.1.1.6.0.20030812172146.0239b728@tnt.isi.edu>
Garret, It would seem that you were never a Common Lisp programmer, or the constraints on RDF lists would seem natural. You apparently are taking it for granted that operations on lists other than the empty list should be "destructive". That decision probably deserves some discussion. I wasn't a party to the discussions that lead to inventing RDF:List semantics, but its likely that the motivation was based on ability to manipulate lists via logic, rather than via Java or some other procedural language. RDF:List semantics is closely aligned with both Prolog-style and KIF-style lists. As such, its semantics is probably not open to debate. A key question is whether or not an API for manipulating lists should make it easy to support both destructive and non-destructive operations. In the Common Lisp world, list operations frequently occur in pairs. For example, "append" is non-destructive concatenation of lists, and "nconc" is its destructive analog. "reverse" is a non-destructive reversal, and "nreverse" is destructive reversal. I would prefer seeing the same thing for an RDF API, unless someone can present a good argument against it. Cheers, Bob At 05:09 PM 8/12/2003 -0700, Garret Wilson wrote: >Everyone, > >I'm just getting around to implementing support for >rdf:parseType="Collection", even though I've been using it for a while in >specifications I've written. > >The design of rdf:List looks good in theory, but there are a few details >that make it a pain to implement---particularly, the way rdf#nil is used: > >1. Empty lists cannot be modified. > >In the RDF world, it's natural to think that one can always add things to >a resource. I can specify another dc:creator to a book. I can later add an >rdfs:label to a resource. Yes, I know that RDF is designed to only be >aware of one set of static relationships, but in the real world we need to >modify resources at some time or another. We can modify rdf:Alt, rdf:Bag, >and rdf:Seq, even if they are empty---we just add one or more resources to >the collection. > >rdf:List is designed so that one cannot add anything to an empty rdf:List, >because there is only one empty rdf:List, the one named rdf#nil. There are >an infinite number of non-empty lists, with an infinite number of (usually >anonymous/blank node) reference URIs, but *none* of those lists can be >empty, because the empty list has its own static universal reference URI. >Conversely, the empty list can never be added to without changing its >reference URI. Put differently, an empty rdf:List cannot be filled---it >can only be replaced with a filled list. (Compare this to an rdf:List with >one element---programmatically, one can add more elements by changing the >rdf:rest property, allowing the list remains the same entity, identified >by the same reference URI. This is impossible with an empty list.) > >2. It is a pain to populate an rdf:List. > >Even if we accept the theoretical notion of RDF as a static snapshot of >relationships, in the real world one has to populate that directed graph >programmatically---when parsing an RDF+XML document, for instance. With >the old containers, that was easy: we start with an empty rdf:Alt, >rdf:Bag, or rdf:Seq and then add elements if and only if they are present. > >With rdf:List, this procedure remains the same *only* after we know we >have one element in a list. Until we have one element in the list, we >don't know whether to create an anonymous rdf:List and populate it with >items, or (if there are no items) to create an rdf#nil list (with its >unique reference URI). This results in very inelegant algorithms: > >while(there are child elements) >{ > create a new rdf:List > if(we've already created an rdf:List) > { > add the new rdf:List to the old one > } > else > { > specify that the new list is the "root" list > save this new list for next time > } >} >if(we have record of finding a "root" list) > use the "root" list as the property value > >In contrast, the old containers allowed very elegant implementations, >because they didn't distinguish conceptually between empty and filled >containers: > >create new container >while(there are child elements) >{ > add the element to the container >} >use the new container as the property value > >3. It is impossible to independently insert an element at the beginning of >an rdf:List. > >In object-oriented programming, I'd like to have an object represent an >rdf:List. In Java, something implementing java.util.List would be great. >Given any MyList, it's a simple matter to insert something at index i+1 >with i>0: I just create a new rdf:List with rdf:first representing the >inserted resource, change rdf:List(i).rdf:rest to point to the new >rdf:List, and change rdf:List(i+1).rdf:rest to the old value of >rdf:List(i).rdf:rest. > >That's all fine except when i=0. To insert at the front of the list, I >have to know for which resource property the rdf:List is the property >value. This is made worse by the fact that several properties (of several >resources) might have the rdf:List as a property value. This leads to the >following inconsistency: if resources example.com#book1, >example.com#book2, and example.com#book3 all have a property of >listOfComments, I can always add another comment to the end of the list >without modifying the property value for any of the books, but if I want >to *insert* a comment at the first of the list, I have to modify the >property value for each of the books. > >In very practical terms, that means if I have the function... > >add(RDFList list, RDFResource resourceElement, int index) > >...it will work for all values of index except index==0, unless I have >access to the entire RDF data model, walk the graph, and find all >resources which have properties for which the list is a property value. > >Similarly, going back to problem #1 (above), the function... > >add(RDFList list, RDFResource resourceElement, int index) > >...cannot work with empty lists! > >I understand that the old collection framework had shortcomings (those >silly indexes, for one thing) and that the new rdf:List framework looks >nice in a pretty static graph on paper. The specific way that rdf#nil is >used as an empty list, however, creates very inelegant impelementation >restrictions. Surely rdf:List could me modified to be better than the old >collections, yet also usable in real life. > >Garret ===================================== Robert MacGregor Senior Project Leader macgregor@isi.edu Phone: 310/448-8423, Fax: 310/822-6592 Mobile: 310/251-8488 USC Information Sciences Institute 4676 Admiralty Way, Marina del Rey, CA 90292 =====================================
Received on Tuesday, 12 August 2003 20:49:17 UTC