Skip to content
timrdf edited this page Mar 10, 2012 · 13 revisions

What is first

Let's get to it

Ripple defines its own human-readable syntax for queries and commands, which is what you see in the examples throughout this wiki. In terms of programming style, Ripple most closely resembles Forth and other stack-oriented languages, but the syntax generally follows the [Turtle](http://www.dajobe.org/2004/01/turtle/ Turtle) RDF triple language, which in turn is based on Notation3. Where not otherwise stated, Ripple's textual syntax may be assumed to be identical to Turtle's. The main difference is that the high-level constructs of Turtle are directives and triple-generating statements, whereas the high-level constructs of Ripple are commands and RDF lists representing path-based queries. Apart from lists and program definitions, Ripple excludes all syntax for the generation of triples, whereas it adds syntax for common components of Ripple programs, such as application operators.

High-level syntax

Anything you type in at the command line or pass into a query pipe the Java API is considered to be a Ripple document. Every document is a sequence of statements, where each statement may be either a query (a list which is evaluated as a program) or a command.

A statement occupies a single line of text unless it is continued using the backslash (\) character. E.g.

"here is a long expression " \
"continued on the following line" concat.

Comments

Technically, a blank line also counts as a statement, and so does a line containing nothing but a comment. Comments begin with the # character and cause the rest of the line to be ignored by Ripple. E.g.

# This line will be ignored
"but this one will not" " " split. each.

Queries and commands

Commands in Ripple are strictly separate from queries. Queries have declarative semantics: they are expressions which a Ripple query evaluator attempts to "solve" by reduction. Commands, on the other hand, are procedural constructs which inspect or modify the scripting environment. They are more closely tied to the command line and the Ripple implementation.

For example, here are two commands:

@prefix foaf: <http://xmlns.com/foaf/0.1/>
@list danny: <http://identi.ca/user/114>

and here is a query:

:danny. foaf:knows{0, 2} foaf:name. distinct.

The former define a namespace prefix and bind a URI to a program, while the latter evaluates a program.

Note: the primitives of the system library straddle the boundary between queries and commands, in that they permit environment-aware operations like issuing system calls and executing programs in languages other than Ripple.

URI references

There are three types of symbol which resolve to RDF URI references in Ripple. In order of increasing compactness, they are absolute URIs, qualified names, and keywords.

Absolute URIs

Absolute URIs are expressed as in Turtle. For instance, <http://xmlns.com/foaf/0.1/Person>. Currently, relative URIs are not supported.

QNames

QNames are URI references abbreviated using namespace-bound prefixes. For example, the QName foaf:Person stands for the same resource as <http://xmlns.com/foaf/0.1/Person>, provided that the "foaf" prefix has been bound to the namespace "http://xmlns.com/foaf/0.1/".

In the Ripple implementation, a large number of common namespace prefixes (specifically, all prefixes provided by prefix.cc) are pre-defined. The empty namespace prefix (e.g. in :foo, :bar, :my-program) corresponds the current default namespace, which may be redefined using the @prefix command (see Commands).

Keywords

Some URIs are important enough to be given an even more compact kind of symbol, which is just the local part of a QName without the prefix or colon. Each Ripple primitive has a corresponding keyword which is simply the local part of its URI. For example, the expression

2 3 add.

represents the same program as

2 3 <http://fortytwo.net/2011/04/ripple/math#add> .

The only other pre-defined keyword is the application operator op. The above example can just as well be written

2 3 <http://fortytwo.net/2011/04/ripple/math#add> op

or even

2 3 <http://fortytwo.net/2011/04/ripple/math#add> <http://fortytwo.net/2007/03/ripple/schema#op>

... but 2 3 add. is easier on the eyes.

At the Ripple command line, you can also define new, temporary keywords as a way of hanging on to query results and inserting them into subsequent queries. For example,

1)  <http://identi.ca/user/114> foaf:knows. = v

  [1]  <http://identi.ca/user/1>
  [2]  <http://identi.ca/user/58>
  [3]  <http://identi.ca/user/58>
  [4]  <http://identi.ca/user/226>
  [5]  <http://identi.ca/user/226>
  [...]

2)  v. foaf:name.

  [1]  "Evan Prodromou"
  [2]  "Dan Brickley"
  [3]  "Brian Manley"
  [4]  "Yoan Blanc"
  [5]  "Robert Mark White"
  [...]

Literals

An RDF literal is any basic value which is completely described by its lexical form. Strings, booleans, and numbers are all special classes of values in Ripple which have equivalence relationships with literals.

Plain literals

A plain literal is simply a string with no datatype. It can be expressed by placing the string between double-quotes, e.g.

"Hello World!"

A plain literal can be combined with an optional language tag using @ syntax, e.g.

"forty-two"@en

or

"zweiundvierzig"@de

You can find the language tag of a plain literal using the lang primitive (see the data library).

Datatypes

