Haskell FFI

소개

FFI(Foreign Function Interface: 외부 함수 인터페이스)는 이름 그대로 Haskell과 다른 언어에서 서로 함수를 불러 쓸 수 있도록 해주는 인터페이스다. 기본적인 사용법은 매우 간단해서 어떤 함수를 사용할 지 선언하기만 하면 된다. FFI를 사용하기 위한 선언의 형태는 기본적으로 다음과 같다.

foreign [import/export] [호출규약] "[C 함수 이름]" [Haskell 함수 이름] :: 자료형

foreign은 FFI 선언을 나타내는 키워드이다. 외부 함수를 불러들일 때는 import, Haskell 함수를 외부로 내보낼 때는 export를 사용한다. 호출규약은 언어에 따라 다른데 C는 ccall, C++은 cplusplus, Java 가상 머신은 jvm, 닷넷 프레임워크는 dotnet, 윈도 API는 stdcall을 사용한다. 대부분의 경우 ccall만을 사용한다. 그 다음엔 C의 함수 이름과 Haskell의 함수 이름을 써주고 자료형을 명시해주면 된다. C의 함수 이름에 따옴표를 쳐주는 이유는 Haskell과 함수 이름을 짓는 방법이 다르기 때문이다.

불러들이기 예제

foreign import ccall "string.h strfry" c_strfry :: CString -> IO CString

위 예는 C의 string.h에 선언된 char* strfry(char* string) 함수를 c_strfry라는 Haskell 함수로 불러들이는 FFI 선언문이다. CString은 C의 char*에 해당하는 자료형이다. 반환값은 CString으로 하든 IO CString으로 하든 컴파일에는 상관이 없지만 실행할 때마다 의미가 달라지는 함수라면 IO를 붙여주는 게 현명하다. strfry는 문자열을 랜덤하게 섞어주는 함수로 당연히 IO를 붙여줘야 한다. 이번에는 좀 더 긴 예를 보도록 하자. 다음 두 개의 파일을 먼저 만든다.

/* add.c */
int add(int x, int y){
    return x + y;
}

-- main.hs
import Foreign.C

foreign import ccall "add" c_add :: CInt -> CInt -> IO CInt

main = c_add 3 5 >>= print

그리고 쉘에서 ghc -ffi main.hs add.c라고 입력하면 add.c를 포함해서 컴파일하여 바이너리로 만들어준다. Foreign.C 모듈은 C 함수를 불러들일 때 기본적으로 필요한 자료형들을 포함한다. CInt는 C의 int에 대응하는 Haskell 자료형이다.

추가할 내용


  1. 내보내기 예제
  2. 고급 예제
  3. DLL 불러들이기, 내보내기
  4. C 외의 다른 언어와 연동