Metaprogramming is one of the most important facilities of Ur. This example shows how to write a function that is able to sum up the fields of records of integers, no matter which set of fields the particular record has.
Ur's support for analysis of types is based around extensible records, or row types. In the definition of the sum function, we see the type parameter fs assigned the kind {Unit}, which stands for records of types of kind Unit. The Unit kind has only one inhabitant, (). The kind Type is for "normal" types.
The sum function also takes an argument fl of type folder fs. Folders represent permutations of the elements of type-level records. We can use a folder to iterate over a type-level record in the order indicated by the permutation.
The unary $ operator is used to build a record Type from a {Type} (that is, the kind of records of types). The library function mapU takes in a type t of kind
Another library function foldUR is defined at the level of expressions, while mapU is a type-level function. foldUR takes 7 arguments, some of them types and some values. Type arguments are distinguished by being written within brackets. The arguments to foldUR respectively tell us:
The general syntax for constant row types is [Name1 = t1, ..., NameN = tN], and there is a shorthand version [Name1, ..., NameN] for records of Units.
With sum defined, it is easy to make some sample calls. The form of the code for main does not make it apparent, but the compiler must "reverse engineer" the appropriate {Unit} from the {Type} available from the context at each call to sum. The compiler also infers a folder for each call, guessing at the desired permutations by examining the orders in which field names are written in the code.