Skip to content
Brandon Elam Barker edited this page May 21, 2020 · 1 revision

Retrieving strings from the MATLAB Engine

When looking into how to grab a string from the MATLAB Engine, it is possible to get a bit lost. There are a lot of functions after all. Here are a few I chased down that seemed possibly relevant:

engineEvalFun :: Engine -> String -> [EngineEvalArg a] -> Int -> IO [MAnyArray]

type MAnyArray = MXArray MAny
anyMXArray :: MXArray a -> MAnyArray

type MXArrayPtr = Ptr MXArrayType

foreign import ccall unsafe mxGetChars :: MXArrayPtr -> IO (Ptr MXChar)

-- `MXArrayType` appears to be an abstract type:
data MXArrayType
-- The only lead is this:
newtype MXAuto a = MXAuto (ForeignPtr MXArrayType)
mxAuto :: MXArray a -> MIO (MXAuto a)
-- However, MXAuto is: A 'MXArray' that is automatically freed.  These arrays must never be put inside other arrays or used as function results.

type With x y a = x -> (y -> a) -> a

withMXArray :: With (MXArray x) MXArrayPtr a
-- ==  ??
withMXArray :: (MXArray x) -> (MXArrayPtr -> a) -> a
withMXArray (MXArray a) f = f a
-- So we give it an (MXArray MAny), and a function to extract
-- an `a` from a `MXArrayPtr`, and we should get an `a` as  a result
-- I'm not entirely sure what the right way is to read this, but I
-- suppose "With x and y->a you get an a" isn't awful: it implies
-- the function embeds logic to go from x-> y.

mapWith :: With x y a -> With [x] [y] a
mapWith' :: With x y a -> With [x] [y] a
mapWithRev :: With x y a -> With [x] [y] a
mapWithArray :: Storable y => With x y (IO a) -> With [x] (Ptr y) (IO a)
mapWithArrayLen :: Storable y => With x y (IO a) -> With [x] (Ptr y, Int) (IO a)

withMXAuto :: MXAuto a -> (MXArray a -> IO b) -> IO b
type MAnyAuto = MXAuto MAny


-- |Get a flat list of all elements in the array.
mxArrayGetAll :: MXArrayComponent a => MXArray a -> IO [a]

In the end, the solution was to realize that:

  1. instance MXArrayComponent MChar exists (original error: No instance for (MXArrayComponent [Char]))
  2. mxArrayGetAll exsits

This allowed for writing an interface to MATLAB's pwd (not necessarily the best interface in terms of error handling):

pwd :: Engine -> IO (Path Abs Dir)
pwd eng = do
  [pwdDirAnyArr] <- engineEvalFun eng "pwd" [] 1
  pwdDirCArrMay <- castMXArray pwdDirAnyArr      
  dirOrEmptyStr <- case pwdDirCArrMay of
    Just pwdDirCArr -> mxArrayGetAll pwdDirCArr  
    Nothing -> pure ""
  parseAbsDir dirOrEmptyStr
Clone this wiki locally