1
  2 /**
  3 Name: RDEL ("Ardele") - Resource Decription Extraction/Execution Language
  4 Description: A mainly functional RDF programming language
  5   .. Inspired by python, n3 and haskell, with a little js sprinkled in.
  6   .. All statically typed with inference.
  7
  8 - Curie (and uri) names are public and shared.
  9   The rest are local (to scope), instrumental names (though somewhat akin to bnodes..).
 10
 11 - Top-level functions (def) represent "subject predicate", use like some:expr() ?object
 12 - Class-level functions represent "predicate", use like subject some:expr() ?object
 13
 14 - Use "name = <expr>" as shorthand+side-effect(!) for "one s p ?name else unknown '...' "
 15   - side-effect: scopes name at same level as <expr> (as opposed to match expressions)
 16   - for now, these assignments *are the only way* to set "same scope level" values..
 17   - NOTE: "=" *is not* shorthand for owl:sameAs (as in n3); it has side-effect as explained
 18
 19 - If some:expr() is used without name for object, expression represents obj,
 20   - only useful when assigning (see = above) and to send as parameters to functions
 21
 22 - Generally, expressions with two atoms are of the form
 23       "subject predicate" and represents the object,
 24       to get subject, you need "is predicate of object". Nest with parens..
 25
 26 - Datatypes. First, the ones from rdf:
 27     - resources with properties. kind of a no-brainer eh? ;)
 28     - literals (xsd:*-things are built-in)
 29     - collection lists
 30   Beyond these are the instrumental:
 31     - functions (see above) - these are the core of RDEL!
 32     - sets are collections rdf-wise, but keeps unique values (in a no-uniqueness world.. ;D)
 33     - @TODO: no traditional dictionaries - use real rdf.. but perhaps.. named tuples?
 34       Or "unpack" - see below?
 35
 36 -  Declaring new values will (just as assignments) be local to the runtime
 37    (@TODO:context? see below) including desc constructs (proper sub-graphs?).
 38
 39 - Builtin prefixes are: rdf:, rdfs:, owl:, xsd:, std:
 40   .. can of course be redefined, as here (std: to :)
 41
 42 - std: is the core of the stdlib and contains a bunch of things, like:
 43     def std:print() ...
 44     def std:<time/now>() ...
 45     def std:<posix/stat>() ...
 46     class xsd:string
 47         def std:expand() ...
 48 */
 49
 50
 51 prefix : <http://oort.to/ts/2008/08/rdel/stdlib/>
 52 prefix l: <http://neverspace.net/ts/2008/08/rdel/testlib#>
 53 prefix foaf: <http://xmlns.com/foaf/0.1/>
 54
 55
 56 def l:sum_ages()
 57     var sum = 0 # use var for mutable values for names (only for instrumental names)
 58     now = :<time/now>() # all other names are final (though their refs belong to the open world..)
 59     each ?person a foaf:Person
 60         # could also use (but may fail with unknown):
 61         #sum += age(now, person foaf:birthday)
 62         one person foaf:birthday ?bday
 63             sum += age(now, bday)
 64     return sum
 65
 66 # Sketch for opt. delimiters (non-indented stuff):
 67 def l:sum_ages() ->
 68     var sum = 0; now = :<time/now>()
 69     each ?person a foaf:Person ->
 70         one person foaf:birthday ?bday -> sum += age(now, bday) .
 71     .
 72     return sum
 73 .
 74 # On one line:
 75 def l:sum_ages() -> var sum = 0; now = :<time/now>(); each ?person a foaf:Person -> one person foaf:birthday ?bday -> sum += age(now, bday) .. return sum .
 76 # use functions as values:
 77 var increased = :apply( [] , def (it)-> return it + 1 . )
 78
 79
 80 # private name
 81 def age(from as xsd:dateTime, to as xsd:dateTime)
 82     return to - from # @TODO: as shorthand for: to std:subtract(from)?
 83     # @TODO: if bad type/datatype, complement to "unknown" called "mismatch"?
 84     # .. but that should be dealt with by caller!
 85
 86 def l:allDescriptions()
 87     each ?thing a owl:Thing
 88         yield thing l:info() or continue # @TODO: odd? "except continue"?
 89
 90
 91 class foaf:Person
 92     def l:info()
 93         one self foaf:homepage ?homepage
 94             return homepage rdfs:label + homepage rdfs:comment
 95             # @TODO: shorthand for (hp label) std:add (hp comment)?
 96         except
 97             unknown "No described homepage for {self}"@en :expand()
 98
 99 # @TODO: classes as "statemachines" too? with e.g. var someState (note: *no* class-level statics)
