For several projects I need to embed long strings into Haskell source code.
The obvious way to do this is to unlines
a list of lines. However, reading and maintaining this is cumbersome.
cCode :: String
cCode = unlines [
"int main(int argc*, char** argv)",
" doStuff();",
"}"]
Is there any way you can embed strings without any overhead (like the list as shown above) or even files? Is TemplateHaskell/Quasi-quotation the way to go here?
Note: This question was answered in Q&A form. Therefore it does not show any research effort.
It is possible using QuasiQuotation as described in this blogpost written by me.
Step 1: Create a module (we'll call it StringEmbed.hs
that contains the required functions
module StringEmbed(embedStr, embedStrFile) where
import Language.Haskell.TH
import Language.Haskell.TH.Quote
embedStr :: QuasiQuoter
embedStr = QuasiQuoter { quoteExp = stringE,
quotePat = undefined,
quoteDec = undefined,
quoteType = undefined }
embedStrFile :: QuasiQuoter
embedStrFile = quoteFile embedStr
Note because of TH peculiarities it is not possible to just copy those functions into the module where you use them.
Step 2a: In your module, embed your strings:
{-# LANGUAGE QuasiQuotes #-}
import StringEmbed
cCode :: String
cCode = [embedStr|
int main(int argc, char** argv) {
doStuff();
}
|]
Note that you only have to add the QuasiQuotes
LANGUAGE
pragma. TemplateHaskell
is not required for this technique.
Because QuasiQuotes are delimited using |]
, you can't use that character sequence anywhere in the quasi-quoted string.
Step 2b: You can just as easily embed a file. Let's assume the file code.c
contains the string you intend to embed.
{-# LANGUAGE QuasiQuotes #-}
import StringEmbed
cFooter :: String
cFooter = [embedStrFile|code.c|]
Alternatively you can use one of the many haskell libraries instead of StringEmbed.hs
, for example heredoc (thanks Ørjan Johansen for the tip!)
{-# LANGUAGE QuasiQuotes #-}
import Text.Heredoc
cCode :: String
cCode = [here|
int main(int argc, char** argv) {
doStuff();
}
|]
You can use multi-line strings with gaps. It might not be as smooth as the quasiquoters, but it is standard Haskell.
cCode :: String
cCode = "\
\int main(int argc*, char** argv)\n\
\ doStuff();\n\
\}\n\
\"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With