-
Notifications
You must be signed in to change notification settings - Fork 18
Builtin domains
An N3 builtin is identified by an IRI, and occurs in the predicate position of a statement.
An N3 builtin operates on its arguments. These arguments are often the subject and object of the builtin statement. For instance (arguments are prefixed with $a
):
-
math:lessThan
results in a true statement if the subject is less than the object. Hence, its arguments,$a_1
and$a_2
, are derived from the builtin statement as follows:$a_1 math:lessThan $a_2
.
Arguments can also be a more complex "deconstruction" of the subject and/or object in case lists or cited formulas are expected. For instance:
-
math:sum
calculates the sum of a list of numbers. In this case, the subject is deconstructed into its constituent elements, which serve as arguments together with the object. In particular, its arguments,$a_1 .. $a_n
and$a_n
, are defined from the builtin statement as follows:($a_1 .. $a_n) math:sum $a_s
If an argument is concrete (i.e., not an unbound variable), it serves as an input argument. Else, i.e., if an argument is an unbound variable, then it serves an output argument.
If an N3 builtin only has input arguments, then the builtin will check the truthfulness of the statement. For instance, in the statement (2 1) math:sum 3
, the builtin math:sum
will check whether 2 + 1 = 3
.
If an N3 builtin has an output argument, then the builtin will calculate a value for the output so as to ensure the truthfulness of the builtin statement. For instance, given (2 1) math:sum ?s
, the system should calculate value 3
for output argument ?s
; or given (?x 2) math:sum 3
, the system should calculate value 1
for output argument ?x
. (Alternatively, this could be seen as applying a basic graph pattern on the builtin’s "theory box", i.e., set of all possible truthful builtin statements, which is often infinite. In the first example above, it would include (2 1) math:sum 3
.)
Hence, an N3 builtin often does not have a single, fixed output ; it depends on which argument is given as an unbound variable.
From now on, we will refer to an N3 builtin's input arguments as inputs, and output arguments as outputs.
Each N3 builtin has an expected datatype for each of its arguments, called the argument domain (or simply domain). If the datatype of an argument value, called the value datatype, does not match the argument domain, it may be possible to cast the value's datatype to, or substitute it for, the domain datatype.
If the value datatype and domain datatype do not match, and no casting or substitution is possible, the builtin statement will be considered false. This is in line with the regular behavior of "incorrect" builtin statements (see XX).
If the numeric value datatype does not match the argument domain, it may be possible to promote or substitute the numeric value datatype:
Numeric type promotion: A numeric value datatype that is derived from the argument domain can be promoted to the latter datatype (e.g., xs:integer
is derived from xs:decimal
). This is done by casting the original value to the required datatype. This kind of promotion may cause loss of precision [can it? if the required type has a higher precision?].
Even if there is no direct derivation relation between the value datatype and domain, the following numeric type promotions can take place:
- A value of type
xs:float
(or any type derived fromxs:float
) can be promoted to typexs:double
. The result is anxs:double
value that is the same as the original value. - A value of type
xs:decimal
(or any type derived fromxs:decimal
) can be promoted to either of the typesxs:float
orxs:double
.
Numeric type substitution: If all values have the same numeric datatype, and this datatype is derived from the domain (e.g., xs:integer
is derived from xs:decimal
), then the values can be used without any casting. I.e., subtype substitution does not change the actual datatype of these values. This substituted numeric datatype will also apply to the builtin's output, if any. For example, if two xs:integer
values are used where xs:decimal
domains are expected, then the values retain their datatype as xs:integer
; the builtin's output (if any) will also have datatype xs:integer
.
Builtins operating on any numeric type: given an N3 builtin (e.g., math:sum
) that operates on values of any numeric type (xs:numeric
, the domain of xs:double
, xs:float
, and xs:decimal
), this builtin can be applied if all value datatypes can be converted into a numeric datatype that is the first type in the ordered list (xs:integer, xs:decimal, xs:float, xs:double)
. At this point, we can rely on numeric type substitution to do the rest. For instance:
-
Given two values with type
xs:integer
, this datatype will be substituted forxs:numeric
. If the builtin has an output, then this output will also have datatypexs:integer
. -
Given two value datatypes
xs:integer
andxs:decimal
, thexs:integer
value will be promoted toxs:decimal
. (At that point, the twoxs:integer
datatypes can be substituted forxs:numeric
, as above.) If the builtin has an output, then this output will also have datatypexs:decimal
.
If the non-numeric value datatype does not match the argument domain, it may be possible to cast the value datatype to the domain.
Below, we consider the case where an input value has an xs:string
datatype that does not match the expected domain. A literal will be considered a "string" when it has an xs:string
datatype, due to the absence of a datatype, or an explicit xs:string
datatype; or a rdf:langString
datatype, due to the presence of a language tag.
Casting from string: if an input value has an xs:string
datatype that does not match the domain, it may be possible to cast the string to the domain datatype, as defined in XPath. The given string will be mapped to a value of the domain datatype as defined in XML Schema 2. The resulting string must be a valid lexical form for the domain datatype.
Casting to string: if an input value is an IRI, or any kind of literal (incl. type xs:anyUri
or its derivations), and the domain is xs:string
, the value will be cast to a string as defined in XPath.
Other types of datatype casting will take place as defined in XPath. [Speaking for myself here; supporting all these casting operations would really increases the complexity of implementing builtins. But I suppose it's unavoidable.]
Comments from the google doc:
(gregg) There's a useful chart in https://www.w3.org/TR/xpath-functions/#casting-from-primitive-to-primitive, a subset of which is in SPARQL (https://www.w3.org/TR/sparql11-query/#FunctionMapping), also describing IRIs.