100 #   .. for what should the state be kept? The call chain? The context?
101
102
103 # exported "constant"
104 l:message = "An english literal."@en
105
106
107 # Add data in current context/scope (also see "load" etc.):
108 # This looks crude (but should work?):
109 item rdfs:label "some item"; item rdfs:comment "this isn't turtle!"
110 # This may be better..:
111 item desc
112     rdfs:label "some item"@en
113     rdfs:comment "..."
114     rdfs:seeAlso <./> desc
115         rdfs:label "this module dir"@en
116     rdfs:seeAlso desc # bnode
117         rdfs:label "related"@en
118     rdfs:seeAlso desc -> rdfs:label "more"@en .
119 # @rejected: Alt. is to have e.g. a "turtle" block, for a given scope. But that
120 #   will make syntax inconsistent - i.e. hard to spot the suble difference
121 #   between turtle/n3 and RDEL..
122 # @TODO: Perhaps allow: load """ .. n3 in opaque string literal .. """, 'text/n3'
123
124 # @TODO: what about "call with context"; to process some things in a local
125 #       context (as opposed to currently, only "global graph")
126
127 # TODO: "class instantiation" use case:
128 prefix html :<html/>
129 parser desc
130     a html:HtmlParser
131     html:parseMode "tagsoup"
132 parser html:parse(<file:test/data/1.html>)
133 # one-liner:
134 parser desc -> a html:HtmlParser; html:parseMode "tagsoup" .
135
136 # TODO: or via factory (requires a new instance equiv. to class.):
137 html:HtmlParser desc # TODO: can we do this!?
138     def :new(parseMode="strict")
139         return desc
140             a self
141             html:parseMode parseMode
142 # usage:
143 parser = html:HtmlParser :new("tagsoup")
144 # .. sugar?:
145 parser = html:HtmlParser("tagsoup")
146
147 # this may also be a powerful data notation in general..
148
149 # as "del" in python:
150 forget parser
151
152
153 main
154
155     :print("Testing stuff, e.g. printing info about {foaf:Person}s." :expand())
156
157     load <file:rdel_test_data.n3>
158
159     me = <http://purl.org/NET/dust/me#self>
160     :print( me l:info() )
161     # @TODO: what about: label = me rdfs:label for @{lang} ?
162
163     # Verbose:
164     one l:sum_ages() ?sum
165         :print(sum)
166     except
167         unknown "..."
168     # More compact (*and* declares sum in scope (if successful)):
169     sum = l:sum_ages()
170     :print( sum )
171     # Most compact:
172     :print( l:sum_ages() )
173
174     list = [:a, :b] # @TODO: cannot use n3 syntax (:a :b) since space is expression segment separator!
175     list :append(me)
176     # TODO: how to loop over lists? Overload each (it's a patter matcher!)? Rather "for... in":
177     for item in list
178         :print(item)
179
180     var counter = 0
181     for descr in l:allDescriptions()
182         counter += 1
183         :print("{counter}: {descr}" :expand())
184
185
186     # List comprehension (long version omitted):
187     hasSites = [?person each ?person a foaf:Person if ?person foaf:homepage]
188     # Generator comprehension:
189     hasSites = ?person each ?person a foaf:Person if ?person foaf:homepage
190     # which is a shorthand for:
191     hasSites = (def () -> each ?person a foaf:Person -> if ?person foaf:homepage -> yield person ...)()
192
193     # Comprehension with result from expression:
194     homepages = (?person one foaf:homepage) each ?person a foaf:Person if ?person foaf:homepage
195
196
197     # Sets:
198     set = :set([:a, :b, :a])
199     uniqueSites = :set(hasSites)
200
201
202     # TODO: pack/unpack tuples (don't? this removes us from the rdf:iness - can't that be clean enough?)
203     first, second = %(1, 2)
204     pair = me %(first=1)
205     :print(pair%first)
206     # TODO: is this needed, or is rdf lookup enough?
207     myName, mySite, myProjects = %(me foaf:name, me foaf:homepage, [?o each me foaf:currentProject ?o])
208     myInfo = %(name=me foaf:name)
209     :print(myInfo%name)
210
211