Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to embed Haskell in a C library opaquely?

Tags:

haskell

i.e. is it possible to embed Haskell code in a C library so that the user of the library doesn't have to know Haskell is being used? In particular, so that the user could use multiple libraries that embed Haskell, without any conflicts?

As far as I understand things, you embed between calls to hs_init and hs_exit, but these involve global state shenanigans and should conflict with other calls, no?

like image 378
Devin Jeanpierre Avatar asked Jun 21 '12 11:06

Devin Jeanpierre


1 Answers

Yes, it's possible to call Haskell code from C (and vice versa) through FFI, the Foreign Function Interface. Unfortunately, as the haskell.org docs says, you can't avoid the calls to initialize and finalize the haskell environment:

The call to hs_init() initializes GHC's runtime system. Do NOT try to invoke any Haskell functions before calling hs_init(): bad things will undoubtedly happen.

But, this is interesting also:

There can be multiple calls to hs_init(), but each one should be matched by one (and only one) call to hs_exit()

And furthermore:

The FFI spec requires the implementation to support re-initialising itself after being shut down with hs_exit(), but GHC does not currently support that.

Basically my idea is that you may exploit this specifications in order to write youself a wrapper C++ class that manages the calls to hs_init and hs_exit for you, in example by using template methods surrounded by hs_init and hs_exit that you can override using any haskell call you want. However, beware of interactions with other libraries calling haskell code: nested layers of calls to hs_init and hs_exit should be OK (so it's safe to use libraries which calls them in between your wrappers), but the total number of calls should always match, meaning that if those libraries only initialize the environment without trying to close it, then it's up to you to finish the job.

Another (probably better) idea, without exploiting inheritance and overriding, may be to have a simple class HaskellEnv that calls hs_init in the constructor and hs_exit in the destructor. If you declare them as automatic variables, you'll obtain that the calls to hs_init and hs_exit will always be matched, and the latest call to hs_exit will be made as soon as the latest HaskellEnv object is destructed when you leave its scope. Have a look at this question in order to prevent the creation of objects on the heap (they may be dangerous in this case).

like image 164
Riccardo T. Avatar answered Oct 13 '22 21:10

Riccardo T.