Type synonyms "not in scope" when using Template Haskell
Asked Answered
G

2

5

I am getting a strange error about a data type being "not in scope" when using Template Haskell.

Here is my Main.hs file:

{-# LANGUAGE TemplateHaskell #-}

module Main where

import Control.Lens
import Data.Aeson
import Data.Aeson.TH

type Foo = Bar

data Baz = Baz
$(deriveJSON defaultOptions ''Baz)
-- $(makeLenses ''Baz)

data Bar = Bar

main :: IO ()
main = print "hello"

When trying to compile it, I get the following error:

test-0.1.0.0: configure
Configuring test-0.1.0.0...
test-0.1.0.0: build
Building test-0.1.0.0...
Preprocessing executable 'test' for test-0.1.0.0...
[1 of 1] Compiling Main             ( Main.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.2.0/build/test/test-tmp/Main.o )

Main.hs:9:12:
    Not in scope: type constructor or class ‘Bar’

--  While building package test-0.1.0.0 using:
      /usr/bin/runhaskell -package=Cabal-1.22.2.0 -clear-package-db -global-package-db -package-db=/home/illabout/.stack/snapshots/x86_64-linux/nightly-2015-06-17/7.10.1/pkgdb/ /tmp/stack1699/Setup.hs --builddir=.stack-work/dist/x86_64-linux/Cabal-1.22.2.0/ build
    Process exited with code: ExitFailure 1

This error occurs whether I use deriveJSON or makeLenses.

If I move the type Foo = Bar line down past the use of Template Haskell, the file compiles fine.

What's causing this error?

Here is a .cabal file and stack.yaml file to compile this:

test.cabal:

name:                test
version:             0.1.0.0
build-type:          Simple
cabal-version:       >=1.10

executable test
  main-is:             Main.hs
  build-depends:       base >=4.8 && <4.9
                     , aeson >= 0.8 && < 0.9
                     , lens >= 4 && < 5
  default-language:    Haskell2010

stack.yaml:

flags: {}
packages:
- '.'
extra-deps: []
resolver: nightly-2015-06-17

This is using ghc-7.10.1.

Garpike answered 13/8, 2015 at 3:43 Comment(0)
G
11

This is caused by declaration groups when using Template Haskell. Here is an excerpt from the GHC Manual:

Top-level declaration splices break up a source file into delcaration groups. A declaration group is the group of declarations created by a top-level declaration splice, plus those following it, down to but not including the next top-level declaration splice. The first declaration group in a module includes all top-level definitions down to but not including the first top-level declaration splice.

Each declaration group is mutually recursive only within the group. Declaration groups can refer to definitions within previous groups, but not later ones.

In my original code, two declaration groups are created:

-- This is the start of the first declaration group.

type Foo = Bar

data Baz = Baz
$(deriveJSON defaultOptions ''Baz)

-- This is the start of the second declaration group.

data Bar = Bar

The first declaration group cannot see Bar, which is causing this error.

Garpike answered 13/8, 2015 at 5:42 Comment(1)
That link to 'GHC Manual' has bitrotted. Try downloads.haskell.org/ghc/latest/docs/users_guide/exts/….Zonate
V
4

Move the data Bar = ... declaration before the template Haskell and it'll work:

type Foo = Bar

data Baz = Baz
data Bar = Bar

$(deriveJSON defaultOptions ''Baz)
$(makeLenses ''Baz)
Venture answered 13/8, 2015 at 3:56 Comment(2)
I realize that this will work. In my question I explicitly state that moving certain lines around will fix this. My question is why this behavior exists, and what is causing it. In my experience, in Haskell it shouldn't matter what order you have declared things. It certainly shouldn't give a compile error.Garpike
@Garpike Order isn't important in Haskell. When you use Template Haskell you cannot assume that.Erinerina

© 2022 - 2024 — McMap. All rights reserved.