packages feed

matlab-0.3.0.0: Foreign/Matlab/Engine/Wrappers.hs

{-|
 Wrappers to common (and some uncommon) MATLAB functions using the MATLAB Engine.

 Note that you cannot use "Foreign.Matlab.Engine" and "Foreign.Matlab.Runtime" in the same program.
 This seems to be a Matlab limitation.
 -}

module Foreign.Matlab.Engine.Wrappers (
  addpath
, clearVar
, getArrayFromByteStream
, getByteStreamFromArray
, MEither(..), isMLeft, isMRight
, VarArgIn, mxVarArgs
) where

import qualified Data.Map.Strict as DM
import           Foreign.Matlab
import           Foreign.Matlab.Engine
import           Path

type VarArgIn = DM.Map String MAnyArray

-- | We require an absolute path in this case
addpath :: Engine -> Path Abs Dir -> IO ()
addpath eng p = engineEvalProc eng "addpath" [EvalStr $ toFilePath p]

-- | TODO: add a test for this, likely not working as expected.
-- | Clears a variable from the engine's workspace
clearVar :: Engine -> String -> IO ()
clearVar eng var = engineEvalProc eng "clear" [EvalStr var]

-- | Wraps an undocumented function to serialize a MATLAB object.
getByteStreamFromArray :: Engine -> MAnyArray -> IO (Either String [MUint8])
getByteStreamFromArray eng mObj = do
  [byteStream] <- engineEvalFun eng "getByteStreamFromArray" [EvalArray mObj] 1
  mxArrMay <- castMXArray byteStream
  case mxArrMay of
    Just mxArr -> Right <$> mxArrayGetAll mxArr
    Nothing -> pure $ Left
      "getByteStreamFromArray: Couldn't convert MATLAB bytestream to [MUint8]"

-- | Wraps an undocumented function to deserialize a MATLAB object.
getArrayFromByteStream :: Engine -> [MUint8] -> IO MAnyArray
getArrayFromByteStream eng bytes = do
  matBsArr <- createMXArray [length bytes]
  mxArraySetAll matBsArr bytes
  [mObj] <- engineEvalFun eng "getArrayFromByteStream" [EvalArray matBsArr] 1
  pure mObj

newtype MEither = MEither {unMXEither :: MStructArray}

isMLeft :: MEither -> IO Bool
isMLeft me = do
  sFields <- mStructFields $ unMXEither me
  pure $ "left" `elem` sFields

isMRight :: MEither -> IO Bool
isMRight me = do
  sFields <- mStructFields $ unMXEither me
  pure $ "right" `elem` sFields

-- | Utility function to create an eval-able list of arguments for a vararg map.
mxVarArgs :: VarArgIn -> [EngineEvalArg MAny]
mxVarArgs varargin = DM.toList varargin >>= kvToArg
  where
  kvToArg :: (String, MAnyArray) -> [EngineEvalArg MAny]
  kvToArg kv = [EvalStr $ fst kv, EvalArray $ snd kv]