Skip to content

Commit 4c57a51

Browse files
bbarkerbmshermanbbarkerro
authored
Update and run in stack nix (#8)
* Update bounds for new versions * added nix/stack config; now getting haskell build errors * updated deps; building but untested * incremental work; engOpen not working on Nix so far * readme updates * minor updates to running examples, still not working in NixOS * minor refactoring for next engine tests * fixing nix-shell script, adding a hello-world test program * adding some more print statements to test * mostly cleaning up documentation * added convenience functions for adding paths to MATLAB, related tests, and other minor tweaks * syntax simplification * minor shell.nix tweaks * refactoring shell.nix into shell and deps to make it easier to customize shell.nix * possible minor fixes in nix expression Co-authored-by: Ben Sherman <[email protected]> Co-authored-by: Brandon Barker <[email protected]>
1 parent be70122 commit 4c57a51

23 files changed

+612
-118
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.stack-work
2+
patchMatlab.lock

Foreign/Matlab/Array.hsc

+6-6
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ module Foreign.Matlab.Array (
3131
-- | array list access
3232
mxArrayGetList, mxArraySetList,
3333
mxArrayGetAll, mxArraySetAll,
34-
34+
3535
-- * Struct access
3636
-- |Structs in Matlab are always arrays, and so can be accessed using most array accessors.
3737
-- |However, the modification functions such as 'mxArraySet' are not implemented because they could disrupt field data in the entire struct array, and so some specialized functions are necessary.
@@ -66,7 +66,7 @@ anyMXArray a = unsafeCastMXArray a
6666
type MNullArray = MXArray MNull
6767
-- |Safely cast a generic array to a NULL array, or return Nothing if the array is not NULL
6868
castMNull :: MAnyArray -> MIO (Maybe MNullArray)
69-
castMNull a
69+
castMNull a
7070
| isMNull a = return $ Just (unsafeCastMXArray a)
7171
| otherwise = return Nothing
7272

@@ -209,8 +209,8 @@ castMXArray a
209209
y <- isMXArray b
210210
return $ if y then Just b else Nothing
211211
where
212-
b :: MXArray a
213-
b = unsafeCastMXArray a
212+
b :: MXArray a
213+
b = unsafeCastMXArray a
214214

215215
foreign import ccall unsafe mxGetData :: MXArrayPtr -> IO (Ptr a)
216216

@@ -327,8 +327,8 @@ foreign import ccall unsafe mxIsObject :: MXArrayPtr -> IO CBool
327327
foreign import ccall unsafe mxCreateStructArray :: MWSize -> Ptr MWSize -> CInt -> Ptr CString -> IO MXArrayPtr
328328
-- |Create an N-Dimensional structure array having the specified fields; initialize all values to 'MNullArray'
329329
createStruct :: MSize -> [String] -> MIO MStructArray
330-
createStruct s f =
331-
withNDims s (\(nd,d) ->
330+
createStruct s f =
331+
withNDims s (\(nd,d) ->
332332
mapWithArrayLen withCString f (\(f,nf) ->
333333
mxCreateStructArray nd d (ii nf) f))
334334
>>= mkMXArray

Foreign/Matlab/Array/IMX.hs

+58-58
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,22 @@ type IMXArray a = Array MIndex a
3636
-- |The basic immutable (functional) representation of Matlab data structures, representing a generic 'MXArray'
3737
data IMXData =
3838
IMXNull
39-
| IMXCell (IMXArray IMXData)
39+
| IMXCell (IMXArray IMXData)
4040
| IMXStruct [String] (Array (MIndex,Int) IMXData) -- ^ field name list and array mapping (index,field index) to values
41-
| IMXLogical (IMXArray MLogical)
42-
| IMXChar (IMXArray MChar)
43-
| IMXDouble (IMXArray MDouble)
44-
| IMXSingle (IMXArray MSingle)
45-
| IMXInt8 (IMXArray MInt8)
46-
| IMXUint8 (IMXArray MUint8)
47-
| IMXInt16 (IMXArray MInt16)
48-
| IMXUint16 (IMXArray MUint16)
49-
| IMXInt32 (IMXArray MInt32)
50-
| IMXUint32 (IMXArray MUint32)
51-
| IMXInt64 (IMXArray MInt64)
52-
| IMXUint64 (IMXArray MUint64)
53-
| IMXComplexDouble (IMXArray (MComplex MDouble))
54-
| IMXComplexSingle (IMXArray (MComplex MSingle))
41+
| IMXLogical (IMXArray MLogical)
42+
| IMXChar (IMXArray MChar)
43+
| IMXDouble (IMXArray MDouble)
44+
| IMXSingle (IMXArray MSingle)
45+
| IMXInt8 (IMXArray MInt8)
46+
| IMXUint8 (IMXArray MUint8)
47+
| IMXInt16 (IMXArray MInt16)
48+
| IMXUint16 (IMXArray MUint16)
49+
| IMXInt32 (IMXArray MInt32)
50+
| IMXUint32 (IMXArray MUint32)
51+
| IMXInt64 (IMXArray MInt64)
52+
| IMXUint64 (IMXArray MUint64)
53+
| IMXComplexDouble (IMXArray (MComplex MDouble))
54+
| IMXComplexSingle (IMXArray (MComplex MSingle))
5555
| IMXObject String IMXData -- ^ object class name and object data, currently always IMXStruct
5656
deriving (Eq)
5757

@@ -148,28 +148,28 @@ imxData a = do
148148
imxc t c where
149149

150150
imxc :: MXClass -> Bool -> IO IMXData
151-
imxc MXClassNull _ = return IMXNull
152-
imxc MXClassCell False = IMXCell =.< imxa (imxData . mCell)
153-
imxc MXClassStruct False = do
151+
imxc MXClassNull _ = return IMXNull
152+
imxc MXClassCell False = IMXCell =.< imxa (imxData . mCell)
153+
imxc MXClassStruct False = do
154154
s <- mxArraySize a'
155155
fv <- mxArrayGetAll a'
156156
f <- if null fv then mStructFields a' else return (map fst (mStruct (head fv)))
157157
listIMXStruct f s =.< mapM imxData (concatMap (map snd . mStruct) fv)
158-
imxc MXClassLogical False = IMXLogical =.< imxa return
159-
imxc MXClassChar False = IMXChar =.< imxa return
160-
imxc MXClassDouble False = IMXDouble =.< imxa return
161-
imxc MXClassSingle False = IMXSingle =.< imxa return
162-
imxc MXClassInt8 False = IMXInt8 =.< imxa return
163-
imxc MXClassUint8 False = IMXUint8 =.< imxa return
164-
imxc MXClassInt16 False = IMXInt16 =.< imxa return
165-
imxc MXClassUint16 False = IMXUint16 =.< imxa return
166-
imxc MXClassInt32 False = IMXInt32 =.< imxa return
167-
imxc MXClassUint32 False = IMXUint32 =.< imxa return
168-
imxc MXClassInt64 False = IMXInt64 =.< imxa return
169-
imxc MXClassUint64 False = IMXUint64 =.< imxa return
170-
imxc MXClassDouble True = IMXComplexDouble =.< imxa return
171-
imxc MXClassSingle True = IMXComplexSingle =.< imxa return
172-
imxc MXClassObject False = do
158+
imxc MXClassLogical False = IMXLogical =.< imxa return
159+
imxc MXClassChar False = IMXChar =.< imxa return
160+
imxc MXClassDouble False = IMXDouble =.< imxa return
161+
imxc MXClassSingle False = IMXSingle =.< imxa return
162+
imxc MXClassInt8 False = IMXInt8 =.< imxa return
163+
imxc MXClassUint8 False = IMXUint8 =.< imxa return
164+
imxc MXClassInt16 False = IMXInt16 =.< imxa return
165+
imxc MXClassUint16 False = IMXUint16 =.< imxa return
166+
imxc MXClassInt32 False = IMXInt32 =.< imxa return
167+
imxc MXClassUint32 False = IMXUint32 =.< imxa return
168+
imxc MXClassInt64 False = IMXInt64 =.< imxa return
169+
imxc MXClassUint64 False = IMXUint64 =.< imxa return
170+
imxc MXClassDouble True = IMXComplexDouble =.< imxa return
171+
imxc MXClassSingle True = IMXComplexSingle =.< imxa return
172+
imxc MXClassObject False = do
173173
Just c <- mObjectGetClass a'
174174
IMXObject c =.< imxc MXClassStruct False
175175
imxc t c = fail ("imxData: unhandled mxArray type " ++ show t ++ if c then "(complex)" else "")
@@ -192,18 +192,18 @@ iMXData = imxd where
192192
m <- createStruct (mRangeSize (r0,r1)) f
193193
zipWithM_ (\i -> mStructSetFields m (mOffset i) <=< mapM iMXData) [0..] (segment (length f) (elems a))
194194
return $ anyMXArray m
195-
imxd (IMXLogical a) = imxa a return
196-
imxd (IMXChar a) = imxa a return
197-
imxd (IMXDouble a) = imxa a return
198-
imxd (IMXSingle a) = imxa a return
199-
imxd (IMXInt8 a) = imxa a return
200-
imxd (IMXUint8 a) = imxa a return
201-
imxd (IMXInt16 a) = imxa a return
202-
imxd (IMXUint16 a) = imxa a return
203-
imxd (IMXInt32 a) = imxa a return
204-
imxd (IMXUint32 a) = imxa a return
205-
imxd (IMXInt64 a) = imxa a return
206-
imxd (IMXUint64 a) = imxa a return
195+
imxd (IMXLogical a) = imxa a return
196+
imxd (IMXChar a) = imxa a return
197+
imxd (IMXDouble a) = imxa a return
198+
imxd (IMXSingle a) = imxa a return
199+
imxd (IMXInt8 a) = imxa a return
200+
imxd (IMXUint8 a) = imxa a return
201+
imxd (IMXInt16 a) = imxa a return
202+
imxd (IMXUint16 a) = imxa a return
203+
imxd (IMXInt32 a) = imxa a return
204+
imxd (IMXUint32 a) = imxa a return
205+
imxd (IMXInt64 a) = imxa a return
206+
imxd (IMXUint64 a) = imxa a return
207207
imxd (IMXComplexDouble a) = imxa a return
208208
imxd (IMXComplexSingle a) = imxa a return
209209
imxd (IMXObject c a) = do
@@ -295,19 +295,19 @@ showsIMX (IMXStruct f a) = showsReshape (mRangeSize (r0,r1)) $ \d ->
295295
v = transpose $ segment (length f) $ elems a
296296
((r0,_),(r1,_)) = bounds a
297297
showsIMX (IMXLogical a) = showsApp "logical" $ showsIMXArray a
298-
showsIMX (IMXChar a) = showsApp "char" $ showsIMXArray a
299-
showsIMX (IMXDouble a) = showsIMXArray a
300-
showsIMX (IMXSingle a) = showsApp "single" $ showsIMXArray a
301-
showsIMX (IMXInt8 a) = showsApp "int8" $ showsIMXArray a
302-
showsIMX (IMXUint8 a) = showsApp "uint8" $ showsIMXArray a
303-
showsIMX (IMXInt16 a) = showsApp "int16" $ showsIMXArray a
304-
showsIMX (IMXUint16 a) = showsApp "uint16" $ showsIMXArray a
305-
showsIMX (IMXInt32 a) = showsApp "int32" $ showsIMXArray a
306-
showsIMX (IMXUint32 a) = showsApp "uint32" $ showsIMXArray a
307-
showsIMX (IMXInt64 a) = showsApp "int64" $ showsIMXArray a
308-
showsIMX (IMXUint64 a) = showsApp "uint64" $ showsIMXArray a
309-
showsIMX (IMXComplexDouble a) = showsIMXArrayWith showsComplex a
310-
showsIMX (IMXComplexSingle a) = showsApp "single" $ showsIMXArrayWith showsComplex a
298+
showsIMX (IMXChar a) = showsApp "char" $ showsIMXArray a
299+
showsIMX (IMXDouble a) = showsIMXArray a
300+
showsIMX (IMXSingle a) = showsApp "single" $ showsIMXArray a
301+
showsIMX (IMXInt8 a) = showsApp "int8" $ showsIMXArray a
302+
showsIMX (IMXUint8 a) = showsApp "uint8" $ showsIMXArray a
303+
showsIMX (IMXInt16 a) = showsApp "int16" $ showsIMXArray a
304+
showsIMX (IMXUint16 a) = showsApp "uint16" $ showsIMXArray a
305+
showsIMX (IMXInt32 a) = showsApp "int32" $ showsIMXArray a
306+
showsIMX (IMXUint32 a) = showsApp "uint32" $ showsIMXArray a
307+
showsIMX (IMXInt64 a) = showsApp "int64" $ showsIMXArray a
308+
showsIMX (IMXUint64 a) = showsApp "uint64" $ showsIMXArray a
309+
showsIMX (IMXComplexDouble a) = showsIMXArrayWith showsComplex a
310+
showsIMX (IMXComplexSingle a) = showsApp "single" $ showsIMXArrayWith showsComplex a
311311
showsIMX (IMXObject c a) = showsApp "class" $ showsIMX a . showChar ',' . showsMString c
312312

313313
instance Show IMXData where

Foreign/Matlab/Engine.hsc

+20-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ module Foreign.Matlab.Engine (
1212
engineGetVar,
1313
engineSetVar,
1414
EngineEvalArg(..),
15-
engineEvalFun
15+
engineEvalFun,
16+
engineEvalProc,
17+
qt
1618
) where
1719

1820
import Control.Monad
@@ -36,8 +38,8 @@ foreign import ccall unsafe "&" engClose :: FunPtr (EnginePtr -> IO ()) -- CInt
3638

3739
-- |Start Matlab server process. It will automatically be closed down when no longer in use.
3840
newEngine :: FilePath -> IO Engine
39-
newEngine bin = do
40-
eng <- withCString bin engOpen
41+
newEngine host = do
42+
eng <- withCString host engOpen
4143
if eng == nullPtr
4244
then fail "engOpen"
4345
else Engine =.< newForeignPtr engClose eng
@@ -48,7 +50,7 @@ withEngine (Engine eng) = withForeignPtr eng
4850
foreign import ccall unsafe engEvalString :: EnginePtr -> CString -> IO CInt
4951
-- |Execute matlab statement
5052
engineEval :: Engine -> String -> IO ()
51-
engineEval eng s = do
53+
engineEval eng s = do
5254
r <- withEngine eng (withCString s . engEvalString)
5355
when (r /= 0) $ fail "engineEval"
5456

@@ -64,7 +66,7 @@ engineSetVar eng v x = do
6466
r <- withEngine eng (\eng -> withCString v (withMXArray x . engPutVariable eng))
6567
when (r /= 0) $ fail "engineSetVar"
6668

67-
data EngineEvalArg a = EvalArray (MXArray a) | EvalVar String
69+
data EngineEvalArg a = EvalArray (MXArray a) | EvalVar String | EvalStr String
6870

6971
-- |Evaluate a function with the given arguments and number of results.
7072
-- This automates 'engineSetVar' on arguments (using \"hseval_inN\"), 'engineEval', and 'engineGetVar' on results (using \"hseval_outN\").
@@ -79,6 +81,17 @@ engineEvalFun eng fun arg no = do
7981
makearg (EvalArray x) i = do
8082
let v = "hseval_in" ++ show i
8183
engineSetVar eng v x
82-
return v
83-
makearg (EvalVar v) _ = return v
84+
pure v
85+
makearg (EvalVar v) _ = pure v
86+
makearg (EvalStr v) _ = pure $ qt v
8487
makeout i = "hseval_out" ++ show i
88+
89+
-- |Convenience function for calling functions that do not return values (i.e. "procedures").
90+
engineEvalProc :: Engine -> String -> [EngineEvalArg a] -> IO ()
91+
engineEvalProc eng fun arg = do
92+
_ <- engineEvalFun eng fun arg 0
93+
pure ()
94+
95+
-- |Utility function to quote a string
96+
qt :: String -> String
97+
qt s = "'" <> s <> "'"

Foreign/Matlab/Engine/Wrappers.hs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{-|
2+
Wrappers to common MATLAB functions using the Matlab engine.
3+
4+
Note that you cannot use "Foreign.Matlab.Engine" and "Foreign.Matlab.Runtime" in the same program.
5+
This seems to be a Matlab limitation.
6+
-}
7+
8+
module Foreign.Matlab.Engine.Wrappers (
9+
addpath
10+
) where
11+
12+
import Foreign.Matlab.Engine
13+
import Path
14+
15+
-- | We require an absolute path in this case
16+
addpath :: Engine -> Path Abs Dir -> IO ()
17+
addpath eng p = do
18+
engineEvalProc eng "addpath" [EvalStr $ toFilePath p]
19+
-- engineEval eng $ "addpath(" <> toFilePath p <> "');"

Foreign/Matlab/Internal.hsc

+8-8
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import Foreign.Matlab.Util
3636

3737
type MIO a = IO a
3838

39-
type CBool = #type bool
39+
-- type CBool = #type bool
4040

4141
boolC :: CBool -> Bool
4242
boolC = (0 /=)
@@ -45,9 +45,9 @@ cBool :: Bool -> CBool
4545
cBool = ii . fromEnum
4646

4747
type MXClassID = #type mxClassID
48-
data MXClass =
48+
data MXClass =
4949
MXClassNull
50-
| MXClassCell
50+
| MXClassCell
5151
| MXClassStruct
5252
| MXClassLogical
5353
| MXClassChar
@@ -88,7 +88,7 @@ instance MType MXClassID MXClass where
8888
mx2hs (#const mxINT64_CLASS) = MXClassInt64
8989
mx2hs (#const mxUINT64_CLASS) = MXClassUint64
9090
mx2hs (#const mxFUNCTION_CLASS)= MXClassFun
91-
mx2hs (#const mxOBJECT_CLASS) = MXClassObject
91+
mx2hs (#const mxOBJECT_CLASS) = MXClassObject
9292
mx2hs c = error ("MXClass: unknown mxClassID " ++ show c)
9393
hs2mx MXClassNull = #const mxVOID_CLASS
9494
hs2mx MXClassCell = #const mxCELL_CLASS
@@ -106,7 +106,7 @@ instance MType MXClassID MXClass where
106106
hs2mx MXClassInt64 = #const mxINT64_CLASS
107107
hs2mx MXClassUint64 = #const mxUINT64_CLASS
108108
hs2mx MXClassFun = #const mxFUNCTION_CLASS
109-
hs2mx MXClassObject = #const mxOBJECT_CLASS
109+
hs2mx MXClassObject = #const mxOBJECT_CLASS
110110
mxClassOf _ = error "mxClassOf: no class for MXClassID"
111111

112112
type MXChar = #type mxChar
@@ -116,7 +116,7 @@ instance MType MXChar MChar where
116116
mx2hs = Data.Char.chr . ii
117117
mxClassOf _ = MXClassChar
118118

119-
type MXLogical = #type mxLogical
119+
type MXLogical = CBool
120120
type MLogical = Bool
121121
instance MType MXLogical MLogical where
122122
hs2mx = cBool
@@ -176,7 +176,7 @@ data MAny
176176
type MAnyArray = MXArray MAny
177177
178178
-- |Tag for a NULL array
179-
data MNull
179+
data MNull
180180
instance MType MNull MNull where
181181
hs2mx = id
182182
mx2hs = id
@@ -201,7 +201,7 @@ instance MType MStruct MStruct where
201201
202202
type MXFun = CInt -> Ptr MXArrayPtr -> CInt -> Ptr MXArrayPtr -> IO ()
203203
-- |A Matlab function
204-
type MFun =
204+
type MFun =
205205
[MAnyArray] -- ^ RHS input arguments
206206
-> Int -- ^ LHS output argument count
207207
-> IO [MAnyArray] -- ^ LHS output arguments

Foreign/Matlab/MAT.hsc

+9-9
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ data MATMode = MATRead | MATWrite | MATUpdate
3939

4040
-- |Open a MAT-file using mode.
4141
matOpen :: FilePath -> MATMode -> IO MATFile
42-
matOpen f m = do
42+
matOpen f m = do
4343
throwErrnoIfNull ("matOpen: " ++ f)
4444
(withCString f (withCString (ms m) . matOpen_c))
4545
>.= MATFile
@@ -55,7 +55,7 @@ matClose m = throwErrnoIfMinus1_ "matClose" $ withMATFile m matClose_c
5555
foreign import ccall unsafe matPutVariable :: MATFilePtr -> CString -> MXArrayPtr -> IO CInt
5656
foreign import ccall unsafe matPutVariableAsGlobal :: MATFilePtr -> CString -> MXArrayPtr -> IO CInt
5757
-- |Write array value with the specified name to the MAT-file, deleting any previously existing variable with that name in the MAT-file.
58-
matSet :: MATFile
58+
matSet :: MATFile
5959
-> Bool -- ^ Global. If true, the variable will be written such that when the MATLAB LOAD command loads the variable, it will automatically place it in the global workspace.
6060
-> String -> MXArray a -> IO ()
6161
matSet m g n v = do
@@ -66,7 +66,7 @@ foreign import ccall unsafe matGetVariable :: MATFilePtr -> CString -> IO MXArra
6666
-- |Read the array value for the specified variable name from a MAT-file.
6767
matGet :: MATFile -> String -> IO (Maybe MAnyArray)
6868
matGet m n = do
69-
a <- withMATFile m (withCString n . matGetVariable)
69+
a <- withMATFile m (withCString n . matGetVariable)
7070
if a == nullPtr
7171
then return Nothing
7272
else Just =.< mkMXArray a
@@ -103,12 +103,12 @@ matLoad file = do
103103
where
104104
load m = alloca $ \n -> do
105105
a <- matGetNextVariable m n
106-
if a == nullPtr
107-
then return []
108-
else do
109-
a <- mkMXArray a
110-
n <- peek n >>= peekCString
111-
((n,a) :) =.< load m
106+
if a == nullPtr
107+
then return []
108+
else do
109+
a <- mkMXArray a
110+
n <- peek n >>= peekCString
111+
((n,a) :) =.< load m
112112

113113
-- |Write all the variables to a new MAT file
114114
matSave :: FilePath -> [(String,MXArray a)] -> IO ()

0 commit comments

Comments
 (0)