
#13608: Expose the type of quasiquotes -------------------------------------+------------------------------------- Reporter: | Owner: facundo.dominguez | facundo.dominguez Type: bug | Status: patch Priority: normal | Milestone: Component: Template Haskell | Version: 8.0.1 Resolution: | Keywords: QuasiQuotes Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: 12778 | Differential Rev(s): Phab:D3610 Wiki Page: | -------------------------------------+------------------------------------- Comment (by facundo.dominguez): I don't submit a GHC proposal yet because we don't have yet a good solution to propose, we only have a problem and a couple of leads to investigate. I state the problem here in a general form. An account that Mathieu did a while ago can be found in ticket:12778#comment:8. Template Haskell quasiquotes allow to embed other languages in Haskell programs. One can use this ability to generate and compile code in a foreign language and then have the result invoked from Haskell. For quasiquotations to be typesafe though, the implementation of the quasiquoter needs to tell the foreign compiler which types are expected of the antiquoted variables and of the returned value. Quasiquoters currently have no way to find the expected return type if the programmer does not supply it explicitly. Let's consider the following example using inline-java. The package `inline-java` implements a quasiquote which allows to embed fragments of Java programs in Haskell modules. {{{ jappendWorld :: Text -> IO Text jappendWorld = [java| $x + " World!" |] }}} This generates some Java code that is compiled by a Java compiler. It also generates some Haskell code which marshals values between Java and Haskell and invokes the result of compiling the Java code. The java code that is generated looks like {{{ class ClassFreshName { public static Object freshName(String x) { return x + " World!"; } } }}} The quasiquoter knows that the antiquote `x` has type `String` in Java, because it knows that `x` has the type `Text` in Haskell and it can marshal the values between the two types. The quasiquoter can find the Haskell type of `x` via the Template Haskell function `reify` as implemented in ticket:11832. However, the quasiquoter has currently no way to find the expected return type. Therefore, it assumes that any return value is of the catch-all Java type `java.lang.Object`. This is problematic, because it is up to the programmer to use the return value in a way appropriate to its type. If the value returned by the quasiquote does not match the type expected by the programmer on the Haskell side, the program has undefined behavior. Solutions: 1. Have the programmer supply the return type, this is how the package `inline-c` works to embed `C` programs in Haskell. This involves effort on the part of the user to write the return type in every quasiquotation. 2. Use typed splices instead of quasiquotes. e.g. {{{ $$(java [string| $x + " World!" |]) }}} Typed splices do expose the expected type to the implementation, and the generated code could be tailored by using type classes. This is rather clumsy to write while quasiquotes are the best fit. 3. Implement typed quasiquotes, so we can write {{{ [java|| $x + " World!" ||] }}} which desugars to {{{ $$(typedQuoteExp java " $x + \" World!\") }}} 4. What this ticket proposed. 5. Similar to (4), but avoid introducing a name with a hash of the location. For this, we extend the type checker so when it finds a splice, it adds a binding to the typing environment which has the type of the splice and an identifier uniquely associated to the splice. Calls to `reify` can then find this binding and yield the type in the same fashion that it is done with antiquoted variables. Let me know if this should still be sent to GHC proposals. Besides that, any thoughts or advice? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13608#comment:12 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler