packages feed

sauna-vs-gym-cost-0.1.0: src/SaunaVsGym/Cost.hs

-- | Cost-per-session math for home recovery gear.
--
-- A home sauna or cold plunge is a gear price, a usage habit, and an
-- electricity line. The sticker price says nothing until usage spreads
-- it over sessions and the electricity lands on each one. This module
-- restates a purchase into dollars per session and counts the visits
-- until the gear has paid for itself against a per-visit alternative
-- like a gym membership or a day pass.
module SaunaVsGym.Cost
  ( utilityCost
  , annualSessions
  , sessionCost
  , breakEvenSessions
  ) where

-- | Per-session utility cost from kilowatt-hours and the meter rate.
-- A 2 kW heater run 1 hour at $0.17/kWh is 0.34 dollars a session.
utilityCost :: Double -> Double -> Double
utilityCost kwhPerSession ratePerKwh = kwhPerSession * ratePerKwh

-- | Sessions a weekly habit adds up to over a year.
-- Four a week is 208.
annualSessions :: Double -> Double
annualSessions sessionsPerWeek = sessionsPerWeek * 52

-- | Amortized cost of one session: the gear price spread over total
-- sessions plus the electricity line. Sessions accrue as the habit
-- runs, so the same $2,500 unit lands at $25.34 by session 100 and
-- $2.84 by session 1,000 before electricity. No sessions means no
-- denominator, so the cost is infinite rather than zero.
sessionCost :: Double -> Double -> Double -> Double
sessionCost gearCost totalSessions utilityPerSession
  | totalSessions <= 0 = 1 / 0
  | otherwise          = gearCost / totalSessions + utilityPerSession

-- | Visits until the gear has paid for itself against a per-visit
-- alternative. Infinite when the alternative is cheaper than the
-- electricity alone, because usage then never closes the gap. A $22
-- gym visit against $0.34 of power needs 115.4 sessions, about 6.6
-- months at four a week, before every visit after that is free.
breakEvenSessions :: Double -> Double -> Double -> Double
breakEvenSessions gearCost alternativePerVisit utilityPerSession
  | gap <= 0  = 1 / 0
  | otherwise = gearCost / gap
  where gap   = alternativePerVisit - utilityPerSession