interp: Tracery-like randomized text interpolation

[ bsd3, interpolation, library, program, text ] [ Propose Tags ]

Please see the README on GitHub at

[Skip to Readme]


Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


  • No Candidates
Versions [RSS],,
Dependencies aeson, base (>=4.7 && <5), bytestring, containers, hspec, interp, megaparsec, mtl, optparse-applicative, parser-combinators, random-fu, rvar, semigroups, text, transformers, unordered-containers, vector [details]
License BSD-3-Clause
Copyright (c) 2019 sam raker
Author sam raker
Category Text, Interpolation
Home page
Bug tracker
Source repo head: git clone
Uploaded by swizzard at 2019-02-18T20:38:43Z
Executables interp
Downloads 1459 total (12 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2019-02-18 [all 1 reports]

Readme for interp-

[back to package description]


A randomized text-interpolation tool inspired by Tracery, in Haskell.



  • Haskell
  • Stack, unless you can work Cabal yourself

Clone this repo, cd into it, and then:

  • if you want to use the CLI, run stack install
  • if you want to use it as a library, just run stack build


Fork this repo, make some changes, run stack test to make sure everything's ok, then (if you want) submit a PR. Thank you!



Usage: interp (--substitutions ARG | SUBST) (--interpolations ARG | INTERP)
  Randomly interpolate values into a template

Available options:
  --substitutions ARG      JSON file containing map of substitutions
  SUBST                    JSON file containing map of substitutions
  --interpolations ARG     file containing text to interpolate
  INTERP                   file containing text to interpolate
  -h,--help                Show this help text

substitutions is the (path to the) file containing the JSON map of substitutions. interpolations is (path to the) file containing the text to interpolate. See below for more on both.


Data.Text.Interp.Interpolate.interp is probably what you'll want to use. It takes a Subst object (usually parsed from JSON, but you can make one yourself) and a NonEmpty list of ITexts. Check out Data.Text.Interp.Types for more on those types.


In both substitution and interpolation files, keys can be comprised of any letter or number, or the characters "_" or "-". Spaces and other punctuation are not allowed and will give you Problems.


{"coolThings": [
   {"name": "computers",
    "reason": "you can do haskell on them"
   {"name": "dogs",
    "reason": "they're good"
 "badThings": [
  {"name": "flat tires",
   "reason": "they make you late"
  {"name": "jobs",
   "reason": "they make you tired"
 "sam": {
   "likes": "computers"

The substitutions file is a JSON file. JSON maps are treated how one would expect. The values in a JSON array are chosen among randomly (but see also below on binding). Regular values are treated regularly, but note:

  • because of how JSON is parsed, all numeric literals are treated as floating-point, so a 1 will be interpolated as "1.0". If this is an issue, just wrap your numbers in quotes and they'll be treated as strings.
  • null values are explicitly forbidden; empty lists and maps should be avoided.


{{ ... }} sets off a thing to interpolate. Keys, corresponding to keys in the substitutions file, can be period-separated to 'dig into' nested maps. Thus, in the example above, sam.likes will be have the value "computers".


Within braces, values can be bound to variables using the syntax ( When a variable is bound, references to that variable will be interpolated with that same value. Thus, given the interpolation template

{{ (cool#coolThings).name }} are cool because {{ cool.reason }}. {{ (bad#badThings).name }} are bad because {{ bad.reason }}.

cool in the first interpolation will be the same as cool in the second. Note that keys within the parentheses are part of the binding, while those after the closing parentheses are interpolated normally--{{ (cool#coolThings).name }} will be either "computers" or "dogs", while {{ cool.reason }} will be "you can do haskell on them" or "they're good", depending on which sub-map was randomly chosen to be bound to cool.

Binding is primarily useful for map values. It's possible to bind arrays, but since array elements are chosen randomly evey time, there's not much of a point. Similarly, there's no real difference between binding a simple value and just using the full path to it, unless you're trying to save characters.



  • Haddock documentation/comments
  • Add positional args in CLI
  • Other formats (e.g. YAML) for substitutions file
  • More features
    • Preprocessing (prepending "a(n)", title casing, etc.)
    • Other stuff??
      • Check Tracery documentation for stuff to steal
    • Web interface??
  • Come up with a better name
  • Publish to Hackage


PRs, issues, feature requests, etc. are always more than welcome! Feel free to hit me up on twitter or email me at sam dot raker at gmail dot com. Let me know if you like this, hate this, wish it were better, wish it were worse, whatever.