3

I'd like to get both the string and value of arbitrary Haskell code. For example:

f (1+1) -> (2,"1+1")

The reason I want to do this is because I'm writing a programming language and I'd like to provide an option to interpret the code (for fast running, i.e. scripting) or compile it to Haskell code (for efficient runtime). So for each builtin I only want to provide the implementation once. That is I don't want to say

plusop = ((+),"(+)")

I have some ideas involving reading the raw haskell source or a separate script that generates a compiler, but these seem much less elegant that what would be done if this question is possible.

It looks like QuasiQuotation could make this possible, but I can't figure out how to get the Haskell value of the expression if I use it (I can only get the String).

Is it possible? How can it be done?

Darren Smith
  • 207
  • 1
  • 4
  • You can work with a [*Hint Haskell interpreter*](https://hackage.haskell.org/package/hint) – Willem Van Onsem Aug 15 '21 at 20:15
  • True, but I think that could be pretty inefficient as it would be interpreting all code, but with this most of the code in ops is still compiled. Also it is easier to write an interpreter than a compiler (and this would be essentially writing the compiler - although currently that is what I've done so that might not be so bad). – Darren Smith Aug 15 '21 at 20:21

1 Answers1

4

I don't know exactly what you want to do, but here's an example of using Template Haskell to do something similar to your example:

-- TH.hs
{-# LANGUAGE TemplateHaskell #-}
module TH where

import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Ppr

showAndRun :: Q Exp -> Q Exp
showAndRun m = do
  x <- m
  let s = pprint x
  [| ($m, s) |]
-- Main.hs
{-# LANGUAGE TemplateHaskell #-}
import TH

main :: IO ()
main = print $(showAndRun [| 1 + 1 |])
$ runhaskell Main.hs
(2,"1 GHC.Num.+ 1")

I don't know how to pretty print the expression without the qualified GHC.Num prefix. You could try copying the implementation of Language.Haskell.TH.Ppr and change it in the necessary places. Or the easiest is perhaps just a post-processing step where you strip each word that starts with a capital letter and ends in a ..

Noughtmare
  • 9,410
  • 1
  • 12
  • 38
  • 1
    Thanks, this is what I wanted to do! GHC.Num. added in there is fine since that is still haskell code that can be compiled without modification – Darren Smith Aug 15 '21 at 20:58