When, how and why you should call Haskell functions from C
Compiling a language to C means that you can call it from a large set of programming languages, including Go, Java, Python and Node.js. But when should we do it? And how?

After almost 50 years, the C programming language is still considered one of the best choices for writing fast and low-level code. It is a relatively small language, quite easy to learn, widely diffused... and it's universally known to be fast. Really, really fast.

The problem with C is that some algorithms may become really difficult to write, read and debug, due to the low-level nature of the language itself. Sometimes, writing those algorithms in another language may be a good choice.

There are a lot of languages that can interoperate with C, but there's one which is completely different from it and still be an awesome alternative for writing complex algorithms in a beautiful manner: Haskell.

In fact, Haskell is a purely functional programming language which has many advantages over C:

  • Higher level programming language
  • No null
  • No side effects at all
  • More modular code
  • Lazy evaluation
  • Easier to parallelize

and so on.

In terms of performances, most of the time Haskell execution speed is really close to C. So that's makes Haskell a good alternative for writing complex algorithms in an easier way.

For instance, let's say that we want to implement the QuickSort algorithm in both languages. Our C version would be something like this:

void quicksort(int number[25],int first,int last){
   int i, j, pivot, temp;

   if(first<last){
      pivot=first;
      i=first;
      j=last;

      while(i<j){
         while(number[i]<=number[pivot]&&i<last)
            i++;
         while(number[j]>number[pivot])
            j--;
         if(i<j){
            temp=number[i];
            number[i]=number[j];
            number[j]=temp;
         }
      }

      temp=number[pivot];
      number[pivot]=number[j];
      number[j]=temp;
      quicksort(number,first,j-1);
      quicksort(number,j+1,last);

   }
}

and our Haskell version:

quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
    where
        lesser = filter (< p) xs
        greater = filter (>= p) xs

ok, maybe that's not the most performant Haskell QuickSort implementation, but you can clearly see how more coincise, easy and beautiful it can be.

Want another example? Let's see how to encrypt a string using the Caesar Cypher in both languages.

Encrypting a string using the Caesar Cypher in C:

#include 
#include 
#include 
#include 

#define caesar(x) rot(13, x)
#define decaesar(x) rot(13, x)
#define decrypt_rot(x, y) rot((26-x), y)

void rot(int c, char *str)
{
    int l = strlen(str);
    const char *alpha[2] = { "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"};

    int i;
    for (i = 0; i < l; i++)
    {
        if (!isalpha(str[i]))
            continue;

        if (isupper(str[i]))
            str[i] = alpha[1][((int)(tolower(str[i]) - 'a') + c) % 26];
        else
            str[i] = alpha[0][((int)(tolower(str[i]) - 'a') + c) % 26];
    }
}


int main()
{
    char str[] = "A secret and encrypted message!";

    printf("Original:  %s\n", str);
    caesar(str);
    printf("Encrypted: %s\n", str);
    decaesar(str);
    printf("Decrypted: %s\n", str);

    return 0;
}

Encrypting a string using the Caesar Cypher in Haskell:

module Caesar (caesar, decaesar) where 

import Data.Char

caesar, decaesar :: (Integral a) => a -> String -> String
caesar k = map f
    where f c = case generalCategory c of
              LowercaseLetter -> addChar 'a' k c
              UppercaseLetter -> addChar 'A' k c
              _               -> c
decaesar k = caesar (-k)

