Search code examples
haskellhsc2hs

What is % in the Haskell preprocessor and how does it relate to types like Uint8 (if at all)?


I'd like to better understand the following code in general.

The instances for MDouble are included in the snippet to demonstrate an example that doesn't use the preprocessor.

#let numarray t = "\
foreign import ccall unsafe mxIs%s :: MXArrayPtr -> IO CBool\n\
instance MXArrayComponent M%s where\n\
  isMXArray a = boolC =.< withMXArray a mxIs%s\n\
  createMXArray s = withNDims s (uncurry $ createNumericArray (mxClassOf (undefined :: M%s)) False) >>= mkMXArray\n\
  \
mxArrayGetOffset = arrayDataGet ;\
mxArraySetOffset = arrayDataSet ;\
mxArrayGetOffsetList = arrayDataGetList ;\
mxArraySetOffsetList = arrayDataSetList\
  \n\
instance MXArrayData MX%s M%s\
", #t, #t, #t, #t, #t, #t
foreign import ccall unsafe mxIsDouble :: MXArrayPtr -> IO CBool
foreign import ccall unsafe mxCreateDoubleScalar :: MXDouble -> IO MXArrayPtr
foreign import ccall unsafe mxGetScalar :: MXArrayPtr -> IO MXDouble
instance MXArrayComponent MDouble where
  isMXArray a = boolC =.< withMXArray a mxIsDouble
  createMXScalar = mxCreateDoubleScalar . hs2mx >=> mkMXArray
  mxScalarGet a = withMXArray a mxGetScalar
  createMXArray s = withNDims s (uncurry $ createNumericArray (mxClassOf (undefined :: Double)) False) >>= mkMXArray
  #arrayDataComponent
instance MXArrayData MXDouble MDouble
#numarray Single
#numarray Int8
#numarray Int16
#numarray Int32
#numarray Int64
#numarray Uint8
#numarray Uint16
#numarray Uint32
#numarray Uint64

But in particular, looks like they are using some types like Uint8 etc., and I'm not sure where these are defined, or why e.g. Word8 isn't used instead. Also, not sure how the %s is being used. I see a lot of references to # in the hsc2hs docs but so far nothing about %.


Solution

  • The key is bolded sentences in the linked docs:

    #let ⟨name⟩ ⟨parameters⟩ = "⟨definition⟩"
    

    Defines a macro to be applied to the Haskell source. Parameter names are comma-separated, not inside parens. Such macro is invoked as other #-constructs, starting with #name. The definition will be put in the C program inside parens as arguments of printf. To refer to a parameter, close the quote, put a parameter name and open the quote again, to let C string literals concatenate. Or use printf's format directives. Values of arguments must be given as strings, unless the macro stringifies them itself using the C preprocessor's #parameter syntax.

    %s specifies a string parameter in printf (and you can see a fuller explanation e.g. here).

    So there's no Uint8 type involved; it's just a string and when you substitute it into numarray you get

    foreign import ccall unsafe mxIsUint8 :: MXArrayPtr -> IO CBool
    instance MXArrayComponent MUint8 where
      ...
    

    and this type is documented here:

    type MUint8 = Word8