// Assert that a value is a tuple. Generate a compile failure if it is not. let assert_tuple = func (tpl) => select (tpl is "tuple", NULL) => { false = fail "@ is not a tuple" % (tpl), }; // Return a list of the fields in a tuple. let fields = module{ tpl = NULL, } => (result) { let assert_tuple = import "std/tuples.ucg".assert_tuple; // First we check that mod.tpl is a tuple. assert_tuple(mod.tpl); let result = reduce(func (acc, field, value) => acc + [field], [], (mod.tpl)); }; // Return a list of the values in a tuple. let values = module{ tpl = NULL, } => (result) { let assert_tuple = import "std/tuples.ucg".assert_tuple; // First we check that mod.tpl is a tuple. assert_tuple(mod.tpl); let result = reduce(func (acc, field, value) => acc + [value], [], (mod.tpl)); }; // Return a list of the key value pairs in the tuple. let iter = module{ tpl = NULL, } => (result) { let assert_tuple = import "std/tuples.ucg".assert_tuple; // First we check that mod.tpl is a tuple. assert_tuple(mod.tpl); let result = reduce(func (acc, field, value) => acc + [[field, value]], [], (mod.tpl)); }; // Wraps a tuple and provides a number of operations on it. // // * fields - function returns all the fields in the wrapped tuple as a list. // // * values - function returns all the values in the wrapped tuple as a list. // // * iter - function returns a list of pairs of [field, value]. let ops = module{ tpl = NULL, } => ({fields=fields, values=values, iter=iter}) { (mod.tpl != NULL) || fail "tpl must not be null"; let pkg = mod.pkg(); let fields = func() => pkg.fields{tpl=mod.tpl}; let values = func() => pkg.values{tpl=mod.tpl}; let iter = func() => pkg.iter{tpl=mod.tpl}; }; // Strip all the null fields from a tuple. let strip_nulls = module{ tpl = NULL, } => (result) { let assert_tuple = import "std/tuples.ucg".assert_tuple; // First we check that mod.tpl is a tuple. assert_tuple(mod.tpl); let result = filter(func (name, value) => value != NULL, (mod.tpl)); }; // Check if a tuple has all the fields in a given list. let has_fields = module{ tpl = NULL, fields = [], } => (result) { let pkg = mod.pkg(); // First we check that mod.tpl is a tuple. pkg.assert_tuple(mod.tpl); let fs = pkg.fields{tpl=mod.tpl}; let result = reduce(func (acc, f) => acc && (f in fs), true, mod.fields); }; // Check if a field in a tuple is a given type. let field_type = module{ tpl = NULL, field = NULL, type = NULL, } => (result) { let pkg = mod.pkg(); // First we check that mod.tpl is a tuple. pkg.assert_tuple(mod.tpl); // Next we assert that mod.field is a string. select (mod.field is "str", NULL) => { false = fail "@ is not a string" % (mod.field), }; // and finally that mod.type is a string select (mod.type is "str", NULL) => { false = fail "@ is not a string" % (mod.type), }; // Get the list of field value pairs. let it = pkg.iter{tpl=mod.tpl}; // The reducer function used to check the field's types if it exists. let reducer = func (acc, l) => acc && (select (l.0 == mod.field, NULL) => { true = l.1 is mod.type, // if this is the field then we propagate if it's the right type. false = true, // if this isn't the field then we propagate true }); // The computed answer true or false. let result = pkg.has_fields{tpl=mod.tpl, fields=[mod.field]} && reduce(reducer, true, it); };