Reification of out-of-scope variables?

Boespflug, Mathieu m at tweag.io
Fri Apr 8 13:48:39 UTC 2016


Hi all,

the community is increasingly using quasiquotation as a means to
interoperate with foreign languages. E.g. language-c-inline, inline-c
and inline-r allow calling foreign functions using foreign language
syntax, rather than "foreign import" declarations. There are efforts
underway for Java, Javascript and other languages too. The pattern
common to most of these libraries is:

* collect the content of all quasiquotes that appear in a module,
generate a compilable foreign source file based on that, and then link
the object code resulting from compiling that.

When the foreign language is itself statically typed, we need to make
sure we generate code with proper type annotations, including for any
antiquotation variables. In older versions of GHC, we could derive the
type annotations from the inferred Haskell types, but this is not
possible since 7.8 because the types of any variable in the current
"declaration group" are not made available. So libraries like inline-c
ask for some extra verbosity from the user:

mycossin1 :: Double -> IO Double
mycossin1 somex = [cexp| double { cos($(double somex)) * sin($(double
somex)) } |]

The type annotations inside the quasiquote are redundant with the
explicitly provided type signature. C types are typically short
enough, but other languages (e.g. C++, Java), have really long fully
qualified type names, so the extra annotations are a cost.

The are good reasons why types aren't available from within a
declaration group (it was possible to observe the order in which type
inference works), hence why the extra annotations are necessary. But
by the time type checking of the whole module is finished, types are
fixed once and for all. So the question is:

* Could we make it possible to query the types of local variables at
the end of type checking?

The reason I ask is: with 'addModFinalizer' and friends that TH
provides, we're tantalizingly close to being able to generate foreign
code wrappers that have the right types that match those of the
antiquotation variables present in a module.

Template Haskell already provides 'addModFinalizer'. You feed it a Q
action, which will run once the whole module is type checked. If at
that point we could ask, "what's the type of somex (above)?", then we
could let the user write

mycossin2 :: Double -> IO Double
mycossin2 somex = [cexp| cos($somex) * sin($somex) |]

and yet still generate a C file capturing the content of above
quasiquote with the right types:

double module_foo_qq1(double v1)
{
    return (cos(v1) * sin(v1));
}

since we know that somex :: Double and that the Haskell type "Double"
corresponds to C's "double" primitive type.

Bound variables have a unique name associated to them, which we can
get hold of in Template Haskell using the 'var syntax, but

f x = $(let name = 'x in addModFinalizer (reify name >>= \info ->
runIO (print info)) >> [| x |])

results in a compiler error,

    The exact Name `x' is not in scope
      Probable cause: you used a unique Template Haskell name (NameU),
      perhaps via newName, but did not bind it
      If that's it, then -ddump-splices might be useful

because by the time the TH finalizer runs, we're no longer in the scope of x.

But since the names of the local variables are unique, could it
possibly make sense to allow calling reify on them, even outside of
their scope, so as to get at their type?

Best,

Mathieu


More information about the ghc-devs mailing list