 groupEmpty = MkGroup <$> unsafePerformIO $ peek groupEmpty_
 
 
-{-
-This module provides Haskell type that represents values of @MPI_Op@
-type (reduction operations), and predefined reduction operations
-defined in the MPI Report.
--}
-
 -- | Actual Haskell type used depends on the MPI implementation.
 type MPIOperation = {# type MPI_Op #}
+
+{- | Abstract type representing handle for MPI reduction operation
+(that can be used with 'reduce', 'allreduce', and 'reduceScatter').
+-}
 newtype Operation = MkOperation { fromOperation :: MPIOperation } deriving Storable
 peekOperation ptr = MkOperation <$> peek ptr
 withOperation op f = alloca $ \ptr -> do poke ptr (fromOperation op)

            {withRequest* `Request'} -> `()' checkError*- #}
withRequest req f = do alloca $ \ptr -> do poke ptr req
                                           f (castPtr ptr)
{# fun unsafe Scatter as ^
             { id `BufferPtr', id `Count', fromDatatype `Datatype',
               id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromRank `Rank', fromComm `Comm'} -> `()' checkError*- #}

{# fun unsafe Gather as ^
             { id `BufferPtr', id `Count', fromDatatype `Datatype',
               id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromRank `Rank', fromComm `Comm'} -> `()' checkError*- #}

-- We pass counts/displs as Ptr CInt so that caller could supply nullPtr here
-- which would be impossible if we marshal arrays ourselves here.
{# fun unsafe Scatterv as ^
             { id `BufferPtr', id `Ptr CInt', id `Ptr CInt', fromDatatype `Datatype',
               id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromRank `Rank', fromComm `Comm'} -> `()' checkError*- #}
{# fun unsafe Gatherv as ^
             { id `BufferPtr', id `Count', fromDatatype `Datatype',
               id `BufferPtr', id `Ptr CInt', id `Ptr CInt', fromDatatype `Datatype',
               fromRank `Rank', fromComm `Comm'} -> `()' checkError*- #}
{# fun unsafe Allgather as ^
             { id `BufferPtr', id `Count', fromDatatype `Datatype',
               id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromComm `Comm'} -> `()' checkError*- #}
{# fun unsafe Allgatherv as ^
             { id `BufferPtr', id `Count', fromDatatype `Datatype',
               id `BufferPtr', id `Ptr CInt', id `Ptr CInt', fromDatatype `Datatype',
               fromComm `Comm'} -> `()' checkError*- #}
{# fun unsafe Alltoall as ^
             { id `BufferPtr', id `Count', fromDatatype `Datatype',
               id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromComm `Comm'} -> `()' checkError*- #}
{# fun unsafe Alltoallv as ^
             { id `BufferPtr', id `Ptr CInt', id `Ptr CInt', fromDatatype `Datatype',
               id `BufferPtr', id `Ptr CInt', id `Ptr CInt', fromDatatype `Datatype',
               fromComm `Comm'} -> `()' checkError*- #}
-- Reduce, allreduce and reduceScatter could call back to Haskell
-- via user-defined ops, so they should be imported in "safe" mode
{# fun Reduce as ^
             { id `BufferPtr', id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromOperation `Operation', fromRank `Rank', fromComm `Comm'} -> `()' checkError*- #}
{# fun Allreduce as ^
             { id `BufferPtr', id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromOperation `Operation', fromComm `Comm'} -> `()' checkError*- #}
{# fun Reduce_scatter as ^
             { id `BufferPtr', id `BufferPtr', id `Ptr CInt', fromDatatype `Datatype',
               fromOperation `Operation', fromComm `Comm'} -> `()' checkError*- #}
{# fun unsafe Op_create as ^
              {castFunPtr `FunPtr (Ptr t -> Ptr t -> Ptr CInt -> Ptr Datatype -> IO ())', cFromEnum `Bool', alloca- `Operation' peekOperation*} -> `()' checkError*- #}
{# fun Op_free as ^ {withOperation* `Operation'} -> `()' checkError*- #}

{- | Returns a 

{# fun Irecv as irecvPtr
           { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm', castPtr `Ptr Request'} -> `()' checkError*- #}

-- | Broadcast data from one member to all members of the communicator.
{# fun unsafe Bcast as ^
           { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromComm `Comm'} -> `()' checkError*- #}

