```{-# LANGUAGE FlexibleInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module     : Data.Elem.BLAS.Base
-- Maintainer : Patrick Perry <patperry@stanford.edu>
-- Stability  : experimental
--

module Data.Elem.BLAS.Base (
Elem(..),
) where

import Data.AEq
import Data.Complex             ( Complex(..), magnitude )
import qualified Data.Complex as Complex
import Foreign                  ( Storable )
import Foreign.Storable.Complex ()

-- | The base class for elements.
class (AEq e, Storable e, Fractional e) => Elem e where
-- | Get the complex conjugate of a value.
conjugate :: e -> e

-- | Get the magnitude of a value.
norm :: e -> Double

-- | Get the l1 norm of a value.
norm1 :: e -> Double

-- | Convert a double to an element.
fromReal :: Double -> e

-- | Try to coerce a value to a double.  This will fail unless the
-- complex part is zero (according to a comparison by @(~==)@).
maybeToReal :: e -> Maybe Double

instance Elem Double where
conjugate   = id
{-# INLINE conjugate #-}
norm        = abs
{-# INLINE norm #-}
norm1       = abs
{-# INLINE norm1 #-}
fromReal    = id
{-# INLINE fromReal #-}
maybeToReal = Just
{-# INLINE maybeToReal #-}

instance Elem (Complex Double) where
conjugate      = Complex.conjugate
{-# INLINE conjugate #-}
norm           = magnitude
{-# INLINE norm #-}
norm1 (x :+ y) = abs x + abs y
{-# INLINE norm1 #-}
fromReal x     = x :+ 0
{-# INLINE fromReal #-}
maybeToReal (x :+ y) | y ~== 0   = Just x
| otherwise = Nothing
{-# INLINE maybeToReal #-}
```