https://github.com/ruby0b/custom-interpolation
Customizable string interpolation quasiquoters
https://github.com/ruby0b/custom-interpolation
haskell string-interpolation
Last synced: 3 months ago
JSON representation
Customizable string interpolation quasiquoters
- Host: GitHub
- URL: https://github.com/ruby0b/custom-interpolation
- Owner: ruby0b
- License: bsd-3-clause
- Created: 2023-01-12T02:30:59.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-01-13T15:15:09.000Z (over 2 years ago)
- Last Synced: 2024-05-02T04:20:13.037Z (about 1 year ago)
- Topics: haskell, string-interpolation
- Language: Haskell
- Homepage: https://hackage.haskell.org/package/custom-interpolation
- Size: 12.7 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
- Changelog: changelog.md
- License: LICENSE
Awesome Lists containing this project
README
custom-interpolation
This library provides tools for easily generating string interpolation quasiquoters.
The interpolation behavior is customizable and multiple different interpolation methods may be used in a single quasiquoter.## Usage Examples
### Example 1: Multiple interpolators
Let's define a basic string interpolation quasiquoter that
- interpolates any Haskell expressions using `{}` and
- shows the first 10 elements of a list using `@{}`:```hs
i = interpolateQQ simpleConfig
{ handlers = [ simpleInterpolator {prefix = ""}
, (applyInterpolator [|show . take 10|]) {prefix = "@"} ] }
``````hs
>>> [i|2^10 = {show (2 ^ 10)}. Some Fibonacci numbers: @{let fibs = 1 : 1 : zipWith (+) fibs (tail fibs) in fibs}.|]
"2^10 = 1024. Some Fibonacci numbers: [1,1,2,3,5,8,13,21,34,55]."
```### Example 2: SQL substitution
Now for a more complicated example; defining an SQL query quasiquoter that prevents SQL injection.
We can achieve this by replacing expressions between `{}` with `?` and accumulating the actual expression in the first output of the [`Interpolator`](https://hackage.haskell.org/package/custom-interpolation/docs/CustomInterpolation.html#t:Interpolator) handler.
This allows us to then apply some SQL library function to the string and the accumulated expressions which takes care of the actual substitution.```hs
import Language.Haskell.TH (appE, listE, Exp, Q)-- Need an existential type to wrap the differently typed interpolated expressions
data SQLData = forall a. Show a => SQLData a
instance Show SQLData where show (SQLData x) = show x-- Dummy function that would normally run the query
runSQL sql ds = (sql, ds)-- The quasiquoter itself
consumeInterpolated :: ([Q Exp], Q Exp) -> Q Exp
consumeInterpolated (exprs, strExpr) = appE (appE [|runSQL|] strExpr) (listE (map (appE [|SQLData|]) exprs))sql = interpolateQQ defaultConfig
{ finalize = consumeInterpolated,
handlers = [simpleInterpolator { handler = (\q -> (q, [|"?"|])) }]
}
``````hs
>>> [sql|SELECT * FROM user WHERE id = {(11 ^ 5)} AND lastName = {"Smith"}|]
("SELECT * FROM user WHERE id = ? AND lastName = ?",[161051,"Smith"])
```## Acknowledgements
The [`CustomInterpolation.Parser`](https://github.com/ruby0b/custom-interpolation/blob/main/src/CustomInterpolation/Parser.hs) module was derived from the [`here` package](https://github.com/tmhedberg/here).