Skip to content

Instantly share code, notes, and snippets.

@Savelenko
Created July 15, 2022 12:57
Show Gist options
  • Save Savelenko/1b8654ac36460a4064f1d2a914f9e5ac to your computer and use it in GitHub Desktop.
Save Savelenko/1b8654ac36460a4064f1d2a914f9e5ac to your computer and use it in GitHub Desktop.
Representing money in PureScript using phantom types and symbols
newtype Money currency = Money Number -- Constructor is not exported
sumMoney :: forall currency. Money currency -> Money currency -> Money currency
sumMoney (Money a) (Money b) = Money (a `add` b)
infixl 6 sumMoney as +
multiplyMoney :: forall currency. Number -> Money currency -> Money currency
multiplyMoney multiplier (Money a) = Money (multiplier `mul` a)
infixl 7 multiplyMoney as *
eur :: Number -> Money "EUR"
eur = Money
usd :: Number -> Money "USD"
usd = Money
ten = eur 7.0 + 2.0 * eur 3.0
-- illegal = eur 1.0 + usd 1.0 -- Does not type-check: Could not match type "USD" with type "EUR"
-- | A somewhat dangerous helper constructor function. Optional so can (should?) be left out, but interesting because
-- | it avoids extending the module with new smart constructors like `eur` and `usd` for additional currencies.
money :: forall (currency :: Symbol). Number -> Money currency
money = Money
-- Example usage of `money`, without a dedicated yen smart constructor:
yen1000 = money 1000.0 :: Money "YEN" -- Force instantiation of the currency type variable using a type annotation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment