Input/Output

Binary I/O

Some systems (notably Windows 95 and Windows NT) differ in their treatment of binary files and text files. To make the use of binary files easier hbc extend the IOMode type with modes for binaryfile. The new IOMode type looks like this:
    data IOMode = ReadMode
                | WriteMode
                | AppendMode 
                | ReadWriteMode
                | ReadBinaryMode       -- hbc extension
                | WriteBinaryMode      -- hbc extension
                | AppendBinaryMode     -- hbc extension
                | ReadWriteBinaryMode  -- hbc extension
Hbc allows calling C directly from Haskell using the IO monad.

Easy ccall

To enable calling of C functions you need to compile with the -fccall flag and import the CCall module. This enables the language construct ccall.

Calling C has the following form:

  ccall cfunction e1 ... en
The 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

Gory details

You can define new instances of the CValue class. The class declaration looks like this.
class CValue a where
    toCU :: a -> CUnion
    fromCU :: CUnion -> a
The CUnion is used to encode the values used during the C call.
  data CUnion = _CUInt Int
              | _CUDouble Double 
              | _CUString String 
              | _CUPointer CPointer
              | _CUByteVector _ByteVector._ByteVector
The CPointer is used for pointer valued argument/results in C calls. There are some operations available on them:
  nullCPointer :: CPointer
  addCPointer :: CPointer -> Int -> CPointer
There are also two language construct that yield CPointer values:
  cFunction cfunctionname
  cVariable cvariablename
They 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 CUnion
The 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; }

To execute an IO action someplace else than at the top level there is a function
  unsafePerformIO :: IO a -> a
To 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.


Last modified: Thu Feb 6 09:45:18 MET 1997