data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode | ReadBinaryMode -- hbc extension | WriteBinaryMode -- hbc extension | AppendBinaryMode -- hbc extension | ReadWriteBinaryMode -- hbc extensionHbc allows calling C directly from Haskell using the IO monad.
Calling C has the following form:
ccall cfunction e1 ... enThe type of a such an expressions is (CValue a)=>a and each of the ei must also have this type. There is no type checking of the C call so it is the responsiblity of the user to ensure that all arguments and return values are used properly.
The types Int, Double, Float, Bool, Char, and String are all instances of the CValue class.
Example:
gammaIO :: Double -> IO Double gammaIO x = ccall lgamma x >>= return . exp
class CValue a where toCU :: a -> CUnion fromCU :: CUnion -> aThe CUnion is used to encode the values used during the C call.
data CUnion = _CUInt Int | _CUDouble Double | _CUString String | _CUPointer CPointer | _CUByteVector _ByteVector._ByteVectorThe CPointer is used for pointer valued argument/results in C calls. There are some operations available on them:
nullCPointer :: CPointer addCPointer :: CPointer -> Int -> CPointerThere are also two language construct that yield CPointer values:
cFunction cfunctionname cVariable cvariablenameThey both correspond to the addressof, `&', operator in C, but since there is no further information about the type of the object you need to have two depending on if it is a function or a variable you need the address of.
The `ccall' construct does in fact unsuger to an invocation of the ccallCU function.
ccallCU :: CPointer -> [CUnion] -> CUnion -> IO CUnionThe first argument is the function to call, the list is the arguments to the call, the CUnion is just used to indicate the return type of the function call.
Note To be able to use `_' as the leading character in identifiers you need to compile with the -no-pedantic flag.
There are a number of C functions available to call for manipulating C pointers (very unsafe, of course).
Int derefChar (p) char *p; { return *p; } Int derefShort(p) short *p; { return *p; } Int derefInt (p) int *p; { return *p; } Int derefLong (p) long *p; { return *p; } Int derefUChar (p) unsigned char *p; { return *p; } Int derefUShort(p) unsigned short *p; { return *p; } Int derefUInt (p) unsigned int *p; { return *p; } Int derefULong (p) unsigned long *p; { return *p; } double derefFloat (p) float *p; { return *p; } double derefDouble (p) double *p; { return *p; } void setChar (p, x) char *p; Int x; { *p = x; } void setShort(p, x) short *p; Int x; { *p = x; } void setInt (p, x) int *p; Int x; { *p = x; } void setLong (p, x) long *p; Int x; { *p = x; } void setFloat (p, x) float *p; double x; { *p = x; } void setDouble (p, x) double *p; double x; { *p = x; } Int identity(x) Int x; { return x; }
unsafePerformIO :: IO a -> aTo get access to it you must import the module UnsafePerformIO.
Using this function can break referential transparency and it is generally unsafe. Use with care, or preferably, not at all.