Haskell Design – Why No ‘Format’ Function for String Interpolation?

designhaskellmakepythonstrings

I'm trying to use Shake and I stumbled upon the following problem: there's no easy and convenient way to interpolate a string. I know about Text.Printf — it's not what I'm looking for. The interpolation syntax I'm talking about is like this:

(Make)

HEADERS_DIR := /some/path/to/dir

CFLAGS := "-g -I$(HEADERS_DIR) -O2"

(Python)

headers_dir = "/some/path/to/dir"

cflags = "-g -I{headers_dir} -O2".format(**locals())

And now compare this to possible Haskell's solution. Firstly:

$ cabal install interpolatedstring-perl6
$ ghci -XExtendedDefaultRules -XQuasiQuotes

And then:

> import Text.InterpolatedString.Perl6 (qq)
> let headers_dir = "/path/to/some/dir"
> [qq| -g -I$headers_dir -O2 |] :: String

While I think Make goes maybe a step too far in its eagerness to interpolate even when not asked, I wonder why Haskell doesn't have a format function like Python does. It could parse the supplied string and pull the value with same name as referenced in pattern:

let headers_dir = "/path/to/some/dir"
format "-g -I$headers_dir -O2"

Is there a specific reason why it's not implemented, or everyone is just happy with Text.Printf's verbosity and/or lengthy setup of interpolation libraries?

Update: A lot of people misinterpret the question as asking about general string formatting, with possibility of precision specification in case of integers, etc. The examples provided demonstrate one specific case of interpolation, which is just "substitute the result of show a at the place of name". It does allow for simpler syntax, and it does not use a variadic function per se.

Best Answer

I suspect it's done as quasiquoting because this will interpolate the string at compile time, and due to the pure nature of functions in Haskell this is possible while other languages lack such ability because of their impure nature.

Think about it, other languages have to do it during runtime each time which is going to be much slower than the compile time once and done quasi-quoted interpolation.

If you want to do it at runtime explicitly then you should be able to do some simple abstractions that take advantage of Haskell's strings being lists, or you could create a different data structure that's similar pretty easily - but I would go for the more efficient quasi-quoted approach if I were doing this in any code I actually cared about.

That said, I found on Hackage the Data.Text.Format package which appears to do C# style substitution pretty straight forward, here's an answer showing an example on SO: String formatting in Haskell - though as noted by Bryan O'Sullivan and others on that question that answer usess an out-dated package and there's a newer one Bryan has created (my guess the Data.Text.Format package is his new one that should be used) so the usage may be slightly different from in that SO example, though appears fairly similar.