Cからhaskellを使う

またまた備忘録
haskellでオブジェクトファイル作ってそいつをcから利用する方法。
備忘録なんでずいぶん適当。

まずはhaskellで何か書く

module Fib where

foreign export stdcall fib :: Int -> IO Int

fib :: Int -> IO Int
fib n = return . head . drop n $ fib'
	where fib' = 1:1:[a + b | (a, b) <- zip fib' $ tail fib']

モジュール名を明記してやって、foreign exportの行を書く。
この辺は決まり文句らしい。
ん?stdcallじゃなくてccallにすべきなのかも。まぁ、動いたからいいや。
やってることは単純にフィボナッチ数列のn番目を引っ張ってくるだけ。
もちっと賢い方法あるのだろうけどキニシナイ。


あと、Cに渡されるのはIntになる。この場合。
一節によるとCIntとかCに渡すための型があるらしいのだが、その辺はGHCがよきに計らってくれるらしい。
多分真面目にやるんだったらForeign.Cあたりをimportしなくちゃいけないんだろうけど。
配列とか文字列を買えしたいときも同様。
あとGHCの独自拡張とかあるらしいけどキニシナイ。


あとCの方

#include "test_stub.h"
#include <stdlib.h>
#include <stdio.h>

#ifdef __GLASGOW_HASKELL__
extern void __stginit_Fib ( void );
#endif

int main( int argc, char** argv )
{
	int i = 0;
	if( argc > 1 ) {
		i = atoi( argv[1] );
	}

	hs_init( &argc, &argv );
#ifdef __GLASGOW_HASKELL__
	hs_add_root( __stginit_Fib );
#endif

	printf( "%lu\n", fib( i ) );

	hs_exit();
	return 0;
}

test_stub.hはghcが勝手に作ってくれるので気にしない。(test_stub.cも発生。
__GLASGOW_HASKELL__はghc独自。hugsの場合はよく分からない。FFIとか仕様があるらしい。
まぁ、こんな感じ。
コンパイル方法は

$ ghc -c -o test.o test.hs -fglasgow-exts
$ ghc -c -o main.o main.c
$ ghc -c -o test_stub.o test_stub.c
$ ghc -o main *.o

こんな感じ。
スマートなMakefileの書き方が思いつかない...(д)