Here's an example from a recent project. I needed to create UUIDs. Looking around, I found RFC 4122, which describes UUID generation, and helpfully provides a sample implementation in C. Unfortunately, that code generates random UUIDs that aren't very random (32 bits of randomness in a 128 bit value).
Now, I could reimplement this code (or something similar) in Haskell, and fix the lack-of-randomness issue. Or I could find another UUID generator, and reimplement that directly. But really, my goal here is to grab random 128-bit UUID values and move on. Getting distracted by a research project isn't part of the plan.
A little googling found that a version of
uuid_generate(3)is bundled within
e2fsprogs. My target system has
e2fsprogsinstalled, so that's a plus. And, interestingly enough, '
man uuid_generate' on my MacBook turns up this manpage:
UUID_GENERATE(3) UUID_GENERATE(3)(Turns out that Apple includes this as part of the standard C library. Thanks, Apple!)
uuid_generate, uuid_generate_random, uuid_generate_time - create a new
unique UUID value
void uuid_generate(uuid_t out);
void uuid_generate_random(uuid_t out);
void uuid_generate_time(uuid_t out);
Theodore Y. Ts'o
A little more lurking, and I see that a
uuid_tis merely an array of 16 characters. As the man page says, this is an output parameter. (It's odd to see code like this after programming in high level languages for so long, but this is C, and what are you going to do?)
Next, I started paging through the GHC User's Guide and the Standard Libraries documentation, and came up with this declaration:
foreign import ccall unsafe "uuid_generate" uuid_generateThis declaration is a direct translation out of the man page.
:: Ptr Word8 -> IO ()
Next, I needed to construct a 16-byte buffer to receive the UUID value from
uuid_generate, which requires using some functions in the
Foreignlibrary. As soon as
uuid_generatefinishes, the buffer needs to be translated into a Haskell string. Note that the return value is a 128-bit integer, and I want to convert that into sequence of printable hex digits. Here's the more convenient interface into the UUID generator:
import ForeignThats it! Easy Peasy.
import Numeric (showHex)
uuid :: IO String
uuid = allocaBytes 16 $ \p -> do
uuid <- peekArray 16 p
return $ concat $ map toHex uuid
toHex :: Word8 -> String
toHex w = case showHex w "" of
w1:w2: -> w1:w2:
w2: -> '0':w2:
_ -> error "showHex returned "