Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Qualified import of singletons #306

Closed
odr opened this issue Feb 18, 2018 · 7 comments
Closed

Qualified import of singletons #306

odr opened this issue Feb 18, 2018 · 7 comments

Comments

@odr
Copy link

odr commented Feb 18, 2018

If I define in one module

singletons [d| foo = ... |]

and import it qualified (as F) to another module and use F.foo in another template:

singletons [d| bar = F.foo |]

I get errors like Not in scope: type constructor or class ‘FooSym0’
If I import FooSym0 unqualified I also get an error Variable not in scope: sFoo

Is it possible to use qualified names (F.FooSym0, F.sFoo) for qualified name in template?

@RyanGlScott
Copy link
Collaborator

RyanGlScott commented Feb 18, 2018

Is it possible to use qualified names (F.FooSym0, F.sFoo) for qualified name in template?

Unfortunately, no. Template Haskell doesn't give you any way to distinguish between a qualified and non-qualified name, as the following program demonstrates:

{-# LANGUAGE TemplateHaskell #-}

import Language.Haskell.TH
import qualified Prelude
import Prelude

main :: IO ()
main = putStr
  $(do ConT nonQualName <- [t| Bool |]
       ConT qualName    <- [t| Prelude.Bool |]
       stringE $ unlines
                 [ "Non-qualified name " ++ show nonQualName
                 , "Qualified name "     ++ show qualName
                 , "Are they equal? "    ++ show (nonQualName == qualName)
                 ])
λ> main
Non-qualified name GHC.Types.Bool
Qualified name GHC.Types.Bool
Are they equal? True

Therefore, singletons can't generate F.FooSym0 or F.sFoo, as it has no way to know that the original F.foo name was qualified to begin with.

I can't recall if there's an open GHC ticket about this, but one thing is for sure: this is not possible unless Template Haskell were to be changed so that qualified names would be preserved when quoted.

@odr
Copy link
Author

odr commented Feb 19, 2018

Thank you for explanation.
I think it could be done with new QuasiQuoter (say, [dq| ... |]). Am I right?
Though I am not too much interested in it.

@RyanGlScott
Copy link
Collaborator

RyanGlScott commented Feb 19, 2018

I think it could be done with new QuasiQuoter (say, [dq| ... |]). Am I right?

I don't think it would even be possible with quasiquoting. You'd still have to deal with names like F.foo, where F is some qualified prefix. The Template Haskell API for names only gives you NameG and NameQ for dealing with qualified names, but they require giving a full module name, not just a prefix. For instance, if you had import Prelude as Prel, then you'd need to be able to figure out that Prel.show actually means NameG "base" "Prelude" "show", which is a very non-trivial task (especially since Template Haskell doesn't give you the Prel prefix in the first place).

@odr
Copy link
Author

odr commented Feb 19, 2018

Hmm... Maybe it could be done more simple then with QQ?
[d| bar =F.foo|] is something like

[ValD (VarP bar_1) (NormalB (VarE ModuleFoo.foo)) []]

We have to generate other definitions with changing e.g. ModuleFoo.foo to ModuleFoo.sFoo.
Isn't it how it works now? I suppose that now Singletons use just "local" name sFoo, no?
I assume that if we import ModuleFoo qualified it is accessible from TH with its full name (i.e. it doesn't depend on qualified name). It looks natural to me but probably I am too optimistic... I didn't check all these stuffs.

@RyanGlScott
Copy link
Collaborator

RyanGlScott commented Feb 19, 2018

It is true that quoted names do give you the module information, yes. However, this is often not enough to figure out where the singleton definitions are!

For instance, if you quote [| id |], then you'll get a Name that's (roughly) NameG "base" "Prelude" "id". However, the corresponding singleton definitions for id are not in the Prelude—they're in singletons, a completely different package! You'd have the same problem in your scenario, since you cannot know in general whether the singleton definitions for F.foo were defined in the same module that F refers to or not.

In short, this is a complicated problem that's further complicated by Template Haskell inadequacies, and I don't see a straightforward solution.

@goldfirere
Copy link
Owner

I agree with Ryan's summary above. Even if TH could track such qualifications, making use of them would require the assumption that singleton definitions are in the same module as the original definitions. This is not true all the time. I suppose you could also teach singletons a mapping from qualified original names to the modules where the singletons are defined, but that seems overwrought, to me.

My bottom line: singletons does unhygienic, unpleasant things with names. This means that we're never going to be handle all naming situations gracefully. And I don't see a better way while still allowing users to access singletons names without yet more TH.

@RyanGlScott
Copy link
Collaborator

I'll opt to close this, as we can't fix this on singletons's end cleanly. I'll note that there are really two problems here:

  1. Template Haskell cannot generate names of the form F.foo, where F is a qualified prefix.
  2. singletons does not grant users the power to change what names are generated if the default scheme isn't to their liking.

The second issue is surmountable if we fixed #204. The first issue, on the other hand, would need to be fixed by adding more functionality to Template Haskell. So perhaps fixing that could be a jumping point into getting back to this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants