Skip to content

Instantly share code, notes, and snippets.

@brendanzab
Last active September 26, 2024 10:38
Show Gist options
  • Save brendanzab/04d7ee4cd0e2c96440e939048e6d08f0 to your computer and use it in GitHub Desktop.
Save brendanzab/04d7ee4cd0e2c96440e939048e6d08f0 to your computer and use it in GitHub Desktop.
Bank account interface as a codata type in Polarity (see: https://polarity-lang.github.io)
-- UML Class diagram:
--
-- ┌───────────────────────────────────┐
-- │ BankAccount |
-- ├───────────────────────────────────┤
-- │ - owner : String |
-- │ - balance : Dollars = 0 |
-- ├───────────────────────────────────┤
-- │ + getOwner() : String |
-- │ + getBalance() : Dollars |
-- │ + deposit( amount : Dollars ) |
-- │ + withdrawal( amount : Dollars ) |
-- └───────────────────────────────────┘
--
-- Based on https://en.wikipedia.org/wiki/File:BankAccount1.svg
-- Polarity does not have strings, so just use some hard-coded names
data Owner {
Alice,
Sally,
}
data Dollars {
Z,
S(pred: Dollars)
}
def Dollars.add(other: Dollars): Dollars {
Z => other,
S(x) => S(x.add(other))
}
def Dollars.monus(other: Dollars): Dollars {
Z => Z,
S(pred) => other.match {
Z => S(pred),
S(pred') => pred.monus(pred')
}
}
data Option(a: Type) {
None(a: Type): Option(a),
Some(a: Type, x: a): Option(a)
}
-- | Bank account interface
codata BankAccount {
-- | The owner of the account
.getOwner: Owner,
-- | The current balance in the account
.getBalance: Dollars,
-- | Deposit some money into the account
.deposit(a: BankAccount, amount: Dollars): BankAccount,
-- | Withdraw some money from the account, returning `None` in the case of an overdraft
.withdrawal(a: BankAccount, amount: Dollars): Option(BankAccount),
}
-- | Create an account given the owner and the current balance
codef AccountState(owner: Owner, balance: Dollars): BankAccount {
.getOwner => owner,
.getBalance => balance,
.deposit(a, amount) => AccountState(owner, balance.add(amount)),
.withdrawal(a, amount) => balance.match {
Z => None(_),
S(_) => Some(_, AccountState(owner, balance.monus(amount)))
}
}
-- | Create a new bank account for a given owner
let createAccount(owner: Owner): BankAccount {
AccountState(owner, 0)
}
@timsueberkrueb
Copy link

Yes. This would require local recursive (co)definitions. This is not inherently difficult with de-/refunctionalization, as we lift all local (co)matches of a given type to top-level (co)definitions before de-/refunctionalizing that type. The same would have to apply to local recursive (co)definitions. Still, it would be some effort to implement :)

@timsueberkrueb
Copy link

This is related to this issue but depending on how we design it, it might not be sufficient for this use case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment