Poor man's here document

From HaskellWiki
Revision as of 01:17, 3 January 2012 by Treblacy (talk | contribs) (→‎Quasiquoting: update code for recent GHC)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Poor man's heredoc / here document

main = do
  doc <- here "DATA" "Here.hs" [("variable","some"),("substitution","variables")]
  putStrLn doc
  html <- here "HTML" "Here.hs" [("code",doc)]
  putStrLn html

here tag file env = do
  txt <- readFile file
  let (_,_:rest) = span (/="{- "++tag++" START") (lines txt)
      (doc,_) = span (/="   "++tag++" END -}") rest
  return $ unlines $ map subst doc
  where
    subst ('$':'(':cs) = case span (/=')') cs of 
      (var,')':cs) -> maybe ("$("++var++")") id (lookup var env) ++ subst cs
      _ -> '$':'(':subst cs
    subst (c:cs) = c:subst cs
    subst "" = ""

{- DATA START

this is a poor man's here-document

with quotes ", and escapes \, 
and line-breaks, and layout
without escaping \" \\ \n,
without concatenation.

oh, and with $(variable) $(substitution), $(too).
 
   DATA END -}

{- HTML START

<html>
<head><title>very important page</title></head>
<body>
<verb>
$(code)
</verb>
</body>
</html>

   HTML END -}

Even poorer man's here-doc / here-document

If you're just looking to define a multiline string constant, you can just say:

str :: String
str = unlines [
    "Here's a multiline string constant.",
    "\tIt's not as convenient as Perl's here-documents,",
    "\tbut it does the trick for me."
    ]

You can fake interpolation with:

hereDocPraise :: String -> String
hereDocPraise lang = unlines [
    "The language with the best here-document support",
    "in my opinion is " ++ lang ++ "."
    ]

Disadvantages to poorer man's here-docs

  • You still need to escape special characters.
  • It ends with a newline whether you want one or not.

Quasiquoting

-- Str.hs
module Str(str) where

import Language.Haskell.TH
import Language.Haskell.TH.Quote

str = QuasiQuoter { quoteExp = stringE }

-- Main.hs
{-# LANGUAGE QuasiQuotes #-}
module Main where

import Str

foo = [str|This is a multiline string.
It's many lines long.


It contains embedded newlines. And weird stuff:

łe¶→łeđøħeŋønđeøn

It ends here: |]

main = putStrLn foo

-- ghci Str.hs -XQuasiQuotes
{-
-- Note we can only do single-line quotations here

*Str> [str|foo bar baz|]
"foo bar baz"

-}

See also