{-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ViewPatterns #-} module Data.Clipped ( -- * Data.Clipped Clipped, clipped, fromClipped, -- ** Unsafe operations unsafeToClipped, -- unclipped, ) where ----- import Data.Fixed import Data.Default import Data.Ratio import Control.Applicative import qualified Control.Category import Control.Comonad import Control.Comonad.Env import Control.Lens hiding (Indexable, Level, above, below, index, inside, parts, reversed, transform, (|>), (<|)) import Control.Monad import Control.Monad.Plus import Data.AffineSpace import Data.AffineSpace.Point import Data.Distributive import Data.Foldable (Foldable) import qualified Data.Foldable as Foldable import Data.Functor.Rep import qualified Data.List import Data.List.NonEmpty (NonEmpty) import Data.Maybe import Data.NumInstances import Data.Semigroup hiding () import Data.Sequence (Seq) import qualified Data.Sequence as Seq import Data.Traversable (Traversable) import qualified Data.Traversable as T import Data.Typeable import Data.VectorSpace hiding (Sum(..)) import Music.Dynamics.Literal import Music.Pitch.Literal import qualified Data.Ratio as Util_Ratio import qualified Data.List as List import qualified Data.Foldable as Foldable import qualified Data.Ord as Ord ----- -- | A value in the unit interval /(0,1)/. newtype Clipped a = UnsafeClip { unsafeGetClipped :: a } deriving (Eq, Ord, Show) instance Num a => Bounded (Clipped a) where minBound = UnsafeClip 0 maxBound = UnsafeClip 1 instance (Num a, Ord a) => Num (Clipped a) where a + b = unsafeToClipped (fromClipped a + fromClipped b) a - b = unsafeToClipped (fromClipped a - fromClipped b) a * b = unsafeToClipped (fromClipped a * fromClipped b) abs = id signum 0 = 0 signum _ = 1 negate = error "negate: No instance for Clipped" fromInteger = unsafeToClipped . fromInteger instance (Num a, Ord a, Fractional a) => Fractional (Clipped a) where a / b = unsafeToClipped (fromClipped a / fromClipped b) recip 1 = 1 recip _ = error "Can not take reciprocal of a clipped value other than 1" fromRational = unsafeToClipped . fromRational unsafeToClipped = fromMaybe (error "Outside 0-1") . (^? clipped) fromClipped = (^. unclipped) clipped :: (Num a, Ord a) => Prism' a (Clipped a) clipped = prism unsafeGetClipped $ \x -> if 0 <= x && x <= 1 then Right (UnsafeClip x) else Left x unclipped :: (Num a, Ord a) => Getter (Clipped a) a unclipped = re clipped zipClippedWith :: (Num a, Ord a, Num b, Ord b, Num c, Ord c) => (a -> b -> c) -> Clipped a -> Clipped b -> Maybe (Clipped c) zipClippedWith f a b = ((a^.unclipped) `f` (b^.unclipped))^? clipped addLim = zipClippedWith (+)