Monday, September 05, 2016

[fltalwhq] integerLog2 and an introduction to unboxed types

Some notes on using unboxed types in Haskell, and in particular, notes on creating a boxed wrapper for the integer-gmp library function integerLog2# :: Integer -> Int# which returns an unboxed type.

{-# LANGUAGE MagicHash #-}
import GHC.Exts(Int(I#));
import GHC.Integer.Logarithms(integerLog2#);

integerLog2 :: Integer -> Int;
integerLog2 i = if i < 1
then error "must be positive"
-- because integerLog2# does no bounds checking
else I# (integerLog2# i);

The pragma MagicHash prevents GHC from interpreting the hash symbol as an operator.  Without it, one gets error messages like this:

parse error on input `#'
not in scope: `#'

It would be nice if GHC emitted a suggestion of MagicHash on errors like this.

The constructor I# is findable using Hoogle, searching for Int#->Int.

One must use parentheses around the argument to I#.  The standard trick of removing parentheses with the dollar sign results in an error:

bad1 i = I# $ integerLog2# i;

Couldn't match kind `*' with `#'
When matching types
r0 :: *
GHC.Prim.Int# :: #

Using the composition operator in point-free style fails similarly:

bad2 = I# . integerLog2#;

Couldn't match kind `*' with `#'
When matching types
b0 :: *
GHC.Prim.Int# :: #
Expected type: b0 -> Int
Actual type: GHC.Prim.Int# -> Int
In the first argument of `(.)', namely `I#'

Unboxed types are a different "kind", the # kind, than boxed types, which are a * kind.

No comments :