{-# LANGUAGE TypeOperators, FlexibleContexts, TypeFamilies , UndecidableInstances #-} -- {-# OPTIONS_GHC -Wall -fno-warn-orphans #-} {-# OPTIONS_GHC -Wall #-} ---------------------------------------------------------------------- -- | -- Module : Shady.Misc -- Copyright : (c) Conal Elliott 2009 -- License : AGPLv3 -- -- Maintainer : conal@conal.net -- Stability : experimental -- -- Misc useful definitions ---------------------------------------------------------------------- module Shady.Misc ( -- argument, result, (~>), FMod(..), Frac(..), fmodRF, fracRF, fmodViaFrac, fracViaFmod , clamp, clampB, smoothStep , Unop,Binop , padTo , flip1, flip2, flip3, flip4 , Sink, Action, (>+>), forget , R -- * Find another home , EyePos ) where import Control.Applicative ((<$)) -- From TypeCompose package import Control.Compose (result) import Control.Instances () import Data.Maclaurin ((:>)(..)) -- For Frac instance import Data.Boolean type R = Float -- | Clamp to a given range clamp :: Ord a => (a,a) -> a -> a clamp (lo,hi) = max lo . min hi -- | Variation on 'clamp', using 'OrdB' instead of 'Ord' clampB :: (IfB bool a, OrdB bool a) => (a,a) -> a -> a clampB (lo,hi) = maxB lo . minB hi -- | Smooth, clamped transition smoothStep :: (Ord a, Num a) => (a,a) -> a -> a smoothStep loHi val = t*t*(3-2*t) where t = clamp loHi val -- | Unary transformation (endomorphism) type Unop a = a -> a -- | Binary transformation type Binop a = a -> a -> a -- | Pad a string to the given length, adding spaces on the right as needed. padTo :: Int -> String -> String padTo n str = str ++ replicate (n - length str) ' ' -- | Move first argument to first place (for style uniformity) flip1 :: (a -> b) -> (a -> b) flip1 = id -- | Move second argument to first place ('flip' synonym for style uniformity) flip2 :: (a -> b -> c) -> (b -> a -> c) flip2 = flip -- | Move third argument to first place flip3 :: (a -> b -> c -> d) -> (c -> a -> b -> d) flip3 = flip . result flip -- | Move fourth argument to first place flip4 :: (a -> b -> c -> d -> e) -> (d -> a -> b -> c -> e) flip4 = flip . result flip3 {-------------------------------------------------------------------- frac & fmod --------------------------------------------------------------------} -- | Take fractional component(s). Always non-negative. You can use -- 'fracRF' for 'RealFrac' types and 'fracViaFmod' for 'Fmod' types. class Frac a where frac :: a -> a -- | Real-valued modulo. You can use 'fmodRF' for 'RealFrac' types and -- 'fmodViaFrac' for 'Frac' types. class FMod a where fmod :: a -> a -> a -- | Fractional component. Useful for defining 'frac' on 'RealFrac' types. fracRF :: RealFrac a => a -> a fracRF x = x - fromIntegral (floor x :: Int) -- | Fractional modulo. Useful for defining 'fmod' on 'RealFrac' types. fmodRF :: RealFrac a => a -> a -> a x `fmodRF` y = x - y * fromIntegral (floor (x/y) :: Int) -- | Handy defining 'frac' on a 'FMod' type. fracViaFmod :: (Num a, FMod a) => a -> a fracViaFmod = (`fmod` 1) -- | Handy defining 'fmod' on a 'Frac' type. fmodViaFrac :: (Fractional a, Frac a) => a -> a -> a x `fmodViaFrac` y = frac (x/y) * y instance FMod Float where fmod = fmodRF instance Frac Float where frac = fracRF -- 'frac' of a derivative tower is 'frac' of the value and unchanged -- derivatives. Not quite right, since 'frac' introduces discontinuities, -- so all-sided derivatives don't really exist at those points. instance Frac s => Frac (u :> s) where frac (D s l) = D (frac s) l {-------------------------------------------------------------------- Information sinks --------------------------------------------------------------------} -- | Synonym for @IO ()@. Obviates some parentheses. type Action = IO () -- | Sink of information type Sink a = a -> Action infixr 1 >+> -- | Combine sinks (>+>) :: Sink a -> Sink b -> Sink (a,b) (sa >+> sb) (a,b) = sa a >> sb b -- | Discard a functor value. forget :: Functor f => f a -> f () forget = (() <$) -- forget = fmap (const ()) {-------------------------------------------------------------------- Find another home --------------------------------------------------------------------} type EyePos = (R,R,R)