A map operation attempts to pair a key to an associated value, for example mapping a country code
to a country. A select operation goes further by allowing an entire row of a table to be associated with a key, for example selection
by country code of country, capital and surface area in one hit. As part of either operation, the key can be evaluated by an expression, opening up
the ability to work with ranges of values, regular expressions and other possibilities.
Proto Select
proto-select.taqt illustrates the design pattern that both nap and select follow.
The program maps a bank account number of 1, 2 or 3 into type "sav", "cre" and "chq" respectively. The "map_account" flow features
a number match criterion for each account and an "accounts" axiom list to provide the text account values
flow map_account
{
integer account,
integer i,
axiom list accounts(account_type)
{ "sav" }
{ "cre" }
{ "chq" }
}
( account_type,
{
?: account == 1,
++i,
?: account == 2,
++i,
?: account == 3,
i = -1,
?: false
},
? i != -
1
{ account_type = accounts[i] }
)
A selection index, "i" is the link between the account number and the account type. A final criterion ?: false
provides an exit for the default case of the account number is unrecognized.
Both the actual map and select formats require only the axiom list terms and criteria to be programmed while hiding the other implementation
details.
Map
Here is an actual account type map:
map account
{
? 1: "sav"
? 2: "cre"
? 3: "chq"
}
The map keyword is followed by key "account", which is expected to be local variable containing either 1, 2 or 3. The map format allows
the subject of each criteria to be omitted if it is the key. The ==: operator can also be dropped if diong a comparison,
Hence ? 1: for the first criteria instead of ? account == 1:.
Select
Both Map and Select create a matrix, the first column being a template, on it's side and with every term a criterion.
The remaining columns consist of an axiom list where every axiom is a value mapped by the adjoining criterion.
A map axiom contains a single term, while a select axiom has 2 or more terms. The select matrix may be cumbersome to
lay out in a template term, so it is declared separately from the select operation.
Select Declaration
Here is the select declaration from bank-accounts.taq. It's axiom list consists of
two terms, the first is the name of a bank and the second is a 6-digit code to identify a particular branch
select bank
( | Prefix, | Bank, | BSB | ) |
{ | | | | |
| ? "456448": | "Bank of Queensland", | "124-001", | |
| ? "456443": | "Bendigo Bank LTD", | "633-000", | |
| ? "456445": | "Commonwealth Bank Aust.", | "527-146", | |
} | | | | |
Select Operation
A select operation is performed by making a function call. At least one parameter is required to provide the key to match on, The function returns an axiom.
In bank-accounts.taq, the returned axiom of the "bank" select function is assigned to a variable named ""
axiom profile = bank(prefix),
bank = profile->Bank,
bsb = profile->BSB
The result for prefix 456443:
prefix=456443, bank=Bendigo Bank LTD, bsb=633-000, accountType=chq
The select operation can also set previously declared variables as an alternative approach. In this case, the function is invoked using the
flow. This is a rule for any function that not occur on the right hand side of an expression.
Select Index
The index of the last select operation can be read using object method "index()". If none of the criteria are matched,
then the index value is -1. The index for a select operation named "account", for example, would be
account.index()
Branch on Success
stamp-duty.taq provides an example of creating a branch to handle
a successful select operation. This is the converse of the branch on default strategy and is
applicable when the default case can be prepared in advance. The stamp duty is a tax on a real estate purchase and
is calculated using parameters that depend on the value of the property. A purchase under $5,000 attracts a fixed
amount of $20 and represents the select default case. Therefore the stamp duty is initialized to the default amount and
only updated if the select succeeds.
select sale_bracket
( | amount, | threshold, | base | percent | ) |
{ | | | | | |
| ? > 500000: | 500000, | 21330.00, | 5.50 | |
| ? > 300000: | 300000, | 11330.00, | 5.00 | |
| ? > 250000: | 250000, | 8955.00, | 4.75 | |
| ? > 200000: | 200000, | 6830.00, | 4.25 | |
| ? > 100000 | 100000, | 2830.00, | 4.00 | |
| ? > 50000: | 50000, | 1080.00, | 3.50 | |
| ? > 30000: | 30000, | 480.00, | 3.00 | |
| ? > 12000: | 12000, | 120.00, | 2.00 | |
| ? > 5000: | 0, | 0.00, | >1.00 | |
} | | | | | |
term flat =
0
flow stamp_duty_payable
{
currency.USD amount }
(
term id,
amount.format(),
. currency.USD duty = 20.00,
. axiom row = sale_bracket(amount),
bracket = sale_bracket.index() +
1,
? bracket != flat {
duty = row->base + (amount - row->threshold)
* (row->percent / 100) },
payable = duty.format()
)