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).

I’d like to add that this was a fairly special case in which interpolation was to some degree justified, though I’d still prefer a better solution. On the whole, direct interpolation of values into strings is a terrible idea: it’s hard (though, as we’ve seen, not impossible) to make type-safe, and requires one to hard-code variable names into strings, which results in fragility and makes refactoring (for example, to add internationalisation) very difficult, as well as being a generally terrible idea — variable names are part of the logic of the application, and changing them, so long as one is consistent about it, should not affect anything outside that layer.
Solutions such as sprintf add something to this: they remove the variable names from the string itself, and make for easier reading (since the chunk of magic syntax in the middle of an otherwise ordinary string is minimised), but still offers one major barrier to separation: order. When tweaking output, it’s often useful to change the order in which generated values appear. For example, a date in traditional English form might be defined as
sprintf "the %d%s of %s, %d" day (suffix day) (monthName month) year, but if we want to change the output format of the date to Japanese, we have to say something likesprintf "%d年%d月%d日" year month day— the logic has to be modified to accommodate changes in the output. This has most of the disadvantages of the original interpretation idea, albeit by a different path.The ideal conceptual solution, then, is to pass in a map of all potentially useful values. This allows the string to refer to them by the name given to them in the map, which can be assured to be consistent and considered part of the public interface of the program rather than something that is meant to be private, like internal variable names, and the keys to appear in any order within the string that they like. Additionally, by only including a few reference names in the string rather than big lumps of code, the magic syntax can be kept small, and the string remains focussed on presentation.
What would be a nice syntax for this, of course, is left as an exercise, but Python’s
"%(day)d%(suffix)s" % { 'day' : day, 'suffix' : suffix(day) }syntax is not a bad starting point, though perhaps a little noisy for my taste.I’m not sure why the public interface is relevant here: this is internal code. As far as refactoring goes, being consistent about refactoring variable names would seem to include changing all references to them, including references in interpolated strings. If there were more automatic refactoring tools in Haskell, I think it would be a stronger point, but every Haskell hacker I know uses either Emacs or Vim.
Once you get to the point of requiring internationalisation, clearly this is a bad approach, but in accordance with Larry Wall (and tangentially referenced in the title), simple things should be simple and hard things should possible. String interpolation is definitely on the simple side.
I was speaking of the ‘public interface’ between the layers of your application. Perhaps my choice of terminology was a little ham-handed.
The point is that strings are data. They need not be generated in the application itself — they can come from anywhere (ideally, somewhere outside the logic layer, if they’re intended to structure output, although indeed this may be premature refactoring in the case of very small applications).
String interpolation is definitely on the simple side, but then, so are all the alternatives. It’s not as if you have to construct a template renderer to use map interpolation. When the alternatives are clearly superior, I don’t see why anyone would stick with sloppy variable interpolation.
I don’t see that they are clearly superior. The alternatives I see are the dictionary based approach that you illustrated, which is syntactically heavy for simple tasks, or the concatenation-based approach, which is hard to read.
Twey: your analysis seems quite disconnected from the actual day to day practice of programming.
You introduce a mapping of day -> day, suffix -> suffix, primarily for the “purity” of it. Sure, the mapping is sometimes useful and should be an option. If you read a template from disk or a network (for whatever reason) then you should have an easy way of pumping data into it.
But if a template is right in your code, it’s silly to introduce a layer of indirection that you do not need right now because you might need it later. Introduce it later. Rewriting the code will be trivial, and rewriting code is what you do when requirements change.
Python itself has converged towards a middle point that allows some “runtime evaluation” within strings but still requires one to pass in the template arguments explicitly:
For many things I prefer Python, but in this particular case I think that you really want both what Ruby has (simple syntax in the normal case) and what Python has (flexibility for dealing with dynamic strings). I don’t remember off the top of my head how easy it is to do the strings dynamically in Ruby, but of course you could fall back on “eval”.