wvogel日記

自分用の技術備忘録が多めです.

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

とすると、見事実行することが出来ました!!