addChar :: (Integral a) => Char -> a -> Char -> Char
addChar b o c = chr $ fromIntegral (b' + (c' - b' + o) `mod` 26)
    where b' = fromIntegral $ ord b
          c' = fromIntegral $ ord c

main :: IO()
main = do
    putStrLn $ "Original:  " ++ original
    putStrLn $ "Encrypted: " ++ encrypted
    putStrLn $ "Decrypted: " ++ decrypted
    where
        original  = "A secret and encrypted message!"
        encrypted = caesar   13 original
        decrypted = decaesar 13 encrypted

two completely different approaches. But they do the same job! Now let's try to run both:

# Compile our programs
ghc -o haskell main.hs
gcc -o clang main.c

# Make some silly benchmarks:
echo "\n** Running Haskell:\n"
time ./haskell
echo "\n** Running C:\n"
time ./clang

output (on MacBook Pro 2020 16", 16GB RAM, 2,6 GHz 6-Core Intel Core i7):

** Running Haskell:

Original:  A secret and encrypted message!
Encrypted: N frperg naq rapelcgrq zrffntr!
Decrypted: A secret and encrypted message!

real    0m0.017s
user    0m0.002s
sys     0m0.003s

** Running C:

Original:  A secret and encrypted message!
Encrypted: N frperg naq rapelcgrq zrffntr!
Decrypted: A secret and encrypted message!

real    0m0.129s
user    0m0.001s
sys     0m0.001s

Haskell is competing pretty well! If you're not familiar with the syntax, Haskell may be a bit scaring at first. But once you get used to it, you'll find the Haskell program a lot easier to write, reand, understand and debug than the C one!

#Calling Haskell from C

Now let's make a trivial example (just to keep it simple). We want to create a simple fibonacci function in Haskell and then call it from C. First of all: let's write down our Haskell function (taken from the official Haskell wiki):

fibonacci :: Int -> Int
fibonacci n = fibs !! n
    where fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

incredibly easy and straightforward! Now we may want to call it from our C program as follows:

...
i = fibonacci_hs(42);
printf("Fibonacci from Haskell: %d\n", i);
...

how should we compile our Haskell program? First of all, we need to generate stubs for C, in order to make it work with Haskell types:

{-# LANGUAGE ForeignFunctionInterface #-}

module Fibonacci where

import Foreign.C.Types

fibonacci :: Int -> Int
fibonacci n = fibs !! n
    where fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

fibonacci_hs :: CInt -> CInt
fibonacci_hs = fromIntegral . fibonacci . fromIntegral

foreign export ccall fibonacci_hs :: CInt -> CInt

As you can se, we're converting the fibonacci_hs parameter from CInt to Int in order to make it compatible with our original fibonacci function. Then we're converting the result back to CInt, to make it compatible with C. Last but not least, we're exporting our fibonacci_hs function using a foreign export.

Let's compile our Haskell program:

ghc -c -O main.hs

this will generate the following files:

  • main.hi
  • main.o
  • main_stub.h

let's see the content of main_stub.h:

#include "HsFFI.h"
#ifdef __cplusplus
extern "C" {
#endif
extern HsInt32 fibonacci_hs(HsInt32 a1);
#ifdef __cplusplus
}
#endif

Great! We now need to include that header file in our C program:

#include 
#ifdef __GLASGOW_HASKELL__
#include "main_stub.h"
#endif
#include 

int main(int argc, char *argv[])
{
    int i;
    hs_init(&argc, &argv);

    i = fibonacci_hs(42);
    printf("Fibonacci from Haskell: %d\n", i);

    hs_exit();
    return 0;
}

Great! Let's compile that file with gcc and test it:

gcc -o cprogram
./cprogram

Fibonacci: 267914296

Awesome! You've just compiled your first Haskell-to-C program!

#When is it really useful?

There are a lot of situations where compiling Haskell to C can be extremely useful. First of all: when an algorithm is too complex to be written in C. Haskell is an high level and garbage collected language, so most of the time writing algorithms can be incredibly easier.

Same problem may occur with other programming languages. Sometimes, writing algorithms in Java, Go and other languages can be more complex than writing them in Haskell. Compiling your function in C, means that you can call that code from other languages. In fact, many programming languages can interoperate with C for low level tasks or performance-critical algorithms.

Compiling Haskell to C, means that you can call your original Haskell function from languages such as:

  • Go
  • Java
  • Python
  • Node.js
  • Erlang/Elixir

and so on.

So... are you ready to interoperate with Haskell? It will be fun, I promise! You can find the repository containing code examples here