HaskellããCã©ã¤ãã©ãªãå¼ã¶(FFI)
Haskellã®ãªãã§ãã¢ãªå ·åã
ã©ã¤ãã©ãªããã«ããã¦ãã¨ã¡ããã¡ããè¦ããFFIã¨ããæååãæ°ã«ãªã£ã¦èª¿ã¹ã¦ã¿ãã¨ãForeignFunctionInterfaceã¨ãããã®ããã£ã¦ãããã¯HaskellããCã®é¢æ°ãå¼ã³åºãããã®ã¢ã¸ã¥ã¼ã«ã¨ãããæ¡å¼µãããã
Haskellã®ãã®ãããã©ã¤ãã©ãªã®å
å®åº¦ã®å½±ã«ã¯ãããããã®ããã£ãããããã§ããã
ã¨ãããã¨ã§ã¡ãã£ã¨éãã§ã¿ã¾ããã
ã ããããã®è¨äºã®ãã¬ã¹ã§ãã
本物のプログラマはHaskellを使う - 第22回 FFIを使って他の言語の関数を呼び出す:ITpro
æ¢åã®ã©ã¤ãã©ãªãå¼ã¶
ä¸ã®è¨äºã«ç¿ã£ã¦ãlibmã®sinãå¼ã³åºãã¦ã¿ã¾ãã
ã¾ããä½ã¯ãªãã¨ãmanã§ããsin(3)ã®manãè¦ãã¨ã
NAME sin, sinf, sinl - sine function SYNOPSIS #includedouble sin(double x); float sinf(float x); long double sinl(long double x); Link with -lm.
ã ããããããªæãã«æ¸ããã¦ããã¨æãããã
ãããCã§ä½¿ãæã¯ãããªæãã
#include <stdio.h> #include <math.h> int main() { printf("%f\n", sin(0)); printf("%f\n", sin(M_PI / 2)); return 0; }
ã³ã³ãã¤ã«ãã¦å®è¡ããã
% gcc -lm sin.c % ./a.out 0.000000 1.000000
ã³ã³ãã¤ã«ã®æã®"-lm"ã¯ããã£ãã®manã«ãæ¸ãã¦ããã¾ããããlibm(mathã©ã¤ãã©ãª)ããªã³ã¯ããã¨ããæå³ã§ãå®ã¯ä»ã®gccã¯libmã¯æ¨æºã§ãªã³ã¯ãã¦ãããã£ã½ãã®ã§çç¥å¯è½ã§ãã
ãããå²ã¨ãã®ã¾ãã¾Haskellã§ãæ¸ããã
{-# LANGUAGE ForeignFunctionInterface #-} {-# INCLUDE <math.h> #-} module Main where foeign import ccall "sin" c_sin :: Double -> Double main :: IO () main = do print $ c_sin 0 print $ c_sin (pi / 2)
ä»ç§ã使ã£ã¦ããversionã®ghc(7.4.1)ã ã¨ãè¨èªæ¡å¼µã®ForeignFunctionInterfaceæå®ã¯å¿
è¦ããã¾ããã§ããã
ãã¨ã"INCLUDE
Warning: -#include and INCLUDE pragmas are deprecated: They no longer have any effect
ã£ã¦è¨ãããã®ã§ããããè¦ããªãã¿ããã§ããå¤åãæ¨æºã§ãªã³ã¯ããã¦ãã©ã¤ãã©ãªã®åã¯è¦ããªãã£ã¦ãã¨ãªãã§ãããã
ã¨ãããã¨ã§ãæåã®2è¡ã¯åã£ã¦ããã¿ããã§ããå°ãªãã¨ãINCLUDEã®æ¹ã¯è¦ååºãããåã£ãã»ããç¡é£ã§ãããã
ã³ã³ãã¤ã«ï¼å®è¡ã
% ghc -lm Sample.hs [1 of 1] Compiling Main ( Sample.hs, Sample.o ) Linking Sample ... % ./Sample 0.0 1.0
ãããgccã¨åæ§ã«"-lm"ãä»ãããã§ããããã®å ´åãçç¥ãã¦ããã¿ããã§ãã
Cã¨Haskellã®æ°å¤åå¤æ
c_sinãå®ç¾©ãã¦ããã®è¡ã
foeign import ccall "sin" c_sin :: Double -> Double
ãCã®siné¢æ°ãc_sinã¨ããååã®"Double -> Double"åã¨ãã¦importãããã¨ãããããªæãã ã¨æããã¾ãã
ãã ããããããã§Double->Doubleåã¨ãã¦æ¸ãã¦ãããã©ãããã®Haskellã®Doubleåã¨Cã®doubleåã£ã¦ä¸è´ãã¦ãã®ï¼ã精度ã¨ããã¤ãæ°ã¨ã符å·ã¨ãéãããããªãï¼ãã¨ããäºãªãã§ããã©ã
ãã®ããã«Foreign.C.Typesã£ã¦ã¢ã¸ã¥ã¼ã«ããã£ã¦ãCã®åã¨å¯¾å¿ããåã¨Haskellã®åã¸ã®å¤æãå®ç¾©ããã¦ãããããã
Foreign.C.Types
ããããã«ã¯åå®ç¾©ã ãã§ãå¤æã¯æ£ç¢ºã«ã¯Preludeã¢ã¸ã¥ã¼ã«ã«ãããã§ããã©ã
fromIntegralã¨realToFracã§ãããªããããå½åè¦åçµ±ä¸ãã¦ã»ããã§ãããã
ããã使ã£ã¦çé¢ç®ã«æ¸ãç´ãã¨ãããªãã¾ãã
module Main where import Foreign.C.Types foreign import ccall "sin" c_sin :: CDouble -> CDouble cSin :: Double -> Double cSin = realToFrac . c_sin . realToFrac main :: IO () main = do print $ cSin 0 print $ cSin (pi / 2)
å ¥åã¨åºåãããããrealToFracã§å¤æãããããã§ãªãã±ã¼ã
èªä½ã®ã©ã¤ãã©ãªãå¼ã¶
次ãèªåã§ä½ã£ãã©ã¤ãã©ãªããªã³ã¯ãã¦ã¿ãããã®ã¸ãã¯Haskellã¨ããããCè¨èªã£ã¦ãããGCCã¨ããã¤ãããã¯ãªã³ã¯ã©ã¤ãã©ãªã®è©±ããããã¾ãããã
Cã§æ¸ããã©ã¤ãã©ãªãHaskellããå¼ã³åºãã¦ã¿ã¾ãã
èªä½ã©ã¤ãã©ãªã®ä¾ã¨ãã¦ã¨ãããã足ãç®ã§ããã¦ã¿ã¾ãããã
int add(int a, int b) { return a + b; }
ã³ã³ãã¤ã«ãã¦ãã¤ãããã¯ãªã³ã¯ã©ã¤ãã©ãªãä½ãã
% gcc -shared add.c -o libadd.so
ããã¦ããã使ãå´ã®Haskellã³ã¼ããæ¸ãã
module Main where import Foreign.C.Types foreign import ccall "add" c_add :: CInt -> CInt -> CInt cAdd :: Int -> Int -> Int cAdd a b = fromIntegral $ c_add (fromIntegral a) (fromIntegral b) main :: IO () main = do print $ cAdd 0 1 print $ cAdd 3 5
ã³ã³ãã¤ã«ãã¦å®è¡ããã
% ghc -L. -ladd Add.hs [1 of 1] Compiling Main ( Add.hs, Add.o ) Linking Add ... % ./Add 1 8
ã§ããã
ä»åã¯èªä½ã©ã¤ãã©ãªãªã®ã§ã³ã³ãã¤ã«æã«ãã¹ã®æå®ãå¿
è¦ã«ãªãã¾ãã(-LPATH)
ãã¨ã¯ã¾ããfromIntegralã£ã¦æ¸ãã®ãããã©ãããã¨ããã®ãããã§ããããã
å¯ä½ç¨ã¨ã
ããã¾ã§è¦ãã°ãããã¨ããããªãã®å¶ç´ããªãHaskellããCã®é¢æ°ãå¼ã³åºãã¦ãã¾ãã¾ãã
ã¨ãããã¨ã¯ã¤ã¾ããCã®ä¸ã§exitããããIOããããããããæ¾é¡ã§ããã¨ããããããmathã¿ããã«IOãç¡ãæ¹ãçãããã§ããã
éã«ãHaskellå´ãCã®é¢æ°ãã©ãããä»æ§ã«ããããæ¯è¼çèªç±ãªããã§ã
ãã¨ãã°ãã£ãã®addé¢æ°ãå®ã¯IOãä¼´ã£ã¦ããã¨ããã£ãããããã¯ãã®æããããå ´åã¯ãforeign importã®å®ç¾©ããããªãµãã«ããã°ããã
foreign import ccall "add" c_add :: CInt -> CInt -> IO CInt
åæã«ãããªãIOã£ã¦æ¸ãã¦ãä½ãåé¡ããªãã
ã¨ããããããã§Haskellã®ç´ç²ãã¯ä¿ããã¾ãããªãã ããã£ã¦æãã§ããå¤åçµæ§éè¦ã§ãã
ã¾ãæ®éã¯å¯ä½ç¨ã®ç¡ãé¢æ°ãªãã¦ããããå¼ã³ã ããã¨æããªãã ãããããFFIããã¨ãã¯ã ãããIOã£ã¦ä»ããã°ãããã ã¨æãã¾ããæ°å¦ç³»é¢æ°ã§ãä¸ã§malloc/freeã¨ããã£ã¦ããããããªãããã
ã¨ããããã¶ããã£ã¦ã¾ããã«ã¼ãã«ã³ã¼ã«ã¯ãã¹ãããIOã ãæ²¹æãããªï¼
ãã¤ã³ã¿ã¨ã
é¢æ°å¼ã³åºãã®ãã¿ã¼ã³ã«ã¯ããã¤ããã£ã¦ãããã¾ã§ã¿ããã«å¤ãããåãããã¨ããã®ã¯å®ã¯å°æ°æ´¾ã§ãã ãããã¯å¼æ°ãæ ¼ç´ããæ§é ä½ã®ãã¤ã³ã¿ã渡ãããããããã¡ã®ãã¤ã³ã¿ã渡ãããããããã¡ã®ãã¤ã³ã¿ãåãåã£ããããã
readã¨ãwriteã¨ããconnectã¨ãbindã¨ããfopenãexecã¿ãããªæåå渡ããç³»ãããã§ããã
ããããã®ã¯ãããã©ãããã®ã¨ãããã¨ã§ã
ãããããç°¡åãããªmalloc/freeã試ãã¦ã¿ã¾ãã
ã¾ããmalloc/freeã®å®ç¾©ã§ããããããªãããã§ãã
void *malloc(size_t size); void free(void *ptr);
freeã®æ»ãå¤ã®voidã¯ããã¨ãã¦ãmallocã®æ»ãå¤ã¨freeã®å¼æ°ã®void*åã¯ä½ãããä½ã£ã¦ãããå¿ è¦ãããã
ã¨ããã説æããããªãã®ã§çããæ¸ãã¨ãããªãã
import Foreign.C.Types import Foreign.Ptr data CVoid foreign import ccall "malloc" c_malloc :: CSize -> IO (Ptr CVoid) foreign import ccall "free" c_free :: Ptr CVoid -> IO () malloc :: Int -> IO (Ptr CVoid) malloc size = c_malloc $ fromIntegral size free :: Ptr CVoid -> IO () free ptr = c_free ptr
CVoidã¨ãããããã¦ãªåãå®ç¾©ãã¦ãForeign.Ptrã§å®ç¾©ããã¦ããPtrã§å ãããPtr CVoid = void *ãã¨ããæãã§ãã
Ptrã§å ã¾ããåã¯ãPtrã§å ãã§ããéãã¯ä½ã®å¶ç´ããªãã«èªç±ã«ãã£ã¹ããããã§ãã¾ãã
cast :: Ptr CVoid -> Ptr Int cast ptr = castPtr ptr
ãã ãããã以å¤ã®æä½ã¯å ¨ãã§ãã¾ããã
Ptråã¯ãã®åã®éããã¤ã³ã¿ãªãã§ãããããã¤ã³ã¿ã辿ããã¨ããæä½ãããããã§ããªããããã¯è¨±ããã¦ããªããã ããCVoidã¯ãã¼ã¿ã³ã³ã¹ãã©ã¯ã¿ãè¦ããªãããã§ãããã£ã¦ã使ããªããããã
ã¾ãããã ãã ã¨å
¨ãæå³ã¯ãªããã©ããPtrã¯Showã®ã¤ã³ã¹ã¿ã³ã¹ã§ãã¡ã¢ãªã®ã¢ãã¬ã¹ãè¿ã£ã¦ããã®ã§ããããããã¨ã¯ã§ãã¾ãã
main :: IO () main = do p <- malloc 0x1000 print p free p
ãããä½ã®æå³ããããã ã¨ããæãã§ããã©ãCã®ã©ã¤ãã©ãªã§ã¯æåã«åæåé¢æ°ãæ§é ä½ã®ãã¤ã³ã¿ãè¿ãã¦ããã®å¾ã¯é¢æ°ã«ãã¤ã³ã¿ã®å¤ã渡ããªããå¦çããããããæ§é ä½ã®ä¸èº«ã¯ã¦ã¼ã¶ã¯è¦ãªããã¨ããã¿ã¤ãã®ãã®ãçµæ§ãã£ã¦ãããã¯ããã§ããããã¡ã¤ã«èªã¿æ¸ãã¨ããã¾ãã«ããã§ããã
ããã¡ãã£ã¨ã¡ããã¨ã¡ã¢ãªãæ±ãããã£ããForeign.Marshal.Allocã¢ã¸ã¥ã¼ã«ã¨ãã§Storableã®ã¤ã³ã¹ã¿ã³ã¹ã«ãªã£ããã¤ã³ã¿ã確ä¿ãã¦ãpeek/pokeã§èªã¿æ¸ãããã¨ããæãããã¾ããã£ã¦ãããStorableã®ã¤ã³ã¹ã¿ã³ã¹ãªãå¥ã«åé¡ãªãèªã¿æ¸ãã§ããããã§ãã
ãã®ãããã¯ããã¥ã¢ã«è¦ããããããããªè©±ã§ãã
æ§é ä½ã®æ±ãï¼ãããããªãï¼
ããã§ã ãããã®Cé¢æ°ãå¼ã³åºããã¨ã¯ã§ããããã«ãªãã¾ããã
ããä½ãæãããã¾ããã
ã¨è¨ãããã¨ããã§ããã
çµå±æ§é ä½ã®ãã¤ã³ã¿æ¸¡ãã¨ãã¯ã©ãããã®ã£ã¦ãã話ã«ã¯å¾®å¦ã«çãã¦ããªããCã®æ§é ä½ã¨Haskellã®ãã¼ã¿åã®ãããã³ã°æ¹æ³ãããããããªãã
ããããã£ã¼ã«ãæå®ã¨ãã©ãããã®ããªãããããã¾ã§ãããªãã¦ããæ®éã«ã©ããããã ãããã¢ã©ã¤ã³ã¡ã³ãã¨ãã©ããªããã ããã
ã¨ãã£ããããã¯ãªãããã¹ãããã°ã©ã æ¸ãã°è§£æ±ºããããªæ°ããã¾ããã©ã
ããã¾ã§ã¯ã¾ã 調ã¹ã¦ãã¾ããã
次ã¯Data.Bitsã®ä½¿ãæ¹ã§ã調ã¹ãã°ããã®ããªã
ä½ãæ¸ããã¨ãã¦ããã ç§ã¯ã
ã½ã¼ã¹
ä»åéãã ã½ã¼ã¹ã¯ãã¡ãã§ãã念ã®ããã
exercises/ffi at master · yunomu/exercises · GitHub