When it is inappropriate to include data as a part of source code into a Haskell program (e.g. data is binary, data is too large, etc.), Template Haskell can be used to safely embed them. The file-embed package is a simple and clean implementation of this idea.
The concept can be expanded into importing data and doing more processing at the compile-time before embedding it. The external data is accessible from a
Q action with
$ stack build ... $ touch data/my3dmodel.bin $ stack build $ # nothing happened
Since the external file being imported is not part of the Haskell source code, making changes to it won’t trigger a re-build. This must be a huge trouble, because each time developers making changes to binary assets will have to somehow manually force the tool chain to build again. Is file-embed susceptible to this?
$ touch data/my3dmodel.bin $ stack build mypackage-0.1.0.0: unregistering (local file changes: data/my3dmodel.bin) mypackage-0.1.0.0: build ...
No. Surprisingly, a file embedded with file-embed seems to have been marked as relevant and will trigger a re-build when changed. This is because the source code of file-embed includes:
embedFile :: FilePath -> Q Exp embedFile fp = #if MIN_VERSION_template_haskell(2,7,0) qAddDependentFile fp >> #endif (runIO $ B.readFile fp) >>= bsToExp
Language.Haskell.TH.Syntax of the template-haskell package has the type signature of
qAddDependentFile :: FilePath -> m ()
and does the job of “marking as relevant.” As the code excerpt from file-embed suggests, the function has been added in 2.7 of the template-haskell package.
Make sure you call
qAddDependentFile when you
runIO $ B.readFile path in a