Hello: I would like to implement a new "calling convention" for Maple language, so that programers in Haskell may call for Maple routines. Both languages are intereseting for cooperation, due to its symbolic expresiveness. Maple 9.3 has released "Open Maple", somewhat like JNI for Java, if I'm not wrong. So a good start point to conider how to marshall these environments... I'm a newbie on FFI. Help required specilly from those working on Java FFI. Sorry for the obscure points. 1.- My initial schema is: C --------> Java Haskell --------> Maple A C programmer invokes the Java Virtual Machine as a Haskell programmer will invoke the Maple "kernel" handle (MKV). ( Strictly speaking, this should be done by the "calling convention" mechanism in a trasnparent way, since the final user has only to program the maple routines and to use the mandatory declarations: foreign import c e v :: t foreign export c e v :: t file a.maple: ------------- proc e(a,b) return a+b; end; ) 2.- The JVM initializes on a ".class" file, i.e, byte-code, as MKV straightly on source language ".maple" . 3.- What a "calling convention" must implement ? How to implement it ? I mean, JNI exports marshalling/unarshalling of types from Java to C, and access to attrbiutes/ invokes of methods of a given object on Java.. In time, Open Maple exports marshalling/unmarshalling of types between Maple AND C, and several ways of invoke the maple-kernel. So I should implement Maple and Haskell marshalling -via C , right ? I should implement the "maple" convention by using the "ccall" convention. So, there is a sort of "template" to implement a "calling convention"? This is a obscure point for me... 4.- What about side effects ? I mean, invoking a function on Maple may change the state of interpreter, and further calls may diff. Should I pass to the final user a handle to the KVM , or create a new type of monad, like... type MapleMonad a = stateKVM-> (stateKVM,val) instance Monad MapleMonad a ... >>= >> ..
I would like to implement a new "calling convention" for Maple language, so that programers in Haskell may call for Maple routines. Both languages are intereseting for cooperation, due to its symbolic expresiveness.
Making it possible to call Maple would be very cool. Can you give more detail about Open Maple? If I was doing this, I'd start by writing some C code that interfaces to Maple. After that works, I'd translate it into Haskell. That is, I would use the FFI to invoke the Maple FFI functions for pushing arguments, popping results, etc. and use the the FFI libraries which have lots of useful functions for marshaling arguments from Haskell to other formats. Start with something simple (e.g., a single argument function like 'sin'), prototype in C, translate to Haskell. At this point, don't worry too much about the fact that the simplest function call seems to require 10-20 lines of code - we can suggest ways to fix that. Keep trying new features (2 arguments, strings, calling both Haskell->Maple and Maple->Haskell, etc.) [The Open Maple manual probably has a list of examples used to illustrate the interface - start by doing all those.] If it isn't obvious how to do it or it just won't work, step back and write a prototype in C. Ask us as you run into problems. Once you can do all that, there's a bunch of tricks you can play with typeclasses to reduce the number of lines of code you have to write from 10-20 lines down to just one or two. (Ross Paterson has a very nice scheme for doing this - but I can't find it in the mail archives at the moment.) -- Alastair Reid
Making it possible to call Maple would be very cool. Can you give more detail about Open Maple?
Description OpenMaple is a suite of functions that allows you to access Maple algorithms and data structures in your compiled C program. This is the reverse of ExternalCalling, which allows access to C data structures from Maple.
If I was doing this, I'd start by writing some C code that interfaces to Maple. After that works, I'd translate it into Haskell. That is, I would use the FFI to invoke the Maple FFI functions for pushing arguments, popping results, etc. and use the the FFI libraries which have lots of useful functions for marshaling arguments from Haskell to other formats.
Start with something simple (e.g., a single argument function like 'sin'), prototype in C, translate to Haskell. At this point, don't worry too much about the fact that the simplest function call seems to require 10-20 lines of code - we can suggest ways to fix that. Keep trying new features (2 arguments, strings, calling both Haskell->Maple and Maple->Haskell, etc.) [The Open Maple manual probably has a list of examples used to illustrate the interface - start by doing all those.] If it isn't obvious how to do it or it just won't work, step back and write a prototype in C.
Examples ( taken from Open Maple . kv stands for a handle for the Maple Kernel) #include "maplec.h" ALGEB M_DECL MyStats( MKernelVector kv, ALGEB *args ) { ALGEB mean, sd, f; if( 1 != MapleNumArgs(kv,(ALGEB)args) ) { MapleRaiseError(kv,"one argument expected"); return( NULL ); } if( !IsMapleList(kv,args[1]) ) { MapleRaiseError(kv,"list expected"); return( NULL ); } /* get the name of the function to call, and compute the mean */ f = EvalMapleStatement(kv,"stats[describe,mean]:"); mean = EvalMapleProc(kv,f,1,args[1]); /* compute the standard deviation using a different method -- build up the function object and call MapleEval on it */ f = EvalMapleStatement(kv,"stats[describe,standarddeviation]:"); f = ToMapleFunction(kv,f,1,args[1]); sd = MapleEval(kv,f); /* return the pair */ return( ToMapleExpressionSequence(kv,2,mean,sd) ); } Is it what do you mean ? Then, I could use the maple kernel under a "ccall" convention, I mean: foreign export ccall "MyStats" MyStats :: MKenelVector -> [Args] ...
Ask us as you run into problems.
Rather what I would like is to write code in a file foo.maple and then, when invoking the function, to invoke the key funcion in C: sd = MapleEval(kv,f) IDEA : the RTS in the startup function should initialize and instance of the Maple kernel (kv) given a (*.maple) file (exactly as a JVM loads the .class file) , once detected a maple call at compiling time. The (*.maple) should be provided by the end user, as when a dynamic library is provided. OpenMaple allows the C-programmer to initialize the Maple Interpreter; Further calls to Maple-wrapper functions will act only as calls the "MapleEval" function, provided parameters... Once you have setup the Maple handle, it seems like to deal with a C library like HOPenGL Rigth ? I don't know on Marshalling/UnMarshalling...
Once you can do all that, there's a bunch of tricks you can play with typeclasses to reduce the number of lines of code you have to write from 10-20 lines down to just one or two. (Ross Paterson has a very nice scheme for doing this - but I can't find it in the mail archives at the moment.)
-- Alastair Reid
Examples ( taken from Open Maple )
ALGEB M_DECL MyStats( MKernelVector kv, ALGEB *args ) { ALGEB mean, sd, f;
if( 1 != MapleNumArgs(kv,(ALGEB)args) ) { MapleRaiseError(kv,"one argument expected"); return( NULL ); } ... /* return the pair */ return( ToMapleExpressionSequence(kv,2,mean,sd) ); }
Is it what do you mean ?
Yes, now use Haskell's ffi to import all those OpenMaple calls you made in the above. That is, MapleNumArgs, ToMapleExpressionSequence, etc. Having done that, translate the code into Haskell in the obvious way and check it works. Try a range of examples, figure out what works and what doesn't work, figure out where the order of things matters and where it doesn't. After you've done a bunch of examples, show us them and we can suggest how to use type classes to reduce most maple calls to just a line or two of Haskell code.
I don't know on Marshalling/UnMarshalling...
Marshaling/unmarshalling is converting the argument list from Haskell (or, for that matter C) representation into Maple representation. Half the code in your example was doing this. -- Alastair Reid
On Mon, 20 Sep 2004, Alastair Reid wrote:
} ... /* return the pair */ return( ToMapleExpressionSequence(kv,2,mean,sd) ); }
Is it what do you mean ?
Yes, now use Haskell's ffi to import all those OpenMaple calls you made in the above. That is, MapleNumArgs, ToMapleExpressionSequence, etc.
Now in progress...
Having done that, translate the code into Haskell in the obvious way and check it works.
Two questions: ------------- A) The H98 Foreign Function Interface remakrs the next example to import from C. foreign import ccall "string.h strlen" cstrlen:: Ptr CChar -> IO CSize but trying foreign import ccall "maplec.h MapleKernelOptions" mapleKernelOptions :: MKernelVector -> CString -> IO(ALGEB) gives a failure. (ghc-5.02.3) otium@avila:~/OpenMaple> ghc -cpp -fglasgow-exts -c maplec.hs -package lang maplec.hs:82: `maplec.h MapleKernelOptions' is not a valid C identifier When checking declaration: foreign import __ccall_GC maplec.h MapleKernelOptions mapleKernelOptions :: MKernelVector -> CString -> IO ALGEB It's a pitty, because I cannot use "MapleKernelOptions" as a identifier for a function in Haskell.... What to do then ? B) When passing char *string on C, should I use the CString or the Ptr CChar marhalling type from FFI ?
B) When passing char *string on C, should I use the CString or the Ptr CChar marhalling type from FFI ?
Ok. I see. Definition for CSTring is type CString = Ptr CChar C) CInt, CDouble are available...but, concerning Storable class. Given: typedef struct _foostruct { int a; double b; } fooStruct, *fooStructPtr; How to do to marshall it to Haskell ? type CFooStruct = ??? instance Storable CFooStruct where sizeOf _ = ??? peekElement _ = ???? -- Next is certainly OK, provided well defined CFooStruct type CFoosStructPtr = Ptr CFooStruct I need it to marshall the Maple kernel handle into Haskell...
_______________________________________________ FFI mailing list FFI@haskell.org http://www.haskell.org/mailman/listinfo/ffi
C) CInt, CDouble are available...but, concerning Storable class.
Given: typedef struct _foostruct { int a; double b; } fooStruct, *fooStructPtr;
How to do to marshall it to Haskell ?
type CFooStruct = ???
instance Storable CFooStruct where sizeOf _ = ??? peekElement _ = ????
-- Next is certainly OK, provided well defined CFooStruct type CFoosStructPtr = Ptr CFooStruct
Well, after reading some doc, I realised it may not be feasible without a FFI preprocessor. For the time beeing, as I don't want to access the internals of Kernel descriptor, but to deal with it through the given API, I will declare type MKernelDescriptor = Ptr () as a transient solution. It seems to be OK.
Rafael Martinez Torres wrote:
Well, after reading some doc, I realised it may not be feasible without a FFI preprocessor.
It's feasible without a FFI preprocessor, but probably not very portable.
For the time beeing, as I don't want to access the internals of Kernel descriptor, but to deal with it through the given API, I will declare
type MKernelDescriptor = Ptr ()
as a transient solution. It seems to be OK.
A common idiom for an opaque pointer is: newtype Foo = Foo (Ptr Foo) Cheers, S.
------------- A) The H98 Foreign Function Interface remakrs the next example to import from C.
foreign import ccall "string.h strlen" cstrlen:: Ptr CChar -> IO CSize
but trying
foreign import ccall "maplec.h MapleKernelOptions" mapleKernelOptions :: MKernelVector -> CString -> IO(ALGEB)
gives a failure. (ghc-5.02.3) otium@avila:~/OpenMaple> ghc -cpp -fglasgow-exts -c maplec.hs -package lang
maplec.hs:82: `maplec.h MapleKernelOptions' is not a valid C identifier When checking declaration: foreign import __ccall_GC maplec.h MapleKernelOptions mapleKernelOptions :: MKernelVector -> CString -> IO ALGEB
Done. Upgrading ghc-6.0.1 solves it. Still waiting for answer C) on how marshalling C structures...
Rafael Martinez Torres wrote:
Done. Upgrading ghc-6.0.1 solves it.
Why not 6.2.2? 6.0.1 is relatively old...
Still waiting for answer C) on how marshalling C structures...
Perhaps a look at http://www.reid-consulting-uk.ltd.uk/docs/ffi.html and probably http://haskell.org/ghc/docs/latest/html/users_guide/hsc2hs.html might help. Cheers, S.
Yes, now use Haskell's ffi to import all those OpenMaple calls you made in the above. That is, MapleNumArgs, ToMapleExpressionSequence, etc.
Having done that, translate the code into Haskell in the obvious way and check it works.
Done !!!
After you've done a bunch of examples, show us them and we can suggest how to use type classes to reduce most maple calls to just a line or two of Haskell code.
Attached file. Waiting for your comments...
participants (3)
-
Alastair Reid -
Rafael Martinez Torres -
Sven Panne