Haskell from C#
Haskell from Excel という過去の投稿で、C++からのHaskell呼び出しをやりましたが、C#から直接できることを以下のサイトで知り、テストしてみました。
Calling Haskell from C#
http://stackoverflow.com/questions/16615641/calling-haskell-from-c-sharp
このサイトでは、Monoで実行していますが、Windowsでテストしました。
また、Stringを戻り値とする関数が使いたかったので、これを追加しています。
環境: GHC ver 7.6.3, VisualStudio 2010 / Windows 7
Foo.hs
module Foo where import Foreign.C.String import Foreign.C.Types import Data.List.Split foo :: CString -> IO CInt foo c_str = do str <- peekCString c_str result <- hs_foo str return $ fromIntegral result hs_foo :: String -> IO Int hs_foo str = do putStrLn str return (length str) hstest :: CString -> IO CString hstest c_str = do str <- peekCString c_str let s = concat $ fmap cadd $ chunksOf 1 str newCString s cadd :: String -> String cadd c = do c ++ " " foreign export ccall foo :: CString -> IO CInt foreign export ccall hstest :: CString -> IO CString
ghc -no-hs-main -shared -o Foo.so Foo.hs
hstestで、C文字列をHaskell文字列に変換し、文字列操作をして、またC文字列に戻しています。
次にC#側ですが、VisualStudioのC#コンソールアプリケーションプロジェクトで作成します。
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace csConsoleHaskell01
{
class Program
{
[DllImport("Foo.so", CallingConvention = CallingConvention.Cdecl)]
private static extern void hs_init(IntPtr argc, IntPtr argv);
[DllImport("Foo.so", CallingConvention = CallingConvention.Cdecl)]
private static extern void hs_exit();
[DllImport("Foo.so", CallingConvention = CallingConvention.Cdecl)]
private static extern int foo(string str);
[DllImport("Foo.so", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr hstest(string str);
static void Main(string[] args)
{
hs_init(IntPtr.Zero, IntPtr.Zero);
int result = foo("Hello!");
Console.WriteLine("Length : {0}", result);
IntPtr r = hstest("Hello_Haskell_String");
string s = Marshal.PtrToStringAnsi(r);
Console.WriteLine(s);
hs_exit();
}
}
}
intを戻すときは、そのままでしたが、stringは上のようにポインタを取得してから変換する必要があるようです。(戻り値stringは不可)
Haskell Foo.soをcsConsoleHaskell01\bin\Debugディレクトリにおいて、csConsoleHaskell01.exeをコマンドプロンプトで実行します。
Hello!
Length : 6
H e l l o _ H a s k e l l _ S t r i n g
このように表示されます。
.NetとHaskellを結びつけるには、HaskellのFFI(ForeignFunctionInterface)を使ってC++/CLIとリンクして、さらに.Netマネージコードと連携しなくてはいけないと思っていましたが、このように簡単にできてしまうのですね。C#-Haskellができると、ここからいろいろと派生できそうです。