{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE KindSignatures #-}

{-|
Module      : Data.JoinSemilattice.Class.Fractional
Description : Relationships between values and their (floating/fractional) product.
Copyright   : (c) Tom Harding, 2020
License     : MIT
-}
module Data.JoinSemilattice.Class.Fractional where

import Data.Hashable (Hashable)
import Data.JoinSemilattice.Defined (Defined)
import Data.JoinSemilattice.Intersect (Intersect)
import Data.JoinSemilattice.Class.Sum (SumR)
import Data.Kind (Type)

-- | Reversible (fractional or floating-point) multiplication as a three-value
-- relationship between two values and their product.
class SumR x => FractionalR (x :: Type) where
  multiplyR :: ( x, x, x ) -> ( x, x, x )

  default multiplyR :: Fractional x => ( x, x, x ) -> ( x, x, x )
  multiplyR ( x
x, x
y, x
z ) = ( x
z x -> x -> x
forall a. Fractional a => a -> a -> a
/ x
y, x
z x -> x -> x
forall a. Fractional a => a -> a -> a
/ x
x, x
x x -> x -> x
forall a. Num a => a -> a -> a
* x
y )

-- | A three-way division relationships implemented as a flipped multiplication
-- relationship.
divideR :: FractionalR x => ( x, x, x ) -> ( x, x, x )
divideR :: (x, x, x) -> (x, x, x)
divideR ( x
x, x
y, x
z ) = let ( x
z', x
y', x
x' ) = (x, x, x) -> (x, x, x)
forall x. FractionalR x => (x, x, x) -> (x, x, x)
multiplyR ( x
z, x
y, x
x ) in ( x
x', x
y', x
z' )

-- | A two-way relationship between a value and its reciprocal, implemented
-- with a multiplication relationship in which the third value is fixed to be
-- @1@.
recipR :: (FractionalR x, Num x) => ( x, x ) -> ( x, x )
recipR :: (x, x) -> (x, x)
recipR ( x
x, x
y ) = let ( x
x', x
y', x
_ ) = (x, x, x) -> (x, x, x)
forall x. FractionalR x => (x, x, x) -> (x, x, x)
multiplyR ( x
x, x
y, x
1 ) in ( x
x', x
y' )

instance (Eq x, Fractional x) => FractionalR (Defined x)

instance (Bounded x, Enum x, Ord x, Fractional x, Hashable x)
  => FractionalR (Intersect x)