{-
	Copyright (C) 2011 Dr. Alistair Ward

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
-}
{- |
 [@AUTHOR@]	Dr. Alistair Ward

 [@DESCRIPTION@]

	* Describes a /Quotient Ring/; <https://en.wikipedia.org/wiki/Quotient_ring>.

	* This is a /ring/ composed from a residue-class resulting from /modular/ division.
-}

module Factory.Data.QuotientRing(
-- * Type-classes
	QuotientRing(..),
-- * Functions
	quot',
	rem',
-- ** Predicates
	areCongruentModulo,
	isDivisibleBy
) where

import			Factory.Data.Ring((=-=))
import qualified	Factory.Data.Ring	as Data.Ring

-- | Defines a sub-class of 'Data.Ring.Ring', in which division is implemented.
class Data.Ring.Ring q => QuotientRing q	where
	quotRem'	:: q -> q -> (q, q)	-- ^ Divides the first operand by the second, to yield a pair composed from the /quotient/ and the /remainder/.

-- | Returns the /quotient/, after division of the two specified 'QuotientRing's.
quot' :: QuotientRing q
	=> q	-- ^ Numerator.
	-> q	-- ^ Denominator.
	-> q
quot' numerator	= fst . quotRem' numerator

-- | Returns the /remainder/, after division of the two specified 'QuotientRing's.
rem' :: QuotientRing q
	=> q	-- ^ Numerator.
	-> q	-- ^ Denominator.
	-> q
rem' numerator	= snd . quotRem' numerator

{- |
	* 'True' if the two specified 'QuotientRing's are /congruent/ in /modulo/-arithmetic, where the /modulus/ is a third 'QuotientRing'.

	* <http://www.usna.edu/Users/math/wdj/book/node74.html>.
-}
areCongruentModulo :: (Eq q, QuotientRing q)
	=> q	-- ^ LHS.
	-> q	-- ^ RHS.
	-> q	-- ^ Modulus.
	-> Bool
areCongruentModulo l r modulus
	| l == r	= True	-- Only required for efficiency.
	| otherwise	= (l =-= r) `isDivisibleBy` modulus

-- | True if the second operand /divides/ the first.
isDivisibleBy :: (Eq q, QuotientRing q)
	=> q	-- ^ Numerator.
	-> q	-- ^ Denominator.
	-> Bool
numerator `isDivisibleBy` denominator	= rem' numerator denominator == Data.Ring.additiveIdentity