ViewPatterns & FFI (export)
今日はHaskellでの
GHC拡張の一つ、ViewPatternを使ってみました。
更に、それをC言語から利用してみます。
まずはファイルの先頭に以下の拡張宣言を
{-# LANGUAGE ViewPatterns #-}
これでViewPatternsを利用可能になりました。
ぱっとは面白い関数が思いつかなかったので、
何の再利用性もないですが、以下のコードを試しに書いて走らせる。
{-# LANGUAGE ViewPatterns #-} main = print $ map f [1..20] --viewパターン f :: Int -> Int f (check -> Just n) = n*n f _ = 1 check :: Int -> Maybe Int check n = if even n then Just n else Nothing
注目すべきは関数fです。
fに適用する値を記述する部分が、
(check -> Just n)
となっています。
fに適用される値をまずchkに適用し、
その結果に、次に関数fが適用されます。
面白いです。
なんか色々使えそう
次に、これをC言語から利用してみます。
前回FFIの記事を書いた時は、
HaskellからCの関数を利用しましたが、
今回は外部に渡します。
まず、先ほどのコードのmain関数を消して、代わりに
module ViewPatterns where foreign export ccall "f" f :: Int -> Int
を記述。
関数fをexportします。
次に、ターミナルで
ghc -c ViewPatterns.hs
とします。
すると、cファイルやo,hファイルを色々作ってくれます。
すごい。
実際にどのようなCファイルが生成されたかと言うと。
#define IN_STG_CODE 0 #include "Rts.h" #include "Stg.h" #ifdef __cplusplus extern "C" { #endif extern StgClosure Vp_zdffzuap8_closure; HsInt f(HsInt a1) { Capability *cap; HaskellObj ret; HsInt cret; cap = rts_lock(); cap=rts_evalIO(cap, rts_apply(cap,HaskellObj)runNonIO_closure, rts_apply(cap,&Vp_zdffzuap8_closure, rts_mkInt(cap,a1))),&ret); rts_checkSchedStatus("f",cap); cret=rts_getInt(ret); rts_unlock(cap); return cret; } static void stginit_export_Vp_zdffzuap8() __attribute__((constructor)); static void stginit_export_Vp_zdffzuap8() {getStablePtr((StgPtr) &Vp_zdffzuap8_closure);} #ifdef __cplusplus } #endif
さっぱりです。.hファイルはそれに比べて非常に簡潔。
#include "HsFFI.h" #ifdef __cplusplus extern "C" { #endif extern HsInt f(HsInt a1); #ifdef __cplusplus } #endif
さて、では実際にこいつをC言語から呼び出してみましょう。
以下のようにコードを記述
/*importTest.c*/ #include <stdio.h> #include<stdlib.h> #include"HsFFI.h" #ifdef __GLASGOW_HASKELL__ #include "ViewPatterns_stub.h" #endif int main(int argc , char *argv[]){ int i; hs_init(&argc , &argv); for(i = 0 ; i < 20 ; i++) printf("%d\n",f(i)); getchar(); return 0; }
ターミナルで
$ ghc ViewPatterns.o ViewPatterns_stub.o importTest.c -o exportTestC $ exportTestC
とすると、見事実行することが出来ました!!