1

I have a 'QuasiQuoter' which is useful in source code in Haskell, but also as a standalone application. So, I need to be able to run QuasiQuoter

  1. During the compile time in Haskell - [myGrammar|someCommand|]
  2. In runtime (runtime compilation) in shell - mygrammar 'someCommand'

The first part is easy but the second part might be a little clumsy if solved as calling the compiler with some generated code from the runtime.

I would like to solve a second part of the problem using some nice method in Haskell which doesn't accept only the source code, but accepts QuasyQuoter datatype instead so the code is less clumsy. But I can't find any compilation method like that.

Do you know any? Thanks.

Example of usage

Haskell

The function takes tuple [(a,b,c,d,e)] and returns a list of the strings with the products.

function = [lsql| {1..5}, r=[ a.* |> (*) ], "Product of a.1 * a.2 * ... * a.5 is &a.r"|]

Bash

The command reads from stdin csv with at least 5 numerical columns and returns a list of their products (one per line).

lsql-csv '-, r=[ a.* |> (*) ], "Product of a.1 * a.2 * ... * a.5 is &a.r"'
Přemysl Šťastný
  • 1,676
  • 2
  • 18
  • 39
  • It's not clear what you're trying to accomplish with this. Give a complete example. – leftaroundabout Feb 07 '22 at 12:50
  • @leftaroundabout I have added example, which might be useful in Haskell and in shell and which I would like to both compile using the `QuasiQuoter` datastruct. (both parsed to QuasiQuoter and compiled by Haskell) – Přemysl Šťastný Feb 07 '22 at 13:09

1 Answers1

1

I think the question is how to parse and process a string in a uniform way between a quasiquoter and some other chunk of code. If this interpretation is right, then you just... do that. For example:

-- implementation of these is left to the reader, but can use standard Haskell
-- programming techniques and libraries, like parsec and ADTs and stuff
command :: Parser Command
interpret :: Command -> IO ()
jit :: Command -> Exp -- or Q Exp

Then, in your lsql-csv.hs, you would write something like

main = do
    [s] <- getArgs
    case parse command s of
        Left err -> die (show err)
        Right com -> interpret com

and in your LSql/CSV/QQ.hs, you would write something like

lsql = QuasiQuoter { quoteExp = \s -> case parse command s of
    Left err -> qReport True (show err) >> fail ""
    Right com -> return (jit com) -- or just jit com if that's already a Q Exp
    }
Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • This doesn't solve my problem much, because I have to still implement interpret and jit separatly. Not talking about interpret overhead. - I want `lsql-csv` to compile a binary optimilized code from QuasiQuoter, which will be executed by it. I think, that way it will be at least 10x faster for large CSV files then if I just implemented some interpreter. – Přemysl Šťastný Feb 07 '22 at 15:32
  • 1
    @PřemyslŠťastný If you want the Haskell compiler to be available at runtime things get a bit more complicated. Check out the ghc-api; there's also simplified wrappers like hint. – Daniel Wagner Feb 07 '22 at 15:39
  • Yep, that is exactly what I want. I was thinking about ghc-api, but I would rather use some portable function, like `eval`, which works with any Haskell compiler and not only ghc. – Přemysl Šťastný Feb 07 '22 at 15:43
  • @PřemyslŠťastný what you want is the essence of Common Lisp. it's got [`compile`](http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/fun_compile.html), for one. – Will Ness Feb 07 '22 at 17:06