{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}

{- |

There are several types of numbers
where a subset of numbers can be considered as set of scalars.

 * A '(Complex.T Double)' value can be converted to 'Double' if the imaginary part is zero.

 * A value with physical units can be converted to a scalar if there is no unit. 

Of course this can be cascaded,
e.g. a complex number with physical units can be converted to a scalar
if there is both no imaginary part and no unit.

This is somewhat similar to the multi-type classes NormedMax.C and friends.

I hesitate to define an instance for lists
to avoid the mess known of MatLab.
But if you have an application where you think
you need this instance definitely
I'll think about that, again.

-}

module Algebra.OccasionallyScalar where

import Data.Maybe (fromMaybe, )

import NumericPrelude.Base
import NumericPrelude.Numeric


-- this is somehow similar to Normalized classes
class C a v where
   toScalar      :: v -> a
   toMaybeScalar :: v -> Maybe a
   fromScalar    :: a -> v

toScalarDefault :: (C a v) => v -> a
toScalarDefault :: v -> a
toScalarDefault v
v =
   a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe ([Char] -> a
forall a. HasCallStack => [Char] -> a
error ([Char]
"The value is not scalar."))
             (v -> Maybe a
forall a v. C a v => v -> Maybe a
toMaybeScalar v
v)

toScalarShow :: (C a v, Show v) => v -> a
toScalarShow :: v -> a
toScalarShow v
v =
   a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe ([Char] -> a
forall a. HasCallStack => [Char] -> a
error (v -> [Char]
forall a. Show a => a -> [Char]
show v
v [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" is not a scalar value."))
             (v -> Maybe a
forall a v. C a v => v -> Maybe a
toMaybeScalar v
v)


instance C Float Float where
   toScalar :: Float -> Float
toScalar      = Float -> Float
forall a. a -> a
id
   toMaybeScalar :: Float -> Maybe Float
toMaybeScalar = Float -> Maybe Float
forall a. a -> Maybe a
Just
   fromScalar :: Float -> Float
fromScalar    = Float -> Float
forall a. a -> a
id

instance C Double Double where
   toScalar :: Double -> Double
toScalar      = Double -> Double
forall a. a -> a
id
   toMaybeScalar :: Double -> Maybe Double
toMaybeScalar = Double -> Maybe Double
forall a. a -> Maybe a
Just
   fromScalar :: Double -> Double
fromScalar    = Double -> Double
forall a. a -> a
id

{- converting values automatically to integers is a bad idea
instance (Integral b, RealRing.C a)
      => C b a where
   toScalar        = toScalarDefault
   toMaybeScalar x = mapMaybe round (toMaybeScalar x)
-}