connections-0.0.3: src/Data/Prd/Nan.hs
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Data.Prd.Nan where
import Control.Applicative
import Data.Prd
import Data.Connection
import Data.Semiring
import Data.Semifield
import GHC.Generics (Generic, Generic1)
import Prelude hiding (Ord(..), Num(..), Fractional(..))
-- | A type with an additional incomparable element allowing for the possibility of undefined values.
-- Isomorphic to /Maybe a/ but with a different 'Prd' instance.
data Nan a = Nan | Def a deriving ( Show, Generic, Generic1, Functor, Foldable, Traversable)
{-
instance Field a => Field (Nan a) where
u + Nan = Nan + u = Nan − Nan = Nan
u · Nan = Nan · u = Nan Nan−1 = Nan
Nan u ⇔ u = Nan u Nan ⇔ u = Nan
-}
nan :: b -> (a -> b) -> Nan a -> b
nan _ f (Def y) = f y
nan x _ Nan = x
nan' :: Semifield b => (a -> b) -> Nan a -> b
nan' f = nan anan f
isDef :: Nan a -> Bool
isDef Nan = False
isDef _ = True
mapNan :: (a -> b) -> Nan a -> Nan b
mapNan f = nan Nan $ Def . f
joinNan :: Nan (Nan a) -> Nan a
joinNan Nan = Nan
joinNan (Def Nan) = Nan
joinNan (Def (Def a)) = Def a
-- collectNan = joinNan . liftNan id
liftNan :: Prd a => Semifield a => (a -> b) -> a -> Nan b
liftNan f x | x =~ anan = Nan
| otherwise = Def (f x)
-- Lift all exceptional values
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 && x > 0
defnan :: Prd a => Prd b => Conn a b -> Conn (Nan a) (Nan b)
defnan (Conn f g) = Conn (fmap f) (fmap g)
defnan' :: Prd a => Prd b => Trip a b -> Trip (Nan a) (Nan b)
defnan' (Trip f g h) = Trip (fmap f) (fmap g) (fmap h)
--nanfld :: Prd a => Field a => Trip (Nan a) a
-- Field a => Field (Nan a)
-- /Caution/ this is only legal if (Nan a) has no nans.
{-
fldnan :: Prd a => Field a => Trip a (Nan a)
fldnan = Trip f g f where
f a = if a =~ zero / zero then Nan else Def a
g = nan (zero / zero) id
-}
fldord :: Prd a => Field a => Trip a (Nan Ordering)
fldord = Trip f g h where
g (Def GT) = pinf
g (Def LT) = ninf
g (Def EQ) = zero
g Nan = anan
f x | x =~ anan = Nan
| x =~ ninf = Def LT
| x <= zero = Def EQ
| otherwise = Def GT
h x | x =~ anan = Nan
| x =~ pinf = Def GT
| x >= zero = Def EQ
| 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 (Additive-Semigroup) a => Semigroup (Additive (Nan a)) where
Additive a <> Additive b = Additive $ liftA2 (+) a b
-- MinPlus Dioid
instance (Additive-Monoid) a => Monoid (Additive (Nan a)) where
mempty = Additive $ pure zero
instance (Multiplicative-Semigroup) a => Semigroup (Multiplicative (Nan a)) where
Multiplicative a <> Multiplicative b = Multiplicative $ liftA2 (*) a b
-- MinPlus Dioid
instance (Multiplicative-Monoid) a => Monoid (Multiplicative (Nan a)) where
mempty = Multiplicative $ pure one
-- Presemiring with a absorbing element.
instance Presemiring a => Presemiring (Nan a)