{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Rank2Types #-}
module Data.Prd.Nan where
import Control.Applicative
import Data.Data (Data, Typeable)
import Data.Prd
import Data.Connection
import GHC.Generics (Generic, Generic1)
data Nan a = NaN | Def a
deriving ( Eq, Ord, Show, Data, Typeable, Generic, Generic1, Functor, Foldable, Traversable)
nan :: b -> (a -> b) -> Nan a -> b
nan _ f (Def y) = f y
nan x _ NaN = x
defined :: Nan a -> Bool
defined NaN = False
defined _ = True
mapNan :: (a -> b) -> Nan a -> Nan b
mapNan f = nan NaN $ Def . f
maybeNan :: (forall a. a -> a) -> Maybe a -> Nan a
maybeNan _ Nothing = NaN
maybeNan f (Just x) = Def $ f x
nanMaybe :: (forall a. a -> a) -> Nan a -> Maybe a
nanMaybe _ NaN = Nothing
nanMaybe f (Def x) = Just $ f x
eitherNan :: Either a b -> Nan b
eitherNan = either (const NaN) Def
nanEither :: a -> Nan b -> Either a b
nanEither x = nan (Left x) Right
liftNan :: (Prd a, Fractional a) => (a -> b) -> a -> Nan b
liftNan f x | x =~ (0/0) = NaN
| otherwise = Def (f x)
liftNan' :: RealFloat a => (a -> b) -> a -> Nan b
liftNan' f x | isNaN x = NaN
| otherwise = Def (f x)
liftAll :: (RealFloat a, Prd a, Bound b) => (a -> b) -> a -> Nan b
liftAll f x | isNaN x = NaN
| isInf x = Def maximal
| isInf (-x) = Def minimal
| otherwise = Def (f x)
isInf :: (RealFloat a, Prd a) => a -> Bool
isInf x = isInfinite x && gt x 0
floatOrdering :: (RealFloat a, Prd a) => Trip a (Nan Ordering)
floatOrdering = Trip f g h where
g (Def GT) = 1/0
g (Def LT) = - 1/0
g (Def EQ) = 0
g NaN = 0/0
f x | isNaN x = NaN
f x | isInf (-x) = Def LT
f x | x <~ 0 = Def EQ
f x | otherwise = Def GT
h x | isNaN x = NaN
h x | isInf x = Def GT
h x | x >~ 0 = Def EQ
h x | otherwise = Def LT
instance Prd a => Prd (Nan a) where
NaN <~ NaN = True
_ <~ NaN = False
NaN <~ _ = False
Def a <~ Def b = a <~ b
instance Applicative Nan where
pure = Def
NaN <*> _ = NaN
Def f <*> x = f <$> x
instance Num a => Num (Nan a) where
negate = fmap negate
(+) = liftA2 (+)
(*) = liftA2 (*)
fromInteger = pure . fromInteger
abs = fmap abs
signum = fmap signum
nanflt :: Prd a => Fractional a => Conn (Nan a) a
nanflt = Conn (nan (0/0) id) $ \y -> if y =~ (0/0) then NaN else Def y
def :: Prd a => Prd b => Conn a b -> Conn (Nan a) (Nan b)
def conn = Conn f g where
Conn f' g' = _R conn
f = eitherNan . f' . nanEither ()
g = eitherNan . g' . nanEither ()