# Solutions¶

Here we present solutions to the exercises that can be found throughout this language guide – both to the simpler ones from the introductory chapters, and to the more advanced ones presented in the previous section.

The solutions presented here are merely examples.

## Solution: Pay on delivery¶

See the exercise statement.

type Delivery : Event {
recipient : Agent,
item : String
}

type Payment : Event {
amount : Int,
recipient : Agent,
item : String
}

contract entrypoint sale = \(buyer, seller, amount, item) ->
<seller> delivery: Delivery where
delivery.item = item &&
then
payment.amount = amount &&
payment.recipient = seller &&
payment.item = item


## Solution: Pay or return¶

See the exercise statement.

type Delivery : Event {
recipient : Agent,
item : String,
price : Int
}

type Payment : Event {
amount : Int,
recipient : Agent,
item : String
}

type Return : Event {
item : String,
recipient : Agent
}

val inventoryPrice =
\ "Bike" -> 100
| "Hammer" -> 30
| "Saw" -> 40
| _ -> 20000 // Arbitrary large number

contract entrypoint sale = \(buyer, seller, item) ->
<seller> delivery: Delivery where
delivery.item = item &&
delivery.price = inventoryPrice item
then
payment.amount = delivery.price &&
payment.recipient = seller &&
payment.item = item
or
return.item = delivery.item &&
return.recipient = seller
)


## Solution: Bike and helmet¶

See the exercise statement.

type Order : Event {
price : Int,
recipient : Agent,
item : String
}

val inventoryPrice =
\ "Bike" -> 100
| "Helmet" -> 30
| "Brakes" -> 20
| _ -> 20000 // Arbitrary large number

contract entrypoint doubleOrder = \(buyer, seller) ->
helmetOrder.item = "Helmet" &&
helmetOrder.price = inventoryPrice "Helmet" &&
helmetOrder.recipient = seller
and
bikeOrder.item = "Bike" &&
bikeOrder.price = inventoryPrice "Bike" &&
bikeOrder.recipient = seller


## Solution: Late payment¶

See the exercise statement.

type Delivery : Event {
recipient : Agent,
item : String
}

type Payment : Event {
amount : Int,
recipient : Agent,
item : String
}

contract entrypoint sale = \(buyer, seller, amount : Int, item, fine) ->
let val amountFromDate = \delivery -> \timestamp ->
if (timestamp <= Instant::addDays 3 delivery) amount
else amount + fine
in
<seller> delivery: Delivery where
delivery.item = item &&
then
payment.amount = amountFromDate delivery.timestamp payment.timestamp &&
payment.recipient = seller &&
payment.item = item


## Solution: Age-restricted purchase¶

See the exercise statement.

type ProvideId : Event {}

type Purchase : Event {
ageRestriction : Bool,
item : String
}

contract rec loop = \(buyer, shownId) ->
or
not (p.ageRestriction) || shownId



See the exercise statement.

type AddItem : Event{
item : String
}

type RemoveItem : Event{
item : String
}

type Checkout : Event {
total : Int,
}

val priceList =
\ "Cabbage" -> 10
| "Potato" -> 5
| "Milk" -> 7
| "Apple" -> 9
| _ -> 0

val removeFirst = \rm -> \l ->
let val inner = \el -> \(acc : Tuple (List String) Bool) ->
if (snd acc) (Cons el (fst acc), True)
else if (el=rm) (fst acc, True) else (Cons el (fst acc), False) in
fst (foldr inner ([], False) l)

priceList order.item > 0
or
Maybe::isSome (List::first (\(item : String) -> item = order.item) basket)
or
checkout.total = total



See the exercise statement.

type ItemSuggesion : Event {
item : String
}

type SuggestionAccept : Event {}

type PriceEnquiry : Event {
item : String,
seller : Agent
}

type ItemPrice : Event {
item : String,
price : Int,
recipient1 : Agent,
recipient2 : Agent
}

type DeclareShare : Event {
amount : Int
}

type Delivery : Event {
item : String,
recipient1 : Agent,
recipient2 : Agent
}

type InsufficientFunds : Event {}

contract attemptPurchase = \seller -> \buyer1 -> \buyer2 -> \item -> \price ->
then
(<seller> d : Delivery where
d1.amount + d2.amount >= price &&
d.item = item
or
<seller> InsufficientFunds where
d1.amount + d2.amount < price)

p.item = item &&
p.seller = seller
then
<seller> ip : ItemPrice  where
ip.item = item &&
then

then
(
or
)



## Solution: Bank account balance¶

See the exercise statement.

type Deposit : Event { amount : Int }

type Withdraw : Event { amount : Int }

contract rec entrypoint accountOperations = \accountBalance ->
(<*> d : Deposit where
d.amount > 0 then accountOperations (accountBalance + d.amount))
or
(<*> w : Withdraw where
w.amount <= accountBalance &&
w.amount > 0
then accountOperations (accountBalance - w.amount))

relation deposit(timestamp, amount, cid)
| Deposit{timestamp = timestamp, amount = amount} @ cid

relation withdraw(timestamp, amount, cid)
| Withdraw{timestamp = timestamp, amount = amount} @ cid

val when = \bexp -> \f -> if (bexp) f else id

val report getBalance = \cid ->
let val deposited = (for (_, amount, c) in deposit do when (c=cid) (\x -> x + amount)) 0
val withdrawn = (for (_, amount, c) in withdraw do when (c=cid) (\x -> x + amount)) 0
in
deposited - withdrawn


## Solution: Reimbursement for business travel¶

See the exercise statement.

val reimburseForTravel =
\(transport : Transportation) ->
\(startDate: Instant) ->
\(endDate : Instant) ->
let val duration =
Duration::components (Duration::betweenInstants startDate endDate) in
let val perDiem = if (duration.day > 1) duration.day*50 else 0 in
calculateTransportationPrice transport + perDiem

val travelReportForEmployee = \(travelNotices:List TravelNotice) -> \employee ->
let val relevantNotices =
List::filter (\(tn:TravelNotice) -> tn.employee = employee) travelNotices in
(employee,
foldl
(\acc -> \(e:TravelNotice) ->
acc + reimburseForTravel e.transport e.startDate e.endDate)
0
relevantNotices)

val isAcceptedNotice = \(notice : TravelNotice) ->
List::any
(\(ack:TravelAcknowledgement) ->
ack.employee = notice.employee &&
ack.startDate = notice.startDate &&
ack.endDate = notice.endDate)

val report generateTravelReport =
\(eventsFromCids : List (List Event)) ->
\(employees: List Agent) ->
let val travelAcknowledgements =
List::mapMaybe
(\(e:Event) ->
type ta = e of {TravelAcknowledgement -> Some ta; _ -> None})
eventsFromCids in
let val acceptedTravelNotices =
List::mapMaybe
(\(e:Event) ->
type ta = e of {
TravelNotice ->
if (isAcceptedNotice ta travelAcknowledgements) Some ta else None;
_ -> None})
eventsFromCids in
List::map (travelReportForEmployee acceptedTravelNotices) employees