String Interpolation in Haskell, or Doing Easy Things the Hard Way 5
sprintf "I have %d pieces of %s at $%d apiece", number, fruit, unit_costor worse,
"I have "+number+" pieces of "+fruit+" at $"+unit_cost+" apiece"when it's possible to write
"I have #{number} pieces of #{fruit} at $#{unit_cost} apiece"
This is the sort of syntactic polish that Ruby excels at, and it's an area where Haskell lags a little: it's not a terribly sexy feature, semantically speaking, and for structured data it's inappropriate anyway - you should be defining a Show instance instead, or possibly Binary if it's large. For the cases it's good for, though, it's very good, and I miss it in Haskell.
Now, this feature is trivial to implement in a dynamically typed language. If it weren't already there, we could easily write code to parse out the #{ } references, and call "eval" to get their values in the current scope - after that, it's just a case of pasting it together. Statically typed languages, however, generally don't have eval, and while Template Haskell does allow you to do some static computation, it stops short of full 'eval' functionality.
I poked at the problem for a while and was about ready to give in when Matt Morrow (mmorrow on #freenode) posted a beautiful solution. Before I go into the solution, here's the interface:
fruit = "apple" unit_cost = 2 number = 10 result=[$here|I have $(number) pieces of $(fruit) at $(unit_cost) dollars apiece, making $(unit_cost * number) dollars|]
Our syntax here is a little different because we're using Template Haskell, but we've kept all of the important parts: our references are still inline, and we can use expressions, not just variables.
Now, for the implementation: Matt's actually written a parser that can take an arbitrary string to the Template Haskell expression equivalent. The quasiquoter defined as 'here' takes the text inside the $( ) brackets, tries to build a Haskell expression out of it, and inserts it as a string into the result, concatenating them all together. The nicest bit is that this is completely typesafe, so we have no nasty surprises at runtime.
the code is here, but it's probably easier to grab it with
sudo cabal install haskell-src-meta
to use it, you'll need
{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
import Language.Haskell.Meta.QQ.HsHere
at the top of your file, and to include the package 'haskell-src-meta' in your cabal file (or on the ghci command line).
random list of things i found over the weekend
- Flymake mode for Emacs and Haskell is very cool, but needs a bit of poking to get right for literate haskell files
- Some of my Haskell from six months ago is … not very good. Every time I see a fromJust, I cringe a little inside
