diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,13 @@
 Changes
 =======
 
+Version 0.3.3
+-------------
+
+* Expose `Language.Haskell.Names.ModuleSymbols.getTopDecls`
+* Define a `Monoid` instance for `LocalSymbolTable.Table`
+* Support for parallel list comprehensions
+
 Version 0.3.2.8
 ---------------
 
diff --git a/haskell-names.cabal b/haskell-names.cabal
--- a/haskell-names.cabal
+++ b/haskell-names.cabal
@@ -1,5 +1,5 @@
 Name:                   haskell-names
-Version:                0.3.2.8
+Version:                0.3.3
 License:                BSD3
 Author:                 Roman Cheplyaka, Lennart Augustsson
 Maintainer:             Roman Cheplyaka <roma@ro-che.info>
diff --git a/src/Language/Haskell/Names/LocalSymbolTable.hs b/src/Language/Haskell/Names/LocalSymbolTable.hs
--- a/src/Language/Haskell/Names/LocalSymbolTable.hs
+++ b/src/Language/Haskell/Names/LocalSymbolTable.hs
@@ -1,4 +1,5 @@
 -- | This module is designed to be imported qualified.
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 module Language.Haskell.Names.LocalSymbolTable
   ( Table
   , empty
@@ -7,12 +8,14 @@
   ) where
 
 import qualified Data.Map as Map
+import Data.Monoid
 import Language.Haskell.Exts.Annotated
 import Language.Haskell.Names.SyntaxUtils
 import Language.Haskell.Names.Types
 
 -- | Local symbol table — contains locally bound names
 newtype Table = Table (Map.Map NameS SrcLoc)
+  deriving Monoid
 
 addValue :: SrcInfo l => Name l -> Table -> Table
 addValue n (Table vs) =
diff --git a/src/Language/Haskell/Names/ModuleSymbols.hs b/src/Language/Haskell/Names/ModuleSymbols.hs
--- a/src/Language/Haskell/Names/ModuleSymbols.hs
+++ b/src/Language/Haskell/Names/ModuleSymbols.hs
@@ -2,6 +2,7 @@
 module Language.Haskell.Names.ModuleSymbols
   ( moduleSymbols
   , moduleTable
+  , getTopDeclSymbols
   )
   where
 
diff --git a/src/Language/Haskell/Names/Open/Base.hs b/src/Language/Haskell/Names/Open/Base.hs
--- a/src/Language/Haskell/Names/Open/Base.hs
+++ b/src/Language/Haskell/Names/Open/Base.hs
@@ -46,6 +46,12 @@
 initialScope :: Global.Table -> Scope
 initialScope tbl = Scope tbl Local.empty Other []
 
+-- | Merge local tables of two scopes. The other fields of the scopes are
+-- assumed to be the same.
+mergeLocalScopes :: Scope -> Scope -> Scope
+mergeLocalScopes sc1 sc2 =
+  modL lTable (<> sc2 ^. lTable) sc1
+
 -- | The algebra for 'rtraverse'. It's newtype-wrapped because an implicit
 -- parameter cannot be polymorphic.
 newtype Alg w = Alg
diff --git a/src/Language/Haskell/Names/Open/Instances.hs b/src/Language/Haskell/Names/Open/Instances.hs
--- a/src/Language/Haskell/Names/Open/Instances.hs
+++ b/src/Language/Haskell/Names/Open/Instances.hs
@@ -19,6 +19,8 @@
 import Control.Applicative
 import Data.Typeable
 import Data.Lens.Common
+import Data.List
+import qualified Data.Traversable as T
 
 c :: Applicative w => c -> w c
 c = pure
@@ -256,7 +258,16 @@
           <|  scWithStmts -: e
           <*> stmts'
 
-      ParComp {} -> error "haskell-names: parallel list comprehensions are not supported yet"
+      ParComp l e stmtss ->
+        let
+          (stmtss', scsWithStmts) =
+            unzip $ map (\stmts -> chain stmts sc) stmtss
+          scWithAllStmtss = foldl1' mergeLocalScopes scsWithStmts
+        in
+        c ParComp
+          <|  sc -: l
+          <|  scWithAllStmtss -: e
+          <*> T.sequenceA stmtss'
 
       Proc l pat e ->
         let scWithPat = intro pat sc
diff --git a/tests/annotations/ParListComp.hs b/tests/annotations/ParListComp.hs
new file mode 100644
--- /dev/null
+++ b/tests/annotations/ParListComp.hs
@@ -0,0 +1,13 @@
+l1 ax ay az =
+  [ (x,y,z)
+  | x <- ax
+  | y <- ay
+  | z <- az
+  ]
+
+l2 ax ay az =
+  [ (x,y,z)
+  | x <- ax x -- neither of these x's should be in scope
+  | y <- ay x
+  | z <- az x
+  ]
diff --git a/tests/annotations/ParListComp.hs.golden b/tests/annotations/ParListComp.hs.golden
new file mode 100644
--- /dev/null
+++ b/tests/annotations/ParListComp.hs.golden
@@ -0,0 +1,44 @@
+l1       at  1:1 is a value bound here
+ax       at  1:4 is a value bound here
+ay       at  1:7 is a value bound here
+az       at 1:10 is a value bound here
+x        at  2:6 is a local value defined at 3:5
+x        at  2:6 is a local value defined at 3:5
+y        at  2:8 is a local value defined at 4:5
+y        at  2:8 is a local value defined at 4:5
+z        at 2:10 is a local value defined at 5:5
+z        at 2:10 is a local value defined at 5:5
+x        at  3:5 is a value bound here
+ax       at 3:10 is a local value defined at 1:4
+ax       at 3:10 is a local value defined at 1:4
+y        at  4:5 is a value bound here
+ay       at 4:10 is a local value defined at 1:7
+ay       at 4:10 is a local value defined at 1:7
+z        at  5:5 is a value bound here
+az       at 5:10 is a local value defined at 1:10
+az       at 5:10 is a local value defined at 1:10
+l2       at  8:1 is a value bound here
+ax       at  8:4 is a value bound here
+ay       at  8:7 is a value bound here
+az       at 8:10 is a value bound here
+x        at  9:6 is a local value defined at 10:5
+x        at  9:6 is a local value defined at 10:5
+y        at  9:8 is a local value defined at 11:5
+y        at  9:8 is a local value defined at 11:5
+z        at 9:10 is a local value defined at 12:5
+z        at 9:10 is a local value defined at 12:5
+x        at 10:5 is a value bound here
+ax       at 10:10 is a local value defined at 8:4
+ax       at 10:10 is a local value defined at 8:4
+x        at 10:13 is not in scope
+x        at 10:13 is not in scope
+y        at 11:5 is a value bound here
+ay       at 11:10 is a local value defined at 8:7
+ay       at 11:10 is a local value defined at 8:7
+x        at 11:13 is not in scope
+x        at 11:13 is not in scope
+z        at 12:5 is a value bound here
+az       at 12:10 is a local value defined at 8:10
+az       at 12:10 is a local value defined at 8:10
+x        at 12:13 is not in scope
+x        at 12:13 is not in scope