A literal can be associated with a datatype by appending the ^^ symbol and the URI of the datatype. E.g.

"2011-05-20T09:30:03+00:00"^^xsd:dateTime

or

"2011-05-20T09:30:03+00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime>

You can find the datatype of a typed literal using the type primitive (see the data library).

Abbreviated literals

Some typed literals may be written in an abbreviated format, lacking quote characters and data type syntax. As in Turtle, there are four types of literals which may be abbreviated:

  • Boolean values have the xsd:boolean data type. Both possible legal lexical values may be abbreviated:
true
false
  • Integer values have the data type xsd:integer. All legal values may be abbreviated. For example,
42
-127
08
+12
  • Arbitrary-precision decimal numbers have the data type xsd:decimal. All legal values with a decimal point followed by at least one digit may be abbreviated. For example,
365.24
-0.0
+123.00
  • Double-precision floating point numbers have the data type xsd:double. All legal values with an exponent portion may be abbreviated. This excludes the special values "NaN", "INF" and "-INF" as well as values with an implicit exponent such as 32 (which is interpreted as an xsd:integer value) or 0.0 (which is interpreted as an xsd:decimal value). For example,
3.1415e0
1e-16
0.0E0

Lists

Lists are the fundamental data structure in Ripple. There is an equivalence relation between native lists in Ripple (which also represent programs) and RDF Lists. Every RDF List is also a Ripple list, and vice versa. This allows you crawl programs in the Web of Data or (more commonly) to embed them along with the rest of your data in local triple stores.

In the textual syntax, lists follow the Turtle conventions for collections, with the addition of an rdf:type triple for the first item in a list. So, for example, the Ripple list (:foo :bar) can be expanded to the Turtle expression: [ rdf:type rdf:List; rdf:first :foo; rdf:rest [ rdf:first :bar; rdf:rest rdf:nil ]. Every Ripple query is a list from which the parentheses have been omitted. For instance, the query 2 3 add. is a list of four items: the number 2, the number 3, the add primitive, and the application operator. The query result you see at the command line is a list containing a single item (the number 5):

1)  2 3 add.

  [1]  5

The empty list can be expressed as either () or rdf:nil.

Application syntax

While every Ripple list is a program, every program which does something apart from appending itself to the program stack contains the application operator op. In the textual syntax, op is more compactly represented with a ., as mentioned above. The application operator has the effect of causing the topmost item on the program stack to be applied as a mapping. So, for example, the program 2 3 add is merely a list of three items, one of which is a Ripple primitive. However, the program 2 3 add. activates the add primitive and reduces to 5 when evaluated as a query. Similarly, :danny foaf:knows is just a list of two items, one of which is another list, and the other of which is an RDF predicate. However, the two references to op in :danny. foaf:knows. cause the list to be dequoted (producing a reference to Danny) and the RDF predicate to be applied, producing references to all of the people Danny knows.

Inverse application

To every mapping in Ripple, there is an associated inverse mapping capable of producing zero or more solutions which "undo" the action of the primary mapping with respect to its first argument. For example, the inverse of the add primitive is sub. Syntactically, inversion of a mapping is represented by the ~ symbol, e.g. in 2 3 add~. (which evaluates to -1 instead of 5) and :danny. foaf:knows~. (which evaluates to all of the people who know Danny, as opposed to all of the people whom Danny knows).

The tilde symbol expands to the sequence inverse op behind the scenes (see the control library).

Regular expressions

There are several syntactic constructs for regular expressions in Ripple:

  • the option quantifier ? applies a mapping zero or one time. For example, :danny. foaf:knows? foaf:name. finds the name of Danny and everyone he knows
  • the star quantifier * applies a mapping zero or more times. For example, :danny. foaf:knows* foaf:name. finds the name of Danny, everyone he knows, everyone they know, and so on indefinitely.
  • the plus quantifier + applies a mapping one or more times. For example, :danny. foaf:knows+ foaf:name. finds the name of everyone Danny knows, everyone they know, and so on indefinitely, but not of Danny.
  • the times quantifier {n} applies a mapping exactly n times. It behaves like a loop in an imperative programming language. For example, :danny. foaf:knows{2} foaf:name. finds the name of everyone known by everyone Danny knows.
  • the range quantifier {n, m} applies a mapping from n to m times, inclusive. It behaves like a loop in which an intermediate result is produced at each step. For example, :danny. foaf:knows{0, 2} foaf:name. finds the name of Danny, everyone he knows, and everyone they know, then stops.

All of these constructs are syntactic sugar for the application of a corresponding control primitive (see the control library). E.g. :danny. foaf:knows? is the same as :danny op foaf:knows option-apply op op.

Commands

The syntax of commands incudes the name of a directive for each type of command, preceded by an @ character and followed by directive-specific arguments. For example:

@prefix foo: <http://example.org/foo#>

or

@quit

What is next

  • For the standard commands supported by Ripple, see Commands.