HaskellのDLLを作ってRubyから呼ぶ
18. Running GHC on Win32 systems — Glasgow Haskell Compiler 8.6.4 User's Guideを参考にやってみました。Haskellで書いたフィボナッチ関数をDLLにして、それをRubyのWin32APIを使って呼びます。Haskellのコードは必然的にIOになります。
ファイル名: fib.hs
module Fib where foreign export stdcall fib :: Int -> IO Int fib :: Int -> IO Int fib = return . fib' where fib' 0 = 0 fib' 1 = 1 fib' n = fib' (n - 2) + fib' (n - 1)
ファイル名: main.c
#include <Windows.h> #include "HsFFI.h" #include "fib_stub.h" extern void __stginit_Fib(void); BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return TRUE; } HsBool hs_begin(void) { int argc = 2; char *argv[] = {"-B", "C:\\ghc\\ghc-6.8.1", NULL}; char **argvp = argv; hs_init(&argc, &argvp); hs_add_root(__stginit_Fib); return HS_BOOL_TRUE; } HsBool hs_end(void) { hs_exit(); return HS_BOOL_TRUE; }
DLLの生成例:
$ ghc -c fib.hs -fglasgow-exts $ ghc -c main.c $ ghc -shared -o fib.dll fib.o fib_stub.o main.o Creating library file: fib.dll.a
Rubyからの呼び出しはこんな感じになります。
#!/usr/bin/env ruby require 'Win32API' hs_begin = Win32API.new('fib.dll', 'hs_begin', nil, 'i') hs_end = Win32API.new('fib.dll', 'hs_end', nil, 'i') fib = Win32API.new('fib.dll', 'fib@4', ['p'], 'i') hs_begin.call begin p fib.call(0) # => 0 p fib.call(1) # => 1 p fib.call(2) # => 1 p fib.call(3) # => 2 p fib.call(10) # => 55 p fib.call(20) # => 6765 ensure hs_end.call end