Haskell FFI Guide — Foreign Function Interface and C Interoperability
In this tutorial, you will learn about Haskell FFI Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
Haskell FFI enables calling C functions directly using foreign import declarations, with Foreign.Storable for marshalling Haskell values to C memory, ForeignPtr for garbage-collected foreign memory, and alloca for stack allocation.
Basic FFI
import Foreign.C.Types
-- Import C function
foreign import ccall "math.h sin"
c_sin :: CDouble -> CDouble
-- Pure wrapper
sin' :: Double -> Double
sin' x = realToFrac (c_sin (realToFrac x))
-- Import with side effects
foreign import ccall "stdio.h puts"
c_puts :: CString -> IO CInt
Memory Allocation
import Foreign
import Foreign.C.Types
-- Stack allocation with alloca
withInt :: (Ptr CInt -> IO a) -> IO a
withInt = alloca
useInt = withInt $ \ptr -> do
poke ptr 42
val <- peek ptr
print (val :: CInt)
-- Heap allocation
mallocInt :: IO (Ptr CInt)
mallocInt = malloc
freeInt :: Ptr CInt -> IO ()
freeInt = free
Structured Data
import Foreign.Storable
data Point = Point { px :: CDouble, py :: CDouble }
instance Storable Point where
sizeOf _ = 16 -- two doubles
alignment _ = 8
peek ptr = Point
<$> peekByteOff ptr 0
<*> peekByteOff ptr 8
poke ptr (Point x y) = do
pokeByteOff ptr 0 x
pokeByteOff ptr 8 y
ForeignPtr
import Foreign.ForeignPtr
-- Automatically managed foreign memory
mkForeignPtr :: IO (ForeignPtr CInt)
mkForeignPtr = do
ptr <- malloc
newForeignPtr finalizerFree ptr
where
finalizerFree p = free p
-- Using withForeignPtr
useForeign :: ForeignPtr CInt -> IO CInt
useForeign fptr = withForeignPtr fptr peek
Common Mistakes
1. Memory leaks
Forgetting to free allocated memory. Use ForeignPtr for automatic GC-managed cleanup.
2. Wrong type sizes
C types have platform-dependent sizes. Use CInt, CLong, CDouble etc. from Foreign.C.Types for portability.
3. Dangling pointers
Don't use a Ptr after free. ForeignPtr protects against this, but manual management requires care.
Practice Questions
1. How do you import a C function?
foreign import ccall "header.h func_name" haskell_name :: Type.
2. What does alloca do? Allocates memory on the C stack for the duration of a computation. Automatically freed.
3. What is the difference between Ptr and ForeignPtr? Ptr is raw and requires manual management. ForeignPtr is garbage-collected with a finalizer.
FAQ
{{< faq question="Can I call Haskell from C?" >}}
Yes. Use foreign export ccall to make Haskell functions callable from C. Compile with -fno-warn-foreign-safe.
{{< /faq >}}
{{< faq question="How do I handle strings?" >}}
Use CString from Foreign.C.String. Functions: newCString, peekCString, withCString.
{{< /faq >}}
{{< faq question="What is the stable pointer?" >}} Foreign.StablePtr creates a stable reference to a Haskell value that can be passed to C and converted back. {{< /faq >}}
What's Next
Now learn about profiling.
| Topic | Description | Link |
|---|---|---|
| Profiling | Performance profiling | {{< ref "23-profiling" >}} |
| Documentation | Haddock documentation | {{< ref "24-documentation" >}} |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro