Skip to content

Instantly share code, notes, and snippets.

@DavideCanton
Created December 3, 2014 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DavideCanton/fe928e1e51161ca8271f to your computer and use it in GitHub Desktop.
Save DavideCanton/fe928e1e51161ca8271f to your computer and use it in GitHub Desktop.
Change
module Change where
import Control.Arrow ((&&&))
import Data.Function (on)
import Data.List (group)
-- Coin datatype
data Coin = OneCent | TwoCents | FiveCents |
TenCents | TwentyCents | FiftyCents |
OneEuro | TwoEuros | FiveEuros |
TenEuros | TwentyEuros | FiftyEuros |
OneHundredEuros | TwoHundredEuros | FiveHundredEuros
deriving (Show, Eq, Enum, Bounded)
-- Computes the coin value based on the value of OneCent
coinValue :: Integral a => Coin -> a
coinValue OneCent = 1
coinValue TwoCents = 2 * coinValue OneCent
coinValue FiveCents = 5 * coinValue OneCent
coinValue TenCents = 2 * coinValue FiveCents
coinValue TwentyCents = 2 * coinValue TenCents
coinValue FiftyCents = 5 * coinValue TenCents
coinValue OneEuro = 2 * coinValue FiftyCents
coinValue TwoEuros = 2 * coinValue OneEuro
coinValue FiveEuros = 5 * coinValue OneEuro
coinValue TenEuros = 2 * coinValue FiveEuros
coinValue TwentyEuros = 2 * coinValue TenEuros
coinValue FiftyEuros = 5 * coinValue TenEuros
coinValue OneHundredEuros = 2 * coinValue FiftyEuros
coinValue TwoHundredEuros = 2 * coinValue OneHundredEuros
coinValue FiveHundredEuros = 5 * coinValue OneHundredEuros
instance Ord Coin where
compare = compare `on` coinValue
-- Computes the change, in cents. Example:
-- change 1000 600 (I need to pay 6 euros and I give 10 euros):
-- [(TwoEuros,2)]
change :: Integral a => a -> a -> [(Coin, Int)]
change given total
| given < total = []
| otherwise = map (head &&& length) . group $ helper (given - total) maxBound
where helper val coin
| val == 0 = []
| val < coinValue coin = helper val (pred coin)
| otherwise = coin : helper (val - coinValue coin) coin
assertResult :: Integral a => a -> a -> [Coin] -> Bool
assertResult given total coins = (given - total) == sum (map coinValue coins)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment