Day 18 - Conditional data
Skills: 4
Pre-reading: 6.1.1.2, 6.1.2.3, 6.1.3.2, 6.1.3.3
Intro (10 mins)
- Sometimes, rather than data being composed of different parts, as we saw last time, data comes in multiple, incompatible, forms.
- For example, a payment system might need to track the source of payment, which
could be:
- Cash, with no further information
- Check, with the bank account number and routing number (and possibly more information -- account number, check number, etc)
- Credit Card, with the credit card number (and possibly more information -- expiration date, security code, etc)
- This doesn't fit into the pattern of structured data, since different alternatives have different, incompatible, components. A security code makes no sense for a check, and a check number has no bearing on a credit card, and all of the extra fields make no sense for cash.
- Instead, this type of data is conditional -- data that takes the shape of exactly one of several variants.
- We can define the above using the same
data
mechanism:data PaymentMethod:
| cash
| credit(card-number :: String, expiry :: String)
| check(bank-account :: String, routing :: String, check-number :: Number)
end - Note that there is one data type
PaymentMethod
, but three ways of constructing it --cash
,credit
, andcheck
. - We create examples of this data similarly to how we did with structured data:
payment-1 = cash
payment-2 = credit("1111-2222-3333-4444", "09/26")
payment-3 = check("987654321", "111", 55) - To use conditional data, however, we can't use the dot notation for field lookup, like with structured data,
since given a
PaymentMethod
, we don't know which variant we have! Instead, we use a new language feature calledcases
, which allows you to write down what to do in each possible case of the data, creating names for fields in the variants that have fields:fun display-payment(p :: PaymentMethod) -> String:
cases (PaymentMethod) p:
| cash => "Paid in cash"
| credit(cn, exp) => "Paid by credit card " + string-from-number(string-length(cn))
| check(acc, rout, num) => "Paid by check from account " + acc
end
end