외부 함수 인터페이스
외부 함수 인터페이스 (Foreign Function Interface)
Haskell만으로는 잘 안 되는 일이 있어요. 이미 C로 짜여진 라이브러리를 그대로 쓰고 싶다든가, 속도가 중요한 코드를 저수준으로 짜야 한다든가 할 때요. 이 장은 Haskell에서 C 같은 다른 언어의 함수를 부르고, 또 Haskell 함수를 다른 언어가 부를 수 있게 하는 외부 함수 인터페이스(FFI) 를 다뤄요. foreign 키워드로 쓰는 FFI 선언의 문법과 규칙이 여기 있어요.
본문
이 장은 Haskell과 외부 세계(주로 C) 사이의 인터페이스를 정의하는 **외부 함수 인터페이스(Foreign Function Interface, FFI)**를 설명해요. FFI는 두 방향으로 동작해요: Haskell이 외부 언어 함수를 호출하고, 외부 언어가 Haskell 함수를 호출하는 것.
topdecl → foreign fdecl
fdecl → import callconv [safety] impent var :: ftype
| export callconv expent var :: ftype
FFI 선언은 foreign 키워드로 시작해요. 4장의 최상위 선언 문법에서 foreign fdecl이 최상위 선언의 한 형태로 허용돼요.
foreign import는 외부 함수를 Haskell로 가져와(import) 쓰겠다는 뜻이에요.foreign export는 Haskell 함수를 외부 세계가 부를 수 있게 내보내겠다는 뜻이에요.
callconv는 호출 규약(calling convention)을 지정해요. 대부분의 구현은 ccall(C 호출)을 지원해요. 추가로 stdcall(Win32) 같은 규약을 지원할 수 있어요.
callconv → ccall | stdcall | ...
safety → safe | unsafe
impent → [string]
expent → [string]
safety는 foreign import에만 의미가 있어요. safe는 Haskell 런타임과 안전하게 상호작용할 수 있는 호출이고, unsafe는 더 빠르지만 외부 함수가 다시 Haskell로 콜백하지 못하게 제한하는 호출이에요.
impent/expent는 선택적 문자열로, 기본값(예: C 심볼 이름이 변수 var와 같다고 가정)을 재정의할 때 써요.
변수 var의 타입 ftype은 다음 규칙을 만족해야 해요:
foreign import에서var는 타입ftype을 가져야 하고, 보통IO-안의 타입이어야 해요. 호출 규약과 기본 타입(마샬링)은 구현이 정해요.foreign export에서var는 타입IO t이거나 그에 해당하는 형태여야 해요.
예시
C의 strlen을 Haskell에서 부르려면:
foreign import ccall unsafe "strlen" c_strlen :: CString -> IO CSize
다른 모듈이 Haskell 함수 foo를 부르게 하려면:
foreign export ccall "foo" foo :: Int -> IO Int
foreign export ccall foo :: Int -> IO Int
새 이름 문자열 "foo"를 제공하면 C 쪽에서 그 이름으로 참조할 수 있어요.
기본 브릿지 타입과 마샬링
FFI로 주고받는 타입은 언어 사이에서 기계적으로 표현 가능한 **기본 타입(primitive types)**이에요. 예를 들어 Int, Word, Float, Double, Char, 포인터 타입 등이 여기에 속해요. Foreign.C.Types 같은 라이브러리 모듈이 C 타입에 대응하는 타입들을 정의해요. Foreign 모듈은 CString, Ptr a, FunPtr a 같은 타입을 제공해요.
올바른 FFI 사용은 보통 Foreign, Foreign.C.Types, Foreign.Marshal.* 같은 모듈을 함께 쓰는 식이에요. 자세한 표준 라이브러리 사양은 Part II에 있어요.
더 알아보기 (Learn more)
- 4장 선언과 바인딩 (Declarations and Bindings) —
foreign fdecl이 최상위 선언으로 어떻게 들어맞는지 봐요. - 6장 미리 정의된 타입과 클래스 (Predefined Types and Classes) — FFI가 주고받는 기본 타입들과
IO타입을 봐요. - 7장 기본 입출력 (Basic Input/Output) —
IO액션이 외부 세계와 상호작용하는 기본 틀을 봐요.