TemplateHaskell forces manual declaration ordering?

Hey, all, While refactoring some code, I moved a newtype declaration, and suddenly the compiler (up-to-date ghc-7.6.3 on Debian) started complaining that it wasn't in scope when I attempted to use it in an ADT. I'm still new to Haskell, so I assumed it was my misunderstanding, and looked for documentation of declaration ordering constraints and couldn't find any. So then I went to make a toy case to demonstrate the problem, and it worked: data Baz = Baz { foo :: Foo, bar :: !(Maybe Bar) } newtype Foo = Foo String newtype Bar = Bar String So I started looking at the differences between that and my real code, and the only thing that seemed at all signficant was that I was using TH to generate some lenses. And sure enough, adding that caused it to fail: {-# LANGUAGE TemplateHaskell #-} import Control.Lens data Baz = Baz { foo :: Foo, bar :: !(Maybe Bar) } makeLenses ''Baz newtype Foo = Foo String newtype Bar = Bar String If you feed this to ghci, you now get: test.hs:3:25: Not in scope: type constructor or class `Foo' test.hs:3:45: Not in scope: type constructor or class `Bar' Perhaps you meant `Baz' (line 3) Wondering if lens was somehow doing something so exotic it was breaking things, I tried aeson's TH support instead: {-# LANGUAGE TemplateHaskell #-} import Data.Aeson data Baz = Baz { foo :: Foo, bar :: !(Maybe Bar) } deriveJSON defaultOptions ''Baz newtype Foo = Foo String newtype Bar = Bar String Exact same error. That said, if I move the splices to the end of the file, everything works: {-# LANGUAGE TemplateHaskell #-} import Data.Aeson data Baz = Baz { foo :: Foo, bar :: !(Maybe Bar) } newtype Foo = Foo String newtype Bar = Bar String deriveJSON defaultOptions ''Baz I looked at the GHC docs on TH, and read the wiki page, and didn't see anything suggesting that this was a known limitation, nor did I see a bug in the known bug list that seemed pertinent. So, I'm wondering if I've found an actual bug, or a known limitation whose documentation should be made more prominent (since it seems to me that it has pretty dramatic implications for program structure), or what? And is there any way around it other than moving all the splices to the end of the source file? Mike.

Hi Michael, This is a known limitation. You can't refer to items in splices that haven't already been mentioned in the source. I don't know why it isn't (prominently) documented, it's definitely part of the folklore. Ben On Tue May 20 2014 at 11:43:25, Michael Alan Dorman < mdorman@ironicdesign.com> wrote:
Hey, all,
While refactoring some code, I moved a newtype declaration, and suddenly the compiler (up-to-date ghc-7.6.3 on Debian) started complaining that it wasn't in scope when I attempted to use it in an ADT.
I'm still new to Haskell, so I assumed it was my misunderstanding, and looked for documentation of declaration ordering constraints and couldn't find any. So then I went to make a toy case to demonstrate the problem, and it worked:
data Baz = Baz { foo :: Foo, bar :: !(Maybe Bar) } newtype Foo = Foo String newtype Bar = Bar String
So I started looking at the differences between that and my real code, and the only thing that seemed at all signficant was that I was using TH to generate some lenses. And sure enough, adding that caused it to fail:
{-# LANGUAGE TemplateHaskell #-} import Control.Lens data Baz = Baz { foo :: Foo, bar :: !(Maybe Bar) } makeLenses ''Baz newtype Foo = Foo String newtype Bar = Bar String
If you feed this to ghci, you now get:
test.hs:3:25: Not in scope: type constructor or class `Foo'
test.hs:3:45: Not in scope: type constructor or class `Bar' Perhaps you meant `Baz' (line 3)
Wondering if lens was somehow doing something so exotic it was breaking things, I tried aeson's TH support instead:
{-# LANGUAGE TemplateHaskell #-} import Data.Aeson data Baz = Baz { foo :: Foo, bar :: !(Maybe Bar) } deriveJSON defaultOptions ''Baz newtype Foo = Foo String newtype Bar = Bar String
Exact same error.
That said, if I move the splices to the end of the file, everything works:
{-# LANGUAGE TemplateHaskell #-} import Data.Aeson data Baz = Baz { foo :: Foo, bar :: !(Maybe Bar) } newtype Foo = Foo String newtype Bar = Bar String deriveJSON defaultOptions ''Baz
I looked at the GHC docs on TH, and read the wiki page, and didn't see anything suggesting that this was a known limitation, nor did I see a bug in the known bug list that seemed pertinent.
So, I'm wondering if I've found an actual bug, or a known limitation whose documentation should be made more prominent (since it seems to me that it has pretty dramatic implications for program structure), or what? And is there any way around it other than moving all the splices to the end of the source file?
Mike. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

"edwardsbenj@gmail.com"
This is a known limitation. You can't refer to items in splices that haven't already been mentioned in the source. I don't know why it isn't (prominently) documented, it's definitely part of the folklore.
I'm sure this limitation is documented, I was just oblivious to its implications---naively, the fact that my data declaration wasn't being created by the splice would have seemed to exclude it from consideration. However, your explanation helped me think through the implications, at which point it makes perfect sense---it's not that the declaration is created by the splice, but that it is used in the splice, and must thus be amenable to being fully traversed at the point of the splice, else the splice can't complete its job and compilation can't continue. Thanks again, Mike.

On Tue, May 20, 2014 at 7:00 AM, edwardsbenj@gmail.com < edwards.benj@gmail.com> wrote:
This is a known limitation. You can't refer to items in splices that haven't already been mentioned in the source. I don't know why it isn't (prominently) documented, it's definitely part of the folklore.
I think it's pretty well documented? At least I recall noting it first time I looked into TH. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

I was making the naive assumption that if OP didn't know about it then it
wasn't prominent. That perhaps was a little hasty. There is a discussion of
this very thing in the official user guide. First section, 7.16.1. Syntax.
Ben
On Tue May 20 2014 at 15:20:54, Brandon Allbery
On Tue, May 20, 2014 at 7:00 AM, edwardsbenj@gmail.com < edwards.benj@gmail.com> wrote:
This is a known limitation. You can't refer to items in splices that haven't already been mentioned in the source. I don't know why it isn't (prominently) documented, it's definitely part of the folklore.
I think it's pretty well documented? At least I recall noting it first time I looked into TH.
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

"edwardsbenj@gmail.com"
I was making the naive assumption that if OP didn't know about it then it wasn't prominent. That perhaps was a little hasty. There is a discussion of this very thing in the official user guide. First section, 7.16.1. Syntax.
I'm assuming you're referring to the subsection that begins: * The type environment seen by reify includes all the top-level declaration up to the end of the immediately preceding declaration group, but no more. So I'll just note that the text you refer to---which does, as you note, lay out those limitations---is new with 7.8, and I was using the docs for the compiler version I'm using, 7.6.3. http://www.haskell.org/ghc/docs/7.6.3/html/users_guide/template-haskell.html Perhaps it would have made sense to consult the latest docs, but then it also refers to typed TH expression and other things that don't exist in 7.6.3. :) Mike.

Good catch! Hurray for improving docs. Ben On Wednesday, 21 May 2014 12:37:42, Michael Alan Dorman < mdorman@ironicdesign.com> wrote:
"edwardsbenj@gmail.com"
writes: I was making the naive assumption that if OP didn't know about it then it wasn't prominent. That perhaps was a little hasty. There is a discussion of this very thing in the official user guide. First section, 7.16.1. Syntax.
I'm assuming you're referring to the subsection that begins:
* The type environment seen by reify includes all the top-level declaration up to the end of the immediately preceding declaration group, but no more.
So I'll just note that the text you refer to---which does, as you note, lay out those limitations---is new with 7.8, and I was using the docs for the compiler version I'm using, 7.6.3.
http://www.haskell.org/ghc/docs/7.6.3/html/users_guide/ template-haskell.html
Perhaps it would have made sense to consult the latest docs, but then it also refers to typed TH expression and other things that don't exist in 7.6.3. :)
Mike.
participants (4)
-
Benjamin Edwards
-
Brandon Allbery
-
edwardsbenj@gmail.com
-
Michael Alan Dorman