Skip to content
William Van Woensel edited this page Nov 25, 2020 · 10 revisions

Introduction

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.

Input and output domains

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).

Numeric datatype promotion and substitution

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 from xs:float) can be promoted to type xs:double. The result is an xs:double value that is the same as the original value.
  • A value of type xs:decimal (or any type derived from xs:decimal) can be promoted to either of the types xs:float or xs: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 for xs:numeric. If the builtin has an output, then this output will also have datatype xs:integer.

  • Given two value datatypes xs:integer and xs:decimal, the xs:integer value will be promoted to xs:decimal. (At that point, the two xs:integer datatypes can be substituted for xs:numeric, as above.) If the builtin has an output, then this output will also have datatype xs:decimal.

Other kinds of datatype casting.

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:

Clone this wiki locally