Exercises
This chapter collects somewhat more advanced exercises for CSL. Most of them require the use of the CSL standard library and/or some functionality that is documented in the contract language reference or value expression reference and not presented in detail in the introductory chapters.
Writing and running contracts
Exercise: Age-restricted purchase
Write a contract for operating a shop where some items are age-restricted.
This means that the buyer
will have to provide a valid identification in order to purchase these items.
Allow for multiple items to be sold. The valid id only has to be presented once for the entire purchase.
Test the contract with both restricted and unrestricted items (solution).
Exercise: Shopping basket
Write a contract which allows you to add multiple items from the shop to your basket and paying for all of them together.
Try adding an event for removing an item from the basket. Remember to check that the item was indeed first added to it.
Try running the contract to see if Checkout
behaves as you expect.
Test that if you added an item once, you can remove it also only once (solution).
Exercise: Two-buyer protocol
Write a protocol in which two buyers interact with one seller. Buyers first negotiate which item to purchase. They then make enquiries about its price. Seller informs both of them about the price of the item they agreed on. Each of the buyers declares how much of the price they are willing to pay. The buyer who suggested the item to be purchased declares his share first. Otherwise, if the sum of the two offers is at least as high as the price, the seller delivers the item to the buyers.
Try writing this contract using subcontracts for the different stages: item negotiations, price enquiry, two buyers declaring shares etc.
Run the contract and verify that at each stage, correct events are expected (solution).
Expressions and reports
Exercise: Bank account balance
accountOperations
is a very simplistic way of managing a single bank account.
type Deposit : Event { amount : Int }
type Withdraw : Event { amount : Int }
contract rec accountOperations =
(<*> d : Deposit where
d.amount > 0
or
<*> w : Withdraw where
w.amount > 0)
then accountOperations
Write a reporting function which calculates the balance of a bank account.
Your function should be of type ContractInstance -> Int
.
Next, change the contract in such a way, that it prevents the balance to drop below 0 (solution).
Exercise: Reimbursement for business travel
The following declaration specifies a protocol allowing an employee to inform their employer about a planned business travel. The employer can either accept or reject the planned trip.
type Transportation
| Bike
| Bus
| Car
| Plane
| Other Int
val calculateTransportationPrice =
\ Bike -> 0
| Bus -> 10
| Car -> 50
| Plane -> 500
| Other price -> price
type TravelNotice : Event {
employee : Agent,
transport : Transportation,
startDate : Instant,
endDate : Instant
}
type TravelAcknowledgement : Event {
employee : Agent,
startDate: Instant,
endDate: Instant
}
type TravelCancellation : Event {
employee : Agent,
startDate: Instant,
endDate: Instant
}
contract businessTravelAgreement = \employer -> \employee ->
<employee> tn : TravelNotice where
tn.employee = employee
then
(<employer> ta : TravelAcknowledgement where
tn.employee = ta.employee &&
tn.startDate = ta.startDate &&
tn.endDate = ta.endDate
or
<employer> tc : TravelCancellation where
tn.employee = tc.employee &&
tn.startDate = tc.startDate &&
tn.endDate = tc.endDate)
Write a reporting function which calculates how much money should the employee
be reimbursed for, based on the mode of transportation and the duration of travel.
Assume that for trips shorter than 24 hours there is no per diem, but for trips of 1 day or longer, the employee gets 50 Euros for each full day.
Next, write a report which calculates how much should each employee be reimbursed.
The function that calculates this report should have the following type: List ContractInstance -> List Agent -> List (Tuple Agent Int)
.
Remember that employees might take multiple business trips, and that only approved trips are reimbursed (solution).
Hint
Make sure that the source code is the same for all of the contracts to be included in the report.
This ensures that contracts can see each other, allowing you to run generateTravelReport
with all the contract identifiers of different contracts you run.
For instance, if you have 3 instances of businessTravelAgreement
and 2 employees, you can run:
\c1 -> \c2 -> \c3 -> \a1 -> \a2 -> generateTravelReport [c1,c2,c3] [a1,a2]
in the Reports
tab, and select appropriate arguments.