The Foreign Function Interface (FFI) in Haskell allows Haskell programs to call functions written in other programming languages, such as C. This is particularly useful for leveraging existing libraries, optimizing performance-critical sections of code, or interfacing with system-level APIs.
Key Concepts
-
Foreign Imports and Exports:
- Foreign Import: Calling a function written in another language from Haskell.
- Foreign Export: Making a Haskell function available to be called from another language.
-
Marshalling:
- Converting data between Haskell and the foreign language representation.
-
Safety:
- Safe: Ensures that the foreign function call does not interfere with Haskell's runtime system.
- Unsafe: Assumes the foreign function call will not cause any issues, allowing for potential performance improvements.
Foreign Imports
Syntax
To import a foreign function, you use the foreign import
keyword followed by the calling convention, the function signature, and the function name.
Example
Let's import the sin
function from the C standard library and use it in Haskell.
-- Import the sin function from the C standard library foreign import ccall "math.h sin" c_sin :: Double -> Double main :: IO () main = do let angle = 1.0 let result = c_sin angle putStrLn $ "The sine of " ++ show angle ++ " is " ++ show result
Explanation
foreign import ccall "math.h sin"
: Specifies that we are importing thesin
function from the C header filemath.h
.c_sin :: Double -> Double
: Defines the type signature of the imported function in Haskell.
Foreign Exports
Syntax
To export a Haskell function to be used in another language, you use the foreign export
keyword.
Example
Let's export a Haskell function that calculates the sine of a number.
-- Define a Haskell function hs_sin :: Double -> Double hs_sin x = sin x -- Export the Haskell function foreign export ccall "hs_sin" hs_sin :: Double -> Double
Explanation
foreign export ccall "hs_sin"
: Specifies that we are exporting the Haskell functionhs_sin
to be callable from C.hs_sin :: Double -> Double
: Defines the type signature of the exported function.
Marshalling Data
When interfacing with foreign functions, you often need to convert data between Haskell and the foreign language representation. This process is known as marshalling.
Example
Let's see an example of marshalling a C string to a Haskell string.
import Foreign.C.String (CString, newCString, peekCString) -- Haskell function to convert a C string to a Haskell string cStringToHaskellString :: CString -> IO String cStringToHaskellString cstr = peekCString cstr -- Haskell function to convert a Haskell string to a C string haskellStringToCString :: String -> IO CString haskellStringToCString str = newCString(str)
Explanation
CString
: Represents a C string in Haskell.peekCString
: Converts aCString
to a HaskellString
.newCString
: Converts a HaskellString
to aCString
.
Safety
When importing foreign functions, you can specify whether the call is safe
or unsafe
.
Safe Call
Unsafe Call
Explanation
safe
: Ensures that the foreign function call does not interfere with Haskell's runtime system.unsafe
: Assumes the foreign function call will not cause any issues, allowing for potential performance improvements.
Practical Exercise
Exercise
- Import the
cos
function from the C standard library. - Write a Haskell function that calculates the cosine of a number using the imported
cos
function. - Export the Haskell function to be callable from C.
Solution
-- Import the cos function from the C standard library foreign import ccall "math.h cos" c_cos :: Double -> Double -- Define a Haskell function that uses the imported cos function hs_cos :: Double -> Double hs_cos x = c_cos x -- Export the Haskell function foreign export ccall "hs_cos" hs_cos :: Double -> Double main :: IO () main = do let angle = 1.0 let result = hs_cos angle putStrLn $ "The cosine of " ++ show angle ++ " is " ++ show result
Explanation
foreign import ccall "math.h cos" c_cos :: Double -> Double
: Imports thecos
function from the C standard library.hs_cos :: Double -> Double
: Defines a Haskell function that uses the importedcos
function.foreign export ccall "hs_cos" hs_cos :: Double -> Double
: Exports the Haskell function to be callable from C.
Conclusion
In this section, we explored the Foreign Function Interface (FFI) in Haskell, which allows Haskell programs to call functions written in other languages and vice versa. We covered the syntax for importing and exporting functions, marshalling data, and ensuring safety in foreign function calls. By understanding and utilizing FFI, you can extend the capabilities of your Haskell programs and leverage existing libraries and system-level APIs.
Haskell Programming Course
Module 1: Introduction to Haskell
- What is Haskell?
- Setting Up the Haskell Environment
- Basic Syntax and Hello World
- Haskell REPL (GHCi)