matlab-0.1: Foreign/Matlab/Types.hs
{-|
Mapping of basic Matlab types to Haskell types.
-}
module Foreign.Matlab.Types (
-- * Representations of Matlab types
-- |Most types are simple aliases of Haskell types, given simply to identify them and provide a consistent naming scheme.
MIO,
MXClass(..),
MChar,
MLogical,
MScalar,
MNumeric,
-- * Numeric types
MDouble,
MSingle,
MInt8,
MInt16,
MInt32,
MInt64,
MUint8,
MUint16,
MUint32,
MUint64,
MComplex,
-- * Array indexing
MSize, MSubs,
MIndex(..),
mStart, mOffset,
mSizeRange, mRangeSize,
normMSize, realMSize,
-- * Opaque types
MXArray,
MAnyArray,
MCell(MCell), mCell,
MStruct,
MFun
) where
import Data.Complex
import Data.Ix
import Foreign.Matlab.Internal
-- |The class of types which are simple Matlab scalars and can be array elements
class MScalar a
-- |The class of types which Matlab consisters \"numeric\"
class (MScalar a, Num a) => MNumeric a
instance MScalar MChar
instance MScalar MLogical
instance MScalar MDouble
instance MScalar MSingle
instance MScalar MInt8
instance MScalar MInt16
instance MScalar MInt32
instance MScalar MInt64
instance MScalar MUint8
instance MScalar MUint16
instance MScalar MUint32
instance MScalar MUint64
instance MNumeric a => MScalar (MComplex a)
instance MNumeric MDouble
instance MNumeric MSingle
instance MNumeric MInt8
instance MNumeric MInt16
instance MNumeric MInt32
instance MNumeric MInt64
instance MNumeric MUint8
instance MNumeric MUint16
instance MNumeric MUint32
instance MNumeric MUint64
-- |Complex numeric types. Unfortunately, 'Complex' only applies to 'RealFloat' types, whereas Matlab allows any numeric type, so some types are (currently) unaccessable.
type MComplex = Complex
-- |The type of array sizes, which are the column-major lengths of each dimensions
type MSize = [Int]
-- |The type of array index subscripts, which are the column-major, 0-based indices in each dimension with normal Matlab semantics (flatten along last dimension)
type MSubs = [Int]
-- |Ways to index an array. Using Matlab semantics, a singleton MSubs [n] is equivalent to a raw 0-based offset (MOffset n).
newtype MIndex = MSubs MSubs
-- MOffset Int -- ^0-based offset from the beginning of the array (equivalent to singleton MSubs)
-- |First index in array
mStart :: MIndex
mStart = MSubs []
-- |Raw, 0-based array offset index
mOffset :: Int -> MIndex
mOffset i = MSubs [i]
instance Show MIndex where
showsPrec _ (MSubs []) = id
showsPrec _ (MSubs l) = showChar '(' . foldr1 (\s r -> s . showChar ',' . r) (map shows l) . showChar ')'
instance Eq MIndex where
MSubs a == MSubs b = eq a b where
eq [] [] = True
eq (x:a) (y:b) = (x == y) && eq a b
eq [] b = eq [0] b
eq a [] = eq a [0]
instance Ord MIndex where
compare (MSubs a) (MSubs b) = cmp a b where
cmp [] [] = EQ
cmp (x:a) (y:b) = case cmp a b of { EQ -> compare x y ; r -> r }
cmp [] b = cmp [0] b
cmp a [] = cmp a [0]
instance Ix MIndex where
range (MSubs a, MSubs b) = map MSubs $ rng a b where
rng [] [] = [[]]
rng (x:a) (y:b) = concatMap (\l -> map (:l) [x..y]) $ rng a b
rng [] b = rng [0] b
rng _ _ = error "MIndex.range: length mismatch"
index (MSubs a, MSubs b) (MSubs l) = idx a b l where
idx _ _ [] = 0
idx (x:a) (y:b) (i:l) = i-x+((y-x+1)*idx a b l)
idx [] [] (0:l) = idx [] [] l
idx [] b l = idx [0] b l
idx _ _ _ = error "MIndex.index: length mismatch"
inRange (MSubs a, MSubs b) (MSubs l) = inr a b l where
inr _ _ [] = True
inr a@(x:_) b@(_:_) [i] = i >= x && i-x < rangeSize (MSubs a, MSubs b)
inr (x:a) (y:b) (i:l) = i >= x && i <= y && inr a b l
inr [] [] (0:l) = inr [] [] l
inr [] b l = inr [0] b l
inr _ _ _ = error "MIndex.inRange: length mismatch"
rangeSize (MSubs a, MSubs b) = rsz a b where
rsz [] b = product $ map succ b
rsz (x:a) (y:b) = (y-x+1)*rsz a b
rsz _ _ = error "MIndex.rangeSize: length mismatch"
-- |Convert an array size to an index range, which will be of the form ((0,0,0...),(i-1,j-1,k-1,...))
mSizeRange :: MSize -> (MIndex,MIndex)
mSizeRange l = (MSubs [], MSubs $ map pred $ normMSize l)
-- |Convert an index range to an array size
mRangeSize :: (MIndex,MIndex) -> MSize
mRangeSize (MSubs [], MSubs l) = map succ l
mRangeSize _ = error "mRangeSize: invalid lower bound"
-- |Get the size form that Matlab likes (@length (realMSize s) >= 2@)
realMSize :: MSize -> MSize
realMSize [] = [1,1]
realMSize [n] = [n,1]
realMSize s = s
-- |Get a more useful size form (no trailing singletons)
normMSize :: MSize -> MSize
normMSize [] = []
normMSize (1:l) = case normMSize l of { [] -> [] ; l -> (1:l) }
normMSize (x:l) = x : normMSize l