To Dream of Magick

Dreamer Shaper Seeker Maker

As part of a research project, I did a tiny bit of work to figure out the tiniest part of Haskell's Foreign Function Interface today. This is just the tip of the iceburg, but I thought I would show off the extremely simple demo that I worked out. I present both the C and Haskell versions of a program that feeds "abc" and "def" into the standard Unix crypt() function.

C, Venerable C

I did not do things in this order. However, for demonstration, we should start with the C operation. First, crypt() has the data prototype `char crypt(const char key, const char *salt);'. The code to call it takes a mere eleven lines:

Compile this with gcc -o crypt crypt.c -lcrypt. When I compile I get the warning crypt.c:7:9: warning: assignment makes pointer from integer without a cast [enabled by default], which I do not understand unless crypt() is not actually present in unistd.h. But, the code works correctly and as expected.

An important note: crypt() apparently returns a pointer to an internal data structure that you MUST NOT deallocate. I read comments in the man page about a GNU version of crypt(), crypt_r(), that is re-entrant, which reenforces my belief. If you want to keep the result of crypt(), be sure to copy it away, but otherwise do not allocate it. Running the program against valgrind indicates no leaked memory, which really solidifies this understanding for me.

Haskell FFI

The Haskell FFI was pretty easy to use, ultimately, and the cookbook really shows what we need to make this work. It takes a little bit more code, though, because we have to do the marshalling to and from C data types:

According to the FFI cookbook, prepending the name of the function with c_ is simply a standard.

What I do not know is whether c_crypt should have been declared as above, or as c_crypt :: CString -> CString -> IO CString. I am not yet clear on when a C call should be within the IO context and when it should not. I suspect that the compiler will not enforce anything and that it is up to me to make a (potentially unsafe) judgement call in the matter.

What's the Point?

I want to do Haskell on the new Ubuntu software stack for tablets. This uses QML (though the rest of Ubuntu seems to still use GTK). I have found a QML library for Haskell, but it is out of date and does not work with the current QT 5. So, I can either recode it from scratch, or I can fully understand it and update it for the modern QT. In both cases, I need to learn the FFI. But I've needed to learn the FFI for a long time, anyway.