-- | -- SPDX-License-Identifier: BSD-3-Clause -- -- Creation and utilities for the unit interval module Swarm.Util.UnitInterval ( UnitInterval, getValue, mkInterval, safeIndex, ) where import Data.List.NonEmpty (NonEmpty, (!!)) import Prelude hiding ((!!)) newtype UnitInterval a = UnitInterval { getValue :: a } -- | Guarantees that the stored value falls within the closed interval -- @[0, 1]@. It is up to clients to ensure that the promotion -- to this type is lossless. mkInterval :: (Ord a, Num a) => a -> UnitInterval a mkInterval = UnitInterval . max 0 . min 1 -- | Since '(!!)' is partial, here is "proof" that it is safe: -- If "alpha" is its maximum value of @1@, then the maximum value -- of the computed index shall be one less than the length of the -- list (i.e., a valid index). -- -- See also: 'Swarm.Util.indexWrapNonEmpty'. safeIndex :: RealFrac a => -- | alpha UnitInterval a -> NonEmpty b -> b safeIndex (UnitInterval alpha) xs = xs !! floor (alpha * fromIntegral (length xs - 1))