The domain of an argument is specified in the function header using the following syntax
variable_name = default_value in domain
For example, the function header may look like
global._RP = (0+ to inf); func = function (x = 1 in _RP, options = "real" in {"real", "complex") -> y in _RP ... endThe above defines a function that takes two arguments x and options. _RP is the set of all positive numbers. So the argument x must be a positive number, while options must be either "real" or "complex". The output argument value y must be a positive number as well. Whenever func is called with invalid argument values, the interpreter will complain.
>> func(-5, 6) // !! domain error ...
When function definition is processed, the default value and the domain of an argument are evaluated in the scope surrounding the function definition. Therefore they can be expressions containing the local variables of the surrounding scope, but they cannot make an reference to the other argument names of the function definition. For example
x = 3; p = function (x = x) -> (y = x) ... endHere in (x = x) -> (y = x), the first x is the name of the formal argument, while the second and third x are the default values of arguments and refer to the value of the local variable x (whose value is 3) of the surrounding scope.
We may define a set, and then use it as the domain in a function definition immediately
Dmx = x -> (x <= -1 || x >= 2); Dmy = x -> (x >= -1 && x <= 2); f = function (x = 3 in Dmx, y = 0 in Dmy) -> z in _RP ... end
In practice sometimes the domains of two arguments are not independent of each other. For example
Dxy = v -> (v[0] >= 0 && v[0] <= 1 && v[1] >= 0 && v[1] <= v[0]); f = function v = [0, 0] in Dxy -> w w = (1 - v[0] - v[1]) / (v[0]^2 + v[1]^2); end
Note that if the domain of an input argument is given, a default value must be provided. Otherwise the interpreter may find the default default value (= null) does not belong to the domain, and have difficulty processing a call to the function that provides default argument value. On the other hand, one may specify the default value but omit the domain. Whenever the domain is not specified, a default domain, which is _ALL, the set of everything, will be set as the domain of the argument.
Programming languages can roughly be divided into two categories: statically typed, in which argument value must be of a certain type, and dynamically typed, in which formal arguments can be any type. Shang has both the flexibility of dynamically typed language and the rigorousness of statically typed language. It is in fact superior to statically typed language with respect to type-checking since the domain is a set, which can be much more expressive and specific than a type. Many times, being a value of certain type doesn't guarantee that the argument is a valid one. For example, if an argument a represent age. Statical type checking only guarantees that a is an integer, while in Shang, the domain of a can be a customized set that contain all valid ages, such as integers between 0 and 150.
oz 2009-12-22