diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,327 @@
+Change log for curry-frontend
+=============================
+
+Version 2.0.0
+=============
+
+  * Implemented the "MonadFail-Proposal" for curry
+    (see <https://wiki.haskell.org/MonadFail_Proposal>)
+  * Data class (see <https://arxiv.org/abs/1908.10607>)
+  * Fixed bug with partially imported Typeclasses
+  * Fixed bug with parsing of empty blocks
+  * Fixed bug with re-export of record labels
+
+Version 1.0.4
+=============
+
+  * Fixed bug in type checking of instances
+  * Fixed bugs in deriving of `Bounded` instances.
+
+Version 1.0.3
+=============
+
+  * Fixed bug in type checking of typeclasses
+
+Version 1.0.2
+=============
+
+  * Added 'short-ast' and 'ast' as new compilation targets
+  * Fixed bug with wrong type of free variables in the intermediate language.
+  * Fixed bug with generated default implementations of nullary class methods.
+  * Fixed bug in desugaring of record patterns.
+  * Fixed bug that external data declarations weren't considered when
+    AbstractCurry was generated
+
+Version 1.0.1
+=============
+
+  * Fixed bug with wrong order of super classes in selector functions
+    generated by the dictionary transformation.
+  * Changed desugaring of numeric literals. It now generates calls to the
+    functions `Prelude.fromInt` and `Prelude.fromFloat`.
+  * Fixed bug with wrong original names of imported record labels
+  * Fixed bug when compiling type constructor classes with super classes
+  * Adjusted warning message for potentially unreachable pattern matches
+
+Version 1.0.0
+=============
+
+  * Added support for typeclasses as known from Haskell
+
+Version 0.4.2
+=============
+
+  * Improved readability of environment information in dumps
+    (option dump-simple)
+  * Added option to dump all bindings instead of just local ones
+    (dump-all-bindings)
+  * Introduced annotated FlatCurry as a new output format
+    (annotated-flat)
+
+Version 0.4.1
+=============
+
+  * Added a simple cabal test suite
+  * Split import of interfaces/modules and expansion and checking of
+    import specifications into two modules.
+  * Improved error messages generated by export check (fixes #1253)
+  * Split checking and expansion of export specification into two
+    subsequent steps (by Yannik Potdevin, fixes #1335)
+  * Consider parenthesized type expressions in the Curry AST (by Katharina Rahf)
+  * Added syntax extension `ExistentialQuantification` that allows the use
+    of existentially quantified types in data and newtype constructors
+  * Fixed bug that type declarations weren't syntax checked
+
+Version 0.4.0
+=============
+
+  * Refactored AbstractCurry generation
+
+  * Complete refactoring of FlatCurry generation
+
+  * Removed support for Curry's record syntax and introduced Haskell's record
+    syntax instead
+
+  * During desugaring record updates are translated to fcase-expressions instead
+    of introducing explicit update functions
+
+  * HTML generation now places HTML files for hierarchical modules into
+    files named `<Module>_curry.html`, i.e., no sub-folders reflecting
+    the the module name hierarchy are generated. In addition, if the option
+    `--html-dir` is not given, the current directory is used as the output
+    directory.
+
+  * Removed record type extensions
+
+  * Enabled declaration of (mutually) recursive record types
+
+  * Removed expansion of record types in type error messages
+
+  * Replaced `MessageM` monad with `CYT` monads and moved `CYT` monads
+    to package `curry-base`
+
+  * Implemented warnings for overlapping module aliases - fixes #14
+
+  * The check for overlapping rules has been completely refactored and
+    improved to now also handle rigid case expressions.
+
+  * The check for missing pattern matching alternatives now correctly handles
+    String literals - fixes #1048.
+
+  * Added warnings for top-level functions without type signatures - fixes #769
+
+  * Moved pretty-printing of types from Checks.TypeCheck to Base.CurryTypes
+
+  * Type synonyms in typed expressions are now desugared - fixes #921
+
+  * Declaration of operator precedence is now optional in infix operator
+    declarations
+
+  * Moved module `InterfaceEquivalence` to curry-base
+    (`Curry.Syntax.InterfaceEquivalence`)
+
+  * Converted literate Haskell files into simple Haskell files
+
+  * Removed support for FlatCurry XML files.
+
+  * Added syntax extension `NegativeLiterals` to translate negated literals
+    into negative literals instead of a call to `Prelude.negate` and
+    `Prelude.negateFloat`, respectively.
+
+  * The frontend now considers options pragmas of the following form:
+
+    ~~~ {.curry}
+    {-# OPTIONS_CYMAKE opt1 ... optn #-}
+    ~~~
+
+    The string following `OPTIONS_CYMAKE` will be split at white spaces
+    and treated like an ordinary command line argument string.
+
+    If one wishes to provide options containing spaces, e.g., directory
+    paths or alike, this can be achieved by quoting the respective argument
+    using either `'single quotes'` or `'double quotes'` (may bot be mixed).
+
+    Note that *following options are excluded*:
+
+      * A change of the current mode
+        (e.g., change from compilation to HTML generation)
+      * A change of the import  paths
+      * A change of the library paths
+      * A change of the compilation targets
+        (e.g., change from FlatCurry to AbstractCurry)
+
+    These options can only be set via the command line.
+
+  * Refactored the source code HTML generation.
+    The generation now supports full Curry with all supported extensions,
+    i.e., it supports pragmas, record types and functional patterns.
+    Furthermore, the created HTML has been simplified, and updated towards
+    HTML 5.
+
+  * The HTML generation now accepts an option `--htmldir=dir` to specify
+    the output directory of the generated HTML files.
+
+Version 0.3.10
+==============
+
+  * Various improvements of the internal structure.
+
+  * Improved status messages. The compilation status message are now of the form
+
+        [m of n] Compiling/Skipping <Module> (<source file>, <target file>)
+
+  * Implemented support for custom preprocessors. It is now possible to run
+    a custom preprocessor command via the following options:
+
+    * `-F` enables support for a preprocessor
+    * `-pgmF <cmd>` set the preprocessor command to `<cmd>`
+    * `-optF <arg>` adds an additional argument to the preprocessor command
+      (can be repeated to add multiple arguments)
+
+    The preprocessor is applied to all source files which are (re)compiled
+    after unliterating *and after determining the import list*.
+    Consequently, adding modules via the preprocessor will results in
+    compilation errors due to missing imports.
+    On the other hand, the frontend will automatically determine changed
+    files which are then handed to the preprocessor.
+
+    The command is called with at least three arguments:
+
+     #. The (normalised) file name of the source file currently processed.
+        **This name is intended only for reference.**
+     #. The name of the file containing the (potentially unliterated)
+        contents of the original file.
+        **This is the file the preprocessor should read from.**
+     #. The name of the file where the preprocessed source code should go to.
+        **This is the file the preprocessor should write to.**
+     #. Optionally, any additional arguments specified using `-optF`.
+
+Version 0.3.9
+=============
+
+  * Simplified verbosity options by merging options "-v1" and "-v2".
+    Now only "-v0" and "-v1" are supported.
+
+  * Fixed bug in non-exhaustive pattern matching check which occured
+    when retrieving the siblings of a constructor imported using an alias.
+
+  * Fixed bug when using functional patterns in `case`-expressions.
+    Functional patterns are only allowed in the patterns of a function
+    definition and forbidden elsewhere, i.e., in `case`-expressions,
+    `do`-sequences, list comprehensions or lambda expressions.
+
+  * Implementation of module pragmas added. Module pragmas of the following
+    types are now parsed and represented in the abstract syntax tree:
+
+    ~~~ {.curry}
+    {-# LANGUAGE LANG_EXT+ #-}
+    {-# OPTIONS "string" #-}
+    {-# OPTIONS_TOOL "string" #-}
+    module Main where
+    ~~~
+
+    where
+
+      - `LANGEXT+` is a non-empty, comma-separated list of the following
+        language extensions: `AnonFreeVars`, `FunctionalPatterns`,
+        `NoImplicitPrelude`, `Records`
+      - `TOOL` is either `KICS2`, `PAKCS`, or some other tool, represented
+        as `Unknown String`.
+
+    While the distinct language pragmas enable the respective language
+    extensions, the OPTIONS pragma is ignored.
+
+    All other texts given in the pragma braces is ignored and treated as
+    a nested comment.
+
+  * Error message for different arities of function equations now also
+    report the corresponding source code positions.
+
+Version 0.3.8
+=============
+
+  * Implemented warnings for non-exhaustive pattern matchings
+    both in function declarations and `case`-expressions - fixes #349.
+
+  * Extended options to enable/disable certain types of warnings.
+
+  * Fixed problem when defining an operator directly after an import statement
+    without import restrictions - fixes #494.
+
+  * Fixed bug w.r.t. polymorphically typed local variables - fixes #480.
+
+  * Fixed missing polymorphism in record labels - fixes #445.
+
+  * Dumping of intermediate structures improved.
+
+  * Fixed bug in type checking w.r.t. recursive type synonyms - fixes 489.
+
+  * Reactivation of Curry interface files.
+    During adaption of the MCC frontend to FlatCurry the Curry interface
+    files have been deactivated and replaced by FlatCurry's interface
+    files. To allow the later addition of type classes to Curry,
+    they have now been reactivated.
+
+  * Implemented missing semantics of functional patterns in combination
+    with non-linear left-hand-sides and as-patterns.
+
+  * Various improvements.
+
+Version 0.3.7
+=============
+
+  * Support for typed FlatCurry expressions added. Now additional type
+    information given by the programmer as in
+
+    ~~~ {.curry}
+    null (unknown :: [()])
+    ~~~
+
+    is represented in FlatCurry and cann therefore be processed by other
+    programs like PAKCS or KICS2.
+
+Version 0.3.6
+=============
+
+  * Error messages are now sorted according to their source code position.
+
+Version 0.3.5
+=============
+
+  * Improved reporting of mutiple type signatures.
+
+Version 0.3.4
+=============
+
+  * Bug in renaming phase fixed.
+
+Version 0.3.3
+=============
+
+  * Corrected translation of `fcase`-expressions.
+
+Version 0.3.2
+=============
+
+  * Non-linear left-hand-sides now work with guarded expressions - fixes #328.
+
+  * Implemented precedence check - fixes #327.
+
+  * Case completion refactored and corrected - fixes #323.
+
+  * Various improvements and refactorings.
+
+Version 0.3.1
+=============
+
+  * Corrected renaming of anonymous free variables - fixes #288.
+
+Version 0.3.0
+=============
+
+  * Massive refactoring of the previous version.
+
+  * All compiler warnings removed.
+
+  * Fixed various implementation bugs (#9, #16, #19, #29, #289).
+
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,5 @@
 Copyright (c) 1998-2004, Wolfgang Lux
+Copyright (c) 2005-2016, Michael Hanus
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/LIESMICH b/LIESMICH
deleted file mode 100644
--- a/LIESMICH
+++ /dev/null
@@ -1,172 +0,0 @@
-===============================================================================
-==
-==  Münster-Curry-Compiler
-==  Distribution zur Anwendung als Frontend in PAKCS
-==
-==  Letztes Update: 27.10.05
-
-Diese Distribution enthält die modifizierte Version des 
-Münster-Curry-Compilers (MCC) für die Verwendung als Frontend in PAKCS. Dieses 
-System ist u.a. in der Lage aus Curry-Programmen (entwickelt nach 
-PAKCS-Standard) Flat-Darstellungen (FlatCurry ".fcy", FlatInterface ".fint" 
-und FlatXML "_flat.xml"), sowie Abstract-Darstellungen (AbstractCurry ".acy" 
-und untyped AbstractCurry ".uacy") zu generieren.
-
-
-
-1. Installation
----------------
-
-1.1 Installation der Binary-Distribution
-
-Die Binary-Distribution befindet sich in einem tar-Archiv und wird
-durch folgendes Kommando entpackt:
-
-	tar zxvf <Distribution>.tar.gz
-
-Danach steht der Compiler im Verzeichnis 'mcc' zur Verfügung.
-
-
-1.2 Installation der Source-Distribution
-
-Nach dem Entpacken des tar-Archivs mittels
-
-	tar zxvf <Distribution>.tar.gz
-
-kann der Compiler durch Aufruf von 'make' im Verzeichnis 'mcc' installiert
-werden. Bei Recompilierung (z.B. nach Änderungen in der Quelldateien)
-wird empfohlen vor einer erneuten Installation 'make clean' auszuführen.
-
-
-
-Nach erfolgreicher Installation befindet sich in beiden Fällen im Verzeichnis 
-'mcc/bin/' folgende ausführbare Datei:
-
-	cymake		- der Curry-Programm-Builder
-
-Dieses Tool übersetzt Curry-Programme unter Berücksichtigung der Import-
-abhängigkeiten.
-
-
-
-2. Kommandoübersicht
---------------------
-
-In der folgenden Tabelle sind die Optionen zur Generierung der jeweiligen
-Darstellungen für das Kommando 'cymake' aufgelistet:
-
-	--flat		: Erzeugt FlatCurry- und FlatInterface-Datei
-	--xml		: Erzeugt FlatXML-Datei
-	--acy		: Erzeugt (typinferierte) AbstractCurry-Datei
-	--uacy		: Erzeugt ungetypte AbstractCurry-Datei
-
-
-
-3. Erzeugung von FlatCurry- und FlatXML-Programmen
---------------------------------------------------
-
-Die Übersetzung eines Curry-Programms 'file.curry', sowie sämtlicher
-importierter Module nach FlatCurry bzw. FlatInterface, bewirkt folgendes
-Kommando:
-
-	cymake --flat <filename>
-
-Hierdurch werden die Dateien mit den entsprechenden Endungen ".fcy" und
-".fint" generiert. Der Dateiname <filename> kann hierbei mit oder ohne 
-Endung ".curry" bzw. ".lcurry" angegeben werden.
-
-Die analogen Übersetzungen in die FlatXML-Darstellung bewirkt folgendes
-Kommando:
-
-	cymake --xml <file name>
-
-Die hierdurch generierte Flat-XML-Datei hat die Endung '_flat.xml'.
-
-
-
-4. Erzeugung von AbstractCurry-Programmen
------------------------------------------
-
-Die Übersetzung eines Curry-Programms 'file.curry' nach (typgeprüftem)
-AbstractCurry bewirkt folgendes Kommando:
-
-	cymake --acy <filename>
-
-Hierdurch wird die entsprechende Datei (mit der Endung ".acy") generiert.
-Der Dateiname <filename> kann hierbei mit oder ohne Endung ".curry" bzw.
-".lcurry" angegeben werden.
-
-Ungetypte, bzw. typsignierte AbstractCurry-Programme werden mit folgendem
-Kommando generiert:
-
-	cymake --uacy <filename>
-
-Die hierdurch generierte Datei besitzt die Endung ".uacy".
-
-Die Generierung des ungetypten AbstractCurry-Programms findet ohne
-Typüberprüfung statt (d.h. auch Programme mit Typfehlern werden übersetzt).
-Alle Funktionen besitzen entweder die im Quellprogramm angegebenen Typsignatur,
-oder, sofern diese nicht vorhanden ist, den Dummy-Typ "prelude.untyped".
-
-In beiden Fällen werden für die Übersetzung FlatCurry-Dateien 
-für alle importierten Module erzeugt. Dies ist notwendig, da die 
-entsprechenden Interfaces für die Typinferenz (nur im Fall der getypten 
-AbstractCurry-Generierung) und die statisch-semantische Analyse benötigt 
-werden.
-
-
-
-5. Anmerkungen
---------------
-
-- Um die PAKCS-Bibliotheken (insbesondere die Prelude) für Übersetzungen 
-  nutzen zu können muß die Umgebungsvariable 'PAKCS_LIB' auf die
-  entsprechenden Pfade verweisen, z.B. mittels
-
-	export PAKCS_LIB=<pakcs path>/pacs/lib:<pakcs path>/pacs/lib/meta:...
-
-  wobei <pakcs path> das Verzeichnis ist, das die PAKCS-Distribution
-  enthält.
-
-- Im Gegensatz zu PAKCS erlaubt das Frontend die Verwendung anonymer
-  Variablen (dargestellt durch dem Unterstrich '_') in Typdeklarationen,
-  z.B.
-
-	data T _ = C
-
-
-
-Bekannte Probleme
-------------------
-
-- Lambda-, do-, if-, case-, oder let-Ausdrücke, die in Argumenten von
-  Funktionsaufrufen verwendet werden, müssen immer geklammert werden.
-
-- 'let'-Anweisungen dürfen nicht folgendes Layout besitzen:
-
-           let x = <expr>
-               in ...
-
-- Die Regeln einer Funktionsdeklaration müssen immer zusammenstehen, d.h.
-  nicht durch andere Deklarationen unterbrochen werden.
-
-- Es ist bislang nicht möglich, den Konstruktor für leere Listen [], sowie 
-  den Unit-Konstruktor () zu qualifizieren (z.B. führt 'prelude.[]' zu 
-  einem Fehler). Der Listenkonstruktor (:), sowie Tupel-Konstruktoren
-  dagegen sind qualifizierbar.
-
-- FlatXML-Übersetzungen können derzeit mittels der Funktionen aus dem
-  PAKCS-Modul "FlatXML" noch nicht eingelesen werden, da es Unstimmigkeiten
-  zwischen dem generierten und den erforderlichen Formaten gibt.
-
-- Bei der Erzeugung von typgeprüftem AbstractCurry können die im Quelltext
-  verwendeten Bezeichner für Typvariablen nicht ins AbstractCurry-Programm
-  übernommen werden. Stattdessen generiert der Übersetzer neue
-  Bezeichner.
-
-- Bei der Erzeugung von ungetyptem AbstractCurry werden Typsynonyme in
-  Typsignaturen von Funktionen nicht dereferenziert.
-
-- Das Frontend gibt derzeit noch keinerlei Warnungen aus.
-
-
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,65 @@
+# Curry Frontend
+
+The frontend lexes, parses, type-checks and transforms Curry source files into a variety of intermediate formats, including
+
+* **FlatCurry** for program analyzers and backends
+* **AbstractCurry** for program manipulation tools
+* **HTML** for documentation
+
+It is used by the two major Curry compilers, [PAKCS](https://git.ps.informatik.uni-kiel.de/curry/pakcs) and
+[KiCS2](https://git.ps.informatik.uni-kiel.de/curry/kics2).
+
+## Requirements
+
+* Make sure that a recent version of Haskell Stack is installed on your computer
+
+## Building
+
+* To build the project, run `make`.
+* To test the project, run `make runtests`.
+
+The built executable will be located at `bin/curry-frontend`.
+
+## Usage
+
+For a detailed overview of the available options, you can use the following command:
+
+`curry-frontend --help`
+
+### Available Formats
+
+```
+--flat  : Generate a FlatCurry (.fcy) and FlatInterface (.fint) file
+--xml   : Generate a FlatXML (_flat.xml) file
+--acy   : Generate a (type-inferred) AbstractCurry (.acy) file
+--uacy  : Generate an untyped AbstractCurry (.uacy) file
+```
+
+The generation of an untyped AbstractCurry program is performed without
+type checking (i.e. programs with type checks will compile). All functions
+will either have the type signature specified in the source or, if not
+available, the dummy type `prelude.untyped`.
+
+FlatCurry files will always be generated for the imported modules,
+since the interfaces are required for static-semantic analysis and type
+inference (only for typed AbstractCurry).
+
+## Remarks
+
+- To use the PAKCS libraries (especially for the `Prelude`), the environment
+  variable `PAKCS_LIB` has to point to the correct paths, e.g. using
+  
+  `export PAKCS_LIB=[pakcs path]/pacs/lib:[pakcs path]/pacs/lib/meta:...`
+
+  where `[pakcs path]` is the directory containing the PAKCS distribution.
+
+- In contrast to PAKCS, the frontend allow use of anonymous variables
+  (denoted by an underscore `_`) in type declarations, e.g.
+  
+  ```curry
+  data T _ = c
+  ```
+
+## Known Issues
+
+[See GitLab](https://git.ps.informatik.uni-kiel.de/curry/curry-frontend/-/issues)
diff --git a/app/cymake.hs b/app/cymake.hs
new file mode 100644
--- /dev/null
+++ b/app/cymake.hs
@@ -0,0 +1,57 @@
+{- |
+    Module      :  $Header$
+    Description :  Main module
+    Copyright   :  (c) 2005        Martin Engelke
+                       2011 - 2016 Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    Command line tool for generating Curry representations (e.g. FlatCurry,
+    AbstractCurry) for a Curry source file including all imported modules.
+-}
+module Main (main) where
+
+import Curry.Base.Monad (runCYIO)
+
+import Base.Messages
+import Files.CymakePath (cymakeGreeting, cymakeVersion)
+
+import CurryBuilder     (buildCurry)
+import CompilerOpts     (Options (..), CymakeMode (..), getCompilerOpts, usage)
+
+-- |The command line tool cymake
+main :: IO ()
+main = getCompilerOpts >>= cymake
+
+-- |Invoke the curry builder w.r.t the command line arguments
+cymake :: (String, Options, [String], [String]) -> IO ()
+cymake (prog, opts, files, errs) = case optMode opts of
+  ModeHelp             -> printUsage prog
+  ModeVersion          -> printVersion
+  ModeNumericVersion   -> printNumericVersion
+  ModeMake | not (null errs) -> badUsage prog errs
+           | null files      -> badUsage prog ["No input files"]
+           | otherwise       -> runCYIO (mapM_ (buildCurry opts) files) >>=
+                                either abortWithMessages continueWithMessages
+  where continueWithMessages = warnOrAbort (optWarnOpts opts) . snd
+
+-- |Print the usage information of the command line tool
+printUsage :: String -> IO ()
+printUsage prog = putStrLn $ usage prog
+
+-- |Print the program version
+printVersion :: IO ()
+printVersion = putStrLn cymakeGreeting
+
+-- |Print the numeric program version
+printNumericVersion :: IO ()
+printNumericVersion = putStrLn cymakeVersion
+
+-- |Print errors and abort execution on bad parameters
+badUsage :: String -> [String] -> IO ()
+badUsage prog errs = do
+  putErrsLn $ map (\ err -> prog ++ ": " ++ err) errs
+  abortWith ["Try '" ++ prog ++ " --help' for more information"]
diff --git a/curry-frontend.cabal b/curry-frontend.cabal
--- a/curry-frontend.cabal
+++ b/curry-frontend.cabal
@@ -1,71 +1,207 @@
-Name:          curry-frontend
-Version:       0.2.12
-Cabal-Version: >= 1.6
-Synopsis:      Compile the functional logic language Curry to several
+name:          curry-frontend
+version:       2.0.0
+cabal-version: 2.0
+synopsis:      Compile the functional logic language Curry to several
                intermediate formats
-Description:   The Curry Frontend consists of the executable program "cymake".
+description:   The Curry front end consists of the executable program
+               "curry-frontend".
                It is used by various backends to compile Curry programs to
-               an internal representation.
+               an intermediate representation.
                The code is a stripped-down version of an early version of
                the Muenster Curry Compiler
-               (<http://danae.uni-muenster.de/~lux/curry/>)
-Category:      Language
-License:       OtherLicense
-License-File:  LICENSE
-Author:        Wolfgang Lux, Martin Engelke, Bernd Brassel, Holger Siegel
-Maintainer:    Björn Peemöller
-Bug-Reports:   http://www-ps.informatik.uni-kiel.de/redmine/projects/curry-frontend
-Homepage:      http://www.curry-language.org
-Build-Type:    Simple
-Stability:     experimental
+               (<http://danae.uni-muenster.de/curry/>)
+               which has been extended to produce different intermediate
+               representations.
+               For further information, please check
+               <http://curry-language.org>
+category:      Language
+license:       BSD3
+license-file:  LICENSE
+author:        Wolfgang Lux, Martin Engelke, Bernd Brassel, Holger Siegel,
+               Bjoern Peemoeller, Finn Teegen
+maintainer:    fte@informatik.uni-kiel.de
+homepage:      http://curry-language.org
+build-type:    Simple
+stability:     experimental
 
-Extra-Source-Files: LIESMICH
-Data-Files:         src/currydoc.css
+extra-source-files: README.md CHANGELOG.md
 
-Flag split-syb
-  Description: Has the syb functionality been split into the package syb?
-  Default:     True
+data-dir:   data
+data-files: currysource.css
 
-Executable cymake
-  hs-source-dirs: src
-  Main-is:        cymake.hs
-  if flag(split-syb)
-    Build-Depends: base == 4.*, syb
-  else
-    Build-Depends: base == 3.*
-  Build-Depends:
-    curry-base >= 0.2.9 && < 0.3
-    , mtl, old-time, containers, pretty
-  ghc-options: -Wall
-  Other-Modules:    Curry.Syntax.Lexer, Curry.Syntax.LexComb
-                    Curry.Syntax.Parser, Curry.Syntax.LLParseComb
-                    Curry.Syntax.ShowModule, Curry.Syntax.Pretty
-                    Curry.Syntax, Curry.Syntax.Type
-                    Curry.Syntax.Unlit,
-                    Curry.Syntax.Utils,
-                    Curry.Syntax.Frontend,
-                    CurryBuilder, IL.Type
-                    CurryCompilerOpts, Modules, Subst, Arity
-                    CurryDeps, Eval, IL.Pretty, NestEnv, SyntaxCheck, Base
-                    Exports, IL.Scope, SyntaxColoring, CurryEnv
-                    IL.CurryToIL, OldScopeEnv, CurryHtml
-                    IL.XML, PatchPrelude, TopEnv, CaseCompletion
-                    Imports,
-                    TypeCheck,
-                    InterfaceCheck,
-                    Types, PrecCheck
-                    TypeSubst, GenAbstractCurry
-                    Typing
-                    GenFlatCurry, KindCheck, Qual
-                    SCC, Utils
-                    Lift, ScopeEnv, WarnCheck
-                    Desugar,
-                    Simplify
+source-repository head
+  type:     git
+  location: https://git.ps.informatik.uni-kiel.de/curry/curry-frontend.git
 
-Library
-  hs-source-dirs:  src
-  Build-Depends:   filepath
-  Exposed-Modules:
-    Curry.Files.CymakePath
-  Other-Modules:
-    Paths_curry_frontend
+library
+  hs-source-dirs:   src
+  default-language: Haskell2010
+  other-extensions: CPP, TemplateHaskell
+  ghc-options:      -Wall
+  build-depends:
+      base             >= 4.11  && < 4.15
+    , template-haskell >= 2.10  && < 2.16
+    , extra            >= 1.4.6 && < 1.8
+    , transformers     >= 0.5   && < 0.6
+    , mtl              >= 2.2   && < 2.3
+    , directory        >= 1.2   && < 1.4
+    , filepath         >= 1.4   && < 1.5
+    , file-embed       >= 0.0   && < 0.1
+    , containers       >= 0.6   && < 0.7
+    , set-extra        >= 1.4   && < 1.5
+    , bytestring       >= 0.10  && < 0.11
+    , process          >= 1.6   && < 1.7
+    , network-uri      >= 2.6   && < 2.7
+    , pretty           >= 1.1   && < 1.2
+    , binary           >= 0.8   && < 0.9
+    , time             >= 1.9   && < 2.0
+    , parsec           >= 3.1   && < 3.2
+  exposed-modules:
+      Base.AnnotExpr
+    , Base.CurryKinds
+    , Base.CurryTypes
+    , Base.Expr
+    , Base.KindSubst
+    , Base.Kinds
+    , Base.Messages
+    , Base.NestEnv
+    , Base.PrettyKinds
+    , Base.PrettyTypes
+    , Base.SCC
+    , Base.Subst
+    , Base.TopEnv
+    , Base.TypeExpansion
+    , Base.TypeSubst
+    , Base.Types
+    , Base.Typing
+    , Base.Utils
+    , Checks
+    , Checks.DeriveCheck
+    , Checks.ExportCheck
+    , Checks.ExtensionCheck
+    , Checks.ImportSyntaxCheck
+    , Checks.InstanceCheck
+    , Checks.InterfaceCheck
+    , Checks.InterfaceSyntaxCheck
+    , Checks.KindCheck
+    , Checks.PrecCheck
+    , Checks.SyntaxCheck
+    , Checks.TypeCheck
+    , Checks.TypeSyntaxCheck
+    , Checks.WarnCheck
+    , Curry.AbstractCurry
+    , Curry.AbstractCurry.Files
+    , Curry.AbstractCurry.Type
+    , Curry.Base.Ident
+    , Curry.Base.LexComb
+    , Curry.Base.LLParseComb
+    , Curry.Base.Message
+    , Curry.Base.Monad
+    , Curry.Base.Position
+    , Curry.Base.Pretty
+    , Curry.Base.Span
+    , Curry.Base.SpanInfo
+    , Curry.CondCompile.Parser
+    , Curry.CondCompile.Transform
+    , Curry.CondCompile.Type
+    , Curry.Files.Filenames
+    , Curry.Files.PathUtils
+    , Curry.Files.Unlit
+    , Curry.FlatCurry
+    , Curry.FlatCurry.Files
+    , Curry.FlatCurry.Goodies
+    , Curry.FlatCurry.InterfaceEquivalence
+    , Curry.FlatCurry.Pretty
+    , Curry.FlatCurry.Type
+    , Curry.FlatCurry.Typeable
+    , Curry.FlatCurry.Annotated.Goodies
+    , Curry.FlatCurry.Annotated.Type
+    , Curry.FlatCurry.Typed.Goodies
+    , Curry.FlatCurry.Typed.Type
+    , Curry.Syntax
+    , Curry.Syntax.Extension
+    , Curry.Syntax.InterfaceEquivalence
+    , Curry.Syntax.Lexer
+    , Curry.Syntax.Parser
+    , Curry.Syntax.Pretty
+    , Curry.Syntax.ShowModule
+    , Curry.Syntax.Type
+    , Curry.Syntax.Utils
+    , CompilerEnv
+    , CompilerOpts
+    , CondCompile
+    , CurryBuilder
+    , CurryDeps
+    , Env.Class
+    , Env.Instance
+    , Env.Interface
+    , Env.ModuleAlias
+    , Env.OpPrec
+    , Env.Type
+    , Env.TypeConstructor
+    , Env.Value
+    , Exports
+    , Files.CymakePath
+    , Generators
+    , Generators.GenAbstractCurry
+    , Generators.GenFlatCurry
+    , Generators.GenTypedFlatCurry
+    , Generators.GenAnnotatedFlatCurry
+    , Html.CurryHtml
+    , Html.SyntaxColoring
+    , IL
+    , IL.Pretty
+    , IL.ShowModule
+    , IL.Type
+    , IL.Typing
+    , Imports
+    , Interfaces
+    , Modules
+    , TokenStream
+    , Transformations
+    , Transformations.CaseCompletion
+    , Transformations.CurryToIL
+    , Transformations.Derive
+    , Transformations.Desugar
+    , Transformations.Dictionary
+    , Transformations.Lift
+    , Transformations.Newtypes
+    , Transformations.Qual
+    , Transformations.Simplify
+    , Paths_curry_frontend
+  autogen-modules:
+      Paths_curry_frontend
+
+executable curry-frontend
+  hs-source-dirs:   app
+  main-is:          cymake.hs
+  default-language: Haskell2010
+  ghc-options:      -Wall
+  build-depends:
+      base >= 4.11
+    , curry-frontend
+
+test-suite test-frontend
+  type:             detailed-0.9
+  hs-source-dirs:   test
+  test-module:      TestFrontend
+  default-language: Haskell2010
+  other-extensions: CPP, TemplateHaskell
+  ghc-options:      -Wall
+  build-depends:
+      base >= 4.11
+    , Cabal >= 1.20
+    , template-haskell >= 2.10
+    , extra >= 1.4.6
+    , transformers
+    , mtl
+    , directory >= 1.2.0.1
+    , filepath
+    , file-embed
+    , containers
+    , set-extra
+    , bytestring >= 0.10
+    , process
+    , network-uri >= 2.6
+    , pretty
+    , curry-frontend
diff --git a/data/currysource.css b/data/currysource.css
new file mode 100644
--- /dev/null
+++ b/data/currysource.css
@@ -0,0 +1,95 @@
+:root {
+  --link-bg-color: lightyellow;
+  --line-number-color: grey;
+  --pragma-color: green;
+  --comment-color: green;
+  --keyword-color: blue;
+  --symbol-color: red;
+  --type-color: orange;
+  --cons-color: magenta;
+  --label-color: darkgreen;
+  --func-color: purple;
+  --ident-color: black;
+  --module-color: brown;
+  --number-color: teal;
+  --string-color: maroon;
+  --char-color: maroon;
+  color-scheme: light dark;
+}
+
+body {
+  font-family: monospace;
+  text-size-adjust: none;
+  -moz-text-size-adjust: none;
+  -ms-text-size-adjust: none;
+  -webkit-text-size-adjust: none;
+}
+
+table {
+  border-collapse: collapse;
+}
+
+/* Hyperlinks */
+a:link,
+a:visited,
+a:active {
+  background: var(--link-bg-color);
+  text-decoration: none;
+}
+
+/* Line numbers */
+.line-numbers {
+  border-right: 1px solid var(--line-number-color);
+  color: var(--line-number-color);
+  min-width: 5ch;
+  padding-right: 1em;
+  text-align: right;
+}
+
+/* Source code */
+.source-code {
+  padding-left: 1em;
+}
+
+/* Code highlighting */
+.pragma  { color: var(--pragma-color)  }
+.comment { color: var(--comment-color) }
+.keyword { color: var(--keyword-color) }
+.symbol  { color: var(--symbol-color)  }
+.type    { color: var(--type-color)    }
+.cons    { color: var(--cons-color)    }
+.label   { color: var(--label-color)   }
+.func    { color: var(--func-color)    }
+.ident   { color: var(--ident-color)   }
+.module  { color: var(--module-color)  }
+.number  { color: var(--number-color)  }
+.string  { color: var(--string-color)  }
+.char    { color: var(--char-color)    }
+
+@supports not (color-scheme: light dark) {
+  @media (prefers-color-scheme: dark) {
+    html {
+      background: hsl(0, 0%, 12%);
+      color: white;
+    }
+  }
+}
+
+@media (prefers-color-scheme: dark) {
+  :root {
+    --link-bg-color: hsl(0, 0%, 17%);
+    --pragma-color: hsl(0, 0%, 60%);
+    --comment-color: hsl(0, 0%, 60%);
+    --keyword-color: hsl(300, 66%, 70%);
+    --symbol-color: hsl(0, 66%, 70%);
+    --type-color: hsl(60, 66%, 70%);
+    --cons-color: hsl(330, 66%, 70%);
+    --label-color: hsl(240, 66%, 70%);
+    --func-color: hsl(200, 66%, 70%);
+    --ident-color: hsl(0, 0%, 85%);
+    --module-color: hsl(20, 66%, 70%);
+    --number-color: hsl(180, 66%, 70%);
+    --string-color: hsl(120, 66%, 70%);
+    --char-color: hsl(120, 66%, 70%);
+  }
+}
diff --git a/src/Arity.hs b/src/Arity.hs
deleted file mode 100644
--- a/src/Arity.hs
+++ /dev/null
@@ -1,133 +0,0 @@
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---
--- Arity - provides functions for expanding the arity environment 'ArityEnv'
---         (see Module "Base")
---
--- September 2005,
--- Martin Engelke (men@informatik.uni-kiel.de)
---
-module Arity (bindArities) where
-
-import Curry.Base.Ident
-import Curry.Syntax
-
-import Base(ArityEnv, bindArity)
-
-
--------------------------------------------------------------------------------
-
--- Expands the arity envorinment with (global / local) function arities and
--- constructor arities
-bindArities :: ArityEnv -> Module -> ArityEnv
-bindArities aEnv (Module mid _ decls)
-   = foldl (visitDecl mid) aEnv decls
-
-
--------------------------------------------------------------------------------
-
-visitDecl :: ModuleIdent -> ArityEnv -> Decl -> ArityEnv
-visitDecl mid aEnv (DataDecl _ _ _ cdecls)
-   = foldl (visitConstrDecl mid) aEnv cdecls
-visitDecl mid aEnv (ExternalDecl _ _ _ id texpr)
-   = bindArity mid id (typeArity texpr) aEnv
-visitDecl mid aEnv (FunctionDecl _ id equs)
-   = let (Equation _ lhs rhs) = head equs
-     in  visitRhs mid (visitLhs mid id aEnv lhs) rhs
-visitDecl _ aEnv _ = aEnv
-
-
-visitConstrDecl :: ModuleIdent -> ArityEnv -> ConstrDecl -> ArityEnv
-visitConstrDecl mid aEnv (ConstrDecl _ _ id texprs)
-   = bindArity mid id (length texprs) aEnv
-visitConstrDecl mid aEnv (ConOpDecl _ _ _ id _)
-   = bindArity mid id 2 aEnv
-
-
-visitLhs :: ModuleIdent -> Ident -> ArityEnv -> Lhs -> ArityEnv
-visitLhs mid _ aEnv (FunLhs id params)
-   = bindArity mid id (length params) aEnv
-visitLhs mid id aEnv (OpLhs _ _ _)
-   = bindArity mid id 2 aEnv
-visitLhs _ _ aEnv _ = aEnv
-
-
-visitRhs :: ModuleIdent -> ArityEnv -> Rhs -> ArityEnv
-visitRhs mid aEnv (SimpleRhs _ expr decls)
-   = foldl (visitDecl mid) (visitExpression mid aEnv expr) decls
-visitRhs mid aEnv (GuardedRhs cexprs decls)
-   = foldl (visitDecl mid) (foldl (visitCondExpr mid) aEnv cexprs) decls
-
-
-visitCondExpr :: ModuleIdent -> ArityEnv -> CondExpr -> ArityEnv
-visitCondExpr mid aEnv (CondExpr _ cond expr)
-   = visitExpression mid (visitExpression mid aEnv expr) cond
-
-
-visitExpression :: ModuleIdent -> ArityEnv -> Expression -> ArityEnv
-visitExpression mid aEnv (Paren expr)
-   = visitExpression mid aEnv expr
-visitExpression mid aEnv (Typed expr _)
-   = visitExpression mid aEnv expr
-visitExpression mid aEnv (Tuple _ exprs)
-   = foldl (visitExpression mid) aEnv exprs
-visitExpression mid aEnv (List _ exprs)
-   = foldl (visitExpression mid) aEnv exprs
-visitExpression mid aEnv (ListCompr _ expr stmts)
-   = foldl (visitStatement mid) (visitExpression mid aEnv expr) stmts
-visitExpression mid aEnv (EnumFrom expr)
-   = visitExpression mid aEnv expr
-visitExpression mid aEnv (EnumFromThen expr1 expr2)
-   = foldl (visitExpression mid) aEnv [expr1,expr2]
-visitExpression mid aEnv (EnumFromTo expr1 expr2)
-   = foldl (visitExpression mid) aEnv [expr1,expr2]
-visitExpression mid aEnv (EnumFromThenTo expr1 expr2 expr3)
-   = foldl (visitExpression mid) aEnv [expr1,expr2,expr3]
-visitExpression mid aEnv (UnaryMinus _ expr)
-   = visitExpression mid aEnv expr
-visitExpression mid aEnv (Apply expr1 expr2)
-   = foldl (visitExpression mid) aEnv [expr1,expr2]
-visitExpression mid aEnv (InfixApply expr1 _ expr2)
-   = foldl (visitExpression mid) aEnv [expr1,expr2]
-visitExpression mid aEnv (LeftSection expr _)
-   = visitExpression mid aEnv expr
-visitExpression mid aEnv (RightSection _ expr)
-   = visitExpression mid aEnv expr
-visitExpression mid aEnv (Lambda _ _ expr)
-   = visitExpression mid aEnv expr
-visitExpression mid aEnv (Let decls expr)
-   = foldl (visitDecl mid) (visitExpression mid aEnv expr) decls
-visitExpression mid aEnv (Do stmts expr)
-   = foldl (visitStatement mid) (visitExpression mid aEnv expr) stmts
-visitExpression mid aEnv (IfThenElse _ expr1 expr2 expr3)
-   = foldl (visitExpression mid) aEnv [expr1,expr2,expr3]
-visitExpression mid aEnv (Case _ expr alts)
-   = visitExpression mid (foldl (visitAlt mid) aEnv alts) expr
-visitExpression _ aEnv _ = aEnv
-
-
-visitStatement :: ModuleIdent -> ArityEnv -> Statement -> ArityEnv
-visitStatement mid aEnv (StmtExpr _ expr)
-   = visitExpression mid aEnv expr
-visitStatement mid aEnv (StmtDecl decls)
-   = foldl (visitDecl mid) aEnv decls
-visitStatement mid aEnv (StmtBind _ _ expr)
-   = visitExpression mid aEnv expr
-
-
-visitAlt :: ModuleIdent -> ArityEnv -> Alt -> ArityEnv
-visitAlt mid aEnv (Alt _ _ rhs)
-   = visitRhs mid aEnv rhs
-
-
-
--------------------------------------------------------------------------------
-
--- Computes the function arity using a type expression
-typeArity :: TypeExpr -> Int
-typeArity (ArrowType _ t2) = 1 + typeArity t2
-typeArity _                = 0
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
diff --git a/src/Base.lhs b/src/Base.lhs
deleted file mode 100644
--- a/src/Base.lhs
+++ /dev/null
@@ -1,557 +0,0 @@
-% $Id: Base.lhs,v 1.77 2004/02/15 22:10:25 wlux Exp $
-%
-% Copyright (c) 1999-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{Base.lhs}
-\section{Common Definitions for the Compiler}
-
-The module Base implements the anti-pattern 'God-object'.
-By providing definitions for various unrelated phases of the
-compiler, it irrevocably turns the module structure into spaghetti.
-(hsi, 2009)
-
-\begin{verbatim}
-
-> module Base where
-
-> import Data.List
-> import Control.Monad
-> import Data.Maybe
-> import qualified Data.Map as Map
-
-> import Curry.Base.Ident 
-> import Curry.Base.Position
-> import Types
-> import qualified Curry.Syntax as CS
-> import Curry.Syntax.Utils
-> import TopEnv
-> import Utils
-
-
-
-\end{verbatim}
-\paragraph{Types}
-The functions \texttt{toType}, \texttt{toTypes}, and \texttt{fromType}
-convert Curry type expressions into types and vice versa. The
-functions \texttt{qualifyType} and \texttt{unqualifyType} add and
-remove module qualifiers in a type, respectively.
-
-When Curry type expression are converted with \texttt{toType} or
-\texttt{toTypes}, type variables are assigned ascending indices in the
-order of their occurrence. It is possible to pass a list of additional
-type variables to both functions which are assigned indices before
-those variables occurring in the type. This allows preserving the
-order of type variables in the left hand side of a type declaration.
-\begin{verbatim}
-
-> toQualType :: ModuleIdent -> [Ident] -> CS.TypeExpr -> Type
-> toQualType m tvs = qualifyType m . toType tvs
-
-> toQualTypes :: ModuleIdent -> [Ident] -> [CS.TypeExpr] -> [Type]
-> toQualTypes m tvs = map (qualifyType m) . toTypes tvs
-
-> toType :: [Ident] -> CS.TypeExpr -> Type
-> toType tvs ty = toType' (Map.fromList (zip (tvs ++ tvs') [0..])) ty
->   where tvs' = [tv | tv <- nub (fv ty), tv `notElem` tvs]
-
-> toTypes :: [Ident] -> [CS.TypeExpr] -> [Type]
-> toTypes tvs tys = map (toType' (Map.fromList (zip (tvs ++ tvs') [0..]))) tys
->   where tvs' = [tv | tv <- nub (concatMap fv tys), tv `notElem` tvs]
-
-> toType' :: Map.Map Ident Int -> CS.TypeExpr -> Type
-> toType' tvs (CS.ConstructorType tc tys) =
->   TypeConstructor tc (map (toType' tvs) tys)
-> toType' tvs (CS.VariableType tv) =
->   maybe (internalError ("toType " ++ show tv)) TypeVariable (Map.lookup tv tvs)
-> toType' tvs (CS.TupleType tys)
->   | null tys = TypeConstructor (qualify unitId) []
->   | otherwise = TypeConstructor (qualify (tupleId (length tys'))) tys'
->   where tys' = map (toType' tvs) tys
-> toType' tvs (CS.ListType ty) = TypeConstructor (qualify listId) [toType' tvs ty]
-> toType' tvs (CS.ArrowType ty1 ty2) =
->   TypeArrow (toType' tvs ty1) (toType' tvs ty2)
-> toType' tvs (CS.RecordType fs rty) =
->   TypeRecord (concatMap (\ (ls,ty) -> map (\l -> (l, toType' tvs ty)) ls) fs)
->              (maybe Nothing 
->	              (\ty -> case toType' tvs ty of
->	                        TypeVariable tv -> Just tv 
->	                        _ -> internalError ("toType " ++ show ty))
->	              rty)
-
-> fromQualType :: ModuleIdent -> Type -> CS.TypeExpr
-> fromQualType m = fromType . unqualifyType m
-
-> fromType :: Type -> CS.TypeExpr
-> fromType (TypeConstructor tc tys)
->   | isTupleId c = CS.TupleType tys'
->   | c == listId && length tys == 1 = CS.ListType (head tys')
->   | c == unitId && null tys = CS.TupleType []
->   | otherwise = CS.ConstructorType tc tys'
->   where c = unqualify tc
->         tys' = map fromType tys
-> fromType (TypeVariable tv) =
->   CS.VariableType (if tv >= 0 then nameSupply !! tv
->                            else mkIdent ('_' : show (-tv)))
-> fromType (TypeConstrained tys _) = fromType (head tys)
-> fromType (TypeArrow ty1 ty2) = CS.ArrowType (fromType ty1) (fromType ty2)
-> fromType (TypeSkolem k) = CS.VariableType (mkIdent ("_?" ++ show k))
-> fromType (TypeRecord fs rty) = 
->   CS.RecordType (map (\ (l,ty) -> ([l], fromType ty)) fs)
->              (maybe Nothing (Just . fromType . TypeVariable) rty)
-
-
-
-\end{verbatim}
-\paragraph{Interfaces}
-The compiler maintains a global environment holding all (directly or
-indirectly) imported interfaces.
-
-The function \texttt{bindFlatInterface} transforms FlatInterface
-information (type \texttt{FlatCurry.Prog} to MCC interface declarations
-(type \texttt{CurrySyntax.IDecl}. This is necessary to process
-FlatInterfaces instead of ".icurry" files when using MCC as frontend
-for PAKCS.
-\begin{verbatim}
-
-> type ModuleEnv = Map.Map ModuleIdent [CS.IDecl]
-
-> lookupModule :: ModuleIdent -> ModuleEnv -> Maybe [CS.IDecl]
-> lookupModule = Map.lookup
-
-
-\end{verbatim}
-\paragraph{Type constructors}
-For all defined types the compiler must maintain kind information. At
-present, Curry does not support type classes. Therefore its type
-language is first order and the only information that must be recorded
-is the arity of each type. For algebraic data types and renaming types
-the compiler also records all data constructors belonging to that
-type, for alias types the type expression to be expanded is saved. In
-order to manage the import and export of types, the names of the
-original definitions are also recorded. On import two types are
-considered equal if their original names match.
-
-The information for a data constructor comprises the number of
-existentially quantified type variables and the list of the argument
-types. Note that renaming type constructors have only one type
-argument.
-
-Importing and exporting algebraic data types and renaming types is
-complicated by the fact that the constructors of the type may be
-(partially) hidden in the interface. This facilitates the definition
-of abstract data types. An abstract type is always represented as a
-data type without constructors in the interface regardless of whether
-it is defined as a data type or as a renaming type. When only some
-constructors of a data type are hidden, those constructors are
-replaced by underscores in the interface. Furthermore, if the
-right-most constructors of a data type are hidden, they are not
-exported at all in order to make the interface more stable against
-changes which are private to the module.
-\begin{verbatim}
-
-> data TypeInfo = DataType QualIdent Int [Maybe (Data [Type])]
->               | RenamingType QualIdent Int (Data Type)
->               | AliasType QualIdent Int Type
->               deriving Show
-
-> data Data a = Data Ident Int a deriving Show
-
-> instance Entity TypeInfo where
->   origName (DataType tc _ _) = tc
->   origName (RenamingType tc _ _) = tc
->   origName (AliasType tc _ _) = tc
->   merge (DataType tc n cs) (DataType tc' _ cs')
->     | tc == tc' = Just (DataType tc n (mergeData cs cs'))
->     where mergeData ds [] = ds
->           mergeData [] ds = ds
->           mergeData (d:ds) (d':ds') = d `mplus` d' : mergeData ds ds'
->   merge (DataType tc n _) (RenamingType tc' _ nc)
->     | tc == tc' = Just (RenamingType tc n nc)
->   merge (RenamingType tc n nc) (DataType tc' _ _)
->     | tc == tc' = Just (RenamingType tc n nc)
->   merge (RenamingType tc n nc) (RenamingType tc' _ _)
->     | tc == tc' = Just (RenamingType tc n nc)
->   merge (AliasType tc n ty) (AliasType tc' _ _)
->     | tc == tc' = Just (AliasType tc n ty)
->   merge _ _ = Nothing
-
-> tcArity :: TypeInfo -> Int
-> tcArity (DataType _ n _) = n
-> tcArity (RenamingType _ n _) = n
-> tcArity (AliasType _ n _) = n
-
-\end{verbatim}
-Types can only be defined on the top-level; no nested environments are
-needed for them. Tuple types must be handled as a special case because
-there is an infinite number of potential tuple types making it
-impossible to insert them into the environment in advance.
-\begin{verbatim}
-
-> type TCEnv = TopEnv TypeInfo
-
-> bindTypeInfo :: (QualIdent -> Int -> a -> TypeInfo) -> ModuleIdent
->              -> Ident -> [Ident] -> a -> TCEnv -> TCEnv
-> bindTypeInfo f m tc tvs x 
->   = bindTopEnv "Base.bindTypeInfo" tc t 
->     . qualBindTopEnv "Base.bindTypeInfo" tc' t
->   where tc' = qualifyWith m tc
->         t = f tc' (length tvs) x
-
-> lookupTC :: Ident -> TCEnv -> [TypeInfo]
-> lookupTC tc tcEnv = lookupTopEnv tc tcEnv ++! lookupTupleTC tc
-
-> qualLookupTC :: QualIdent -> TCEnv -> [TypeInfo]
-> qualLookupTC tc tcEnv =
->   qualLookupTopEnv tc tcEnv ++! lookupTupleTC (unqualify tc)
-
-> lookupTupleTC :: Ident -> [TypeInfo]
-> lookupTupleTC tc
->   | isTupleId tc = [tupleTCs !! (tupleArity tc - 2)]
->   | otherwise = []
-
-> tupleTCs :: [TypeInfo]
-> tupleTCs = map typeInfo tupleData
->   where typeInfo (Data c _ tys) =
->           DataType (qualifyWith preludeMIdent c) (length tys)
->                    [Just (Data c 0 tys)]
-
-> tupleData :: [Data [Type]]
-> tupleData = [Data (tupleId n) 0 (take n tvs) | n <- [2..]]
->   where tvs = map typeVar [0..]
-
-\end{verbatim}
-\paragraph{Function and constructor types}
-In order to test the type correctness of a module, the compiler needs
-to determine the type of every data constructor, function,
-variable, record and label in the module. 
-For the purpose of type checking there is no
-need for distinguishing between variables and functions. For all objects
-their original names and their types are saved. Functions also
-contain arity information. Labels currently contain the name of their
-defining record. On import two values
-are considered equal if their original names match.
-\begin{verbatim}
-
-> data ValueInfo = DataConstructor QualIdent ExistTypeScheme
->                | NewtypeConstructor QualIdent ExistTypeScheme
->                | Value QualIdent TypeScheme
->	         | Label QualIdent QualIdent TypeScheme
->	           -- Label <label> <record name> <type>
->                deriving Show
-
-> instance Entity ValueInfo where
->   origName (DataConstructor origName _) = origName
->   origName (NewtypeConstructor origName _) = origName
->   origName (Value origName _) = origName
->   origName (Label origName _ _) = origName
->   
->   merge (Label l r ty) (Label l' r' ty')
->     | l == l' && r == r' = Just (Label l r ty)
->     | otherwise = Nothing
->   merge x y
->     | origName x == origName y = Just x
->     | otherwise = Nothing
-
-
-\end{verbatim}
-Even though value declarations may be nested, the compiler uses only
-flat environments for saving type information. This is possible
-because all identifiers are renamed by the compiler. Here we need
-special cases for handling tuple constructors.
-
-\em{Note:} the function \texttt{qualLookupValue} has been extended to
-allow the usage of the qualified list constructor \texttt{(Prelude.:)}.
-\begin{verbatim}
-
-> type ValueEnv = TopEnv ValueInfo
-
-> bindGlobalInfo :: (QualIdent -> a -> ValueInfo) -> ModuleIdent -> Ident -> a
->                -> ValueEnv -> ValueEnv
-> bindGlobalInfo f m c ty 
->   = bindTopEnv "Base.bindGlobalInfo" c v 
->     . qualBindTopEnv "Base.bindGlobalInfo" c' v
->   where c' = qualifyWith m c
->         v = f c' ty
-
-> bindFun :: ModuleIdent -> Ident -> TypeScheme -> ValueEnv -> ValueEnv
-> bindFun m f ty tyEnv
->   | uniqueId f == 0 
->     = bindTopEnv "Base.bindFun" f v (qualBindTopEnv "Base.bindFun" f' v tyEnv)
->   | otherwise = bindTopEnv "Base.bindFun" f v tyEnv
->   where f' = qualifyWith m f
->         v = Value f' ty
-
-> rebindFun :: ModuleIdent -> Ident -> TypeScheme -> ValueEnv -> ValueEnv
-> rebindFun m f ty
->   | uniqueId f == 0 = rebindTopEnv f v . qualRebindTopEnv f' v
->   | otherwise = rebindTopEnv f v
->   where f' = qualifyWith m f
->         v = Value f' ty
-
-> bindLabel :: Ident -> QualIdent -> TypeScheme -> ValueEnv -> ValueEnv
-> bindLabel l r ty tyEnv = bindTopEnv "Base.bindLabel" l v tyEnv
->   where v  = Label (qualify l) r ty
-
-> lookupValue :: Ident -> ValueEnv -> [ValueInfo]
-> lookupValue x tyEnv = lookupTopEnv x tyEnv ++! lookupTuple x
-
-> qualLookupValue :: QualIdent -> ValueEnv -> [ValueInfo]
-> qualLookupValue x tyEnv =
->   qualLookupTopEnv x tyEnv 
->   ++! qualLookupCons x tyEnv
->   ++! lookupTuple (unqualify x)
-
-> qualLookupCons :: QualIdent -> ValueEnv -> [ValueInfo]
-> qualLookupCons x tyEnv
->    | maybe False ((==) preludeMIdent) mmid && id == consId
->       = qualLookupTopEnv (qualify id) tyEnv
->    | otherwise = []
->  where (mmid, id) = (qualidMod x, qualidId x)
-
-> lookupTuple :: Ident -> [ValueInfo]
-> lookupTuple c
->   | isTupleId c = [tupleDCs !! (tupleArity c - 2)]
->   | otherwise = []
-
-> tupleDCs :: [ValueInfo]
-> tupleDCs = map dataInfo tupleTCs
->   where dataInfo (DataType tc tvs [Just (Data c _ tys)]) =
->           DataConstructor (qualUnqualify preludeMIdent tc)
->                           (ForAllExist (length tys) 0
->                                        (foldr TypeArrow (tupleType tys) tys))
-
-\end{verbatim}
-\paragraph{Arity}
-In order to generate correct FlatCurry application it is necessary
-to define the number of arguments as the arity value (instead of
-using the arity computed from the type). For this reason the compiler
-needs a table containing the information for all known functions
-and constructors. 
-\begin{verbatim}
-
-> type ArityEnv = TopEnv ArityInfo
-
-> data ArityInfo = ArityInfo QualIdent Int deriving Show
-
-> instance Entity ArityInfo where
->   origName (ArityInfo origName _) = origName
-
-> bindArity :: ModuleIdent -> Ident -> Int -> ArityEnv -> ArityEnv
-> bindArity mid id arity aEnv
->    | uniqueId id == 0 
->      = bindTopEnv "Base.bindArity" id arityInfo 
->                   (qualBindTopEnv "Base.bindArity" qid arityInfo aEnv)
->    | otherwise        
->      = bindTopEnv "Base.bindArity" id arityInfo aEnv
->  where
->  qid = qualifyWith mid id
->  arityInfo = ArityInfo qid arity
-
-> lookupArity :: Ident -> ArityEnv -> [ArityInfo]
-> lookupArity id aEnv = lookupTopEnv id aEnv ++! lookupTupleArity id
-
-> qualLookupArity :: QualIdent -> ArityEnv -> [ArityInfo]
-> qualLookupArity qid aEnv = qualLookupTopEnv qid aEnv
->		             ++! qualLookupConsArity qid aEnv
->			     ++! lookupTupleArity (unqualify qid)
-
-> qualLookupConsArity :: QualIdent -> ArityEnv -> [ArityInfo]
-> qualLookupConsArity qid aEnv
->    | maybe False ((==) preludeMIdent) mmid && id == consId
->      = qualLookupTopEnv (qualify id) aEnv
->    | otherwise
->      = []
->  where (mmid, id) = (qualidMod qid, qualidId qid)
-
-> lookupTupleArity :: Ident -> [ArityInfo]
-> lookupTupleArity id 
->    | isTupleId id 
->      = [ArityInfo (qualifyWith preludeMIdent id) (tupleArity id)]
->    | otherwise
->      = []
-
-\end{verbatim}
-\paragraph{Module alias}
-\begin{verbatim}
-
-> type ImportEnv = Map.Map ModuleIdent ModuleIdent
-
-> bindAlias :: CS.Decl -> ImportEnv -> ImportEnv
-> bindAlias (CS.ImportDecl _ mid _ mmid _)
->    = Map.insert mid (fromMaybe mid mmid)
-
-> lookupAlias :: ModuleIdent -> ImportEnv -> Maybe ModuleIdent
-> lookupAlias = Map.lookup
-
-> sureLookupAlias :: ModuleIdent -> ImportEnv -> ModuleIdent
-> sureLookupAlias m = fromMaybe m . lookupAlias m
-
-
-\end{verbatim}
-\paragraph{Operator precedences}
-In order to parse infix expressions correctly, the compiler must know
-the precedence and fixity of each operator. Operator precedences are
-associated with entities and will be checked after renaming was
-applied. Nevertheless, we need to save precedences for ambiguous names
-in order to handle them correctly while computing the exported
-interface of a module.
-
-If no fixity is assigned to an operator, it will be given the default
-precedence 9 and assumed to be a left-associative operator.
-
-\em{Note:} this modified version uses Haskell type \texttt{Integer}
-for representing the precedence. This change had to be done due to the
-introduction of unlimited integer constants in the parser / lexer.
-\begin{verbatim}
-
-> data OpPrec = OpPrec CS.Infix Integer deriving Eq
-
-> instance Show OpPrec where
->   showsPrec _ (OpPrec fix p) = showString (assoc fix) . shows p
->     where assoc CS.InfixL = "left "
->           assoc CS.InfixR = "right "
->           assoc CS.Infix  = "non-assoc "
-
-> defaultP :: OpPrec
-> defaultP = OpPrec CS.InfixL 9
-
-\end{verbatim}
-The lookup functions for the environment which maintains the operator
-precedences are simpler than for the type and value environments
-because they do not need to handle tuple constructors.
-\begin{verbatim}
-
-> data PrecInfo = PrecInfo QualIdent OpPrec deriving (Eq,Show)
-
-> instance Entity PrecInfo where
->   origName (PrecInfo op _) = op
-
-> type PEnv = TopEnv PrecInfo
-
-> bindP :: ModuleIdent -> Ident -> OpPrec -> PEnv -> PEnv
-> bindP m op p
->   | uniqueId op == 0 
->     = bindTopEnv "Base.bindP" op info . qualBindTopEnv "Base.bindP" op' info
->   | otherwise = bindTopEnv "Base.bindP" op info
->   where op' = qualifyWith m op
->         info = PrecInfo op' p
-
-> lookupP :: Ident -> PEnv -> [PrecInfo]
-> lookupP = lookupTopEnv
-
-> qualLookupP :: QualIdent -> PEnv -> [PrecInfo]
-> qualLookupP = qualLookupTopEnv
-
-\end{verbatim}
-\paragraph{Evaluation modes}
-The compiler has to collect the evaluation annotations for a program
-in an environment. As these annotations affect only local declarations,
-a flat environment mapping unqualified names onto annotations is
-sufficient.
-\begin{verbatim}
-
-> type EvalEnv = Map.Map Ident CS.EvalAnnotation
-
-
-\end{verbatim}
-\paragraph{Predefined types}
-The list and unit data types must be predefined because their
-definitions
-\begin{verbatim}
-data () = ()
-data [] a = [] | a : [a]
-\end{verbatim}
-are not allowed by Curry's syntax. The corresponding types
-are available in the environments \texttt{initTCEnv} and
-\texttt{initDCEnv}. In addition, the precedence of the (infix) list
-constructor is available in the environment \texttt{initPEnv}.
-
-Note that only the unqualified names are predefined. This is correct,
-because neither \texttt{Prelude.()} nor \texttt{Prelude.[]} are valid
-identifiers.
-\begin{verbatim}
-
-> initPEnv :: PEnv
-> initPEnv =
->   predefTopEnv qConsId (PrecInfo qConsId (OpPrec CS.InfixR 5)) emptyTopEnv
-
-> initTCEnv :: TCEnv
-> initTCEnv = foldr (uncurry predefTC) emptyTopEnv predefTypes
->   where predefTC (TypeConstructor tc tys) =
->           predefTopEnv (qualify (unqualify tc)) .
->             DataType tc (length tys) . map Just
-
-> initDCEnv :: ValueEnv
-> initDCEnv =
->   foldr (uncurry predefDC) emptyTopEnv
->         [(c,constrType (polyType ty) n' tys)
->         | (ty,cs) <- predefTypes, Data c n' tys <- cs]
->   where predefDC c ty = predefTopEnv c' (DataConstructor c' ty)
->           where c' = qualify c
->         constrType (ForAll n ty) n' = ForAllExist n n' . foldr TypeArrow ty
-
-> initAEnv :: ArityEnv
-> initAEnv
->    = foldr bindPredefArity emptyTopEnv (concatMap snd predefTypes)
->  where
->  bindPredefArity (Data id _ ts)
->     = bindArity preludeMIdent id (length ts)
-
-> initIEnv :: ImportEnv
-> initIEnv = Map.empty
-
-> predefTypes :: [(Type,[Data [Type]])]
-> predefTypes =
->   let a = typeVar 0 in [
->     (unitType,   [Data unitId 0 []]),
->     (listType a, [Data nilId 0 [],Data consId 0 [a,listType a]])
->   ]
-
-
-\end{verbatim}
-
-\paragraph{Miscellany}
-Error handling
-\begin{verbatim}
-
-> errorAt :: Position -> String -> a
-> errorAt p msg = error ("\n" ++ show p ++ ": " ++ msg)
-
-> errorAt' :: (Position,String) -> a
-> errorAt' = uncurry errorAt
-
-> internalError :: String -> a
-> internalError what = error ("internal error: " ++ what)
-
-\end{verbatim}
-Name supply for the generation of (type) variable names.
-\begin{verbatim}
-
-> nameSupply :: [Ident]
-> nameSupply = map mkIdent [c:showNum i | i <- [0..], c <- ['a'..'z']]
->   where showNum 0 = ""
->         showNum n = show n
-
-\end{verbatim}
-\ToDo{The \texttt{nameSupply} should respect the current case mode, 
-i.e., use upper case for variables in Prolog mode.}
-
-\end{verbatim}
-The function \texttt{findDouble} checks whether a list of entities is
-linear, i.e., if every entity in the list occurs only once. If it is
-non-linear, the first offending object is returned.
-\begin{verbatim}
-
-> findDouble :: Eq a => [a] -> Maybe a
-> findDouble (x:xs)
->   | x `elem` xs = Just x
->   | otherwise = findDouble xs
-> findDouble [] = Nothing
-
-\end{verbatim}
-
-
-
diff --git a/src/Base/AnnotExpr.hs b/src/Base/AnnotExpr.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/AnnotExpr.hs
@@ -0,0 +1,124 @@
+{- |
+    Module      :  $Header$
+    Description :  Extraction of free qualified annotated variables
+    Copyright   :  (c) 2017        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    TODO
+-}
+module Base.AnnotExpr (QualAnnotExpr (..)) where
+
+import qualified Data.Set  as Set (fromList, notMember)
+
+import Curry.Base.Ident
+import Curry.Base.SpanInfo
+import Curry.Syntax
+
+import Base.Expr
+import Base.Types
+import Base.Typing
+
+class QualAnnotExpr e where
+  -- |Free qualified annotated variables in an 'Expr'
+  qafv :: ModuleIdent -> e Type -> [(Type, Ident)]
+
+-- The 'Decl' instance of 'QualAnnotExpr' returns all free
+-- variables on the right hand side, regardless of whether they are bound
+-- on the left hand side. This is more convenient as declarations are
+-- usually processed in a declaration group where the set of free
+-- variables cannot be computed independently for each declaration.
+
+instance QualAnnotExpr Decl where
+  qafv m (FunctionDecl    _ _ _ eqs) = concatMap (qafv m) eqs
+  qafv m (PatternDecl       _ _ rhs) = qafv m rhs
+  qafv m (ClassDecl    _ _ _ _ _ ds) = concatMap (qafv m) ds
+  qafv m (InstanceDecl _ _ _ _ _ ds) = concatMap (qafv m) ds
+  qafv _ _                           = []
+
+instance QualAnnotExpr Equation where
+  qafv m (Equation _ lhs rhs) = filterBv lhs $ qafv m lhs ++ qafv m rhs
+
+instance QualAnnotExpr Lhs where
+  qafv m = concatMap (qafv m) . snd . flatLhs
+
+instance QualAnnotExpr Rhs where
+  qafv m (SimpleRhs _ _ e ds) = filterBv ds $ qafv m e ++ concatMap (qafv m) ds
+  qafv m (GuardedRhs _ _ es ds) =
+    filterBv ds $ concatMap (qafv m) es ++ concatMap (qafv m) ds
+
+instance QualAnnotExpr CondExpr where
+  qafv m (CondExpr _ g e) = qafv m g ++ qafv m e
+
+instance QualAnnotExpr Expression where
+  qafv _ (Literal             _ _ _) = []
+  qafv m (Variable           _ ty v) =
+    maybe [] (return . (\v' -> (ty, v'))) $ localIdent m v
+  qafv _ (Constructor         _ _ _) = []
+  qafv m (Paren                 _ e) = qafv m e
+  qafv m (Typed               _ e _) = qafv m e
+  qafv m (Record           _ _ _ fs) = concatMap (qafvField m) fs
+  qafv m (RecordUpdate       _ e fs) = qafv m e ++ concatMap (qafvField m) fs
+  qafv m (Tuple                _ es) = concatMap (qafv m) es
+  qafv m (List               _ _ es) = concatMap (qafv m) es
+  qafv m (ListCompr          _ e qs) = foldr (qafvStmt m) (qafv m e) qs
+  qafv m (EnumFrom              _ e) = qafv m e
+  qafv m (EnumFromThen      _ e1 e2) = qafv m e1 ++ qafv m e2
+  qafv m (EnumFromTo        _ e1 e2) = qafv m e1 ++ qafv m e2
+  qafv m (EnumFromThenTo _ e1 e2 e3) = qafv m e1 ++ qafv m e2 ++ qafv m e3
+  qafv m (UnaryMinus            _ e) = qafv m e
+  qafv m (Apply             _ e1 e2) = qafv m e1 ++ qafv m e2
+  qafv m (InfixApply     _ e1 op e2) = qafv m op ++ qafv m e1 ++ qafv m e2
+  qafv m (LeftSection        _ e op) = qafv m op ++ qafv m e
+  qafv m (RightSection       _ op e) = qafv m op ++ qafv m e
+  qafv m (Lambda             _ ts e) = filterBv ts $ qafv m e
+  qafv m (Let              _ _ ds e) =
+    filterBv ds $ concatMap (qafv m) ds ++ qafv m e
+  qafv m (Do              _ _ sts e) = foldr (qafvStmt m) (qafv m e) sts
+  qafv m (IfThenElse     _ e1 e2 e3) = qafv m e1 ++ qafv m e2 ++ qafv m e3
+  qafv m (Case         _ _ _ e alts) = qafv m e ++ concatMap (qafv m) alts
+
+qafvField :: QualAnnotExpr e => ModuleIdent -> Field (e Type) -> [(Type, Ident)]
+qafvField m (Field _ _ t) = qafv m t
+
+qafvStmt :: ModuleIdent -> Statement Type -> [(Type, Ident)] -> [(Type, Ident)]
+qafvStmt m st fvs = qafv m st ++ filterBv st fvs
+
+instance QualAnnotExpr Statement where
+  qafv m (StmtExpr   _  e) = qafv m e
+  qafv m (StmtDecl _ _ ds) = filterBv ds $ concatMap (qafv m) ds
+  qafv m (StmtBind _ _  e) = qafv m e
+
+instance QualAnnotExpr Alt where
+  qafv m (Alt _ t rhs) = filterBv t $ qafv m rhs
+
+instance QualAnnotExpr InfixOp where
+  qafv m (InfixOp    ty op) = qafv m $ Variable NoSpanInfo ty op
+  qafv _ (InfixConstr _ _ ) = []
+
+instance QualAnnotExpr Pattern where
+  qafv _ (LiteralPattern           _ _ _) = []
+  qafv _ (NegativePattern          _ _ _) = []
+  qafv _ (VariablePattern          _ _ _) = []
+  qafv m (ConstructorPattern    _ _ _ ts) = concatMap (qafv m) ts
+  qafv m (InfixPattern       _ _ t1 _ t2) = qafv m t1 ++ qafv m t2
+  qafv m (ParenPattern               _ t) = qafv m t
+  qafv m (RecordPattern         _ _ _ fs) = concatMap (qafvField m) fs
+  qafv m (TuplePattern              _ ts) = concatMap (qafv m) ts
+  qafv m (ListPattern             _ _ ts) = concatMap (qafv m) ts
+  qafv m (AsPattern                _ _ t) = qafv m t
+  qafv m (LazyPattern                _ t) = qafv m t
+  qafv m (FunctionPattern      _ ty f ts) =
+    maybe [] (return . (\f' -> (ty', f'))) (localIdent m f) ++
+      concatMap (qafv m) ts
+    where ty' = foldr TypeArrow ty $ map typeOf ts
+  qafv m (InfixFuncPattern _ ty t1 op t2) =
+    maybe [] (return . (\op' -> (ty', op'))) (localIdent m op) ++
+      concatMap (qafv m) [t1, t2]
+    where ty' = foldr TypeArrow ty $ map typeOf [t1, t2]
+
+filterBv :: QuantExpr e => e -> [(Type, Ident)] -> [(Type, Ident)]
+filterBv e = filter ((`Set.notMember` Set.fromList (bv e)) . snd)
diff --git a/src/Base/CurryKinds.hs b/src/Base/CurryKinds.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/CurryKinds.hs
@@ -0,0 +1,45 @@
+{- |
+    Module      :  $Header$
+    Description :  Conversion of kind representation
+    Copyright   :  (c) 2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   The functions 'tokind' and 'fromKind' convert Curry kind expressions into
+   kinds and vice versa.
+
+   When Curry kinds are converted with 'fromKind', kind variables are
+   instantiated with the kind *.
+-}
+
+module Base.CurryKinds
+  ( toKind, toKind', fromKind, fromKind', ppKind
+  ) where
+
+import Curry.Base.Pretty (Doc)
+import Curry.Syntax.Pretty (pPrintPrec)
+import Curry.Syntax.Type (KindExpr (..))
+
+import Base.Kinds
+
+toKind :: KindExpr -> Kind
+toKind Star              = KindStar
+toKind (ArrowKind k1 k2) = KindArrow (toKind k1) (toKind k2)
+
+toKind' :: Maybe KindExpr -> Int -> Kind
+toKind' k n = maybe (simpleKind n) toKind k
+
+fromKind :: Kind -> KindExpr
+fromKind KindStar          = Star
+fromKind (KindVariable  _) = Star
+fromKind (KindArrow k1 k2) = ArrowKind (fromKind k1) (fromKind k2)
+
+fromKind' :: Kind -> Int -> Maybe KindExpr
+fromKind' k n | k == simpleKind n = Nothing
+              | otherwise         = Just (fromKind k)
+
+ppKind :: Kind -> Doc
+ppKind = pPrintPrec 0 . fromKind
diff --git a/src/Base/CurryTypes.hs b/src/Base/CurryTypes.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/CurryTypes.hs
@@ -0,0 +1,213 @@
+{- |
+    Module      :  $Header$
+    Description :  Conversion of type representation
+    Copyright   :  (c)         Wolfgang Lux
+                   2011 - 2012 Björn Peemöller
+                   2015        Jan Tikovsky
+                   2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   The functions 'toType', 'toTypes', and 'fromType' convert Curry type
+   expressions into types and vice versa. The functions 'qualifyType' and
+   'unqualifyType' add and remove module qualifiers in a type, respectively.
+
+   When Curry type expression are converted with 'toType' or 'toTypes',
+   type variables are assigned ascending indices in the order of their
+   occurrence. It is possible to pass a list of additional type variables
+   to both functions which are assigned indices before those variables
+   occurring in the type. This allows preserving the order of type variables
+   in the left hand side of a type declaration.
+-}
+
+module Base.CurryTypes
+  ( toType, toTypes, toQualType, toQualTypes
+  , toPred, toQualPred, toPredSet, toQualPredSet, toPredType, toQualPredType
+  , toConstrType, toMethodType
+  , fromType, fromQualType
+  , fromPred, fromQualPred, fromPredSet, fromQualPredSet, fromPredType
+  , fromQualPredType
+  , ppType, ppPred, ppPredType, ppTypeScheme
+  ) where
+
+import Data.List (nub)
+import qualified Data.Map as Map (Map, fromList, lookup)
+import qualified Data.Set as Set
+
+import Curry.Base.Ident
+import Curry.Base.Pretty (Doc)
+import Curry.Base.SpanInfo
+import qualified Curry.Syntax as CS
+import Curry.Syntax.Pretty (pPrint, pPrintPrec)
+
+import Base.Expr
+import Base.Messages (internalError)
+import Base.Types
+
+enumTypeVars :: (Expr a, QuantExpr a) => [Ident] -> a -> Map.Map Ident Int
+enumTypeVars tvs ty = Map.fromList $ zip (tvs ++ tvs') [0..]
+  where
+    tvs' = [tv | tv <- nub (fv ty), tv `notElem` tvs] ++
+             [tv | tv <- nub (bv ty), tv `notElem` tvs]
+
+toType :: [Ident] -> CS.TypeExpr -> Type
+toType tvs ty = toType' (enumTypeVars tvs ty) ty []
+
+toTypes :: [Ident] -> [CS.TypeExpr] -> [Type]
+toTypes tvs tys = map ((flip (toType' (enumTypeVars tvs tys))) []) tys
+
+toType' :: Map.Map Ident Int -> CS.TypeExpr -> [Type] -> Type
+toType' _   (CS.ConstructorType _ tc) tys = applyType (TypeConstructor tc) tys
+toType' tvs (CS.ApplyType  _ ty1 ty2) tys =
+  toType' tvs ty1 (toType' tvs ty2 [] : tys)
+toType' tvs (CS.VariableType    _ tv) tys =
+  applyType (TypeVariable (toVar tvs tv)) tys
+toType' tvs (CS.TupleType      _ tys) tys'
+  | null tys  = internalError "Base.CurryTypes.toType': zero-element tuple"
+  | null tys' = tupleType $ map ((flip $ toType' tvs) []) tys
+  | otherwise = internalError "Base.CurryTypes.toType': tuple type application"
+toType' tvs (CS.ListType        _ ty) tys
+  | null tys  = listType $ toType' tvs ty []
+  | otherwise = internalError "Base.CurryTypes.toType': list type application"
+toType' tvs (CS.ArrowType  _ ty1 ty2) tys
+  | null tys = TypeArrow (toType' tvs ty1 []) (toType' tvs ty2 [])
+  | otherwise = internalError "Base.CurryTypes.toType': arrow type application"
+toType' tvs (CS.ParenType       _ ty) tys = toType' tvs ty tys
+toType' tvs (CS.ForallType _ tvs' ty) tys
+  | null tvs' = toType' tvs ty tys
+  | otherwise = applyType (TypeForall (map (toVar tvs) tvs')
+                                      (toType' tvs ty []))
+                          tys
+
+toVar :: Map.Map Ident Int -> Ident -> Int
+toVar tvs tv = case Map.lookup tv tvs of
+  Just tv' -> tv'
+  Nothing  -> internalError "Base.CurryTypes.toVar: unknown type variable"
+
+toQualType :: ModuleIdent -> [Ident] -> CS.TypeExpr -> Type
+toQualType m tvs = qualifyType m . toType tvs
+
+toQualTypes :: ModuleIdent -> [Ident] -> [CS.TypeExpr] -> [Type]
+toQualTypes m tvs = map (qualifyType m) . toTypes tvs
+
+toPred :: [Ident] -> CS.Constraint -> Pred
+toPred tvs c = toPred' (enumTypeVars tvs c) c
+
+toPred' :: Map.Map Ident Int -> CS.Constraint -> Pred
+toPred' tvs (CS.Constraint _ qcls ty) = Pred qcls (toType' tvs ty [])
+
+toQualPred :: ModuleIdent -> [Ident] -> CS.Constraint -> Pred
+toQualPred m tvs = qualifyPred m . toPred tvs
+
+toPredSet :: [Ident] -> CS.Context -> PredSet
+toPredSet tvs cx = toPredSet' (enumTypeVars tvs cx) cx
+
+toPredSet' :: Map.Map Ident Int -> CS.Context -> PredSet
+toPredSet' tvs = Set.fromList . map (toPred' tvs)
+
+toQualPredSet :: ModuleIdent -> [Ident] -> CS.Context -> PredSet
+toQualPredSet m tvs = qualifyPredSet m . toPredSet tvs
+
+toPredType :: [Ident] -> CS.QualTypeExpr -> PredType
+toPredType tvs qty = toPredType' (enumTypeVars tvs qty) qty
+
+toPredType' :: Map.Map Ident Int -> CS.QualTypeExpr -> PredType
+toPredType' tvs (CS.QualTypeExpr _ cx ty) =
+  PredType (toPredSet' tvs cx) (toType' tvs ty [])
+
+toQualPredType :: ModuleIdent -> [Ident] -> CS.QualTypeExpr -> PredType
+toQualPredType m tvs = qualifyPredType m . toPredType tvs
+
+-- The function 'toConstrType' returns the type of a data or newtype
+-- constructor. Hereby, it restricts the context to those type variables
+-- which are free in the argument types.
+
+toConstrType :: QualIdent -> [Ident] -> [CS.TypeExpr] -> PredType
+toConstrType tc tvs tys = toPredType tvs $
+  CS.QualTypeExpr NoSpanInfo [] ty'
+  where ty'  = foldr (CS.ArrowType NoSpanInfo) ty0 tys
+        ty0  = foldl (CS.ApplyType NoSpanInfo)
+                     (CS.ConstructorType NoSpanInfo tc)
+                     (map (CS.VariableType NoSpanInfo) tvs)
+
+-- The function 'toMethodType' returns the type of a type class method.
+-- It adds the implicit type class constraint to the method's type signature
+-- and ensures that the class' type variable is always assigned index 0.
+
+toMethodType :: QualIdent -> Ident -> CS.QualTypeExpr -> PredType
+toMethodType qcls clsvar (CS.QualTypeExpr spi cx ty) =
+  toPredType [clsvar] (CS.QualTypeExpr spi cx' ty)
+  where cx' = CS.Constraint NoSpanInfo qcls
+                (CS.VariableType NoSpanInfo clsvar) : cx
+
+fromType :: [Ident] -> Type -> CS.TypeExpr
+fromType tvs ty = fromType' tvs ty []
+
+fromType' :: [Ident] -> Type -> [CS.TypeExpr] -> CS.TypeExpr
+fromType' _   (TypeConstructor    tc) tys
+  | isQTupleId tc && qTupleArity tc == length tys
+    = CS.TupleType NoSpanInfo tys
+  | tc == qListId && length tys == 1
+    = CS.ListType NoSpanInfo (head tys)
+  | otherwise
+  = foldl (CS.ApplyType NoSpanInfo) (CS.ConstructorType NoSpanInfo tc) tys
+fromType' tvs (TypeApply     ty1 ty2) tys =
+  fromType' tvs ty1 (fromType tvs ty2 : tys)
+fromType' tvs (TypeVariable       tv) tys =
+  foldl (CS.ApplyType NoSpanInfo) (CS.VariableType NoSpanInfo (fromVar tvs tv))
+    tys
+fromType' tvs (TypeArrow     ty1 ty2) tys =
+  foldl (CS.ApplyType NoSpanInfo)
+    (CS.ArrowType NoSpanInfo (fromType tvs ty1) (fromType tvs ty2)) tys
+fromType' tvs (TypeConstrained tys _) tys' = fromType' tvs (head tys) tys'
+fromType' tvs (TypeForall    tvs' ty) tys
+  | null tvs' = fromType' tvs ty tys
+  | otherwise = foldl (CS.ApplyType NoSpanInfo)
+                      (CS.ForallType NoSpanInfo (map (fromVar tvs) tvs')
+                                                (fromType tvs ty))
+                      tys
+
+fromVar :: [Ident] -> Int -> Ident
+fromVar tvs tv = if tv >= 0 then tvs !! tv else mkIdent ('_' : show (-tv))
+
+fromQualType :: ModuleIdent -> [Ident] -> Type -> CS.TypeExpr
+fromQualType m tvs = fromType tvs . unqualifyType m
+
+fromPred :: [Ident] -> Pred -> CS.Constraint
+fromPred tvs (Pred qcls ty) = CS.Constraint NoSpanInfo qcls (fromType tvs ty)
+
+fromQualPred :: ModuleIdent -> [Ident] -> Pred -> CS.Constraint
+fromQualPred m tvs = fromPred tvs .  unqualifyPred m
+
+-- Due to the sorting of the predicate set, the list of constraints is sorted
+-- as well.
+
+fromPredSet :: [Ident] -> PredSet -> CS.Context
+fromPredSet tvs = map (fromPred tvs) . Set.toAscList
+
+fromQualPredSet :: ModuleIdent -> [Ident] -> PredSet -> CS.Context
+fromQualPredSet m tvs = fromPredSet tvs . unqualifyPredSet m
+
+fromPredType :: [Ident] -> PredType -> CS.QualTypeExpr
+fromPredType tvs (PredType ps ty) =
+  CS.QualTypeExpr NoSpanInfo (fromPredSet tvs ps) (fromType tvs ty)
+
+fromQualPredType :: ModuleIdent -> [Ident] -> PredType -> CS.QualTypeExpr
+fromQualPredType m tvs = fromPredType tvs . unqualifyPredType m
+
+-- The following functions implement pretty-printing for types.
+
+ppType :: ModuleIdent -> Type -> Doc
+ppType m = pPrintPrec 0 . fromQualType m identSupply
+
+ppPred :: ModuleIdent -> Pred -> Doc
+ppPred m = pPrint . fromQualPred m identSupply
+
+ppPredType :: ModuleIdent -> PredType -> Doc
+ppPredType m = pPrint . fromQualPredType m identSupply
+
+ppTypeScheme :: ModuleIdent -> TypeScheme -> Doc
+ppTypeScheme m (ForAll _ pty) = ppPredType m pty
diff --git a/src/Base/Expr.hs b/src/Base/Expr.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/Expr.hs
@@ -0,0 +1,212 @@
+{- |
+    Module      :  $Header$
+    Description :  Extraction of free and bound variables
+    Copyright   :  (c)             Wolfgang Lux
+                       2011 - 2015 Björn Peemöller
+                       2015        Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    The compiler needs to compute the lists of free and bound variables for
+    various different entities. We will devote three type classes to that
+    purpose. The 'QualExpr' class is expected to take into account
+    that it is possible to use a qualified name to refer to a function
+    defined in the current module and therefore @M.x@ and @x@, where
+    @M@ is the current module name, should be considered the same name.
+    However, note that this is correct only after renaming all local
+    definitions as @M.x@ always denotes an entity defined at the
+    top-level.
+-}
+module Base.Expr (Expr (..), QualExpr (..), QuantExpr (..)) where
+
+import           Data.List        (nub)
+import qualified Data.Set  as Set (fromList, notMember)
+
+import Curry.Base.Ident
+import Curry.Base.SpanInfo
+import Curry.Syntax
+
+class Expr e where
+  -- |Free variables in an 'Expr'
+  fv :: e -> [Ident]
+
+class QualExpr e where
+  -- |Free qualified variables in an 'Expr'
+  qfv :: ModuleIdent -> e -> [Ident]
+
+class QuantExpr e where
+  -- |Bounded variables in an 'Expr'
+  bv :: e -> [Ident]
+
+instance Expr e => Expr [e] where
+  fv = concatMap fv
+
+instance QualExpr e => QualExpr [e] where
+  qfv m = concatMap (qfv m)
+
+instance QuantExpr e => QuantExpr [e] where
+  bv = concatMap bv
+
+-- The 'Decl' instance of 'QualExpr' returns all free
+-- variables on the right hand side, regardless of whether they are bound
+-- on the left hand side. This is more convenient as declarations are
+-- usually processed in a declaration group where the set of free
+-- variables cannot be computed independently for each declaration.
+
+instance QualExpr (Decl a) where
+  qfv m (FunctionDecl    _ _ _ eqs) = qfv m eqs
+  qfv m (PatternDecl       _ _ rhs) = qfv m rhs
+  qfv m (ClassDecl    _ _ _ _ _ ds) = qfv m ds
+  qfv m (InstanceDecl _ _ _ _ _ ds) = qfv m ds
+  qfv _ _                           = []
+
+instance QuantExpr (Decl a) where
+  bv (TypeSig         _ vs _) = vs
+  bv (FunctionDecl   _ _ f _) = [f]
+  bv (ExternalDecl      _ vs) = bv vs
+  bv (PatternDecl      _ t _) = bv t
+  bv (FreeDecl          _ vs) = bv vs
+  bv (ClassDecl _ _ _ _ _ ds) = concatMap methods ds
+  bv _                        = []
+
+instance QualExpr (Equation a) where
+  qfv m (Equation _ lhs rhs) = filterBv lhs $ qfv m lhs ++ qfv m rhs
+
+instance QuantExpr (Lhs a) where
+  bv = bv . snd . flatLhs
+
+instance QualExpr (Lhs a) where
+  qfv m lhs = qfv m $ snd $ flatLhs lhs
+
+instance QualExpr (Rhs a) where
+  qfv m (SimpleRhs  _ _ e  ds) = filterBv ds $ qfv m e  ++ qfv m ds
+  qfv m (GuardedRhs _ _ es ds) = filterBv ds $ qfv m es ++ qfv m ds
+
+instance QualExpr (CondExpr a) where
+  qfv m (CondExpr _ g e) = qfv m g ++ qfv m e
+
+instance QualExpr (Expression a) where
+  qfv _ (Literal             _ _ _) = []
+  qfv m (Variable            _ _ v) = maybe [] return $ localIdent m v
+  qfv _ (Constructor         _ _ _) = []
+  qfv m (Paren               _   e) = qfv m e
+  qfv m (Typed               _ e _) = qfv m e
+  qfv m (Record           _ _ _ fs) = qfv m fs
+  qfv m (RecordUpdate       _ e fs) = qfv m e ++ qfv m fs
+  qfv m (Tuple                _ es) = qfv m es
+  qfv m (List               _ _ es) = qfv m es
+  qfv m (ListCompr          _ e qs) = foldr (qfvStmt m) (qfv m e) qs
+  qfv m (EnumFrom              _ e) = qfv m e
+  qfv m (EnumFromThen      _ e1 e2) = qfv m e1 ++ qfv m e2
+  qfv m (EnumFromTo        _ e1 e2) = qfv m e1 ++ qfv m e2
+  qfv m (EnumFromThenTo _ e1 e2 e3) = qfv m e1 ++ qfv m e2 ++ qfv m e3
+  qfv m (UnaryMinus            _ e) = qfv m e
+  qfv m (Apply             _ e1 e2) = qfv m e1 ++ qfv m e2
+  qfv m (InfixApply     _ e1 op e2) = qfv m op ++ qfv m e1 ++ qfv m e2
+  qfv m (LeftSection        _ e op) = qfv m op ++ qfv m e
+  qfv m (RightSection       _ op e) = qfv m op ++ qfv m e
+  qfv m (Lambda             _ ts e) = filterBv ts $ qfv m e
+  qfv m (Let              _ _ ds e) = filterBv ds $ qfv m ds ++ qfv m e
+  qfv m (Do              _ _ sts e) = foldr (qfvStmt m) (qfv m e) sts
+  qfv m (IfThenElse     _ e1 e2 e3) = qfv m e1 ++ qfv m e2 ++ qfv m e3
+  qfv m (Case         _ _ _ e alts) = qfv m e ++ qfv m alts
+
+qfvStmt :: ModuleIdent -> (Statement a) -> [Ident] -> [Ident]
+qfvStmt m st fvs = qfv m st ++ filterBv st fvs
+
+instance QualExpr (Statement a) where
+  qfv m (StmtExpr   _ e)  = qfv m e
+  qfv m (StmtDecl _ _ ds) = filterBv ds $ qfv m ds
+  qfv m (StmtBind _ _ e)  = qfv m e
+
+instance QualExpr (Alt a) where
+  qfv m (Alt _ t rhs) = filterBv t $ qfv m rhs
+
+instance QuantExpr (Var a) where
+  bv (Var _ v) = [v]
+
+instance QuantExpr a => QuantExpr (Field a) where
+  bv (Field _ _ t) = bv t
+
+instance QualExpr a => QualExpr (Field a) where
+  qfv m (Field _ _ t) = qfv m t
+
+instance QuantExpr (Statement a) where
+  bv (StmtExpr   _ _)  = []
+  bv (StmtBind _ t _)  = bv t
+  bv (StmtDecl _ _ ds) = bv ds
+
+instance QualExpr (InfixOp a) where
+  qfv m (InfixOp     a op) = qfv m $ Variable NoSpanInfo a op
+  qfv _ (InfixConstr _ _ ) = []
+
+instance QuantExpr (Pattern a) where
+  bv (LiteralPattern         _ _ _) = []
+  bv (NegativePattern        _ _ _) = []
+  bv (VariablePattern        _ _ v) = [v]
+  bv (ConstructorPattern  _ _ _ ts) = bv ts
+  bv (InfixPattern     _ _ t1 _ t2) = bv t1 ++ bv t2
+  bv (ParenPattern             _ t) = bv t
+  bv (RecordPattern       _ _ _ fs) = bv fs
+  bv (TuplePattern           _  ts) = bv ts
+  bv (ListPattern          _  _ ts) = bv ts
+  bv (AsPattern              _ v t) = v : bv t
+  bv (LazyPattern              _ t) = bv t
+  bv (FunctionPattern     _ _ _ ts) = nub $ bv ts
+  bv (InfixFuncPattern _ _ t1 _ t2) = nub $ bv t1 ++ bv t2
+
+instance QualExpr (Pattern a) where
+  qfv _ (LiteralPattern          _ _ _) = []
+  qfv _ (NegativePattern         _ _ _) = []
+  qfv _ (VariablePattern         _ _ _) = []
+  qfv m (ConstructorPattern   _ _ _ ts) = qfv m ts
+  qfv m (InfixPattern      _ _ t1 _ t2) = qfv m [t1, t2]
+  qfv m (ParenPattern              _ t) = qfv m t
+  qfv m (RecordPattern        _ _ _ fs) = qfv m fs
+  qfv m (TuplePattern             _ ts) = qfv m ts
+  qfv m (ListPattern            _ _ ts) = qfv m ts
+  qfv m (AsPattern              _ _ ts) = qfv m ts
+  qfv m (LazyPattern               _ t) = qfv m t
+  qfv m (FunctionPattern      _ _ f ts)
+    = maybe [] return (localIdent m f) ++ qfv m ts
+  qfv m (InfixFuncPattern _ _ t1 op t2)
+    = maybe [] return (localIdent m op) ++ qfv m [t1, t2]
+
+instance Expr Constraint where
+  fv (Constraint _ _ ty) = fv ty
+
+instance QuantExpr Constraint where
+  bv _ = []
+
+instance Expr QualTypeExpr where
+  fv (QualTypeExpr _ _ ty) = fv ty
+
+instance QuantExpr QualTypeExpr where
+  bv (QualTypeExpr _ _ ty) = bv ty
+
+instance Expr TypeExpr where
+  fv (ConstructorType     _ _) = []
+  fv (ApplyType     _ ty1 ty2) = fv ty1 ++ fv ty2
+  fv (VariableType       _ tv) = [tv]
+  fv (TupleType         _ tys) = fv tys
+  fv (ListType          _  ty) = fv ty
+  fv (ArrowType     _ ty1 ty2) = fv ty1 ++ fv ty2
+  fv (ParenType          _ ty) = fv ty
+  fv (ForallType      _ vs ty) = filter (`notElem` vs) $ fv ty
+
+instance QuantExpr TypeExpr where
+  bv (ConstructorType     _ _) = []
+  bv (ApplyType     _ ty1 ty2) = bv ty1 ++ bv ty2
+  bv (VariableType        _ _) = []
+  bv (TupleType         _ tys) = bv tys
+  bv (ListType           _ ty) = bv ty
+  bv (ArrowType     _ ty1 ty2) = bv ty1 ++ bv ty2
+  bv (ParenType          _ ty) = bv ty
+  bv (ForallType     _ tvs ty) = tvs ++ bv ty
+
+filterBv :: QuantExpr e => e -> [Ident] -> [Ident]
+filterBv e = filter (`Set.notMember` Set.fromList (bv e))
diff --git a/src/Base/KindSubst.hs b/src/Base/KindSubst.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/KindSubst.hs
@@ -0,0 +1,48 @@
+{- |
+    Module      :  $Header$
+    Description :  Kind substitution
+    Copyright   :  (c) 2016      Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   This module implements substitutions on kinds.
+-}
+
+module Base.KindSubst
+  ( module Base.KindSubst, idSubst, singleSubst, bindSubst, compose
+  ) where
+
+import Base.Kinds
+import Base.Subst
+import Base.TopEnv
+
+import Env.TypeConstructor
+
+type KindSubst = Subst Int Kind
+
+class SubstKind a where
+  subst :: KindSubst -> a -> a
+
+bindVar :: Int -> Kind -> KindSubst -> KindSubst
+bindVar kv k = compose (bindSubst kv k idSubst)
+
+substVar :: KindSubst -> Int -> Kind
+substVar = substVar' KindVariable subst
+
+instance SubstKind Kind where
+  subst _     KindStar             = KindStar
+  subst sigma (KindVariable    kv) = substVar sigma kv
+  subst sigma (KindArrow    k1 k2) = KindArrow (subst sigma k1) (subst sigma k2)
+
+instance SubstKind TypeInfo where
+  subst theta (DataType     tc k cs) = DataType tc (subst theta k) cs
+  subst theta (RenamingType tc k nc) = RenamingType tc (subst theta k) nc
+  subst theta (AliasType  tc k n ty) = AliasType tc (subst theta k) n ty
+  subst theta (TypeClass   cls k ms) = TypeClass cls (subst theta k) ms
+  subst theta (TypeVar            k) = TypeVar (subst theta k)
+
+instance SubstKind a => SubstKind (TopEnv a) where
+  subst = fmap . subst
diff --git a/src/Base/Kinds.hs b/src/Base/Kinds.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/Kinds.hs
@@ -0,0 +1,62 @@
+{- |
+    Module      :  $Header$
+    Description :  Internal representation of kinds
+    Copyright   :  (c) 2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   This module modules provides the definitions for the internal
+   representation of kinds in the compiler.
+-}
+
+module Base.Kinds where
+
+-- A kind is either *, which is the kind of a value's type, a kind
+-- variable, or an arrow kind. Kind variables are used internally during
+-- kind inference. Kind variables are not supported in Curry kind
+-- expressions and all kind variables that remain free after kind
+-- inference are instantiated to *.
+
+data Kind = KindStar
+          | KindVariable Int
+          | KindArrow Kind Kind
+  deriving (Eq, Show)
+
+-- |The function 'kindArity' computes the arity n of a kind.
+kindArity :: Kind -> Int
+kindArity (KindArrow _ k) = 1 + kindArity k
+kindArity _               = 0
+
+-- |The function 'kindVars' returns a list of all kind variables
+-- occurring in a kind.
+kindVars :: Kind -> [Int]
+kindVars k = vars k []
+  where
+    vars KindStar          kvs = kvs
+    vars (KindVariable kv) kvs = kv : kvs
+    vars (KindArrow k1 k2) kvs = vars k1 $ vars k2 kvs
+
+-- |The function 'defaultKind' instantiates all kind variables
+-- occurring in a kind to *.
+defaultKind :: Kind -> Kind
+defaultKind (KindArrow k1 k2) = KindArrow (defaultKind k1) (defaultKind k2)
+defaultKind _                 = KindStar
+
+-- |The function 'simpleKind' returns the kind of a type
+-- constructor with arity n whose arguments all have kind *.
+simpleKind :: Int -> Kind
+simpleKind n = foldr KindArrow KindStar $ replicate n KindStar
+
+-- |The function 'isSimpleKind' returns whether a kind is simple or not.
+isSimpleKind :: Kind -> Bool
+isSimpleKind k = k == simpleKind (kindArity k)
+
+-- |Fetches a kind's 'arguments', i.e. everything before an
+-- arrow at the top-level. For example: A kind k1 -> k2 -> k3
+-- would have the arguments [k1, k2].
+kindArgs :: Kind -> [Kind]
+kindArgs (KindArrow k k') = k : kindArgs k'
+kindArgs _                = []
diff --git a/src/Base/Messages.hs b/src/Base/Messages.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/Messages.hs
@@ -0,0 +1,78 @@
+{- |
+    Module      :  $Header$
+    Description :  Construction and output of compiler messages
+    Copyright   :  (c) 2011 - 2016 Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module defines several operations to construct and emit compiler
+    messages to the user.
+-}
+module Base.Messages
+  ( -- * Output of user information
+    MonadIO (..), status, putMsg, putErrLn, putErrsLn
+    -- * program abortion
+  , abortWith, abortWithMessage, abortWithMessages, warnOrAbort, internalError
+    -- * creating messages
+  , Message, message, posMessage, spanInfoMessage
+  ) where
+
+import Control.Monad              (unless, when)
+import Control.Monad.IO.Class     (MonadIO(..))
+import Data.List                  (sort)
+import System.IO                  (hFlush, hPutStrLn, stderr, stdout)
+import System.Exit                (exitFailure)
+
+import Curry.Base.Message         ( Message, message, posMessage, spanInfoMessage
+                                  , ppWarning, ppMessagesWithPreviews, ppError)
+import Curry.Base.Pretty          (Doc, text)
+import CompilerOpts               (Options (..), WarnOpts (..), Verbosity (..))
+
+-- |Print a status message, depending on the current verbosity
+status :: MonadIO m => Options -> String -> m ()
+status opts msg = unless (optVerbosity opts < VerbStatus) (putMsg msg)
+
+-- |Print a message on 'stdout'
+putMsg :: MonadIO m => String -> m ()
+putMsg msg = liftIO (putStrLn msg >> hFlush stdout)
+
+-- |Print an error message on 'stderr'
+putErrLn :: MonadIO m => String -> m ()
+putErrLn msg = liftIO (hPutStrLn stderr msg >> hFlush stderr)
+
+-- |Print a list of error messages on 'stderr'
+putErrsLn :: MonadIO m => [String] -> m ()
+putErrsLn = mapM_ putErrLn
+
+-- |Print a list of 'String's as error messages on 'stderr'
+-- and abort the program
+abortWith :: [String] -> IO a
+abortWith errs = putErrsLn errs >> exitFailure
+
+-- |Print a single error message on 'stderr' and abort the program
+abortWithMessage :: Message -> IO a
+abortWithMessage msg = abortWithMessages [msg]
+
+-- |Print a list of error messages on 'stderr' and abort the program
+abortWithMessages :: [Message] -> IO a
+abortWithMessages msgs = printMessages ppError msgs >> exitFailure
+
+-- |Print a list of warning messages on 'stderr' and abort the program
+-- |if the -Werror option is set
+warnOrAbort :: WarnOpts -> [Message] -> IO ()
+warnOrAbort opts msgs = when (wnWarn opts && not (null msgs)) $ do
+  if wnWarnAsError opts
+    then abortWithMessages (msgs ++ [message $ text "Failed due to -Werror"])
+    else printMessages ppWarning msgs
+
+-- |Print a list of messages on 'stderr'
+printMessages :: (Message -> Doc) -> [Message] -> IO ()
+printMessages msgType msgs
+  = unless (null msgs) $ putErrLn =<< (fmap show $ ppMessagesWithPreviews msgType $ sort msgs)
+
+-- |Raise an internal error
+internalError :: String -> a
+internalError msg = error $ "Internal error: " ++ msg
diff --git a/src/Base/NestEnv.hs b/src/Base/NestEnv.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/NestEnv.hs
@@ -0,0 +1,120 @@
+{- |
+    Module      :  $Header$
+    Description :  Nested Environments
+    Copyright   :  (c) 1999 - 2003 Wolfgang Lux
+                       2011 - 2015 Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   The 'NestEnv' environment type extends top-level environments  to manage
+   nested scopes. Local scopes allow only for a single, unambiguous definition.
+
+   As a matter of convenience, the module 'TopEnv' is exported by
+   the module 'NestEnv'. Thus, only the latter needs to be imported.
+-}
+
+module Base.NestEnv
+  ( module Base.TopEnv
+  , NestEnv, emptyEnv, bindNestEnv, qualBindNestEnv
+  , lookupNestEnv, qualLookupNestEnv
+  , rebindNestEnv, qualRebindNestEnv
+  , unnestEnv, toplevelEnv, globalEnv, nestEnv, elemNestEnv
+  , qualModifyNestEnv, modifyNestEnv, localNestEnv, qualInLocalNestEnv
+  ) where
+
+import qualified Data.Map         as Map
+import           Curry.Base.Ident
+
+import Base.Messages (internalError)
+import Base.TopEnv
+
+data NestEnv a
+  = GlobalEnv (TopEnv  a)
+  | LocalEnv  (NestEnv a) (Map.Map Ident a)
+    deriving Show
+
+instance Functor NestEnv where
+  fmap f (GlobalEnv     env) = GlobalEnv (fmap f  env)
+  fmap f (LocalEnv genv env) = LocalEnv  (fmap f genv) (fmap f env)
+
+globalEnv :: TopEnv a -> NestEnv a
+globalEnv = GlobalEnv
+
+emptyEnv :: NestEnv a
+emptyEnv = globalEnv emptyTopEnv
+
+nestEnv :: NestEnv a -> NestEnv a
+nestEnv env = LocalEnv env Map.empty
+
+unnestEnv :: NestEnv a -> NestEnv a
+unnestEnv g@(GlobalEnv   _) = g
+unnestEnv (LocalEnv genv _) = genv
+
+toplevelEnv :: NestEnv a -> TopEnv a
+toplevelEnv (GlobalEnv   env) = env
+toplevelEnv (LocalEnv genv _) = toplevelEnv genv
+
+bindNestEnv :: Ident -> a -> NestEnv a -> NestEnv a
+bindNestEnv x y (GlobalEnv     env) = GlobalEnv $ bindTopEnv x y env
+bindNestEnv x y (LocalEnv genv env) = case Map.lookup x env of
+  Just  _ -> internalError $ "NestEnv.bindNestEnv: " ++ show x ++ " is already bound"
+  Nothing -> LocalEnv genv $ Map.insert x y env
+
+qualBindNestEnv :: QualIdent -> a -> NestEnv a -> NestEnv a
+qualBindNestEnv x y (GlobalEnv     env) = GlobalEnv $ qualBindTopEnv x y env
+qualBindNestEnv x y (LocalEnv genv env)
+  | isQualified x = internalError $ "NestEnv.qualBindNestEnv " ++ show x
+  | otherwise     = case Map.lookup x' env of
+      Just  _ -> internalError $ "NestEnv.qualBindNestEnv " ++ show x
+      Nothing -> LocalEnv genv $ Map.insert x' y env
+    where x' = unqualify x
+
+-- Rebinds a value to a variable, failes if the variable was unbound before
+rebindNestEnv :: Ident -> a -> NestEnv a -> NestEnv a
+rebindNestEnv = qualRebindNestEnv . qualify
+
+qualRebindNestEnv :: QualIdent -> a -> NestEnv a -> NestEnv a
+qualRebindNestEnv x y (GlobalEnv     env) = GlobalEnv $ qualRebindTopEnv x y env
+qualRebindNestEnv x y (LocalEnv genv env)
+  | isQualified x = internalError $ "NestEnv.qualRebindNestEnv " ++ show x
+  | otherwise     = case Map.lookup x' env of
+      Just  _ -> LocalEnv genv $ Map.insert x' y env
+      Nothing -> LocalEnv (qualRebindNestEnv x y genv) env
+    where x' = unqualify x
+
+lookupNestEnv :: Ident -> NestEnv a -> [a]
+lookupNestEnv x (GlobalEnv     env) = lookupTopEnv x env
+lookupNestEnv x (LocalEnv genv env) = case Map.lookup x env of
+  Just  y -> [y]
+  Nothing -> lookupNestEnv x genv
+
+qualLookupNestEnv :: QualIdent -> NestEnv a -> [a]
+qualLookupNestEnv x env
+  | isQualified x = qualLookupTopEnv x $ toplevelEnv env
+  | otherwise     = lookupNestEnv (unqualify x) env
+
+elemNestEnv :: Ident -> NestEnv a -> Bool
+elemNestEnv x env = not (null (lookupNestEnv x env))
+
+-- Applies a function to a value binding, does nothing if the variable is unbound
+modifyNestEnv :: (a -> a) -> Ident -> NestEnv a -> NestEnv a
+modifyNestEnv f = qualModifyNestEnv f . qualify
+
+qualModifyNestEnv :: (a -> a) -> QualIdent -> NestEnv a -> NestEnv a
+qualModifyNestEnv f x env = case qualLookupNestEnv x env of
+  []    -> env
+  y : _ -> qualRebindNestEnv x (f y) env
+
+-- Returns the variables and values bound on the bottom (meaning non-top) scope
+localNestEnv :: NestEnv a -> [(Ident, a)]
+localNestEnv (GlobalEnv env)  = localBindings env
+localNestEnv (LocalEnv _ env) = Map.toList env
+
+-- Returns wether the variable is bound on the bottom (meaning non-top) scope
+qualInLocalNestEnv :: QualIdent -> NestEnv a -> Bool
+qualInLocalNestEnv x (GlobalEnv  env) = qualElemTopEnv x env
+qualInLocalNestEnv x (LocalEnv _ env) =    (not (isQualified x))
+                                        && Map.member (unqualify x) env
diff --git a/src/Base/PrettyKinds.hs b/src/Base/PrettyKinds.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/PrettyKinds.hs
@@ -0,0 +1,22 @@
+{- |
+    Module      :  $Header$
+    Description :  TODO
+    Copyright   :  (c) 2017        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   TODO
+-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+module Base.PrettyKinds where
+
+import Curry.Base.Pretty
+
+import Base.CurryKinds
+import Base.Kinds
+
+instance Pretty Kind where
+  pPrint = ppKind
diff --git a/src/Base/PrettyTypes.hs b/src/Base/PrettyTypes.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/PrettyTypes.hs
@@ -0,0 +1,55 @@
+{- |
+    Module      :  $Header$
+    Description :  TODO
+    Copyright   :  (c) 2017        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   TODO
+-}
+{-# LANGUAGE     CPP        #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+module Base.PrettyTypes where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+import Data.Maybe (fromMaybe)
+import qualified Data.Set as Set (Set, toAscList)
+
+import Curry.Base.Ident (identSupply)
+import Curry.Base.Pretty
+
+import Base.CurryTypes
+import Base.Types
+
+instance Pretty Type where
+  pPrint = pPrintPrec 0 . fromType identSupply
+
+instance Pretty Pred where
+  pPrint = pPrint . fromPred identSupply
+
+instance Pretty a => Pretty (Set.Set a) where
+  pPrint = parens . list . map pPrint . Set.toAscList
+
+instance Pretty PredType where
+  pPrint = pPrint . fromPredType identSupply
+
+instance Pretty DataConstr where
+  pPrint (DataConstr i tys)      = pPrint i <+> hsep (map pPrint tys)
+  pPrint (RecordConstr i ls tys) =     pPrint i
+                                   <+> braces (hsep (punctuate comma pLs))
+    where
+      pLs = zipWith (\l ty -> pPrint l <+> colon <> colon <+> pPrint ty) ls tys
+
+instance Pretty ClassMethod where
+  pPrint (ClassMethod f mar pty) =     pPrint f
+                                   <>  text "/" <> int (fromMaybe 0 mar)
+                                   <+> colon <> colon <+> pPrint pty
+
+instance Pretty TypeScheme where
+  pPrint (ForAll _ ty) = pPrint ty
diff --git a/src/Base/SCC.hs b/src/Base/SCC.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/SCC.hs
@@ -0,0 +1,62 @@
+{- |
+    Module      :  $Header$
+    Description :  Computation of strongly connected components
+    Copyright   :  (c) 2000, 2002 - 2003 Wolfgang Lux
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   At various places in the compiler we had to partition a list of
+   declarations into strongly connected components. The function
+   'scc' computes this relation in two steps. First, the list is
+   topologically sorted downwards using the 'defs' relation.
+   Then the resulting list is sorted upwards using the 'uses' relation
+   and partitioned into the connected components. Both relations
+   are computed within this module using the bound and free names of each
+   declaration.
+
+   In order to avoid useless recomputations, the code in the module first
+   decorates the declarations with their bound and free names and a
+   unique number. The latter is only used to provide a trivial ordering
+   so that the declarations can be used as set elements.
+-}
+
+module Base.SCC (scc) where
+
+import qualified Data.Set as Set (empty, member, insert)
+
+data Node a b = Node { key :: Int, bvs :: [b], fvs :: [b], node :: a }
+
+instance Eq (Node a b) where
+  n1 == n2 = key n1 == key n2
+
+instance Ord (Node b a) where
+  n1 `compare` n2 = key n1 `compare` key n2
+
+-- |Computation of strongly connected components
+scc :: Eq b => (a -> [b]) -- ^entities defined by node
+            -> (a -> [b]) -- ^entities used by node
+            -> [a]        -- ^list of nodes
+            -> [[a]]      -- ^strongly connected components
+scc bvs' fvs' = map (map node) . tsort' . tsort . zipWith wrap [0 ..]
+  where wrap i n = Node i (bvs' n) (fvs' n) n
+
+tsort :: Eq b => [Node a b] -> [Node a b]
+tsort xs = snd (dfs xs Set.empty []) where
+  dfs [] marks stack = (marks,stack)
+  dfs (x : xs') marks stack
+    | x `Set.member` marks = dfs xs' marks stack
+    | otherwise = dfs xs' marks' (x : stack')
+    where (marks',stack') = dfs (defs x) (x `Set.insert` marks) stack
+          defs x1 = filter (any (`elem` fvs x1) . bvs) xs
+
+tsort' :: Eq b => [Node a b] -> [[Node a b]]
+tsort' xs = snd (dfs xs Set.empty []) where
+  dfs [] marks stack = (marks,stack)
+  dfs (x : xs') marks stack
+    | x `Set.member` marks = dfs xs' marks stack
+    | otherwise = dfs xs' marks' ((x : concat stack') : stack)
+    where (marks',stack') = dfs (uses x) (x `Set.insert` marks) []
+          uses x1 = filter (any (`elem` bvs x1) . fvs) xs
diff --git a/src/Base/Subst.hs b/src/Base/Subst.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/Subst.hs
@@ -0,0 +1,127 @@
+{- |
+    Module      :  $Header$
+    Description :  General substitution implementation
+    Copyright   :  (c) 2002 Wolfgang Lux
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   The module Subst implements substitutions. A substitution
+   sigma = {x_1 |-> t_1, ... ,x_n |-> t_n} is a finite mapping from
+   (finitely many) variables x_1, ... ,x_n to some kind of expression
+   or term.
+
+   In order to implement substitutions efficiently,
+   composed substitutions are marked with a boolean flag (see below).
+-}
+
+module Base.Subst
+  ( Subst (..), IntSubst (..), idSubst, singleSubst, bindSubst, unbindSubst
+  , substToList, compose, substVar', isubstVar, restrictSubstTo
+  ) where
+
+import qualified Data.Map as Map
+
+-- |Data type for substitution
+data Subst a b = Subst Bool (Map.Map a b)
+  deriving Show
+
+-- |Identity substitution
+idSubst :: Subst a b
+idSubst = Subst False Map.empty
+
+-- |Convert a substitution to a list of replacements
+substToList :: Subst v e -> [(v, e)]
+substToList (Subst _ sigma) = Map.toList sigma
+
+-- |Create a substitution for a single replacement
+singleSubst :: Ord v => v -> e -> Subst v e
+singleSubst v e = bindSubst v e idSubst
+
+-- |Extend a substitution with a single replacement
+bindSubst :: Ord v => v -> e -> Subst v e -> Subst v e
+bindSubst v e (Subst comp sigma) = Subst comp $ Map.insert v e sigma
+
+-- |Remove a single replacement from a substitution
+unbindSubst :: Ord v => v -> Subst v e -> Subst v e
+unbindSubst v (Subst comp sigma) = Subst comp $ Map.delete v sigma
+
+-- For any substitution we have the following definitions:
+--     sigma(x)     = t_i   if x = x_i
+--                    x    otherwise
+--     Dom(sigma)   = {x_1, ... , x_n}
+--     Codom(sigma) = {t_1, ... , t_n}
+-- Note that obviously the set of variables must be a subset of the set
+-- of expressions. Also it is usually possible to extend the substitution
+-- to a homomorphism on the codomain of the substitution. This is
+-- captured by the following class declaration:
+
+-- class Ord v => Subst v e where
+--   var :: v -> e
+--   subst :: Subst v e -> e -> e
+
+-- With the help of the injection 'var', we can then compute the
+-- substitution for a variable sigma(v) and also the composition of
+-- two substitutions sigma1 o sigma2(e) := sigma1(sigma2(e)).
+-- A naive implementation of the composition were
+--
+--   compose sigma sigma' =
+--     foldr (uncurry bindSubst) sigma (substToList (fmap (subst sigma) sigma'))
+--
+-- However, such an implementation is very inefficient because the
+-- number of substiutions applied to a variable increases in
+-- O(n) of the number of compositions.
+
+-- A more efficient implementation is to apply 'subst' again to
+-- the value substituted for a variable in Dom(sigma).
+-- However, this is correct only as long as the result of the substitution
+-- does not include any variables which are in Dom(sigma). For instance,
+-- it is impossible to implement simple variable renamings in this way.
+
+-- Therefore we use the simple strategy to apply 'subst' again
+-- only in case of a substitution which was returned from 'compose'.
+
+-- substVar :: Subst v e => Subst v e -> v -> e
+-- substVar (Subst comp sigma) v = maybe (var v) subst' (Map.lookup v sigma)
+--   where subst' = if comp then subst (Subst comp sigma) else id
+
+-- |Compose two substitutions
+compose :: Ord v => Subst v e -> Subst v e -> Subst v e
+compose sigma sigma' =
+  composed (foldr (uncurry bindSubst) sigma' (substToList sigma))
+  where composed (Subst _ sigma'') = Subst True sigma''
+
+-- Unfortunately Haskell does not (yet) support multi-parameter type
+-- classes. For that reason we have to define a separate class for each
+-- kind of variable type for these functions. We implement
+-- 'substVar' as a function that takes the class functions as an
+-- additional parameters. As an example for the use of this function the
+-- module includes a class 'IntSubst' for substitution whose
+-- domain are integer numbers.
+
+-- |Apply a substitution to a variable
+substVar' :: Ord v => (v -> e) -> (Subst v e -> e -> e)
+          -> Subst v e -> v -> e
+substVar' var subst (Subst comp sigma) v =
+  maybe (var v) subst' (Map.lookup v sigma)
+  where subst' = if comp then subst (Subst comp sigma) else id
+
+-- |Type class for terms where variables are represented as 'Int's
+class IntSubst e where
+  -- |Construct a variable from an 'Int'
+  ivar :: Int -> e
+  -- |Apply a substitution to a term
+  isubst :: Subst Int e -> e -> e
+
+-- |Apply a substitution to a term with variables represented as 'Int's
+isubstVar :: IntSubst e => Subst Int e -> Int -> e
+isubstVar = substVar' ivar isubst
+
+-- |The function 'restrictSubstTo' implements the restriction of a
+-- substitution to a given subset of its domain.
+restrictSubstTo :: Ord v => [v] -> Subst v e -> Subst v e
+restrictSubstTo vs (Subst comp sigma) =
+  foldr (uncurry bindSubst) (Subst comp Map.empty)
+        (filter ((`elem` vs) . fst) (Map.toList sigma))
diff --git a/src/Base/TopEnv.hs b/src/Base/TopEnv.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/TopEnv.hs
@@ -0,0 +1,181 @@
+{- |
+    Module      :  $Header$
+    Description :  Top-Level Environments
+    Copyright   :   1999 - 2003 Wolfgang Lux
+                    2005        Martin Engelke
+                    2011 - 2012 Björn Peemöller
+                    2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    The module 'TopEnv' implements environments for qualified and
+    possibly ambiguous identifiers. An identifier is ambiguous if two
+    different entities are imported under the same name or if a local
+    definition uses the same name as an imported entity. Following an idea
+    presented in a paper by Diatchki, Jones and Hallgren (2002),
+    an identifier is associated with a list of entities in order to handle
+    ambiguous names properly.
+
+    In general, two entities are considered equal if the names of their
+    original definitions match. However, in the case of algebraic data
+    types it is possible to hide some or all of their data constructors on
+    import and export, respectively. In this case we have to merge both
+    imports such that all data constructors which are visible through any
+    import path are visible in the current module. The class
+    Entity is used to handle this merge.
+
+    The code in this module ensures that the list of entities returned by
+    the functions 'lookupTopEnv' and 'qualLookupTopEnv' contains exactly one
+    element for each imported entity regardless of how many times and
+    from which module(s) it was imported. Thus, the result of these function
+    is a list with exactly one element if and only if the identifier is
+    unambiguous. The module names associated with an imported entity identify
+    the modules from which the entity was imported.
+-}
+
+module Base.TopEnv
+  ( -- * Data types
+    TopEnv (..), Entity (..)
+    -- * creation and insertion
+  , emptyTopEnv, predefTopEnv, importTopEnv, qualImportTopEnv
+  , bindTopEnv, qualBindTopEnv, rebindTopEnv
+  , qualRebindTopEnv, unbindTopEnv, qualUnbindTopEnv
+  , lookupTopEnv, qualLookupTopEnv, qualElemTopEnv
+  , allImports, moduleImports, localBindings, allLocalBindings, allBindings
+  , allEntities
+  ) where
+
+import           Control.Arrow        (second)
+import qualified Data.Map      as Map
+  (Map, empty, insert, findWithDefault, lookup, toList)
+
+import Curry.Base.Ident
+import Base.Messages (internalError)
+
+class Entity a where
+ origName :: a -> QualIdent
+ merge    :: a -> a -> Maybe a
+ merge x y
+   | origName x == origName y = Just x
+   | otherwise                = Nothing
+
+data Source = Local | Import [ModuleIdent] deriving (Eq, Show)
+
+-- |Top level environment
+newtype TopEnv a = TopEnv { topEnvMap :: Map.Map QualIdent [(Source, a)] }
+  deriving Show
+
+instance Functor TopEnv where
+  fmap f (TopEnv env) = TopEnv (fmap (map (second f)) env)
+
+-- local helper
+entities :: QualIdent -> Map.Map QualIdent [(Source, a)] -> [(Source, a)]
+entities = Map.findWithDefault []
+
+-- |Empty 'TopEnv'
+emptyTopEnv :: TopEnv a
+emptyTopEnv = TopEnv Map.empty
+
+-- |Insert an 'Entity' into a 'TopEnv' as a predefined 'Entity'
+predefTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a
+predefTopEnv k v (TopEnv env) = case Map.lookup k env of
+  Just  _ -> internalError $ "TopEnv.predefTopEnv " ++ show k
+  Nothing -> TopEnv $ Map.insert k [(Import [], v)] env
+
+-- |Insert an 'Entity' as unqualified into a 'TopEnv'
+importTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a
+             -> TopEnv a
+importTopEnv m x y env = addImport m (qualify x) y env
+
+-- |Insert an 'Entity' as qualified into a 'TopEnv'
+qualImportTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a
+                 -> TopEnv a
+qualImportTopEnv m x y env = addImport m (qualifyWith m x) y env
+
+-- local helper
+addImport :: Entity a => ModuleIdent -> QualIdent -> a -> TopEnv a
+          -> TopEnv a
+addImport m k v (TopEnv env) = TopEnv $
+  Map.insert k (mergeImport v (entities k env)) env
+  where
+  mergeImport :: Entity a => a -> [(Source, a)] -> [(Source, a)]
+  mergeImport y []                         = [(Import [m], y)]
+  mergeImport y (loc@(Local    ,  _) : xs) = loc : mergeImport y xs
+  mergeImport y (imp@(Import ms, y') : xs) = case merge y y' of
+    Just y'' -> (Import (m : ms), y'') : xs
+    Nothing  -> imp : mergeImport y xs
+
+bindTopEnv :: Ident -> a -> TopEnv a -> TopEnv a
+bindTopEnv x y env = qualBindTopEnv (qualify x) y env
+
+qualBindTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a
+qualBindTopEnv x y (TopEnv env)
+  = TopEnv $ Map.insert x (bindLocal y (entities x env)) env
+  where
+  bindLocal y' ys
+    | null [ y'' | (Local, y'') <- ys ] = (Local, y') : ys
+    | otherwise = internalError $ "qualBindTopEnv " ++ show x
+
+rebindTopEnv :: Ident -> a -> TopEnv a -> TopEnv a
+rebindTopEnv = qualRebindTopEnv . qualify
+
+qualRebindTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a
+qualRebindTopEnv x y (TopEnv env) =
+  TopEnv $ Map.insert x (rebindLocal (entities x env)) env
+  where
+  rebindLocal []                = internalError
+                                $ "TopEnv.qualRebindTopEnv " ++ show x
+  rebindLocal ((Local, _) : ys) = (Local, y) : ys
+  rebindLocal (imported   : ys) = imported   : rebindLocal ys
+
+unbindTopEnv :: Ident -> TopEnv a -> TopEnv a
+unbindTopEnv x (TopEnv env) =
+  TopEnv $ Map.insert x' (unbindLocal (entities x' env)) env
+  where x' = qualify x
+        unbindLocal [] = internalError $ "TopEnv.unbindTopEnv " ++ show x
+        unbindLocal ((Local, _) : ys) = ys
+        unbindLocal (imported   : ys) = imported : unbindLocal ys
+
+qualUnbindTopEnv :: QualIdent -> TopEnv a -> TopEnv a
+qualUnbindTopEnv x (TopEnv env) =
+  TopEnv $ Map.insert x (unbind (entities x env)) env
+  where unbind [] = internalError $ "TopEnv.qualUnbindTopEnv " ++ show x
+        unbind _  = []
+
+lookupTopEnv :: Ident -> TopEnv a -> [a]
+lookupTopEnv = qualLookupTopEnv . qualify
+
+qualLookupTopEnv :: QualIdent -> TopEnv a -> [a]
+qualLookupTopEnv x (TopEnv env) = map snd (entities x env)
+
+qualElemTopEnv :: QualIdent -> TopEnv a -> Bool
+qualElemTopEnv x env = not (null (qualLookupTopEnv x env))
+
+allImports :: TopEnv a -> [(QualIdent, a)]
+allImports (TopEnv env) =
+  [ (x, y) | (x, ys) <- Map.toList env, (Import _, y) <- ys ]
+
+unqualBindings :: TopEnv a -> [(Ident, (Source, a))]
+unqualBindings (TopEnv env) =
+  [ (x', y) | (x, ys) <- filter (not . isQualified . fst) (Map.toList env)
+            , let x' = unqualify x, y <- ys]
+
+moduleImports :: ModuleIdent -> TopEnv a -> [(Ident, a)]
+moduleImports m env =
+  [(x, y) | (x, (Import ms, y)) <- unqualBindings env, m `elem` ms]
+
+localBindings :: TopEnv a -> [(Ident, a)]
+localBindings env = [ (x, y) | (x, (Local, y)) <- unqualBindings env ]
+
+allLocalBindings :: TopEnv a -> [(QualIdent, a)]
+allLocalBindings (TopEnv env) = [ (x, y) | (x, ys)    <- Map.toList env
+                                         , (Local, y) <- ys ]
+
+allBindings :: TopEnv a -> [(QualIdent, a)]
+allBindings (TopEnv env) = [(x, y) | (x, ys) <- Map.toList env, (_, y) <- ys]
+
+allEntities :: TopEnv a -> [a]
+allEntities (TopEnv env) = [ y | (_, ys) <- Map.toList env, (_, y) <- ys]
diff --git a/src/Base/TypeExpansion.hs b/src/Base/TypeExpansion.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/TypeExpansion.hs
@@ -0,0 +1,112 @@
+{- |
+    Module      :  $Header$
+    Description :  Type expansion
+    Copyright   :  (c) 2016 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   This module implements expansion of alias types in types and predicates.
+-}
+
+module Base.TypeExpansion
+  ( module Base.TypeExpansion
+  ) where
+
+import qualified Data.Set.Extra as Set (map)
+
+import Curry.Base.Ident
+import Curry.Syntax
+
+import Base.CurryTypes
+import Base.Messages
+import Base.Types
+import Base.TypeSubst
+
+import Env.Class
+import Env.TypeConstructor
+
+-- The function 'expandType' expands all type synonyms in a type
+-- and also qualifies all type constructors with the name of the module
+-- in which the type was defined. Similarly, 'expandPred' expands all
+-- type synonyms in a predicate and also qualifies all class identifiers
+-- with the name of the module in which the class was defined. The
+-- function 'expandPredSet' minimizes the predicate set after expansion.
+
+expandType :: ModuleIdent -> TCEnv -> Type -> Type
+expandType m tcEnv ty = expandType' m tcEnv ty []
+
+expandType' :: ModuleIdent -> TCEnv -> Type -> [Type] -> Type
+expandType' m tcEnv (TypeConstructor     tc) tys =
+  case qualLookupTypeInfo tc tcEnv of
+    [DataType       tc' _ _ ] -> applyType (TypeConstructor tc') tys
+    [RenamingType   tc' _ _ ] -> applyType (TypeConstructor tc') tys
+    [AliasType    _ _   n ty] -> let (tys', tys'') = splitAt n tys
+                                 in  applyType (expandAliasType tys' ty) tys''
+    _ -> case qualLookupTypeInfo (qualQualify m tc) tcEnv of
+      [DataType       tc' _ _ ] -> applyType (TypeConstructor tc') tys
+      [RenamingType   tc' _ _ ] -> applyType (TypeConstructor tc') tys
+      [AliasType    _ _   n ty] -> let (tys', tys'') = splitAt n tys
+                                   in  applyType (expandAliasType tys' ty) tys''
+      _ -> internalError $ "Base.TypeExpansion.expandType: " ++ show tc
+expandType' m tcEnv (TypeApply      ty1 ty2) tys =
+  expandType' m tcEnv ty1 (expandType m tcEnv ty2 : tys)
+expandType' _ _     tv@(TypeVariable      _) tys = applyType tv tys
+expandType' _ _     tc@(TypeConstrained _ _) tys = applyType tc tys
+expandType' m tcEnv (TypeArrow      ty1 ty2) tys =
+  applyType (TypeArrow (expandType m tcEnv ty1) (expandType m tcEnv ty2)) tys
+expandType' m tcEnv (TypeForall      tvs ty) tys =
+  applyType (TypeForall tvs (expandType m tcEnv ty)) tys
+
+expandPred :: ModuleIdent -> TCEnv -> Pred -> Pred
+expandPred m tcEnv (Pred qcls ty) = case qualLookupTypeInfo qcls tcEnv of
+  [TypeClass ocls _ _] -> Pred ocls (expandType m tcEnv ty)
+  _ -> case qualLookupTypeInfo (qualQualify m qcls) tcEnv of
+    [TypeClass ocls _ _] -> Pred ocls (expandType m tcEnv ty)
+    _ -> internalError $ "Base.TypeExpansion.expandPred: " ++ show qcls
+
+expandPredSet :: ModuleIdent -> TCEnv -> ClassEnv -> PredSet -> PredSet
+expandPredSet m tcEnv clsEnv = minPredSet clsEnv . Set.map (expandPred m tcEnv)
+
+expandPredType :: ModuleIdent -> TCEnv -> ClassEnv -> PredType -> PredType
+expandPredType m tcEnv clsEnv (PredType ps ty) =
+  PredType (expandPredSet m tcEnv clsEnv ps) (expandType m tcEnv ty)
+
+-- The functions 'expandMonoType' and 'expandPolyType' convert (qualified)
+-- type expressions into (predicated) types and also expand all type synonyms
+-- and qualify all type constructors during the conversion.
+
+expandMonoType :: ModuleIdent -> TCEnv -> [Ident] -> TypeExpr -> Type
+expandMonoType m tcEnv tvs = expandType m tcEnv . toType tvs
+
+expandPolyType :: ModuleIdent -> TCEnv -> ClassEnv -> QualTypeExpr -> PredType
+expandPolyType m tcEnv clsEnv =
+  normalize 0 . expandPredType m tcEnv clsEnv . toPredType []
+
+-- The function 'expandConstrType' computes the predicated type for a data
+-- or newtype constructor. Similar to 'toConstrType' from 'CurryTypes', the
+-- type's context is restricted to those type variables which are free in
+-- the argument types. However, type synonyms are expanded and type constructors
+-- and type classes are qualified with the name of the module containing their
+-- definition.
+
+expandConstrType :: ModuleIdent -> TCEnv -> ClassEnv -> QualIdent -> [Ident]
+                 -> [TypeExpr] -> PredType
+expandConstrType m tcEnv clsEnv tc tvs tys =
+  normalize n $ expandPredType m tcEnv clsEnv pty
+  where n = length tvs
+        pty = toConstrType tc tvs tys
+
+-- The function 'expandMethodType' converts the type of a type class method
+-- Similar to function 'toMethodType' from 'CurryTypes', the implicit class
+-- constraint is added to the method's type and the class' type variable is
+-- assigned index 0. However, type synonyms are expanded and type constructors
+-- and type classes are qualified with the name of the module containing their
+-- definition.
+
+expandMethodType :: ModuleIdent -> TCEnv -> ClassEnv -> QualIdent -> Ident
+                 -> QualTypeExpr -> PredType
+expandMethodType m tcEnv clsEnv qcls tv =
+  normalize 1 . expandPredType m tcEnv clsEnv . toMethodType qcls tv
diff --git a/src/Base/TypeSubst.hs b/src/Base/TypeSubst.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/TypeSubst.hs
@@ -0,0 +1,137 @@
+{- |
+    Module      :  $Header$
+    Description :  Type substitution
+    Copyright   :  (c) 2003 Wolfgang Lux
+                       2016 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   This module implements substitutions on types.
+-}
+
+module Base.TypeSubst
+  ( module Base.TypeSubst, idSubst, singleSubst, bindSubst, compose
+  ) where
+
+import           Data.List       (nub)
+import           Data.Maybe      (fromMaybe)
+import qualified Data.Set as Set (Set, map)
+
+import Base.Subst
+import Base.TopEnv
+import Base.Types
+
+import Env.Value (ValueInfo (..))
+
+type TypeSubst = Subst Int Type
+
+class SubstType a where
+  subst :: TypeSubst -> a -> a
+
+bindVar :: Int -> Type -> TypeSubst -> TypeSubst
+bindVar tv ty = compose (bindSubst tv ty idSubst)
+
+substVar :: TypeSubst -> Int -> Type
+substVar = substVar' TypeVariable subst
+
+instance (Ord a, SubstType a) => SubstType (Set.Set a) where
+  subst sigma = Set.map (subst sigma)
+
+instance SubstType a => SubstType [a] where
+  subst sigma = map (subst sigma)
+
+instance SubstType Type where
+  subst sigma ty = subst' sigma ty []
+
+subst' :: TypeSubst -> Type -> [Type] -> Type
+subst' _     tc@(TypeConstructor   _) = foldl TypeApply tc
+subst' sigma (TypeApply      ty1 ty2) = subst' sigma ty1 . (subst sigma ty2 :)
+subst' sigma (TypeVariable        tv) = applyType (substVar sigma tv)
+subst' sigma (TypeArrow      ty1 ty2) =
+  foldl TypeApply (TypeArrow (subst sigma ty1) (subst sigma ty2))
+subst' sigma (TypeConstrained tys tv) = case substVar sigma tv of
+  TypeVariable tv' -> foldl TypeApply (TypeConstrained tys tv')
+  ty               -> foldl TypeApply ty
+subst' sigma (TypeForall      tvs ty) =
+  applyType (TypeForall tvs (subst sigma ty))
+
+instance SubstType Pred where
+  subst sigma (Pred qcls ty) = Pred qcls (subst sigma ty)
+
+instance SubstType PredType where
+  subst sigma (PredType ps ty) = PredType (subst sigma ps) (subst sigma ty)
+
+instance SubstType TypeScheme where
+  subst sigma (ForAll n ty) =
+    ForAll n (subst (foldr unbindSubst sigma [0 .. n-1]) ty)
+
+instance SubstType ValueInfo where
+  subst _     dc@(DataConstructor  _ _ _ _) = dc
+  subst _     nc@(NewtypeConstructor _ _ _) = nc
+  subst theta (Value             v cm a ty) = Value v cm a (subst theta ty)
+  subst theta (Label                l r ty) = Label l r (subst theta ty)
+
+instance SubstType a => SubstType (TopEnv a) where
+  subst = fmap . subst
+
+-- The class method 'expandAliasType' expands all occurrences of a
+-- type synonym in its second argument.
+
+class ExpandAliasType a where
+  expandAliasType :: [Type] -> a -> a
+
+instance ExpandAliasType a => ExpandAliasType [a] where
+  expandAliasType tys = map (expandAliasType tys)
+
+instance (Ord a, ExpandAliasType a) => ExpandAliasType (Set.Set a) where
+  expandAliasType tys = Set.map (expandAliasType tys)
+
+instance ExpandAliasType Type where
+  expandAliasType tys ty = expandAliasType' tys ty []
+
+expandAliasType' :: [Type] -> Type -> [Type] -> Type
+expandAliasType' _   tc@(TypeConstructor   _) = applyType tc
+expandAliasType' tys (TypeApply      ty1 ty2) =
+  expandAliasType' tys ty1 . (expandAliasType tys ty2 :)
+expandAliasType' tys tv@(TypeVariable      n)
+  | n >= 0    = applyType (tys !! n)
+  | otherwise = applyType tv
+expandAliasType' _   tc@(TypeConstrained _ _) = applyType tc
+expandAliasType' tys (TypeArrow      ty1 ty2) =
+  applyType (TypeArrow (expandAliasType tys ty1) (expandAliasType tys ty2))
+expandAliasType' tys (TypeForall      tvs ty) =
+  applyType (TypeForall tvs (expandAliasType tys ty))
+
+instance ExpandAliasType Pred where
+  expandAliasType tys (Pred qcls ty) = Pred qcls (expandAliasType tys ty)
+
+instance ExpandAliasType PredType where
+  expandAliasType tys (PredType ps ty) =
+    PredType (expandAliasType tys ps) (expandAliasType tys ty)
+
+-- After the expansion we have to reassign the type indices for all type
+-- variables. Otherwise, expanding a type synonym like type 'Pair a b = (b,a)'
+-- could break the invariant that the universally quantified type variables
+-- are assigned indices in the order of their occurrence. This is handled by
+-- the function 'normalize'. The function has a threshold parameter that allows
+-- preserving the indices of type variables bound on the left hand side
+-- of a type declaration and in the head of a type class declaration,
+-- respectively.
+
+normalize :: Int -> PredType -> PredType
+normalize n ty = expandAliasType [TypeVariable (occur tv) | tv <- [0..]] ty
+  where tvs = zip (nub (filter (>= n) (typeVars ty))) [n..]
+        occur tv = fromMaybe tv (lookup tv tvs)
+
+-- The function 'instanceType' computes an instance of a polymorphic type by
+-- substituting the first type argument for all occurrences of the type
+-- variable with index 0 in the second argument. The function carefully
+-- assigns new indices to all other type variables of the second argument
+-- so that they do not conflict with the type variables of the first argument.
+
+instanceType :: ExpandAliasType a => Type -> a -> a
+instanceType ty = expandAliasType (ty : map TypeVariable [n ..])
+  where ForAll n _ = polyType ty
diff --git a/src/Base/Types.hs b/src/Base/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/Types.hs
@@ -0,0 +1,478 @@
+{- |
+    Module      :  $Header$
+    Description :  Internal representation of types
+    Copyright   :  (c) 2002 - 2004 Wolfgang Lux
+                                   Martin Engelke
+                       2015        Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   This module modules provides the definitions for the internal
+   representation of types in the compiler along with some helper functions.
+-}
+
+-- TODO: Use MultiParamTypeClasses ?
+
+module Base.Types
+  ( -- * Representation of types
+    Type (..), applyType, unapplyType, rootOfType
+  , isArrowType, arrowArity, arrowArgs, arrowBase, arrowUnapply
+  , IsType (..), typeConstrs
+  , qualifyType, unqualifyType, qualifyTC
+    -- * Representation of predicate, predicate sets and predicated types
+  , Pred (..), qualifyPred, unqualifyPred
+  , PredSet, emptyPredSet, partitionPredSet, minPredSet, maxPredSet
+  , qualifyPredSet, unqualifyPredSet
+  , PredType (..), predType, unpredType, qualifyPredType, unqualifyPredType
+    -- * Representation of data constructors
+  , DataConstr (..), constrIdent, constrTypes, recLabels, recLabelTypes
+  , tupleData
+    -- * Representation of class methods
+  , ClassMethod (..), methodName, methodArity, methodType
+    -- * Representation of quantification
+  , TypeScheme (..), monoType, polyType, typeScheme
+  , rawType
+    -- * Predefined types
+  , arrowType, unitType, predUnitType, boolType, predBoolType, charType
+  , intType, predIntType, floatType, predFloatType, stringType, predStringType
+  , listType, consType, ioType, tupleType
+  , numTypes, fractionalTypes
+  , predefTypes
+  ) where
+
+import qualified Data.Set.Extra as Set
+
+import Curry.Base.Ident
+
+import Base.Messages (internalError)
+
+import Env.Class (ClassEnv, allSuperClasses)
+
+-- ---------------------------------------------------------------------------
+-- Types
+-- ---------------------------------------------------------------------------
+
+-- A type is either a type constructor, a type variable, an application
+-- of a type to another type, or an arrow type. Although the latter could
+-- be expressed by using 'TypeApply' with the function type constructor,
+-- we currently use 'TypeArrow' because arrow types are used so frequently.
+
+-- The 'TypeConstrained' case is used for representing type variables that
+-- are restricted to a particular set of types. At present, this is used
+-- for typing integer literals, which are restricted to types 'Int' and
+-- 'Float'. If the type is not restricted, it defaults to the first type
+-- from the constraint list.
+
+-- Type variables are represented with deBruijn style indices. Universally
+-- quantified type variables are assigned indices in the order of their
+-- occurrence in the type from left to right. This leads to a canonical
+-- representation of types where alpha-equivalence of two types
+-- coincides with equality of the representation.
+
+-- Note that even though 'TypeConstrained' variables use indices
+-- as well, these variables must never be quantified.
+
+-- Note further that the order of constructors is important for the derived
+-- 'Ord' instance. In particular, it is essential that the type variable
+-- is considered less than the type application (see predicates and predicate
+-- sets below for more information).
+
+data Type
+  = TypeConstructor QualIdent
+  | TypeVariable Int
+  | TypeConstrained [Type] Int
+  | TypeApply Type Type
+  | TypeArrow Type Type
+  | TypeForall [Int] Type
+  deriving (Eq, Ord, Show)
+
+-- The function 'applyType' applies a type to a list of argument types,
+-- whereas applications of the function type constructor to two arguments
+-- are converted into an arrow type. The function 'unapplyType' decomposes
+-- a type into a root type and a list of argument types.
+
+applyType :: Type -> [Type] -> Type
+applyType (TypeConstructor tc) tys
+  | tc == qArrowId && length tys == 2 = TypeArrow (tys !! 0) (tys !! 1)
+applyType (TypeApply (TypeConstructor tc) ty) tys
+  | tc == qArrowId && length tys == 1 = TypeArrow ty (head tys)
+applyType ty tys = foldl TypeApply ty tys
+
+unapplyType :: Bool -> Type -> (Type, [Type])
+unapplyType dflt ty = unapply ty []
+  where
+    unapply (TypeConstructor     tc) tys  = (TypeConstructor tc, tys)
+    unapply (TypeApply      ty1 ty2) tys  = unapply ty1 (ty2 : tys)
+    unapply (TypeVariable        tv) tys  = (TypeVariable tv, tys)
+    unapply (TypeArrow      ty1 ty2) tys  =
+      (TypeConstructor qArrowId, ty1 : ty2 : tys)
+    unapply (TypeConstrained tys tv) tys'
+      | dflt      = unapply (head tys) tys'
+      | otherwise = (TypeConstrained tys tv, tys')
+    unapply (TypeForall     tvs ty') tys  = (TypeForall tvs ty', tys)
+
+-- The function 'rootOfType' returns the name of the type constructor at the
+-- root of a type. This function must not be applied to a type whose root is
+-- a type variable or a skolem type.
+
+rootOfType :: Type -> QualIdent
+rootOfType ty = case fst (unapplyType True ty) of
+  TypeConstructor tc -> tc
+  _ -> internalError $ "Base.Types.rootOfType: " ++ show ty
+
+-- The function 'isArrowType' checks whether a type is a function
+-- type t_1 -> t_2 -> ... -> t_n. The function 'arrowArity' computes
+-- the arity n of a function type, 'arrowArgs' computes the types
+-- t_1 ... t_n-1 and 'arrowBase' returns the type t_n. 'arrowUnapply'
+-- combines 'arrowArgs' and 'arrowBase' in one call.
+
+isArrowType :: Type -> Bool
+isArrowType (TypeArrow _ _) = True
+isArrowType _               = False
+
+arrowArity :: Type -> Int
+arrowArity = length. arrowArgs
+
+arrowArgs :: Type -> [Type]
+arrowArgs = fst . arrowUnapply
+
+arrowBase :: Type -> Type
+arrowBase = snd. arrowUnapply
+
+arrowUnapply :: Type -> ([Type], Type)
+arrowUnapply (TypeArrow ty1 ty2) = (ty1 : tys, ty)
+  where (tys, ty) = arrowUnapply ty2
+arrowUnapply ty                  = ([], ty)
+
+-- The function 'typeConstrs' returns a list of all type constructors
+-- occuring in a type t.
+
+typeConstrs :: Type -> [QualIdent]
+typeConstrs ty = constrs ty [] where
+  constrs (TypeConstructor  tc) tcs = tc : tcs
+  constrs (TypeApply   ty1 ty2) tcs = constrs ty1 (constrs ty2 tcs)
+  constrs (TypeVariable      _) tcs = tcs
+  constrs (TypeConstrained _ _) tcs = tcs
+  constrs (TypeArrow   ty1 ty2) tcs = constrs ty1 (constrs ty2 tcs)
+  constrs (TypeForall    _ ty') tcs = constrs ty' tcs
+
+-- The method 'typeVars' returns a list of all type variables occurring in a
+-- type t. Note that 'TypeConstrained' variables are not included in the set of
+-- type variables because they cannot be generalized.
+
+class IsType t where
+  typeVars :: t -> [Int]
+
+instance IsType Type where
+  typeVars = typeVars'
+
+typeVars' :: Type -> [Int]
+typeVars' ty = vars ty [] where
+  vars (TypeConstructor   _) tvs = tvs
+  vars (TypeApply   ty1 ty2) tvs = vars ty1 (vars ty2 tvs)
+  vars (TypeVariable     tv) tvs = tv : tvs
+  vars (TypeConstrained _ _) tvs = tvs
+  vars (TypeArrow   ty1 ty2) tvs = vars ty1 (vars ty2 tvs)
+  vars (TypeForall tvs' ty') tvs = filter (`notElem` tvs') (typeVars' ty') ++ tvs
+
+-- The functions 'qualifyType' and 'unqualifyType' add/remove the
+-- qualification with a module identifier for type constructors.
+
+qualifyType :: ModuleIdent -> Type -> Type
+qualifyType m (TypeConstructor     tc) = TypeConstructor (qualifyTC m tc)
+qualifyType m (TypeApply      ty1 ty2) =
+  TypeApply (qualifyType m ty1) (qualifyType m ty2)
+qualifyType _ tv@(TypeVariable      _) = tv
+qualifyType m (TypeConstrained tys tv) =
+  TypeConstrained (map (qualifyType m) tys) tv
+qualifyType m (TypeArrow      ty1 ty2) =
+  TypeArrow (qualifyType m ty1) (qualifyType m ty2)
+qualifyType m (TypeForall      tvs ty) = TypeForall tvs (qualifyType m ty)
+
+unqualifyType :: ModuleIdent -> Type -> Type
+unqualifyType m (TypeConstructor     tc) = TypeConstructor (qualUnqualify m tc)
+unqualifyType m (TypeApply      ty1 ty2) =
+  TypeApply (unqualifyType m ty1) (unqualifyType m ty2)
+unqualifyType _ tv@(TypeVariable      _) = tv
+unqualifyType m (TypeConstrained tys tv) =
+  TypeConstrained (map (unqualifyType m) tys) tv
+unqualifyType m (TypeArrow      ty1 ty2) =
+  TypeArrow (unqualifyType m ty1) (unqualifyType m ty2)
+unqualifyType m (TypeForall      tvs ty) = TypeForall tvs (unqualifyType m ty)
+
+qualifyTC :: ModuleIdent -> QualIdent -> QualIdent
+qualifyTC m tc | isPrimTypeId tc = tc
+               | otherwise       = qualQualify m tc
+
+-- ---------------------------------------------------------------------------
+-- Predicates
+-- ---------------------------------------------------------------------------
+
+data Pred = Pred QualIdent Type
+  deriving (Eq, Show)
+
+-- We provide a custom 'Ord' instance for predicates here where we consider
+-- the type component of the predicate before the class component. This way,
+-- we ensure that a class method's implicit class constraint is always the
+-- minimum w.r.t. this order, because the type expression for that constraint
+-- is a type variable with index 0 and there are no other class constraints
+-- in a predicate set that constraint the same type variable as restrictions
+-- on class variables are not allowed (see predicate sets below for more
+-- information why this order is relevant).
+
+instance Ord Pred where
+  Pred qcls1 ty1 `compare` Pred qcls2 ty2 = case ty1 `compare` ty2 of
+    LT -> LT
+    EQ -> qcls1 `compare` qcls2
+    GT -> GT
+
+instance IsType Pred where
+  typeVars (Pred _ ty) = typeVars ty
+
+qualifyPred :: ModuleIdent -> Pred -> Pred
+qualifyPred m (Pred qcls ty) = Pred (qualQualify m qcls) (qualifyType m ty)
+
+unqualifyPred :: ModuleIdent -> Pred -> Pred
+unqualifyPred m (Pred qcls ty) =
+  Pred (qualUnqualify m qcls) (unqualifyType m ty)
+
+-- ---------------------------------------------------------------------------
+-- Predicate sets
+-- ---------------------------------------------------------------------------
+
+-- A predicate set is an ordered set of predicates. This way, we do not
+-- have to manually take care of duplicate predicates and have automatically
+-- achieved a canonical representation (as only original names for type classes
+-- are used). Having the order on types and predicates in mind, we have also
+-- ensured that a class method's implicit class constraint is always the minimum
+-- element of a method's predicate set, thus making it very easy to remove it.
+
+type PredSet = Set.Set Pred
+
+instance (IsType a, Ord a) => IsType (Set.Set a) where
+  typeVars = concat . Set.toList . Set.map typeVars
+
+emptyPredSet :: PredSet
+emptyPredSet = Set.empty
+
+partitionPredSet :: PredSet -> (PredSet, PredSet)
+partitionPredSet = Set.partition $ \(Pred _ ty) -> isTypeVariable ty
+  where
+    isTypeVariable (TypeVariable _) = True
+    isTypeVariable (TypeApply ty _) = isTypeVariable ty
+    isTypeVariable _                = False
+
+-- The function 'minPredSet' transforms a predicate set by removing all
+-- predicates from the predicate set which are implied by other predicates
+-- according to the super class hierarchy. Inversely, the function 'maxPredSet'
+-- adds all predicates to a predicate set which are implied by the predicates
+-- in the given predicate set.
+
+minPredSet :: ClassEnv -> PredSet -> PredSet
+minPredSet clsEnv ps =
+  ps `Set.difference` Set.concatMap implied ps
+  where implied (Pred cls ty) = Set.fromList
+          [Pred cls' ty | cls' <- tail (allSuperClasses cls clsEnv)]
+
+maxPredSet :: ClassEnv -> PredSet -> PredSet
+maxPredSet clsEnv ps = Set.concatMap implied ps
+  where implied (Pred cls ty) = Set.fromList
+          [Pred cls' ty | cls' <- allSuperClasses cls clsEnv]
+
+qualifyPredSet :: ModuleIdent -> PredSet -> PredSet
+qualifyPredSet m = Set.map (qualifyPred m)
+
+unqualifyPredSet :: ModuleIdent -> PredSet -> PredSet
+unqualifyPredSet m = Set.map (unqualifyPred m)
+
+-- ---------------------------------------------------------------------------
+-- Predicated types
+-- ---------------------------------------------------------------------------
+
+data PredType = PredType PredSet Type
+  deriving (Eq, Show)
+
+-- When enumarating the type variables and skolems of a predicated type, we
+-- consider the type variables occuring in the predicate set after the ones
+-- occuring in the type itself.
+
+instance IsType PredType where
+  typeVars (PredType ps ty) = typeVars ty ++ typeVars ps
+
+predType :: Type -> PredType
+predType = PredType emptyPredSet
+
+unpredType :: PredType -> Type
+unpredType (PredType _ ty) = ty
+
+qualifyPredType :: ModuleIdent -> PredType -> PredType
+qualifyPredType m (PredType ps ty) =
+  PredType (qualifyPredSet m ps) (qualifyType m ty)
+
+unqualifyPredType :: ModuleIdent -> PredType -> PredType
+unqualifyPredType m (PredType ps ty) =
+  PredType (unqualifyPredSet m ps) (unqualifyType m ty)
+
+-- ---------------------------------------------------------------------------
+-- Data constructors
+-- ---------------------------------------------------------------------------
+
+-- The type 'DataConstr' is used to represent value or record constructors
+-- introduced by data or newtype declarations.
+
+data DataConstr = DataConstr   Ident [Type]
+                | RecordConstr Ident [Ident] [Type]
+  deriving (Eq, Show)
+
+constrIdent :: DataConstr -> Ident
+constrIdent (DataConstr     c _) = c
+constrIdent (RecordConstr c _ _) = c
+
+constrTypes :: DataConstr -> [Type]
+constrTypes (DataConstr     _ tys) = tys
+constrTypes (RecordConstr _ _ tys) = tys
+
+recLabels :: DataConstr -> [Ident]
+recLabels (DataConstr      _ _) = []
+recLabels (RecordConstr _ ls _) = ls
+
+recLabelTypes :: DataConstr -> [Type]
+recLabelTypes (DataConstr       _ _) = []
+recLabelTypes (RecordConstr _ _ tys) = tys
+
+tupleData :: [DataConstr]
+tupleData = [DataConstr (tupleId n) (take n tvs) | n <- [2 ..]]
+  where tvs = map TypeVariable [0 ..]
+
+-- ---------------------------------------------------------------------------
+-- Class methods
+-- ---------------------------------------------------------------------------
+
+-- The type 'ClassMethod' is used to represent class methods introduced
+-- by class declarations. The 'Maybe Int' denotes the arity of the provided
+-- default implementation.
+
+data ClassMethod = ClassMethod Ident (Maybe Int) PredType
+  deriving (Eq, Show)
+
+methodName :: ClassMethod -> Ident
+methodName (ClassMethod f _ _) = f
+
+methodArity :: ClassMethod -> Maybe Int
+methodArity (ClassMethod _ a _) = a
+
+methodType :: ClassMethod -> PredType
+methodType (ClassMethod _ _ pty) = pty
+
+-- ---------------------------------------------------------------------------
+-- Quantification
+-- ---------------------------------------------------------------------------
+
+-- We support only universally quantified type schemes
+-- (forall alpha . tau(alpha)). Quantified type variables are assigned
+-- ascending indices starting from 0. Therefore it is sufficient to record the
+-- numbers of quantified type variables in the 'ForAll' constructor.
+
+data TypeScheme = ForAll Int PredType deriving (Eq, Show)
+
+instance IsType TypeScheme where
+  typeVars (ForAll _ pty) = [tv | tv <- typeVars pty, tv < 0]
+
+-- The functions 'monoType' and 'polyType' translate a type tau into a
+-- monomorphic type scheme and a polymorphic type scheme, respectively.
+-- 'polyType' assumes that all universally quantified variables in the type are
+-- assigned indices starting with 0 and does not renumber the variables.
+
+monoType :: Type -> TypeScheme
+monoType = ForAll 0 . predType
+
+polyType :: Type -> TypeScheme
+polyType = typeScheme . predType
+
+typeScheme :: PredType -> TypeScheme
+typeScheme pty = ForAll (maximum (-1 : typeVars pty) + 1) pty
+
+-- The function 'rawType' strips the quantifier and predicate set from a
+-- type scheme.
+
+rawType :: TypeScheme -> Type
+rawType (ForAll _ (PredType _ ty)) = ty
+
+-- ---------------------------------------------------------------------------
+-- Predefined types
+-- ---------------------------------------------------------------------------
+
+primType :: QualIdent -> [Type] -> Type
+primType = applyType . TypeConstructor
+
+arrowType :: Type -> Type -> Type
+arrowType ty1 ty2 = primType qArrowId [ty1, ty2]
+
+unitType :: Type
+unitType = primType qUnitId []
+
+predUnitType :: PredType
+predUnitType = predType unitType
+
+boolType :: Type
+boolType = primType qBoolId []
+
+predBoolType :: PredType
+predBoolType = predType boolType
+
+charType :: Type
+charType = primType qCharId []
+
+intType :: Type
+intType = primType qIntId []
+
+predIntType :: PredType
+predIntType = predType intType
+
+floatType :: Type
+floatType = primType qFloatId []
+
+predFloatType :: PredType
+predFloatType = predType floatType
+
+stringType :: Type
+stringType = listType charType
+
+predStringType :: PredType
+predStringType = predType stringType
+
+listType :: Type -> Type
+listType ty = primType qListId [ty]
+
+consType :: Type -> Type
+consType ty = TypeArrow ty (TypeArrow (listType ty) (listType ty))
+
+ioType :: Type -> Type
+ioType ty = primType qIOId [ty]
+
+tupleType :: [Type] -> Type
+tupleType tys = primType (qTupleId (length tys)) tys
+
+-- 'numTypes' and 'fractionalTypes' define the eligible types for
+-- numeric literals in patterns.
+
+numTypes :: [Type]
+numTypes = [intType, floatType]
+
+fractionalTypes :: [Type]
+fractionalTypes = drop 1 numTypes
+
+predefTypes :: [(Type, [DataConstr])]
+predefTypes =
+  [ (arrowType a b, [])
+  , (unitType     , [ DataConstr unitId [] ])
+  , (listType a   , [ DataConstr nilId  []
+                    , DataConstr consId [a, listType a]
+                    ])
+  ]
+  where a = TypeVariable 0
+        b = TypeVariable 1
diff --git a/src/Base/Typing.hs b/src/Base/Typing.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/Typing.hs
@@ -0,0 +1,190 @@
+{- |
+    Module      :  $Header$
+    Description :  Type computation of Curry expressions
+    Copyright   :  (c) 2003 - 2006 Wolfgang Lux
+                       2014 - 2015 Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    After the compiler has attributed patterns and expressions with type
+    information during type inference, it is straightforward to recompute
+    the type of every pattern and expression. Since all annotated types
+    are monomorphic, there is no need to instantiate any variables or
+    perform any (non-trivial) unifications.
+-}
+
+module Base.Typing
+  ( Typeable (..)
+  , withType, matchType
+  , bindDecls, bindDecl, bindPatterns, bindPattern, declVars, patternVars
+  ) where
+
+import Data.List (nub)
+import Data.Maybe (fromMaybe)
+
+import Curry.Base.Ident
+import Curry.Syntax
+
+import Base.Messages (internalError)
+import Base.Types
+import Base.TypeSubst
+import Base.Utils (fst3)
+
+import Env.Value
+
+class Typeable a where
+  typeOf :: a -> Type
+
+instance Typeable Type where
+  typeOf = id
+
+instance Typeable PredType where
+  typeOf = unpredType
+
+instance Typeable a => Typeable (Rhs a) where
+  typeOf (SimpleRhs  _ _ e _ ) = typeOf e
+  typeOf (GuardedRhs _ _ es _) = head [typeOf e | CondExpr _ _ e <- es]
+
+instance Typeable a => Typeable (Pattern a) where
+  typeOf (LiteralPattern _ a _) = typeOf a
+  typeOf (NegativePattern _ a _) = typeOf a
+  typeOf (VariablePattern _ a _) = typeOf a
+  typeOf (ConstructorPattern _ a _ _) = typeOf a
+  typeOf (InfixPattern _ a _ _ _) = typeOf a
+  typeOf (ParenPattern _ t) = typeOf t
+  typeOf (RecordPattern _ a _ _) = typeOf a
+  typeOf (TuplePattern _ ts) = tupleType $ map typeOf ts
+  typeOf (ListPattern _ a _) = typeOf a
+  typeOf (AsPattern _ _ t) = typeOf t
+  typeOf (LazyPattern _ t) = typeOf t
+  typeOf (FunctionPattern _ a _ _) = typeOf a
+  typeOf (InfixFuncPattern _ a _ _ _) = typeOf a
+
+instance Typeable a => Typeable (Expression a) where
+  typeOf (Literal _ a _) = typeOf a
+  typeOf (Variable _ a _) = typeOf a
+  typeOf (Constructor _ a _) = typeOf a
+  typeOf (Paren _ e) = typeOf e
+  typeOf (Typed _ e _) = typeOf e
+  typeOf (Record _ a _ _) = typeOf a
+  typeOf (RecordUpdate _ e _) = typeOf e
+  typeOf (Tuple _ es) = tupleType (map typeOf es)
+  typeOf (List _ a _) = typeOf a
+  typeOf (ListCompr _ e _) = listType (typeOf e)
+  typeOf (EnumFrom _ e) = listType (typeOf e)
+  typeOf (EnumFromThen _ e _) = listType (typeOf e)
+  typeOf (EnumFromTo _ e _) = listType (typeOf e)
+  typeOf (EnumFromThenTo _ e _ _) = listType (typeOf e)
+  typeOf (UnaryMinus _ e) = typeOf e
+  typeOf (Apply _ e _) = case typeOf e of
+    TypeArrow _ ty -> ty
+    _ -> internalError "Base.Typing.typeOf: application"
+  typeOf (InfixApply _ _ op _) = case typeOf (infixOp op) of
+    TypeArrow _ (TypeArrow _ ty) -> ty
+    _ -> internalError "Base.Typing.typeOf: infix application"
+  typeOf (LeftSection _ _ op) = case typeOf (infixOp op) of
+    TypeArrow _ ty -> ty
+    _ -> internalError "Base.Typing.typeOf: left section"
+  typeOf (RightSection _ op _) = case typeOf (infixOp op) of
+    TypeArrow ty1 (TypeArrow _ ty2) -> TypeArrow ty1 ty2
+    _ -> internalError "Base.Typing.typeOf: right section"
+  typeOf (Lambda _ ts e) = foldr (TypeArrow . typeOf) (typeOf e) ts
+  typeOf (Let _ _ _ e) = typeOf e
+  typeOf (Do _ _ _ e) = typeOf e
+  typeOf (IfThenElse _ _ e _) = typeOf e
+  typeOf (Case _ _ _ _ as) = typeOf $ head as
+
+instance Typeable a => Typeable (Alt a) where
+  typeOf (Alt _ _ rhs) = typeOf rhs
+
+-- When inlining variable and function definitions, the compiler must
+-- eventually update the type annotations of the inlined expression. To
+-- that end, the variable or function's annotated type and the type of
+-- the inlined expression must be unified. Since the program is type
+-- correct, this unification is just a simple one way matching where we
+-- only need to match the type variables in the inlined expression's type
+-- with the corresponding types in the variable or function's annotated
+-- type.
+
+withType :: (Functor f, Typeable (f Type)) => Type -> f Type -> f Type
+withType ty e = fmap (subst (matchType (typeOf e) ty idSubst)) e
+
+matchType :: Type -> Type -> TypeSubst -> TypeSubst
+matchType ty1 ty2 = fromMaybe noMatch (matchType' ty1 ty2)
+  where
+    noMatch = internalError $ "Base.Typing.matchType: " ++
+                                showsPrec 11 ty1 " " ++ showsPrec 11 ty2 ""
+
+matchType' :: Type -> Type -> Maybe (TypeSubst -> TypeSubst)
+matchType' (TypeVariable tv) ty
+  | ty == TypeVariable tv = Just id
+  | otherwise = Just (bindSubst tv ty)
+matchType' (TypeConstructor tc1) (TypeConstructor tc2)
+  | tc1 == tc2 = Just id
+matchType' (TypeConstrained _ tv1) (TypeConstrained _ tv2)
+  | tv1 == tv2 = Just id
+matchType' (TypeApply ty11 ty12) (TypeApply ty21 ty22) =
+  fmap (. matchType ty12 ty22) (matchType' ty11 ty21)
+matchType' (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) =
+  Just (matchType ty11 ty21 . matchType ty12 ty22)
+matchType' (TypeApply ty11 ty12) (TypeArrow ty21 ty22) =
+  fmap (. matchType ty12 ty22)
+       (matchType' ty11 (TypeApply (TypeConstructor qArrowId) ty21))
+matchType' (TypeArrow ty11 ty12) (TypeApply ty21 ty22) =
+  fmap (. matchType ty12 ty22)
+       (matchType' (TypeApply (TypeConstructor qArrowId) ty11) ty21)
+matchType' (TypeForall _ ty1) (TypeForall _ ty2) = matchType' ty1 ty2
+matchType' (TypeForall _ ty1) ty2 = matchType' ty1 ty2
+matchType' ty1 (TypeForall _ ty2) = matchType' ty1 ty2
+matchType' _ _ = Nothing
+
+-- The functions 'bindDecls', 'bindDecl', 'bindPatterns' and 'bindPattern'
+-- augment the value environment with the types of the entities defined in
+-- local declaration groups and patterns, respectively, using the types from
+-- their type annotations.
+
+bindDecls :: (Eq t, Typeable t, ValueType t) => [Decl t] -> ValueEnv -> ValueEnv
+bindDecls = flip $ foldr bindDecl
+
+bindDecl :: (Eq t, Typeable t, ValueType t) => Decl t -> ValueEnv -> ValueEnv
+bindDecl d vEnv = bindLocalVars (filter unbound $ declVars d) vEnv
+  where unbound v = null $ lookupValue (fst3 v) vEnv
+
+bindPatterns :: (Eq t, Typeable t, ValueType t) => [Pattern t] -> ValueEnv
+             -> ValueEnv
+bindPatterns = flip $ foldr bindPattern
+
+bindPattern :: (Eq t, Typeable t, ValueType t) => Pattern t -> ValueEnv
+            -> ValueEnv
+bindPattern t vEnv = bindLocalVars (filter unbound $ patternVars t) vEnv
+  where unbound v = null $ lookupValue (fst3 v) vEnv
+
+declVars :: (Eq t, Typeable t, ValueType t) => Decl t -> [(Ident, Int, t)]
+declVars (InfixDecl        _ _ _ _) = []
+declVars (TypeSig            _ _ _) = []
+declVars (FunctionDecl  _ ty f eqs) = [(f, eqnArity $ head eqs, ty)]
+declVars (PatternDecl        _ t _) = patternVars t
+declVars (FreeDecl            _ vs) = [(v, 0, ty) | Var ty v <- vs]
+declVars _                          = internalError "Base.Typing.declVars"
+
+patternVars :: (Eq t, Typeable t, ValueType t) => Pattern t -> [(Ident, Int, t)]
+patternVars (LiteralPattern         _ _ _) = []
+patternVars (NegativePattern        _ _ _) = []
+patternVars (VariablePattern       _ ty v) = [(v, 0, ty)]
+patternVars (ConstructorPattern  _ _ _ ts) = concatMap patternVars ts
+patternVars (InfixPattern     _ _ t1 _ t2) = patternVars t1 ++ patternVars t2
+patternVars (ParenPattern             _ t) = patternVars t
+patternVars (RecordPattern       _ _ _ fs) =
+  concat [patternVars t | Field _ _ t <- fs]
+patternVars (TuplePattern            _ ts) = concatMap patternVars ts
+patternVars (ListPattern           _ _ ts) = concatMap patternVars ts
+patternVars (AsPattern              _ v t) =
+  (v, 0, toValueType $ typeOf t) : patternVars t
+patternVars (LazyPattern              _ t) = patternVars t
+patternVars (FunctionPattern     _ _ _ ts) = nub $ concatMap patternVars ts
+patternVars (InfixFuncPattern _ _ t1 _ t2) =
+  nub $ patternVars t1 ++ patternVars t2
diff --git a/src/Base/Utils.hs b/src/Base/Utils.hs
new file mode 100644
--- /dev/null
+++ b/src/Base/Utils.hs
@@ -0,0 +1,94 @@
+{- |
+    Module      :  $Header$
+    Description :  Auxiliary functions
+    Copyright   :  (c) 2001 - 2003 Wolfgang Lux
+                       2011 - 2015 Björn Peemöler
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   The module Utils provides a few simple functions that are
+   commonly used in the compiler, but not implemented in the Haskell
+   Prelude or standard library.
+-}
+
+module Base.Utils
+  ( fst3, snd3, thd3, curry3, uncurry3
+  , (++!), foldr2, mapAccumM, findDouble, findMultiples
+  ) where
+
+import Control.Monad (MonadPlus, mzero, mplus)
+
+import Data.List     (partition)
+
+infixr 5 ++!
+
+-- The Prelude does not contain standard functions for triples.
+-- We provide projection, (un-)currying, and mapping for triples here.
+
+fst3 :: (a, b, c) -> a
+fst3 (x, _, _) = x
+
+snd3 :: (a, b, c) -> b
+snd3 (_, y, _) = y
+
+thd3 :: (a, b, c) -> c
+thd3 (_, _, z) = z
+
+curry3 :: ((a, b, c) -> d) -> a -> b -> c -> d
+curry3 f x y z = f (x,y,z)
+
+uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d
+uncurry3 f (x, y, z) = f x y z
+
+-- The function (++!) is variant of the list concatenation operator (++)
+-- that ignores the second argument if the first is a non-empty list.
+-- When lists are used to encode non-determinism in Haskell,
+-- this operator has the same effect as the cut operator in Prolog,
+-- hence the ! in the name.
+
+(++!) :: [a] -> [a] -> [a]
+xs ++! ys = if null xs then ys else xs
+
+-- Fold operations with two arguments lists can be defined using
+-- zip and foldl or foldr, resp. Our definitions are unfolded for
+-- efficiency reasons.
+
+-- foldl2 :: (a -> b -> c -> a) -> a -> [b] -> [c] -> a
+-- foldl2 _ z []       _        = z
+-- foldl2 _ z _        []       = z
+-- foldl2 f z (x : xs) (y : ys) = foldl2 f (f z x y) xs ys
+
+foldr2 :: (a -> b -> c -> c) -> c -> [a] -> [b] -> c
+foldr2 _ z []       _        = z
+foldr2 _ z _        []       = z
+foldr2 f z (x : xs) (y : ys) = f x y (foldr2 f z xs ys)
+
+mapAccumM :: (Monad m, MonadPlus p) => (acc -> x -> m (acc, y)) -> acc -> [x]
+          -> m (acc, p y)
+mapAccumM _ z [] = return (z, mzero)
+mapAccumM f z (x:xs) = do
+  (z', y) <- f z x
+  (z'', ys) <- mapAccumM f z' xs
+  return (z'', return y `mplus` ys)
+
+-- The function 'findDouble' checks whether a list of entities is linear,
+-- i.e., if every entity in the list occurs only once. If it is non-linear,
+-- the first offending object is returned.
+
+findDouble :: Eq a => [a] -> Maybe a
+findDouble []   = Nothing
+findDouble (x : xs)
+  | x `elem` xs = Just x
+  | otherwise   = findDouble xs
+
+findMultiples :: Eq a => [a] -> [[a]]
+findMultiples []       = []
+findMultiples (x : xs)
+  | null same = multiples
+  | otherwise = (x : same) : multiples
+  where (same, other) = partition (==x) xs
+        multiples     = findMultiples other
diff --git a/src/CaseCompletion.hs b/src/CaseCompletion.hs
deleted file mode 100644
--- a/src/CaseCompletion.hs
+++ /dev/null
@@ -1,662 +0,0 @@
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---
--- CaseCompletion - expands case branches with missing constructors
---
--- The MMC translates case expressions into the intermediate language
--- representation (IL) without completing them (i.e. without generating
--- case branches for missing contructors). Because they are necessary for
--- the PAKCS back end this module expands all case expressions accordingly.
---
--- May 2005,
--- Martin Engelke, (men@informatik.uni-kiel.de)
--- 
-module CaseCompletion (completeCase) where
-
-import Data.Maybe
-
-import Curry.Base.Position (SrcRef)
-import Curry.Base.Ident
-import qualified Curry.Syntax
-
-import Base (ModuleEnv, lookupModule)
-import IL.Type
-import OldScopeEnv -- as ScopeEnv
-import IL.Scope
-
-
-
--------------------------------------------------------------------------------
-
--- Completes case expressions by adding branches for missing constructors.
--- The module environment 'menv' is needed to compute these constructors.
---
--- Call:
---      completeCase <module environment>
---                   <IL module>
---
-completeCase :: ModuleEnv -> Module -> Module
-completeCase menv mod = let (mod', _) = visitModule menv mod in mod'
-
-
--------------------------------------------------------------------------------
--- The following functions run through an IL term searching for
--- case expressions
-
---
-visitModule :: ModuleEnv -> Module -> (Module, [Message])
-visitModule menv (Module mident imports decls)
-   = ((Module mident (insertUnique preludeMIdent imports) decls'), msgs')
- where
-   (decls', msgs') = visitList (visitDecl (Module mident imports decls) menv)
-		               insertDeclScope
-			       []
-			       (getModuleScope (Module mident imports decls))
-			       decls
-
-
---
-visitDecl :: Module -> ModuleEnv -> [Message] -> ScopeEnv -> Decl
-	     -> (Decl, [Message])
-visitDecl mod menv msgs senv (DataDecl qident arity cdecls)
-   = ((DataDecl qident arity cdecls), msgs)
-
-visitDecl mod menv msgs senv (NewtypeDecl qident arity cdecl)
-   = ((NewtypeDecl qident arity cdecl), msgs)
-
-visitDecl mod menv msgs senv (FunctionDecl qident params typeexpr expr)
-   = ((FunctionDecl qident params typeexpr expr'), msgs)
- where
-   (expr', _, _) = visitExpr mod menv msgs (insertExprScope senv expr) expr
-
-visitDecl mod menv msgs senv (ExternalDecl qident cconv name typeexpr)
-   = ((ExternalDecl qident cconv name typeexpr), msgs)
-
-
---
-visitExpr :: Module -> ModuleEnv -> [Message] -> ScopeEnv -> Expression 
-	     -> (Expression, [Message],ScopeEnv)
-visitExpr mod menv msgs senv (Literal lit) 
-   = ((Literal lit), msgs, senv)
-
-visitExpr mod menv msgs senv (Variable ident) 
-   = ((Variable ident), msgs, senv)
-
-visitExpr mod menv msgs senv (Function qident arity) 
-   = ((Function qident arity), msgs, senv)
-
-visitExpr mod menv msgs senv (Constructor qident arity)
-   = ((Constructor qident arity), msgs, senv)
-
-visitExpr mod menv msgs senv (Apply expr1 expr2)
-   = ((Apply expr1' expr2'), msgs2, senv2)
- where
-   (expr1', msgs1, senv1) = visitExpr mod menv msgs (insertExprScope senv expr1) expr1
-   (expr2', msgs2, senv2) = visitExpr mod menv msgs1 (insertExprScope senv1 expr2) expr2
-
-visitExpr mod menv msgs senv (Case r evalannot expr alts)
-   | null altsR
-     = intError "visitExpr" "empty alternative list"
-   | evalannot == Flex   -- pattern matching causes flexible case expressions
-     = (Case r evalannot expr' altsR, msgs, senv1)
-   | isConstrAlt altR
-     = (expr2, msgs3, senv3)
-   | isLitAlt altR
-     = (completeLitAlts r evalannot expr' altsR, msgs3, senv2)
-   | isVarAlt altR
-     = (completeVarAlts expr' altsR, msgs3, senv2)
-   | otherwise 
-     = intError "visitExpr" "illegal alternative list"
- where
-   altR           = head altsR
-   (expr', _, senv1) = visitExpr mod menv msgs (insertExprScope senv expr) expr
-   (alts', _, senv2) = visitListWithEnv (visitAlt mod menv) insertAltScope msgs senv1 alts
-   (altsR, msgs3) = removeRedundantAlts msgs alts'
-   (expr2, senv3) = completeConsAlts r mod menv senv2 evalannot expr' altsR
-
-visitExpr mod menv msgs senv (Or expr1 expr2)
-   = ((Or expr1' expr2'), msgs2, senv3)
- where
-   (expr1', msgs1, senv2) = visitExpr mod menv msgs (insertExprScope senv expr1) expr1
-   (expr2', msgs2, senv3) = visitExpr mod menv msgs1 (insertExprScope senv2 expr2) expr2
-
-visitExpr mod menv msgs senv (Exist ident expr)
-   = ((Exist ident expr'), msgs', senv2)
- where
-   (expr', msgs', senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr
-
-visitExpr mod menv msgs senv (Let bind expr)
-   = ((Let bind' expr'), msgs2, senv3)
- where
-   (expr', _, senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr
-   (bind', msgs2, senv3) = visitBinding mod menv msgs (insertBindingScope senv2 bind) bind
-
-visitExpr mod menv msgs senv (Letrec binds expr)
-   = ((Letrec binds' expr'), msgs2, senv3)
- where
-   (expr', msgs1, senv2)  = visitExpr mod menv msgs (insertExprScope senv expr) expr
-   (binds', msgs2, senv3) = visitListWithEnv (visitBinding mod menv)
-		               const
-			       msgs1
-			       (foldl insertBindingScope senv2 binds)
-			       binds
-
-
---
-visitAlt :: Module -> ModuleEnv -> [Message] -> ScopeEnv -> Alt 
-	    -> (Alt, [Message], ScopeEnv)
-visitAlt mod menv msgs senv (Alt pattern expr)
-   = ((Alt pattern expr'), msgs', senv2)
- where
-   (expr', msgs', senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr
-
-
---
-visitBinding :: Module -> ModuleEnv -> [Message] -> ScopeEnv -> Binding 
-	        -> (Binding, [Message], ScopeEnv)
-visitBinding mod menv msgs senv (Binding ident expr)
-   = ((Binding ident expr'), msgs', senv2)
- where
-   (expr', msgs', senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr
-
-
---
-visitList :: ([Message] -> ScopeEnv -> a -> (a, [Message]))
-	     -> (ScopeEnv -> a -> ScopeEnv)
-	     -> [Message] -> ScopeEnv -> [a]
-	     -> ([a], [Message])
-visitList visitTerm insertScope msgs senv []
-   = ([], msgs)
-visitList visitTerm insertScope msgs senv (term:terms)
-   = ((term':terms'), msgs2)
- where
-   (term', msgs1)  = visitTerm msgs (insertScope senv term) term
-   (terms', msgs2) = visitList visitTerm insertScope msgs1 senv terms
-
-visitListWithEnv :: ([Message] -> ScopeEnv -> a -> (a, [Message], ScopeEnv))
-	     -> (ScopeEnv -> a -> ScopeEnv)
-	     -> [Message] -> ScopeEnv -> [a]
-	     -> ([a], [Message], ScopeEnv)
-visitListWithEnv visitTerm insertScope msgs senv []
-   = ([], msgs, senv)
-visitListWithEnv visitTerm insertScope msgs senv (term:terms)
-   = ((term':terms'), msgs2, senv3)
- where
-   (term', msgs1, senv2)  = visitTerm msgs (insertScope senv term) term
-   (terms', msgs2, senv3) = visitListWithEnv visitTerm insertScope msgs1 senv2 terms
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--- Functions for completing case alternatives
-
--- Completes a case alternative list which branches via constructor patterns
--- by adding alternatives of the form
---
---      comp_pattern -> default_expr
---
--- where "comp_pattern" is a complementary constructor pattern and
--- "default_expr" is the expression from the first alternative containing
--- a variable pattern. If there is no such alternative the defualt expression
--- is set to the prelude function 'failed'.
---
--- This funtions uses a scope environment ('ScopeEnv') to generate fresh
--- variables for the arguments of the new constructors.
---
-completeConsAlts :: SrcRef -> Module -> ModuleEnv -> ScopeEnv 
-		    -> Eval -> Expression -> [Alt]
-		    -> (Expression, ScopeEnv)
-completeConsAlts r mod menv senv evalannot expr alts
-   = (Case r evalannot expr (alts1 ++ alts2), senv2)
- where
-   (Alt varpatt defaultexpr) = getDefaultAlt alts
-   (VariablePattern varid)   = varpatt
-   alts1       = filter isConstrAlt alts
-   constrs     = (map p_getConsAltIdent alts1)
-   cconsinfos  = getComplConstrs mod menv constrs
-   (cconstrs,senv2) = 
-                 foldr p_genConstrTerm
-                       ([],senv) 
-                       cconsinfos
-   alts2       = map (\cconstr -> 
-		      (Alt cconstr 
-		        (replaceVar varid (cterm2expr cconstr) defaultexpr))) 
-		     cconstrs
-
-   p_getConsAltIdent (Alt (ConstructorPattern qident _) _) = qident
-
-   p_genConstrTerm (qident, arity) (cconstrs,senv3) =
-       let args = OldScopeEnv.genIdentList arity "x" senv3
-           senv4 = foldr OldScopeEnv.insertIdent senv3 args
-       in (ConstructorPattern qident args : cconstrs, senv4)
-
-
--- If the alternatives branches via literal pattern complementary
--- constructor list cannot be generated because it would become infinite.
--- So the function 'completeLitAlts' transforms case expressions like
---      case <cexpr> of
---        <lit_1> -> <expr_1>
---        <lit_2> -> <expr_2>
---                    :
---        <lit_n> -> <expr_n>
---       [<var>   -> <default_expr>]
--- to 
---      case (<cexpr> == <lit_1>) of
---        True  -> <expr_1>
---        False -> case (<cexpr> == <lit_2>) of
---                   True  -> <expr_2>
---                   False -> case ...
---                                  :
---                               -> case (<cexpr> == <lit_n>) of
---                                    True  -> <expr_n>
---                                    False -> <default_expr>
---
-completeLitAlts :: SrcRef -> Eval -> Expression -> [Alt] -> Expression
-completeLitAlts r evalannot expr [] = failedExpr
-completeLitAlts r evalannot expr (alt:alts)
-   | isLitAlt alt 
-     = (Case r evalannot 
-	     (eqExpr expr (p_makeLitExpr alt))
-	     [(Alt truePatt  (getAltExpr alt)),
-	      (Alt falsePatt (completeLitAlts r evalannot expr alts))])
-   | otherwise
-     = case alt of
-         Alt (VariablePattern v) expr'
-	   -> replaceVar v expr expr'
-	 _ -> intError "completeLitAlts" "illegal alternative"
- where
-   p_makeLitExpr alt
-      = case (getAltPatt alt) of
-	  LiteralPattern lit -> Literal lit
-	  _                  -> intError "completeLitAlts" 
-				         "literal pattern expected"
-
-
--- For the unusual case of having only one alternative containing a variable
--- pattern it is necessary to tranform it to a 'let' term because FlatCurry
--- does not support variable patterns in case alternatives. So the
--- case expression
---      case <ce> of 
---        x -> <expr>
--- is transformed ot
---      let x = <ce> in <expr>
-completeVarAlts :: Expression -> [Alt] -> Expression
-completeVarAlts expr [] = failedExpr
-completeVarAlts expr (alt:_)
-   = (Let (Binding (p_getVarIdent alt) expr) (getAltExpr alt))
- where
-   p_getVarIdent alt
-      = case (getAltPatt alt) of
-	  VariablePattern ident -> ident
-	  _                     -> intError "completeVarAlts" 
-				            "variable pattern expected"
-
-
--------------------------------------------------------------------------------
--- The function 'removeRedundantAlts' removes case branches which are
--- either idle (i.e. they will never be reached) or multiply declared.
--- Note: unlike the PAKCS frontend MCC does not support warnings. So
--- there will be no messages if alternatives have been removed.
- 
-removeRedundantAlts :: [Message] -> [Alt] -> ([Alt], [Message])
-removeRedundantAlts msgs alts
-   = let
-         (alts1, msgs1) = removeIdleAlts msgs alts
-	 (alts2, msgs2) = removeMultipleAlts msgs1 alts1
-     in
-         (alts2, msgs2)
-
-
--- An alternative is idle if it occurs anywehere behind another alternative 
--- which contains a variable pattern. Example:
---    case x of
---      (y:ys) -> e1
---      z      -> e2
---      []     -> e3
--- Here all alternatives behind (z  -> e2) are idle and will be removed.
-removeIdleAlts :: [Message] -> [Alt] -> ([Alt], [Message])
-removeIdleAlts msgs alts 
-   | null alts2 = (alts1, msgs)
-   | otherwise  = (alts1, msgs)
- where
-   (alts1, alts2) = splitAfter isVarAlt alts
-
-
--- An alternative occures multiply if at least two alternatives
--- use the same pattern. Example:
---    case x of
---      []     -> e1
---      (y:ys) -> e2
---      []     -> e3
--- Here the last alternative occures multiply because its pattern is already
--- used in the first alternative. All multiple alternatives will be
--- removed except for the first occurrence.
-removeMultipleAlts :: [Message] -> [Alt] -> ([Alt], [Message])
-removeMultipleAlts msgs alts
-   = p_remove msgs [] alts
- where
-   p_remove msgs altsR []     = ((reverse altsR), msgs)
-   p_remove msgs altsR (alt:alts)
-      | p_containsAlt alt altsR = p_remove msgs altsR alts
-      | otherwise               = p_remove msgs (alt:altsR) alts
-
-   p_containsAlt alt alts = any (p_eqAlt alt) alts
-
-   p_eqAlt (Alt (LiteralPattern lit1) _) alt2
-      = case alt2 of
-	  (Alt (LiteralPattern lit2) _) -> lit1 == lit2
-	  _                             -> False
-   p_eqAlt (Alt (ConstructorPattern qident1 _) _) alt2
-      = case alt2 of
-	  (Alt (ConstructorPattern qident2 _) _) -> qident1 == qident2
-	  _                                      -> False
-   p_eqAlt (Alt (VariablePattern _) _) alt2
-      = case alt2 of
-	  (Alt (VariablePattern _) _) -> True
-	  _                           -> False
-
-
--------------------------------------------------------------------------------
--- Some functions for testing and extracting terms from case alternatives
-
---
-isVarAlt :: Alt -> Bool
-isVarAlt alt = case (getAltPatt alt) of
-	         VariablePattern _ -> True
-		 _                 -> False
-
---
-isConstrAlt :: Alt -> Bool
-isConstrAlt alt = case (getAltPatt alt) of
-		    ConstructorPattern _ _ -> True
-		    _                      -> False
-
---
-isLitAlt :: Alt -> Bool
-isLitAlt alt = case (getAltPatt alt) of
-	         LiteralPattern _ -> True
-		 _                -> False
-
-
---
-getAltExpr :: Alt -> Expression
-getAltExpr (Alt _ expr) = expr
-
-
---
-getAltPatt :: Alt -> ConstrTerm
-getAltPatt (Alt cterm _) = cterm
-
-
--- Note: the newly generated variable 'x!' is just a dummy and will never
--- occur in the transformed program
-getDefaultAlt :: [Alt] -> Alt
-getDefaultAlt alts 
-   = fromMaybe (Alt (VariablePattern (mkIdent "x!")) failedExpr)
-               (find isVarAlt alts)
-
-
--------------------------------------------------------------------------------
--- This part of the module contains functions for replacing variables
--- with expressions. This is necessary in the case of having a default 
--- alternative like
---      v -> <expr>
--- where the variable v occurs in the default expression <expr>. When
--- building additional alternatives for this default expression the variable
--- must be replaced with the newly generated constructors.
-
--- Call:
---      replaceVar <variable id>
---                 <replace-with expression>
---                 <replace-in expression>
---
-replaceVar :: Ident -> Expression -> Expression -> Expression
-replaceVar ident expr (Variable ident')
-   | ident == ident' = expr
-   | otherwise       = Variable ident'
-replaceVar ident expr (Apply expr1 expr2)
-   = Apply (replaceVar ident expr expr1) (replaceVar ident expr expr2)
-replaceVar ident expr (Case r eval expr' alts)
-   = Case r eval 
-          (replaceVar ident expr expr') 
-	  (map (replaceVarInAlt ident expr) alts)
-replaceVar ident expr (Or expr1 expr2)
-   = Or (replaceVar ident expr expr1) (replaceVar ident expr expr2)
-replaceVar ident expr (Exist ident' expr')
-   | ident == ident' = Exist ident' expr'
-   | otherwise       = Exist ident' (replaceVar ident expr expr')
-replaceVar ident expr (Let binding expr')
-   | varOccursInBinding ident binding
-     = Let binding expr'
-   | otherwise
-     = Let (replaceVarInBinding ident expr binding) 
-	   (replaceVar ident expr expr')
-replaceVar ident expr (Letrec bindings expr')
-   | any (varOccursInBinding ident) bindings
-     = Letrec bindings expr'
-   | otherwise
-     = Letrec (map (replaceVarInBinding ident expr) bindings)
-              (replaceVar ident expr expr')
-replaceVar _ _ expr'
-   = expr'
-
-
---
-replaceVarInAlt :: Ident -> Expression -> Alt -> Alt
-replaceVarInAlt ident expr (Alt patt expr')
-   | varOccursInPattern ident patt 
-     = Alt patt expr'
-   | otherwise 
-     = Alt patt (replaceVar ident expr expr')
-
-
---
-replaceVarInBinding :: Ident -> Expression -> Binding -> Binding
-replaceVarInBinding ident expr (Binding ident' expr')
-   | ident == ident' = Binding ident' expr'
-   | otherwise       = Binding ident' (replaceVar ident expr expr')
-
-
---
-varOccursInPattern :: Ident -> ConstrTerm -> Bool
-varOccursInPattern ident (VariablePattern ident')
-   = ident == ident'
-varOccursInPattern ident (ConstructorPattern _ idents)
-   = elem ident idents
-varOccursInPattern _ _
-   = False
-
-
---
-varOccursInBinding :: Ident -> Binding -> Bool
-varOccursInBinding ident (Binding ident' _)
-   = ident == ident'
-
-
--------------------------------------------------------------------------------
--- The following functions generate several IL expressions and patterns
-
---
-failedExpr :: Expression
-failedExpr = Function (qualifyWith preludeMIdent (mkIdent "failed")) 0
-
---
-eqExpr :: Expression -> Expression -> Expression
-eqExpr e1 e2 = Apply
-	         (Apply 
-		   (Function (qualifyWith preludeMIdent (mkIdent "==")) 2)
-		   e1)
-		 e2
-
-
---
-truePatt :: ConstrTerm
-truePatt = ConstructorPattern qTrueId []
-
---
-falsePatt :: ConstrTerm
-falsePatt = ConstructorPattern qFalseId []
-
-
---
-cterm2expr :: ConstrTerm -> Expression
-cterm2expr (LiteralPattern lit) = Literal lit
-cterm2expr (ConstructorPattern qident args)
-   = p_genApplic (Constructor qident (length args)) args
- where
-   p_genApplic expr []     = expr
-   p_genApplic expr (v:vs) = p_genApplic (Apply expr (Variable v)) vs
-cterm2expr (VariablePattern ident) = Variable ident
-
-
-
--------------------------------------------------------------------------------
--- The folowing functions compute the missing constructors for generating
--- new case alternatives
-
--- Computes the complementary constructors for a list of constructors. All
--- specified constructors must have the same type.
--- This functions uses the module environment 'menv' which contains all known
--- constructors, except for those which are declared in the module and
--- except for the list constructors.
---
--- Call:
---      getComplConstr <IL module>
---                     <module environment>
---                     <list of (qualified) constructor ids>
---
-getComplConstrs :: Module -> ModuleEnv -> [QualIdent] -> [(QualIdent, Int)]
-getComplConstrs (Module mid _ decls) menv constrs
-   | null constrs 
-     = intError "getComplConstrs" "empty constructor list"
-   | cons == qNilId || cons == qConsId
-     = getCC constrs [(qNilId, 0), (qConsId, 2)]
-   | mid' == mid
-     = getCCFromDecls mid constrs decls
-   | otherwise
-     = maybe [] -- error ...
-             (getCCFromIDecls mid' constrs) 
-	     (lookupModule mid' menv)
- where
-   cons = head constrs
-
-   mid' = fromMaybe mid (qualidMod cons)
-
-
--- Find complementary constructors within the declarations of the
--- current module
-getCCFromDecls :: ModuleIdent -> [QualIdent] -> [Decl] -> [(QualIdent, Int)]
-getCCFromDecls _ constrs decls
-   = let
-         cdecls = maybe [] -- error ...
-		        p_extractConstrDecls
-			(find (p_declaresConstr (head constrs)) decls)
-	 cinfos = map p_getConstrDeclInfo cdecls
-     in
-         getCC constrs cinfos
- where
-   p_declaresConstr qident decl
-      = case decl of
-	  DataDecl _ _ cdecls   -> any (p_isConstrDecl qident) cdecls
-	  NewtypeDecl _ _ cdecl -> p_isConstrDecl qident cdecl
-	  _                     -> False
-
-   p_isConstrDecl qident (ConstrDecl qid _) = qident == qid
-
-   p_extractConstrDecls decl
-      = case decl of
-	  DataDecl _ _ cdecls   -> cdecls
-	  _                     -> []
-
-   p_getConstrDeclInfo (ConstrDecl qident types) = (qident, length types)
-
-
--- Find complementary constructors within the module environment
-getCCFromIDecls :: ModuleIdent -> [QualIdent] -> [Curry.Syntax.IDecl] 
-		   -> [(QualIdent, Int)]
-getCCFromIDecls mident constrs idecls
-   = let
-         cdecls = maybe [] -- error ...
-		        p_extractIConstrDecls
-		        (find (p_declaresIConstr (head constrs)) idecls)
-	 cinfos = map (p_getIConstrDeclInfo mident) cdecls
-     in
-         getCC constrs cinfos
- where
-   p_declaresIConstr qident idecl
-      = case idecl of
-	  Curry.Syntax.IDataDecl _ _ _ cdecls
-	      -> any (p_isIConstrDecl qident) 
-		     (map fromJust (filter isJust cdecls))
-	  Curry.Syntax.INewtypeDecl _ _ _ ncdecl 
-	      -> p_isINewConstrDecl qident ncdecl
-	  _   -> False
-
-   p_isIConstrDecl qident (Curry.Syntax.ConstrDecl _ _ ident _)
-      = (unqualify qident) == ident
-   p_isIConstrDecl qident (Curry.Syntax.ConOpDecl _ _ _ ident _)
-      = (unqualify qident) == ident
-
-   p_isINewConstrDecl qident (Curry.Syntax.NewConstrDecl _ _ ident _)
-      = (unqualify qident) == ident
-
-   p_extractIConstrDecls idecl
-      = case idecl of
-	  Curry.Syntax.IDataDecl _ _ _ cdecls 
-	      -> map fromJust (filter isJust cdecls)
-	  _   -> []
-
-   p_getIConstrDeclInfo mid (Curry.Syntax.ConstrDecl _ _ ident types)
-      = (qualifyWith mid ident, length types)
-   p_getIConstrDeclInfo mid (Curry.Syntax.ConOpDecl _ _ _ ident _)
-      = (qualifyWith mid ident, 2)
-
-
--- Compute complementary constructors
-getCC :: [QualIdent] -> [(QualIdent, Int)] -> [(QualIdent, Int)]
-getCC _ [] = []
-getCC constrs ((qident,arity):cis)
-   | any ((==) qident) constrs = getCC constrs cis
-   | otherwise                 = (qident,arity):(getCC constrs cis)
-
-
--------------------------------------------------------------------------------
--- Message handling
--- Not in use in this version, but intended for further versions
-
-type Message = String
-
-
--------------------------------------------------------------------------------
--- Miscellaneous
-
--- Splits a list behind the first element which satify 'cond'
-splitAfter :: (a -> Bool) -> [a] -> ([a], [a])
-splitAfter cond xs = p_splitAfter cond [] xs
- where
-   p_splitAfter c fs []     = ((reverse fs),[])
-   p_splitAfter c fs (l:ls) | c l       = ((reverse (l:fs)), ls)
-			    | otherwise = p_splitAfter c (l:fs) ls
-
-
--- Returns the first element which satisfy 'cond'. The returned element is
--- embedded in a 'Maybe' term
-find :: (a -> Bool) -> [a] -> Maybe a
-find _    []     = Nothing
-find cond (x:xs) | cond x    = Just x
-		 | otherwise = find cond xs
-
-
--- Prefixes an element to a list if it does not already exit within the
--- list
-insertUnique :: Eq a => a -> [a] -> [a]
-insertUnique x xs | elem x xs = xs
-		  | otherwise = x:xs
-
-
--- Raises an internal error
-intError :: String -> String -> a
-intError fun msg = error ("CaseCompletion." ++ fun ++ " - " ++ msg)
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
diff --git a/src/Checks.hs b/src/Checks.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks.hs
@@ -0,0 +1,161 @@
+{- |
+    Module      :  $Header$
+    Description :  Different checks on a Curry module
+    Copyright   :  (c) 2011 - 2013 Björn Peemöller
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module subsumes the different checks to be performed on a Curry
+    module during compilation, e.g. type checking.
+-}
+module Checks where
+
+import qualified Checks.InstanceCheck     as INC (instanceCheck)
+import qualified Checks.InterfaceCheck    as IC  (interfaceCheck)
+import qualified Checks.ImportSyntaxCheck as ISC (importCheck)
+import qualified Checks.DeriveCheck       as DC  (deriveCheck)
+import qualified Checks.ExportCheck       as EC  (exportCheck, expandExports)
+import qualified Checks.ExtensionCheck    as EXC (extensionCheck)
+import qualified Checks.KindCheck         as KC  (kindCheck)
+import qualified Checks.PrecCheck         as PC  (precCheck)
+import qualified Checks.SyntaxCheck       as SC  (syntaxCheck)
+import qualified Checks.TypeCheck         as TC  (typeCheck)
+import qualified Checks.TypeSyntaxCheck   as TSC (typeSyntaxCheck)
+import qualified Checks.WarnCheck         as WC  (warnCheck)
+
+import Curry.Base.Monad
+import Curry.Syntax (Module (..), Interface (..), ImportSpec)
+
+import Base.Messages
+import Base.Types
+
+import CompilerEnv
+import CompilerOpts
+
+type Check m a = Options -> CompEnv a -> CYT m (CompEnv a)
+
+interfaceCheck :: Monad m => Check m Interface
+interfaceCheck _ (env, intf)
+  | null msgs = ok (env, intf)
+  | otherwise = failMessages msgs
+  where msgs = IC.interfaceCheck (opPrecEnv env) (tyConsEnv env) (classEnv env)
+                                 (instEnv env) (valueEnv env) intf
+
+importCheck :: Monad m => Interface -> Maybe ImportSpec
+            -> CYT m (Maybe ImportSpec)
+importCheck intf is
+  | null msgs = ok is'
+  | otherwise = failMessages msgs
+  where (is', msgs) = ISC.importCheck intf is
+
+-- |Check for enabled language extensions.
+--
+-- * Declarations: remain unchanged
+-- * Environment:  The enabled language extensions are updated
+extensionCheck :: Monad m => Check m (Module a)
+extensionCheck opts (env, mdl)
+  | null msgs = ok (env { extensions = exts }, mdl)
+  | otherwise = failMessages msgs
+  where (exts, msgs) = EXC.extensionCheck opts mdl
+
+-- |Check the type syntax of type definitions and signatures.
+--
+-- * Declarations: Nullary type constructors and type variables are
+--                 disambiguated
+-- * Environment:  remains unchanged
+typeSyntaxCheck :: Monad m => Check m (Module a)
+typeSyntaxCheck _ (env, mdl)
+  | null msgs = ok (env, mdl')
+  | otherwise = failMessages msgs
+  where (mdl', msgs) = TSC.typeSyntaxCheck (tyConsEnv env) mdl
+
+-- |Check the kinds of type definitions and signatures.
+--
+-- * Declarations: remain unchanged
+-- * Environment:  The type constructor and class environment are updated
+kindCheck :: Monad m => Check m (Module a)
+kindCheck _ (env, mdl)
+  | null msgs = ok (env { tyConsEnv = tcEnv', classEnv = clsEnv' }, mdl)
+  | otherwise = failMessages msgs
+  where ((tcEnv', clsEnv'), msgs) = KC.kindCheck (tyConsEnv env) (classEnv env)
+                                                 mdl
+
+-- |Check for a correct syntax.
+--
+-- * Declarations: Nullary data constructors and variables are
+--                 disambiguated, variables are renamed
+-- * Environment:  remains unchanged
+syntaxCheck :: Monad m => Check m (Module ())
+syntaxCheck _ (env, mdl)
+  | null msgs = ok (env { extensions = exts }, mdl')
+  | otherwise = failMessages msgs
+  where ((mdl', exts), msgs) = SC.syntaxCheck (extensions env) (tyConsEnv env)
+                                              (valueEnv env) mdl
+
+-- |Check the precedences of infix operators.
+--
+-- * Declarations: Expressions are reordered according to the specified
+--                 precedences
+-- * Environment:  The operator precedence environment is updated
+precCheck :: Monad m => Check m (Module a)
+precCheck _ (env, Module spi li ps m es is ds)
+  | null msgs = ok (env { opPrecEnv = pEnv' }, Module spi li ps m es is ds')
+  | otherwise = failMessages msgs
+  where (ds', pEnv', msgs) = PC.precCheck (moduleIdent env) (opPrecEnv env) ds
+
+-- |Check the deriving clauses.
+--
+-- * Declarations: remain unchanged
+-- * Environment:  remain unchanged
+deriveCheck :: Monad m => Check m (Module a)
+deriveCheck _ (env, mdl) = case DC.deriveCheck (tyConsEnv env) mdl of
+  msgs | null msgs -> ok (env, mdl)
+       | otherwise -> failMessages msgs
+
+-- |Check the instances.
+--
+-- * Declarations: remain unchanged
+-- * Environment:  The instance environment is updated
+instanceCheck :: Monad m => Check m (Module a)
+instanceCheck _ (env, Module spi li ps m es is ds)
+  | null msgs = ok (env { instEnv = inEnv' }, Module spi li ps m es is ds)
+  | otherwise = failMessages msgs
+  where (inEnv', msgs) = INC.instanceCheck (moduleIdent env) (tyConsEnv env)
+                                           (classEnv env) (instEnv env) ds
+
+-- |Apply the correct typing of the module.
+--
+-- * Declarations: Type annotations are added to all expressions.
+-- * Environment:  The value environment is updated.
+typeCheck :: Monad m => Options -> CompEnv (Module a)
+          -> CYT m (CompEnv (Module PredType))
+typeCheck _ (env, Module spi li ps m es is ds)
+  | null msgs = ok (env { valueEnv = vEnv' }, Module spi li ps m es is ds')
+  | otherwise = failMessages msgs
+  where (ds', vEnv', msgs) = TC.typeCheck (moduleIdent env) (tyConsEnv env)
+                                          (valueEnv env) (classEnv env)
+                                          (instEnv env) ds
+
+-- |Check the export specification
+exportCheck :: Monad m => Check m (Module a)
+exportCheck _ (env, mdl@(Module _ _ _ _ es _ _))
+  | null msgs = ok (env, mdl)
+  | otherwise = failMessages msgs
+  where msgs = EC.exportCheck (moduleIdent env) (aliasEnv env)
+                              (tyConsEnv env) (valueEnv env) es
+
+-- |Check the export specification
+expandExports :: Monad m => Options -> CompEnv (Module a) -> m (CompEnv (Module a))
+expandExports _ (env, Module spi li ps m es is ds)
+  = return (env, Module spi li ps m (Just es') is ds)
+  where es' = EC.expandExports (moduleIdent env) (aliasEnv env)
+                               (tyConsEnv env) (valueEnv env) es
+
+-- |Check for warnings.
+warnCheck :: Options -> CompilerEnv -> Module a -> [Message]
+warnCheck opts env mdl = WC.warnCheck (optWarnOpts opts) (optCaseMode opts)
+  (aliasEnv env) (valueEnv env) (tyConsEnv env) (classEnv env) mdl
diff --git a/src/Checks/DeriveCheck.hs b/src/Checks/DeriveCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/DeriveCheck.hs
@@ -0,0 +1,111 @@
+{- |
+    Module      :  $Header$
+    Description :  Checks deriving clauses
+    Copyright   :  (c)        2016 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   Before entering derived instances into the instance environment, the
+   compiler has to ensure that it is not asked for other instances than
+   those of supported type classes.
+-}
+module Checks.DeriveCheck (deriveCheck) where
+
+import Curry.Base.Ident
+import Curry.Base.Pretty
+import Curry.Base.SpanInfo (HasSpanInfo)
+import Curry.Syntax
+
+import Base.Messages (Message, spanInfoMessage)
+
+import Env.TypeConstructor
+
+deriveCheck :: TCEnv -> Module a -> [Message]
+deriveCheck tcEnv (Module _ _ _ m _ _ ds) = concatMap (checkDecl m tcEnv) ds
+
+-- No instances can be derived for abstract data types as well as for
+-- existential data types.
+
+checkDecl :: ModuleIdent -> TCEnv -> Decl a -> [Message]
+checkDecl m tcEnv (DataDecl   _ tc _ cs clss)
+  | null clss                       = []
+  | null cs                         = [errNoAbstractDerive tc]
+  | otherwise                       = concatMap (checkDerivable m tcEnv cs) clss
+checkDecl m tcEnv (NewtypeDecl _ _ _ nc clss) =
+  concatMap (checkDerivable m tcEnv [toConstrDecl nc]) clss
+checkDecl _ _     _                           = []
+
+checkDerivable :: ModuleIdent -> TCEnv -> [ConstrDecl] -> QualIdent -> [Message]
+checkDerivable m tcEnv cs cls
+  | ocls == qEnumId && not (isEnum cs)       = [errNotEnum cls]
+  | ocls == qBoundedId && not (isBounded cs) = [errNotBounded cls]
+  | ocls `notElem` derivableClasses          = [errNotDerivable cls]
+  | ocls == qDataId                          = [errNoDataDerive cls]
+  | otherwise                                = []
+  where ocls = getOrigName m cls tcEnv
+
+derivableClasses :: [QualIdent]
+derivableClasses = [qEqId, qOrdId, qEnumId, qBoundedId, qReadId, qShowId, qDataId]
+
+-- Instances of 'Enum' can be derived only for enumeration types, i.e., types
+-- where all data constructors are constants.
+
+isEnum :: [ConstrDecl] -> Bool
+isEnum = all ((0 ==) . constrArity)
+
+-- Instances of 'Bounded' can be derived only for enumerations and for single
+-- constructor types.
+
+isBounded :: [ConstrDecl] -> Bool
+isBounded cs = length cs == 1 || isEnum cs
+
+-- ---------------------------------------------------------------------------
+-- Auxiliary functions
+-- ---------------------------------------------------------------------------
+
+toConstrDecl :: NewConstrDecl -> ConstrDecl
+toConstrDecl (NewConstrDecl p c      ty) = ConstrDecl p c [ty]
+toConstrDecl (NewRecordDecl p c (l, ty)) =
+  RecordDecl p c [FieldDecl p [l] ty]
+
+constrArity :: ConstrDecl -> Int
+constrArity (ConstrDecl  _ _ tys) = length tys
+constrArity (ConOpDecl   _ _ _ _) = 2
+constrArity c@(RecordDecl  _ _ _) = length $ recordLabels c
+
+-- ---------------------------------------------------------------------------
+-- Error messages
+-- ---------------------------------------------------------------------------
+
+errNoAbstractDerive :: HasSpanInfo a => a -> Message
+errNoAbstractDerive s = spanInfoMessage s $
+  text "Instances can only be derived for data types with" <+>
+  text "at least one constructor"
+
+errNotDerivable :: QualIdent -> Message
+errNotDerivable cls = spanInfoMessage cls $ hsep $ map text
+  ["Instances of type class", escQualName cls, "cannot be derived"]
+
+errNoDataDerive :: QualIdent -> Message
+errNoDataDerive qcls = spanInfoMessage qcls $ hsep $ map text
+  [ "Instances of type class"
+  , escQualName qcls
+  , "are automatically derived if possible"
+  ]
+
+errNotEnum :: QualIdent -> Message
+errNotEnum qcls = spanInfoMessage qcls $ hsep $ map text
+  [ "Instances of type class"
+  , escQualName qcls
+  , "can be derived only for enumeration types"
+  ]
+
+errNotBounded :: QualIdent -> Message
+errNotBounded qcls = spanInfoMessage qcls $ hsep $ map text
+  [ "Instances of type class"
+  , escQualName qcls
+  , "can be derived only for enumeration and single constructor types"
+  ]
diff --git a/src/Checks/ExportCheck.hs b/src/Checks/ExportCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/ExportCheck.hs
@@ -0,0 +1,500 @@
+{- |
+    Module      :  $Header$
+    Description :  Check the export specification of a module
+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux
+                       2011 - 2016 Björn Peemöller
+                       2015 - 2016 Yannik Potdevin
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module implements a check and expansion of the export specification.
+    Any errors in the specification are reported, and if there are no errors,
+    the specification is expanded. The expansion does the following:
+      * If there is no export specification, a specification exporting the
+        entire module is generated.
+      * Otherwise, (re)exports of modules are replaced by an export of all
+        respective entities.
+      * The export of a type with all constructors and fields is replaced
+        by an enumeration of all constructors and fields.
+      * The export of types without sub-entities is extended with an empty
+        list of sub-entities.
+-}
+{-# LANGUAGE CPP #-}
+module Checks.ExportCheck (exportCheck, expandExports) where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative        ((<$>))
+#endif
+import           Control.Monad              (unless)
+import qualified Control.Monad.State as S   (State, runState, gets, modify)
+import           Data.List                  (nub, union)
+import qualified Data.Map            as Map ( Map, elems, empty, insert
+                                            , insertWith, lookup, toList )
+import           Data.Maybe                 (fromMaybe)
+import qualified Data.Set            as Set ( Set, empty, fromList, insert
+                                            , member, toList )
+
+import Curry.Base.Ident
+import Curry.Base.Position
+import Curry.Base.SpanInfo
+import Curry.Base.Pretty
+import Curry.Syntax
+
+import Base.Messages       (Message, internalError, spanInfoMessage)
+import Base.TopEnv         (allEntities, origName, localBindings, moduleImports)
+import Base.Types          ( Type (..), unapplyType, arrowBase, PredType (..)
+                           , DataConstr (..), constrIdent, recLabels
+                           , ClassMethod, methodName
+                           , TypeScheme (..), rawType, rootOfType )
+import Base.Utils          (findMultiples)
+
+import Env.ModuleAlias     (AliasEnv)
+import Env.TypeConstructor (TCEnv, TypeInfo (..), qualLookupTypeInfoUnique)
+import Env.Value           (ValueEnv, ValueInfo (..), qualLookupValueUnique)
+
+currentModuleName :: String
+currentModuleName = "Checks.ExportCheck"
+
+-- ---------------------------------------------------------------------------
+-- Check and expansion of the export statement
+-- ---------------------------------------------------------------------------
+
+expandExports :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv
+              -> Maybe ExportSpec -> ExportSpec
+expandExports m aEnv tcEnv tyEnv spec = Exporting (exportSpan spec) es
+  where
+  exportSpan (Just (Exporting spi _)) = spi
+  exportSpan Nothing                  = NoSpanInfo
+
+  es = expand m aEnv tcEnv tyEnv spec
+
+exportCheck :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv
+            -> Maybe ExportSpec -> [Message]
+exportCheck m aEnv tcEnv tyEnv spec = case check m aEnv tcEnv tyEnv spec of
+  [] -> checkNonUniqueness $ expand m aEnv tcEnv tyEnv spec
+  ms -> ms
+
+-- -----------------------------------------------------------------------------
+-- Export Check Monad
+-- -----------------------------------------------------------------------------
+
+data ECState = ECState
+  { moduleIdent  :: ModuleIdent
+  , importedMods :: Set.Set ModuleIdent
+  , tyConsEnv    :: TCEnv
+  , valueEnv     :: ValueEnv
+  , errors       :: [Message]
+  }
+
+type ECM a = S.State ECState a
+
+runECM :: ECM a -> ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv -> (a, [Message])
+runECM ecm m aEnv tcEnv tyEnv
+  = let (a, s') = S.runState ecm initState in (a, reverse $ errors s')
+  where
+  initState  = ECState m imported tcEnv tyEnv []
+  imported   = Set.fromList (Map.elems aEnv)
+
+getModuleIdent :: ECM ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+getImportedModules :: ECM (Set.Set ModuleIdent)
+getImportedModules = S.gets importedMods
+
+getTyConsEnv :: ECM TCEnv
+getTyConsEnv = S.gets tyConsEnv
+
+getValueEnv :: ECM ValueEnv
+getValueEnv = S.gets valueEnv
+
+report :: Message -> ECM ()
+report err = S.modify (\ s -> s { errors = err : errors s })
+
+ok :: ECM ()
+ok = return ()
+
+-- -----------------------------------------------------------------------------
+-- Check
+-- -----------------------------------------------------------------------------
+
+check :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv -> Maybe ExportSpec
+      -> [Message]
+check m aEnv tcEnv tyEnv spec = snd $ runECM (checkSpec spec) m aEnv tcEnv tyEnv
+
+-- |Check export specification.
+checkSpec :: Maybe ExportSpec -> ECM ()
+checkSpec (Just (Exporting _ es)) = mapM_ checkExport es
+checkSpec Nothing                 = ok
+
+-- |Check single export.
+checkExport :: Export -> ECM ()
+checkExport (Export         _ x    ) = checkThing x
+checkExport (ExportTypeWith _ tc cs) = checkTypeWith tc cs
+checkExport (ExportTypeAll  _ tc   ) = checkTypeAll tc
+checkExport (ExportModule   _ em   ) = checkModule em
+
+-- |Check export of type constructor / function
+checkThing :: QualIdent -> ECM ()
+checkThing tc = do
+  m     <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfoUnique m tc tcEnv of
+    []  -> checkThing' tc Nothing
+    [t] -> checkThing' tc (Just [ExportTypeWith NoSpanInfo (origName t) []])
+    ts  -> report (errAmbiguousType tc ts)
+
+-- |Expand export of data cons / function
+checkThing' :: QualIdent -> Maybe [Export] -> ECM ()
+checkThing' f tcExport = do
+  m     <- getModuleIdent
+  tyEnv <- getValueEnv
+  case qualLookupValueUnique m f tyEnv of
+    []  -> justTcOr errUndefinedName
+    [v] -> case v of
+      Value _ _ _ _ -> ok
+      Label   _ _ _ -> report $ errOutsideTypeLabel f (getTc v)
+      _             -> justTcOr $ flip errOutsideTypeConstructor (getTc v)
+    fs  -> report (errAmbiguousName f fs)
+  where
+  justTcOr errFun = maybe (report $ errFun f) (const ok) tcExport
+
+  getTc (DataConstructor  _ _ _ (ForAll _ (PredType _ ty))) = getTc' ty
+  getTc (NewtypeConstructor _ _ (ForAll _ (PredType _ ty))) = getTc' ty
+  getTc (Label _ _ (ForAll _ (PredType _ (TypeArrow tc' _)))) =
+    let (TypeConstructor tc, _) = unapplyType False tc' in tc
+  getTc err = internalError $ currentModuleName ++ ".checkThing'.getTc: " ++ show err
+
+  getTc' ty = let (TypeConstructor tc) = arrowBase ty in tc
+
+checkTypeWith :: QualIdent -> [Ident] -> ECM ()
+checkTypeWith tc xs = do
+  m     <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfoUnique m tc tcEnv of
+    []                   -> report (errUndefinedTypeOrClass tc)
+    [DataType _ _ cs]    ->
+      mapM_ (checkElement errUndefinedElement (visibleElems cs )) xs'
+    [RenamingType _ _ c] ->
+      mapM_ (checkElement errUndefinedElement (visibleElems [c])) xs'
+    [TypeClass   _ _ ms] ->
+      mapM_ (checkElement errUndefinedMethod (visibleMethods ms)) xs'
+    [_]                  -> report (errNonDataTypeOrTypeClass tc)
+    ts                   -> report (errAmbiguousType tc ts)
+  where
+  xs' = nub xs
+  -- check if given identifier is constructor/label/method of type/class tc
+  checkElement err cs' c = unless (c `elem` cs') $ report $ err tc c
+
+-- |Check type constructor with all data constructors and record labels.
+checkTypeAll :: QualIdent -> ECM ()
+checkTypeAll tc = do
+  m     <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfoUnique m tc tcEnv of
+    []                   -> report (errUndefinedTypeOrClass tc)
+    [DataType     _ _ _] -> ok
+    [RenamingType _ _ _] -> ok
+    [TypeClass    _ _ _] -> ok
+    [_]                  -> report (errNonDataTypeOrTypeClass tc)
+    ts                   -> report (errAmbiguousType tc ts)
+
+checkModule :: ModuleIdent -> ECM ()
+checkModule em = do
+  isLocal   <- (em ==)         <$> getModuleIdent
+  isForeign <- (Set.member em) <$> getImportedModules
+  unless (isLocal || isForeign) $ report $ errModuleNotImported em
+
+-- Check whether two entities of the same kind (type or constructor/function)
+-- share the same unqualified name, which is not allowed since they could
+-- not be uniquely resolved at their usage.
+-- For instance, consider the following module
+-- @
+-- module M (Bool, Prelude.Bool) where
+-- data Bool = False | True
+-- @
+-- If this export would be allowed, in a module @M1@ as follows
+-- @
+-- module M1 where
+-- import M (Bool)
+-- @
+-- the type @Bool@ could not be resolved uniquely to its definition.
+-- Naturally, the same applies for constructors or functions.
+checkNonUniqueness :: [Export] -> [Message]
+checkNonUniqueness es = map errMultipleType (findMultiples types )
+                     ++ map errMultipleName (findMultiples values)
+  where
+  types  = [ unqualify tc | ExportTypeWith _ tc _  <- es ]
+  values = [ c            | ExportTypeWith _ _  cs <- es, c <- cs ]
+        ++ [ unqualify f  | Export _ f <- es ]
+
+-- -----------------------------------------------------------------------------
+-- Expansion
+-- -----------------------------------------------------------------------------
+
+expand :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv -> Maybe ExportSpec
+       -> [Export]
+expand m aEnv tcEnv tyEnv spec
+  = fst $ runECM ((joinExports . canonExports tcEnv) <$> expandSpec spec)
+                 m aEnv tcEnv tyEnv
+
+-- While checking all export specifications, the compiler expands
+-- specifications of the form @T(..)@ into @T(C_1,...,C_m,l_1,...,l_n)@,
+-- where @C_1,...,C_m@ are the data constructors of type @T@ and @l_1,...,l_n@
+-- its field labels, and replaces an export specification
+-- @module M@ by specifications for all entities which are defined
+-- in module @M@ and imported into the current module with their
+-- unqualified name. In order to distinguish exported type constructors
+-- from exported functions, the former are translated into the equivalent
+-- form @T()@. Note that the export specification @x@ may
+-- export a type constructor @x@ /and/ a global function
+-- @x@ at the same time.
+--
+-- /Note:/ This frontend allows redeclaration and export of imported
+-- identifiers.
+
+-- |Expand export specification
+expandSpec :: Maybe ExportSpec -> ECM [Export]
+expandSpec (Just (Exporting _ es)) = concat <$> mapM expandExport es
+expandSpec Nothing                 = expandLocalModule
+
+-- |Expand single export
+expandExport :: Export -> ECM [Export]
+expandExport (Export             _ x) = expandThing x
+expandExport (ExportTypeWith _ tc cs) = expandTypeWith tc cs
+expandExport (ExportTypeAll     _ tc) = expandTypeAll tc
+expandExport (ExportModule      _ em) = expandModule em
+
+-- |Expand export of type constructor / function
+expandThing :: QualIdent -> ECM [Export]
+expandThing tc = do
+  m     <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfoUnique m tc tcEnv of
+    []  -> expandThing' tc Nothing
+    [t] -> expandThing' tc
+             (Just [ExportTypeWith NoSpanInfo (origName t @> tc) []])
+    err -> internalError $ currentModuleName ++ ".expandThing: " ++ show err
+
+-- |Expand export of data cons / function
+expandThing' :: QualIdent -> Maybe [Export] -> ECM [Export]
+expandThing' f tcExport = do
+  m     <- getModuleIdent
+  tyEnv <- getValueEnv
+  case qualLookupValueUnique m f tyEnv of
+    [Value f' _ _ _]
+      -> return $ Export NoSpanInfo (f' @> f) : fromMaybe [] tcExport
+    _
+      -> return $ fromMaybe [] tcExport
+
+-- |Expand type constructor with explicit data constructors and record labels
+expandTypeWith :: QualIdent -> [Ident] -> ECM [Export]
+expandTypeWith tc xs = do
+  m     <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfoUnique m tc tcEnv of
+    [t] -> return [ExportTypeWith NoSpanInfo (origName t @> tc) $ nub xs]
+    err -> internalError $ currentModuleName ++ ".expandTypeWith: " ++ show err
+
+-- |Expand type constructor with all data constructors and record labels
+expandTypeAll :: QualIdent -> ECM [Export]
+expandTypeAll tc = do
+  m     <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfoUnique m tc tcEnv of
+    [t] -> return [exportType t]
+    err -> internalError $ currentModuleName ++ ".expandTypeAll: " ++ show err
+
+expandModule :: ModuleIdent -> ECM [Export]
+expandModule em = do
+  isLocal   <- (em ==)         <$> getModuleIdent
+  isForeign <- (Set.member em) <$> getImportedModules
+  locals    <- if isLocal   then expandLocalModule       else return []
+  foreigns  <- if isForeign then expandImportedModule em else return []
+  return $ locals ++ foreigns
+
+expandLocalModule :: ECM [Export]
+expandLocalModule = do
+  tcEnv <- getTyConsEnv
+  tyEnv <- getValueEnv
+  return $
+       [ exportType t
+         | (_, t)              <- localBindings tcEnv ]
+    ++ [ exportLabel l' ty
+         | (l, Label l' _ ty)  <- localBindings tyEnv, hasGlobalScope l ]
+    ++ [ Export NoSpanInfo f'
+         | (f, Value f' _ _ _) <- localBindings tyEnv, hasGlobalScope f ]
+
+-- |Expand a module export
+expandImportedModule :: ModuleIdent -> ECM [Export]
+expandImportedModule m = do
+  tcEnv <- getTyConsEnv
+  tyEnv <- getValueEnv
+  return $ [exportType t        | (_, t)             <- moduleImports m tcEnv]
+        ++ [exportLabel l ty    | (_, Label l _ ty)  <- moduleImports m tyEnv]
+        ++ [Export NoSpanInfo f | (_, Value f _ _ _) <- moduleImports m tyEnv]
+
+exportType :: TypeInfo -> Export
+exportType t = ExportTypeWith NoSpanInfo tc xs
+  where tc = origName t
+        xs = elements t
+
+exportLabel :: QualIdent -> TypeScheme -> Export
+exportLabel qid ty = case rawType ty of
+  TypeArrow a _ -> ExportTypeWith NoSpanInfo (rootOfType a) [qidIdent qid]
+  _             -> internalError $ "ExportCheck.exportLabel: " ++ show (qid, ty)
+
+-- -----------------------------------------------------------------------------
+-- Canonicalization and joining of exports
+-- -----------------------------------------------------------------------------
+
+-- In contrast to Haskell, the export of field labels and record constructors
+-- without their types is NOT allowed.
+-- Thus, given the declaration @data T a = C { l :: a }@
+-- the label @l@ and the constructor @C@ can only be exported together with the
+-- type @T@, i.e., @(T(C,l))@.
+-- Since record update operations are desugared to case expressions matching the
+-- corresponding constructors of the record, the export of a label without its
+-- type could result in a type error, when it is used for an update operation in
+-- another module.
+
+canonExports :: TCEnv -> [Export] -> [Export]
+canonExports tcEnv es = map (canonExport (canonLabels tcEnv es)) es
+
+canonExport :: Map.Map QualIdent Export -> Export -> Export
+canonExport ls (Export spi x)             =
+  fromMaybe (Export spi x) (Map.lookup x ls)
+canonExport _  (ExportTypeWith spi tc xs) = ExportTypeWith spi tc xs
+canonExport _  e                          = internalError $
+  currentModuleName ++ ".canonExport: " ++ show e
+
+canonLabels :: TCEnv -> [Export] -> Map.Map QualIdent Export
+canonLabels tcEnv es = foldr bindLabels Map.empty (allEntities tcEnv)
+  where
+  tcs = [tc | ExportTypeWith _ tc _ <- es]
+  bindLabels t ls
+    | tc' `elem` tcs = foldr (bindLabel tc') ls (elements t)
+    | otherwise     = ls
+      where
+        tc'            = origName t
+        bindLabel tc x =
+          Map.insert (qualifyLike tc x) (ExportTypeWith NoSpanInfo tc [x])
+
+-- The expanded list of exported entities may contain duplicates. These
+-- are removed by the function joinExports. In particular, this
+-- function removes any field labels from the list of exported values
+-- which are also exported along with their types.
+
+joinExports :: [Export] -> [Export]
+joinExports es =  [ExportTypeWith NoSpanInfo tc cs | (tc, cs) <- joinedTypes]
+               ++ [Export NoSpanInfo f             | f        <- joinedFuncs]
+  where joinedTypes = Map.toList $ foldr joinType Map.empty es
+        joinedFuncs = Set.toList $ foldr joinFun  Set.empty es
+
+joinType :: Export -> Map.Map QualIdent [Ident] -> Map.Map QualIdent [Ident]
+joinType (Export             _ _) tcs = tcs
+joinType (ExportTypeWith _ tc cs) tcs = Map.insertWith union tc cs tcs
+joinType export                     _ = internalError $
+  currentModuleName ++ ".joinType: " ++ show export
+
+joinFun :: Export -> Set.Set QualIdent -> Set.Set QualIdent
+joinFun (Export           _ f) fs = f `Set.insert` fs
+joinFun (ExportTypeWith _ _ _) fs = fs
+joinFun export                  _ = internalError $
+  currentModuleName ++ ".joinFun: " ++ show export
+
+-- ---------------------------------------------------------------------------
+-- Auxiliary definitions
+-- ---------------------------------------------------------------------------
+
+elements :: TypeInfo -> [Ident]
+elements (DataType      _ _ cs) = visibleElems cs
+elements (RenamingType   _ _ c) = visibleElems [c]
+elements (AliasType    _ _ _ _) = []
+elements (TypeClass     _ _ ms) = visibleMethods ms
+elements (TypeVar            _) =
+  error "Checks.ExportCheck.elements: type variable"
+
+-- get visible constructor and label identifiers for given constructor
+visibleElems :: [DataConstr] -> [Ident]
+visibleElems cs = map constrIdent cs ++ (nub (concatMap recLabels cs))
+
+-- get class method names
+visibleMethods :: [ClassMethod] -> [Ident]
+visibleMethods = map methodName
+
+-- ---------------------------------------------------------------------------
+-- Error messages
+-- ---------------------------------------------------------------------------
+
+errAmbiguousName :: QualIdent -> [ValueInfo] -> Message
+errAmbiguousName x vs = errAmbiguous "name" x (map origName vs)
+
+errAmbiguousType :: QualIdent -> [TypeInfo] -> Message
+errAmbiguousType tc tcs = errAmbiguous "type" tc (map origName tcs)
+
+errAmbiguous :: String -> QualIdent -> [QualIdent] -> Message
+errAmbiguous what qn qns = spanInfoMessage qn
+  $   text "Ambiguous" <+> text what <+> text (escQualName qn)
+  $+$ text "It could refer to:"
+  $+$ nest 2 (vcat (map (text . escQualName) qns))
+
+errModuleNotImported :: ModuleIdent -> Message
+errModuleNotImported m = spanInfoMessage m $ hsep $ map text
+  ["Module", escModuleName m, "not imported"]
+
+errMultipleName :: [Ident] -> Message
+errMultipleName = errMultiple "name"
+
+errMultipleType :: [Ident] -> Message
+errMultipleType = errMultiple "type"
+
+errMultiple :: String -> [Ident] -> Message
+errMultiple _    []     = internalError $
+  currentModuleName ++ ".errMultiple: empty list"
+errMultiple what (i:is) = spanInfoMessage i $
+  text "Multiple exports of" <+> text what <+> text (escName i) <+> text "at:"
+  $+$ nest 2 (vcat (map showPos (i:is)))
+  where showPos = text . showLine . getPosition
+
+errNonDataTypeOrTypeClass :: QualIdent -> Message
+errNonDataTypeOrTypeClass tc = spanInfoMessage tc $ hsep $ map text
+  [escQualName tc, "is not a data type or type class"]
+
+errOutsideTypeConstructor :: QualIdent -> QualIdent -> Message
+errOutsideTypeConstructor c tc = errOutsideTypeExport "Data constructor" c tc
+
+errOutsideTypeLabel :: QualIdent -> QualIdent -> Message
+errOutsideTypeLabel l tc = errOutsideTypeExport "Label" l tc
+
+errOutsideTypeExport :: String -> QualIdent -> QualIdent -> Message
+errOutsideTypeExport what q tc = spanInfoMessage q
+  $   text what <+> text (escQualName q)
+         <+> text "outside type export in export list"
+  $+$ text "Use `" <> text (qualName tc) <+> parens (text (qualName q))
+  <>  text "' instead"
+
+errUndefinedElement :: QualIdent -> Ident -> Message
+errUndefinedElement tc c = spanInfoMessage c $ hsep $ map text
+  [ escName c, "is not a constructor or label of type", escQualName tc ]
+
+errUndefinedMethod :: QualIdent -> Ident -> Message
+errUndefinedMethod cls f = spanInfoMessage f $ hsep $ map text
+  [ escName f, "is not a method of class", escQualName cls ]
+
+errUndefinedName :: QualIdent -> Message
+errUndefinedName = errUndefined "name"
+
+errUndefinedTypeOrClass :: QualIdent -> Message
+errUndefinedTypeOrClass = errUndefined "type or class"
+
+errUndefined :: String -> QualIdent -> Message
+errUndefined what tc = spanInfoMessage tc $ hsep $ map text
+  ["Undefined", what, escQualName tc, "in export list"]
diff --git a/src/Checks/ExtensionCheck.hs b/src/Checks/ExtensionCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/ExtensionCheck.hs
@@ -0,0 +1,72 @@
+{- |
+    Module      :  $Header$
+    Description :  Checks extensions
+    Copyright   :  (c)        2016 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   First of all, the compiler scans a source file for file-header pragmas
+   that may activate language extensions.
+-}
+module Checks.ExtensionCheck (extensionCheck) where
+
+import qualified Control.Monad.State as S (State, execState, modify)
+
+import Curry.Base.SpanInfo
+import Curry.Base.Pretty
+import Curry.Syntax
+
+import Base.Messages (Message, spanInfoMessage)
+
+import CompilerOpts
+
+extensionCheck :: Options -> Module a -> ([KnownExtension], [Message])
+extensionCheck opts mdl = execEXC (checkModule mdl) initState
+  where
+    initState = EXCState (optExtensions opts) []
+
+type EXCM = S.State EXCState
+
+data EXCState = EXCState
+  { extensions :: [KnownExtension]
+  , errors     :: [Message]
+  }
+
+execEXC :: EXCM a -> EXCState -> ([KnownExtension], [Message])
+execEXC ecm s =
+  let s' = S.execState ecm s in (extensions s', reverse $ errors s')
+
+enableExtension :: KnownExtension -> EXCM ()
+enableExtension e = S.modify $ \s -> s { extensions = e : extensions s }
+
+report :: Message -> EXCM ()
+report msg = S.modify $ \s -> s { errors = msg : errors s }
+
+ok :: EXCM ()
+ok = return ()
+
+-- The extension check iterates over all given pragmas in the module and
+-- gathers all extensions mentioned in a language pragma. An error is reported
+-- if an extension is unknown.
+
+checkModule :: Module a -> EXCM ()
+checkModule (Module _ _ ps _ _ _ _) = mapM_ checkPragma ps
+
+checkPragma :: ModulePragma -> EXCM ()
+checkPragma (LanguagePragma _ exts) = mapM_ checkExtension exts
+checkPragma (OptionsPragma  _  _ _) = ok
+
+checkExtension :: Extension -> EXCM ()
+checkExtension (KnownExtension   _ e) = enableExtension e
+checkExtension (UnknownExtension p e) = report $ errUnknownExtension p e
+
+-- ---------------------------------------------------------------------------
+-- Error messages
+-- ---------------------------------------------------------------------------
+
+errUnknownExtension :: SpanInfo -> String -> Message
+errUnknownExtension p e = spanInfoMessage p $
+  text "Unknown language extension:" <+> text e
diff --git a/src/Checks/ImportSyntaxCheck.hs b/src/Checks/ImportSyntaxCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/ImportSyntaxCheck.hs
@@ -0,0 +1,279 @@
+{- |
+    Module      :  $Header$
+    Description :  Checking import specifications
+    Copyright   :  (c) 2016       Jan Tikovsky
+                       2016       Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  jrt@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module provides the function 'importCheck' to check and expand
+    the import specifications of all import declarations.
+-}
+module Checks.ImportSyntaxCheck(importCheck) where
+
+import           Control.Monad              (liftM, unless)
+import qualified Control.Monad.State as S   (State, gets, modify, runState)
+import           Data.List                  (nub, union)
+import qualified Data.Map            as Map
+import           Data.Maybe                 (fromMaybe)
+
+import Curry.Base.Ident
+import Curry.Base.Pretty
+import Curry.Base.SpanInfo
+import Curry.Syntax hiding (Var (..))
+
+import Base.Messages
+import Base.TopEnv
+
+importCheck :: Interface -> Maybe ImportSpec -> (Maybe ImportSpec, [Message])
+importCheck (Interface m _ ds) is = runExpand (expandSpecs is) m mTCEnv mTyEnv
+  where
+  mTCEnv = intfEnv types  ds
+  mTyEnv = intfEnv values ds
+
+data ITypeInfo = Data  QualIdent [Ident]
+               | Alias QualIdent
+               | Class QualIdent [Ident]
+ deriving Show
+
+instance Entity ITypeInfo where
+  origName (Data  tc  _) = tc
+  origName (Alias tc   ) = tc
+  origName (Class cls _) = cls
+
+  merge (Data tc1 cs1) (Data tc2 cs2)
+    | tc1 == tc2 && (null cs1 || null cs2 || cs1 == cs2) =
+        Just $ Data tc1 (if null cs1 then cs2 else cs1)
+  merge l@(Alias tc1) (Alias tc2)
+    | tc1 == tc2 = Just l
+  merge (Class cls1 ms1) (Class cls2 ms2)
+    | cls1 == cls2 && (null ms1 || null ms2 || ms1 == ms2) =
+        Just $ Class cls1 (if null ms1 then ms2 else ms1)
+  merge _ _ = Nothing
+
+data IValueInfo = Constr QualIdent
+                | Var    QualIdent [QualIdent]
+ deriving Show
+
+instance Entity IValueInfo where
+  origName (Constr c) = c
+  origName (Var  x _) = x
+
+  merge (Constr c1) (Constr c2)
+    | c1 == c2 = Just (Constr c1)
+  merge (Var x1 cs1) (Var x2 cs2)
+    | x1 == x2 = Just (Var x1 (cs1 `union` cs2))
+  merge _ _ = Nothing
+
+
+intfEnv :: Entity a => (IDecl -> [a]) -> [IDecl] -> IdentMap a
+intfEnv idents ds = foldr bindId Map.empty (concatMap idents ds)
+  where bindId x = Map.insert (unqualify (origName x)) x
+
+types :: IDecl -> [ITypeInfo]
+types (IDataDecl     _ tc _ _ cs hs) = [Data tc (filter (`notElem` hs) xs)]
+  where xs = map constrId cs ++ nub (concatMap recordLabels cs)
+types (INewtypeDecl  _ tc _ _ nc hs) = [Data tc (filter (`notElem` hs) xs)]
+  where xs = nconstrId nc : nrecordLabels nc
+types (ITypeDecl         _ tc _ _ _) = [Alias tc]
+types (IClassDecl _ _ cls _ _ ms hs) = [Class cls (filter (`notElem` hs) xs)]
+  where xs = map imethod ms
+types _                              = []
+
+values :: IDecl -> [IValueInfo]
+values (IDataDecl     _ tc _ _ cs hs) =
+  cidents tc (map constrId cs) hs ++
+  lidents tc [(l, lconstrs cs l) | l <- nub (concatMap recordLabels cs)] hs
+  where lconstrs cons l = [constrId c | c <- cons, l `elem` recordLabels c]
+values (INewtypeDecl  _ tc _ _ nc hs) =
+  cidents tc [nconstrId nc] hs ++
+  lidents tc [(l, [c]) | NewRecordDecl _ c (l, _) <- [nc]] hs
+values (IFunctionDecl      _ f _ _ _) = [Var f []]
+values (IClassDecl _ _ cls _ _ ms hs) = midents cls (map imethod ms) hs
+values _                              = []
+
+cidents :: QualIdent -> [Ident] -> [Ident] -> [IValueInfo]
+cidents tc cs hs = [Constr (qualifyLike tc c) | c <- cs, c `notElem` hs]
+
+lidents :: QualIdent -> [(Ident, [Ident])] -> [Ident] -> [IValueInfo]
+lidents tc ls hs = [ Var (qualifyLike tc l) (map (qualifyLike tc) cs)
+                   | (l, cs) <- ls, l `notElem` hs
+                   ]
+
+midents :: QualIdent -> [Ident] -> [Ident] -> [IValueInfo]
+midents cls fs hs = [Var (qualifyLike cls f) [] | f <- fs, f `notElem` hs]
+
+-- ---------------------------------------------------------------------------
+-- Expansion of the import specification
+-- ---------------------------------------------------------------------------
+
+-- After the environments have been initialized, the optional import
+-- specifications can be checked. There are two kinds of import
+-- specifications, a ``normal'' one, which names the entities that shall
+-- be imported, and a hiding specification, which lists those entities
+-- that shall not be imported.
+--
+-- There is a subtle difference between both kinds of
+-- specifications: While it is not allowed to list a data constructor
+-- outside of its type in a ``normal'' specification, it is allowed to
+-- hide a data constructor explicitly. E.g., if module \texttt{A} exports
+-- the data type \texttt{T} with constructor \texttt{C}, the data
+-- constructor can be imported with one of the two specifications
+--
+-- import A (T(C))
+-- import A (T(..))
+--
+-- but can be hidden in three different ways:
+--
+-- import A hiding (C)
+-- import A hiding (T (C))
+-- import A hiding (T (..))
+--
+-- The functions \texttt{expandImport} and \texttt{expandHiding} check
+-- that all entities in an import specification are actually exported
+-- from the module. In addition, all imports of type constructors are
+-- changed into a \texttt{T()} specification and explicit imports for the
+-- data constructors are added.
+
+type IdentMap    = Map.Map Ident
+
+type ExpTCEnv    = IdentMap ITypeInfo
+type ExpValueEnv = IdentMap IValueInfo
+
+data ExpandState = ExpandState
+  { expModIdent :: ModuleIdent
+  , expTCEnv    :: ExpTCEnv
+  , expValueEnv :: ExpValueEnv
+  , errors      :: [Message]
+  }
+
+type ExpandM a = S.State ExpandState a
+
+getModuleIdent :: ExpandM ModuleIdent
+getModuleIdent = S.gets expModIdent
+
+getTyConsEnv :: ExpandM ExpTCEnv
+getTyConsEnv = S.gets expTCEnv
+
+getValueEnv :: ExpandM ExpValueEnv
+getValueEnv = S.gets expValueEnv
+
+report :: Message -> ExpandM ()
+report msg = S.modify $ \ s -> s { errors = msg : errors s }
+
+runExpand :: ExpandM a -> ModuleIdent -> ExpTCEnv -> ExpValueEnv -> (a, [Message])
+runExpand expand m tcEnv tyEnv =
+  let (r, s) = S.runState expand (ExpandState m tcEnv tyEnv [])
+  in (r, reverse $ errors s)
+
+expandSpecs :: Maybe ImportSpec -> ExpandM (Maybe ImportSpec)
+expandSpecs Nothing                 = return Nothing
+expandSpecs (Just (Importing p is)) = (Just . Importing p . concat) `liftM` mapM expandImport is
+expandSpecs (Just (Hiding    p is)) = (Just . Hiding    p . concat) `liftM` mapM expandHiding is
+
+expandImport :: Import -> ExpandM [Import]
+expandImport (Import         spi x    ) =               expandThing    spi x
+expandImport (ImportTypeWith spi tc cs) = (:[]) `liftM` expandTypeWith spi tc cs
+expandImport (ImportTypeAll  spi tc   ) = (:[]) `liftM` expandTypeAll  spi tc
+
+expandHiding :: Import -> ExpandM [Import]
+expandHiding (Import         spi x    ) = expandHide spi x
+expandHiding (ImportTypeWith spi tc cs) = (:[]) `liftM` expandTypeWith spi tc cs
+expandHiding (ImportTypeAll  spi tc   ) = (:[]) `liftM` expandTypeAll  spi tc
+
+-- try to expand as type constructor
+expandThing :: SpanInfo -> Ident -> ExpandM [Import]
+expandThing spi tc = do
+  tcEnv <- getTyConsEnv
+  case Map.lookup tc tcEnv of
+    Just _  -> expandThing' spi tc $ Just [ImportTypeWith spi tc []]
+    Nothing -> expandThing' spi tc Nothing
+
+-- try to expand as function / data constructor
+expandThing' :: SpanInfo -> Ident -> Maybe [Import] -> ExpandM [Import]
+expandThing' spi f tcImport = do
+  m     <- getModuleIdent
+  tyEnv <- getValueEnv
+  expand m f (Map.lookup f tyEnv) tcImport
+  where
+  expand :: ModuleIdent -> Ident
+         -> Maybe IValueInfo -> Maybe [Import] -> ExpandM [Import]
+  expand m e Nothing  Nothing   = report (errUndefinedEntity m e) >> return []
+  expand _ _ Nothing  (Just tc) = return tc
+  expand m e (Just v) maybeTc
+    | isConstr v = case maybeTc of
+        Nothing -> report (errImportDataConstr m e) >> return []
+        Just tc -> return tc
+    | otherwise  = return [Import spi e]
+
+  isConstr (Constr _) = True
+  isConstr (Var  _ _) = False
+
+-- try to hide as type constructor
+expandHide :: SpanInfo -> Ident -> ExpandM [Import]
+expandHide spi tc = do
+  tcEnv <- getTyConsEnv
+  case Map.lookup tc tcEnv of
+    Just _  -> expandHide' spi tc $ Just [ImportTypeWith spi tc []]
+    Nothing -> expandHide' spi tc Nothing
+
+-- try to hide as function / data constructor
+expandHide' :: SpanInfo -> Ident -> Maybe [Import] -> ExpandM [Import]
+expandHide' spi f tcImport = do
+  m     <- getModuleIdent
+  tyEnv <- getValueEnv
+  case Map.lookup f tyEnv of
+    Just _  -> return $ Import spi f : fromMaybe [] tcImport
+    Nothing -> case tcImport of
+      Nothing -> report (errUndefinedEntity m f) >> return []
+      Just tc -> return tc
+
+expandTypeWith :: SpanInfo -> Ident -> [Ident] -> ExpandM Import
+expandTypeWith spi tc cs = do
+  m     <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  ImportTypeWith spi tc `liftM` case Map.lookup tc tcEnv of
+    Just (Data  _ xs) -> mapM (checkElement errUndefinedElement xs) cs
+    Just (Class _ xs) -> mapM (checkElement errUndefinedMethod  xs) cs
+    Just (Alias    _) -> report (errNonDataTypeOrTypeClass tc) >> return []
+    Nothing           -> report (errUndefinedEntity      m tc) >> return []
+  where
+  -- check if given identifier is constructor or label of type tc
+  checkElement err cs' c = do
+    unless (c `elem` cs') $ report $ err tc c
+    return c
+
+expandTypeAll :: SpanInfo -> Ident -> ExpandM Import
+expandTypeAll spi tc = do
+  m     <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  ImportTypeWith spi tc `liftM` case Map.lookup tc tcEnv of
+    Just (Data _  xs) -> return xs
+    Just (Class _ xs) -> return xs
+    Just (Alias    _) -> report (errNonDataTypeOrTypeClass tc) >> return []
+    Nothing           -> report (errUndefinedEntity      m tc) >> return []
+
+-- error messages
+
+errUndefinedElement :: Ident -> Ident -> Message
+errUndefinedElement tc c = spanInfoMessage c $ hsep $ map text
+  [ idName c, "is not a constructor or label of type ", idName tc ]
+
+errUndefinedMethod :: Ident -> Ident -> Message
+errUndefinedMethod cls f = spanInfoMessage f $ hsep $ map text
+  [ idName f, "is not a method of class", idName cls ]
+
+errUndefinedEntity :: ModuleIdent -> Ident -> Message
+errUndefinedEntity m x = spanInfoMessage x $ hsep $ map text
+  [ "Module", moduleName m, "does not export", idName x ]
+
+errNonDataTypeOrTypeClass :: Ident -> Message
+errNonDataTypeOrTypeClass tc = spanInfoMessage tc $ hsep $ map text
+  [ idName tc, "is not a data type or type class" ]
+
+errImportDataConstr :: ModuleIdent -> Ident -> Message
+errImportDataConstr _ c = spanInfoMessage c $ hsep $ map text
+  [ "Explicit import for data constructor", idName c ]
diff --git a/src/Checks/InstanceCheck.hs b/src/Checks/InstanceCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/InstanceCheck.hs
@@ -0,0 +1,414 @@
+{- |
+    Module      :  $Header$
+    Description :  Checks instances
+    Copyright   :  (c)        2016 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   Before type checking, the compiler checks for every instance declaration
+   that all necessary super class instances exist. Furthermore, the compiler
+   infers the contexts of the implicit instance declarations introduced by
+   deriving clauses in data and newtype declarations. The instances declared
+   explicitly and automatically derived by the compiler are added to the
+   instance environment . It is also checked that there are no duplicate
+   instances and that all types specified in a default declaration are
+   instances of the Num class.
+-}
+module Checks.InstanceCheck (instanceCheck) where
+
+import           Control.Monad.Extra        (concatMapM, whileM, unless)
+import qualified Control.Monad.State as S   (State, execState, gets, modify)
+import           Data.List                  (nub, partition, sortBy)
+import qualified Data.Map            as Map
+import qualified Data.Set.Extra      as Set
+
+import Curry.Base.Ident
+import Curry.Base.Pretty
+import Curry.Base.SpanInfo
+import Curry.Syntax hiding (impls)
+import Curry.Syntax.Pretty
+
+import Base.CurryTypes
+import Base.Messages (Message, spanInfoMessage, message, internalError)
+import Base.SCC (scc)
+import Base.TypeExpansion
+import Base.Types
+import Base.TypeSubst
+import Base.Utils (fst3, snd3, findMultiples)
+
+import Env.Class
+import Env.Instance
+import Env.TypeConstructor
+
+instanceCheck :: ModuleIdent -> TCEnv -> ClassEnv -> InstEnv -> [Decl a]
+              -> (InstEnv, [Message])
+instanceCheck m tcEnv clsEnv inEnv ds =
+  case findMultiples (local ++ imported) of
+    [] -> execINCM (checkDecls tcEnv clsEnv ds) state
+    iss -> (inEnv, map (errMultipleInstances tcEnv) iss)
+  where
+    local = map (flip InstSource m) $ concatMap (genInstIdents m tcEnv) ds
+    imported = map (uncurry InstSource . fmap fst3) $ Map.toList inEnv
+    state = INCState m inEnv []
+
+-- In order to provide better error messages, we use the following data type
+-- to keep track of an instance's source, i.e., the module it was defined in.
+
+data InstSource = InstSource InstIdent ModuleIdent
+
+instance Eq InstSource where
+  InstSource i1 _ == InstSource i2 _ = i1 == i2
+
+-- |Instance Check Monad
+type INCM = S.State INCState
+
+-- |Internal state of the Instance Check
+data INCState = INCState
+  { moduleIdent :: ModuleIdent
+  , instEnv     :: InstEnv
+  , errors      :: [Message]
+  }
+
+execINCM :: INCM a -> INCState -> (InstEnv, [Message])
+execINCM incm s =
+  let s' = S.execState incm s in (instEnv s', reverse $ nub $ errors s')
+
+getModuleIdent :: INCM ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+getInstEnv :: INCM InstEnv
+getInstEnv = S.gets instEnv
+
+modifyInstEnv :: (InstEnv -> InstEnv) -> INCM ()
+modifyInstEnv f = S.modify $ \s -> s { instEnv = f $ instEnv s }
+
+report :: Message -> INCM ()
+report err = S.modify (\s -> s { errors = err : errors s })
+
+ok :: INCM ()
+ok = return ()
+
+checkDecls :: TCEnv -> ClassEnv -> [Decl a] -> INCM ()
+checkDecls tcEnv clsEnv ds = do
+  mapM_ (bindInstance tcEnv clsEnv) ids
+  mapM (declDeriveDataInfo tcEnv clsEnv) (filter isDataDecl tds) >>=
+    mapM_ (bindDerivedInstances clsEnv) . groupDeriveInfos
+  mapM (declDeriveInfo tcEnv clsEnv) (filter hasDerivedInstances tds) >>=
+    mapM_ (bindDerivedInstances clsEnv) . groupDeriveInfos
+  mapM_ (checkInstance tcEnv clsEnv) ids
+  mapM_ (checkDefault tcEnv clsEnv) dds
+  where (tds, ods) = partition isTypeDecl ds
+        ids = filter isInstanceDecl ods
+        dds = filter isDefaultDecl ods
+        isDataDecl (DataDecl    _ _ _ _ _) = True
+        isDataDecl (NewtypeDecl _ _ _ _ _) = True
+        isDataDecl _                       = False
+
+-- First, the compiler adds all explicit instance declarations to the
+-- instance environment.
+
+bindInstance :: TCEnv -> ClassEnv -> Decl a -> INCM ()
+bindInstance tcEnv clsEnv (InstanceDecl _ _ cx qcls inst ds) = do
+  m <- getModuleIdent
+  let PredType ps _ = expandPolyType m tcEnv clsEnv $
+                        QualTypeExpr NoSpanInfo cx inst
+  modifyInstEnv $
+    bindInstInfo (genInstIdent m tcEnv qcls inst) (m, ps, impls [] ds)
+  where impls is [] = is
+        impls is (FunctionDecl _ _ f eqs:ds')
+          | f' `elem` map fst is = impls is ds'
+          | otherwise            = impls ((f', eqnArity $ head eqs) : is) ds'
+          where f' = unRenameIdent f
+        impls _ _ = internalError "InstanceCheck.bindInstance.impls"
+bindInstance _     _      _                                = ok
+
+-- Next, the compiler sorts the data and newtype declarations with non-empty
+-- deriving clauses into minimal binding groups and infers contexts for their
+-- instance declarations. In the case of (mutually) recursive data types,
+-- inference of the appropriate contexts may require a fixpoint calculation.
+
+hasDerivedInstances :: Decl a -> Bool
+hasDerivedInstances (DataDecl    _ _ _ _ clss) = not $ null clss
+hasDerivedInstances (NewtypeDecl _ _ _ _ clss) = not $ null clss
+hasDerivedInstances _                          = False
+
+-- For the purposes of derived instances, a newtype declaration is treated
+-- as a data declaration with a single constructor. The compiler also sorts
+-- derived classes with respect to the super class hierarchy so that subclass
+-- instances are added to the instance environment after their super classes.
+
+data DeriveInfo = DeriveInfo SpanInfo QualIdent PredType [Type] [QualIdent]
+
+declDeriveInfo :: TCEnv -> ClassEnv -> Decl a -> INCM DeriveInfo
+declDeriveInfo tcEnv clsEnv (DataDecl p tc tvs cs clss) =
+  mkDeriveInfo tcEnv clsEnv p tc tvs (concat tyss) clss
+  where tyss = map constrDeclTypes cs
+        constrDeclTypes (ConstrDecl     _ _ tys) = tys
+        constrDeclTypes (ConOpDecl  _ ty1 _ ty2) = [ty1, ty2]
+        constrDeclTypes (RecordDecl      _ _ fs) = tys
+          where tys = [ty | FieldDecl _ ls ty <- fs, _ <- ls]
+declDeriveInfo tcEnv clsEnv (NewtypeDecl p tc tvs nc clss) =
+  mkDeriveInfo tcEnv clsEnv p tc tvs [nconstrType nc] clss
+declDeriveInfo _ _ _ =
+  internalError "InstanceCheck.declDeriveInfo: no data or newtype declaration"
+
+declDeriveDataInfo :: TCEnv -> ClassEnv -> Decl a -> INCM DeriveInfo
+declDeriveDataInfo tcEnv clsEnv (DataDecl p tc tvs cs _) =
+  mkDeriveDataInfo tcEnv clsEnv p tc tvs (concat tyss)
+  where tyss = map constrDeclTypes cs
+        constrDeclTypes (ConstrDecl     _ _ tys) = tys
+        constrDeclTypes (ConOpDecl  _ ty1 _ ty2) = [ty1, ty2]
+        constrDeclTypes (RecordDecl      _ _ fs) = tys
+          where tys = [ty | FieldDecl _ ls ty <- fs, _ <- ls]
+declDeriveDataInfo tcEnv clsEnv (NewtypeDecl p tc tvs nc _) =
+  mkDeriveDataInfo tcEnv clsEnv p tc tvs [nconstrType nc]
+declDeriveDataInfo _ _ _ = internalError
+  "InstanceCheck.declDeriveDataInfo: no data or newtype declaration"
+
+mkDeriveInfo :: TCEnv -> ClassEnv -> SpanInfo -> Ident -> [Ident]
+             -> [TypeExpr] -> [QualIdent] -> INCM DeriveInfo
+mkDeriveInfo tcEnv clsEnv spi tc tvs tys clss = do
+  m <- getModuleIdent
+  let otc = qualifyWith m tc
+      oclss = map (flip (getOrigName m) tcEnv) clss
+      PredType ps ty = expandConstrType m tcEnv clsEnv otc tvs tys
+      (tys', ty') = arrowUnapply ty
+  return $ DeriveInfo spi otc (PredType ps ty') tys' $ sortClasses clsEnv oclss
+
+mkDeriveDataInfo :: TCEnv -> ClassEnv -> SpanInfo -> Ident -> [Ident]
+                 -> [TypeExpr] -> INCM DeriveInfo
+mkDeriveDataInfo tcEnv clsEnv spi tc tvs tys = do
+  m <- getModuleIdent
+  let otc = qualifyWith m tc
+      PredType ps ty = expandConstrType m tcEnv clsEnv otc tvs tys
+      (tys', ty') = arrowUnapply ty
+  return $ DeriveInfo spi otc (PredType ps ty') tys' [qDataId]
+
+sortClasses :: ClassEnv -> [QualIdent] -> [QualIdent]
+sortClasses clsEnv clss = map fst $ sortBy compareDepth $ map adjoinDepth clss
+  where (_, d1) `compareDepth` (_, d2) = d1 `compare` d2
+        adjoinDepth cls = (cls, length $ allSuperClasses cls clsEnv)
+
+groupDeriveInfos :: [DeriveInfo] -> [[DeriveInfo]]
+groupDeriveInfos = scc bound free
+  where bound (DeriveInfo _ tc _ _ _) = [tc]
+        free (DeriveInfo _ _ _ tys _) = concatMap typeConstrs tys
+
+bindDerivedInstances :: ClassEnv -> [DeriveInfo] -> INCM ()
+bindDerivedInstances clsEnv dis = unless (any hasDataFunType dis) $ do
+  mapM_ (enterInitialPredSet clsEnv) dis
+  whileM $ concatMapM (inferPredSets clsEnv) dis >>= updatePredSets
+  where
+    hasDataFunType (DeriveInfo _ _ _ tys clss) =
+      clss == [qDataId] && any isFunType tys
+
+enterInitialPredSet :: ClassEnv -> DeriveInfo -> INCM ()
+enterInitialPredSet clsEnv (DeriveInfo spi tc pty _ clss) =
+  mapM_ (bindDerivedInstance clsEnv spi tc pty) clss
+
+-- Note: The methods and arities entered into the instance environment have
+-- to match methods and arities of the later generated instance declarations.
+-- TODO: Add remark about value environment entry
+
+bindDerivedInstance :: HasSpanInfo s => ClassEnv -> s -> QualIdent -> PredType -> QualIdent
+                    -> INCM ()
+bindDerivedInstance clsEnv p tc pty cls = do
+  m <- getModuleIdent
+  ((i, ps), _) <- inferPredSet clsEnv p tc pty [] cls
+  modifyInstEnv (bindInstInfo i (m, ps, impls))
+  where impls | cls == qEqId      = [(eqOpId, 2)]
+              | cls == qOrdId     = [(leqOpId, 2)]
+              | cls == qEnumId    = [ (succId, 1), (predId, 1), (toEnumId, 1)
+                                    , (fromEnumId, 1), (enumFromId, 1)
+                                    , (enumFromThenId, 2)
+                                    ]
+              | cls == qBoundedId = [(maxBoundId, 0), (minBoundId, 0)]
+              | cls == qReadId    = [(readsPrecId, 2)]
+              | cls == qShowId    = [(showsPrecId, 2)]
+              | cls == qDataId    = [(dataEqId, 2), (aValueId, 0)]
+              | otherwise         =
+                internalError "InstanceCheck.bindDerivedInstance.impls"
+
+inferPredSets :: ClassEnv -> DeriveInfo -> INCM [((InstIdent, PredSet), Bool)]
+inferPredSets clsEnv (DeriveInfo spi tc pty tys clss) =
+  mapM (inferPredSet clsEnv spi tc pty tys) clss
+
+inferPredSet :: HasSpanInfo s => ClassEnv -> s -> QualIdent -> PredType -> [Type]
+             -> QualIdent -> INCM ((InstIdent, PredSet), Bool)
+inferPredSet clsEnv p tc (PredType ps inst) tys cls = do
+  m <- getModuleIdent
+  let doc = ppPred m $ Pred cls inst
+      sclss = superClasses cls clsEnv
+      ps'   = Set.fromList [Pred cls ty | ty <- tys]
+      ps''  = Set.fromList [Pred scls inst | scls <- sclss]
+      ps''' = ps `Set.union` ps' `Set.union` ps''
+  (ps4, novarps) <-
+    reducePredSet (cls == qDataId) p "derived instance" doc clsEnv ps'''
+  let ps5 = filter noPolyPred $ Set.toList ps4
+  if any (isDataPred m) (Set.toList novarps ++ ps5) && cls == qDataId
+    then return    (((cls, tc), ps4), False)
+    else mapM_ (reportUndecidable p "derived instance" doc) ps5
+         >> return (((cls, tc), ps4), True)
+  where
+    noPolyPred (Pred _ (TypeVariable _)) = False
+    noPolyPred (Pred _ _               ) = True
+    isDataPred _ (Pred qid _) = qid == qDataId
+
+updatePredSets :: [((InstIdent, PredSet), Bool)] -> INCM Bool
+updatePredSets = fmap or . mapM (uncurry updatePredSet)
+
+updatePredSet :: (InstIdent, PredSet) -> Bool -> INCM Bool
+updatePredSet (i, ps) enter = do
+  inEnv <- getInstEnv
+  case lookupInstInfo i inEnv of
+    Just (m, ps', is)
+      | not enter -> modifyInstEnv (removeInstInfo i) >> return False
+      | ps == ps' -> return False
+      | otherwise -> do
+        modifyInstEnv $ bindInstInfo i (m, ps, is)
+        return True
+    Nothing -> internalError "InstanceCheck.updatePredSet"
+
+reportUndecidable :: HasSpanInfo s => s -> String -> Doc -> Pred -> INCM ()
+reportUndecidable p what doc predicate@(Pred _ ty) = do
+  m <- getModuleIdent
+  case ty of
+    TypeVariable _ -> return ()
+    _ -> report $ errMissingInstance m p what doc predicate
+
+-- Then, the compiler checks the contexts of all explicit instance
+-- declarations to detect missing super class instances. For an instance
+-- declaration
+--
+-- instance cx => C (T u_1 ... u_k) where ...
+--
+-- the compiler ensures that T is an instance of all of C's super classes
+-- and also that the contexts of the corresponding instance declarations are
+-- satisfied by cx.
+
+checkInstance :: TCEnv -> ClassEnv -> Decl a -> INCM ()
+checkInstance tcEnv clsEnv (InstanceDecl _ _ cx cls inst _) = do
+  m <- getModuleIdent
+  let PredType ps ty = expandPolyType m tcEnv clsEnv $
+                         QualTypeExpr NoSpanInfo cx inst
+      ocls = getOrigName m cls tcEnv
+      ps' = Set.fromList [ Pred scls ty | scls <- superClasses ocls clsEnv ]
+      doc = ppPred m $ Pred cls ty
+      what = "instance declaration"
+  (ps'', _) <- reducePredSet False inst what doc clsEnv ps'
+  Set.mapM_ (report . errMissingInstance m inst what doc) $
+    ps'' `Set.difference` maxPredSet clsEnv ps
+checkInstance _ _ _ = ok
+
+-- All types specified in the optional default declaration of a module
+-- must be instances of the Num class. Since these types are used to resolve
+-- ambiguous type variables, the predicate sets of the respective instances
+-- must be empty.
+
+checkDefault :: TCEnv -> ClassEnv -> Decl a -> INCM ()
+checkDefault tcEnv clsEnv (DefaultDecl _ tys) =
+  mapM_ (checkDefaultType tcEnv clsEnv) tys
+checkDefault _ _ _ = ok
+
+checkDefaultType :: TCEnv -> ClassEnv -> TypeExpr -> INCM ()
+checkDefaultType tcEnv clsEnv ty = do
+  m <- getModuleIdent
+  let PredType _ ty' = expandPolyType m tcEnv clsEnv $
+                         QualTypeExpr NoSpanInfo [] ty
+  (ps, _) <- reducePredSet False ty what empty clsEnv
+    (Set.singleton $ Pred qNumId ty')
+  Set.mapM_ (report . errMissingInstance m ty what empty) ps
+  where what = "default declaration"
+
+-- The function 'reducePredSet' simplifies a predicate set of the form
+-- (C_1 tau_1,..,C_n tau_n) where the tau_i are arbitrary types into a
+-- predicate set where all predicates are of the form C u with u being
+-- a type variable. An error is reported if the predicate set cannot
+-- be transformed into this form. In addition, we remove all predicates
+-- that are implied by others within the same set.
+-- When the flag is set, all missing Data preds are ignored
+
+reducePredSet :: HasSpanInfo s => Bool -> s -> String -> Doc -> ClassEnv -> PredSet
+              -> INCM (PredSet, PredSet)
+reducePredSet b p what doc clsEnv ps = do
+  m <- getModuleIdent
+  inEnv <- getInstEnv
+  let (ps1, ps2) = partitionPredSet $ minPredSet clsEnv $ reducePreds inEnv ps
+      ps2' = if b then Set.filter (isNotDataPred m) ps2 else ps2
+  Set.mapM_ (reportMissing m) ps2' >> return (ps1, ps2)
+  where
+    isNotDataPred _ (Pred qid _) = qid /= qDataId
+    reportMissing m pr@(Pred _ _) =
+      report $ errMissingInstance m p what doc pr
+    reducePreds inEnv = Set.concatMap $ reducePred inEnv
+    reducePred inEnv predicate = maybe (Set.singleton predicate)
+                                       (reducePreds inEnv)
+                                       (instPredSet inEnv predicate)
+
+instPredSet :: InstEnv -> Pred -> Maybe PredSet
+instPredSet inEnv (Pred qcls ty) =
+  case unapplyType False ty of
+    (TypeConstructor tc, tys) ->
+      fmap (expandAliasType tys . snd3) (lookupInstInfo (qcls, tc) inEnv)
+    _ -> Nothing
+
+-- ---------------------------------------------------------------------------
+-- Auxiliary definitions
+-- ---------------------------------------------------------------------------
+
+genInstIdents :: ModuleIdent -> TCEnv -> Decl a -> [InstIdent]
+genInstIdents m tcEnv (DataDecl    _ tc _ _ qclss) =
+  map (flip (genInstIdent m tcEnv) $ ConstructorType NoSpanInfo $ qualify tc)
+      qclss
+genInstIdents m tcEnv (NewtypeDecl _ tc _ _ qclss) =
+  map (flip (genInstIdent m tcEnv) $ ConstructorType NoSpanInfo $ qualify tc)
+      qclss
+genInstIdents m tcEnv (InstanceDecl _ _ _ qcls ty _) =
+  [genInstIdent m tcEnv qcls ty]
+genInstIdents _ _     _                            = []
+
+genInstIdent :: ModuleIdent -> TCEnv -> QualIdent -> TypeExpr -> InstIdent
+genInstIdent m tcEnv qcls = qualInstIdent m tcEnv . (,) qcls . typeConstr
+
+-- When qualifiying an instance identifier, we replace both the class and
+-- type constructor with their original names as found in the type constructor
+-- environment.
+
+qualInstIdent :: ModuleIdent -> TCEnv -> InstIdent -> InstIdent
+qualInstIdent m tcEnv (cls, tc) = (qual cls, qual tc)
+  where
+    qual = flip (getOrigName m) tcEnv
+
+unqualInstIdent :: TCEnv -> InstIdent -> InstIdent
+unqualInstIdent tcEnv (qcls, tc) = (unqual qcls, unqual tc)
+  where
+    unqual = head . flip reverseLookupByOrigName tcEnv
+
+isFunType :: Type -> Bool
+isFunType (TypeArrow         _ _) = True
+isFunType (TypeApply       t1 t2) = isFunType t1 || isFunType t2
+isFunType (TypeForall      _  ty) = isFunType ty
+isFunType (TypeConstrained tys _) = any isFunType tys
+isFunType _                       = False
+
+-- ---------------------------------------------------------------------------
+-- Error messages
+-- ---------------------------------------------------------------------------
+
+errMultipleInstances :: TCEnv -> [InstSource] -> Message
+errMultipleInstances tcEnv iss = message $
+  text "Multiple instances for the same class and type" $+$
+    nest 2 (vcat (map ppInstSource iss))
+  where
+    ppInstSource (InstSource i m) = ppInstIdent (unqualInstIdent tcEnv i) <+>
+      parens (text "defined in" <+> ppMIdent m)
+
+errMissingInstance :: HasSpanInfo s => ModuleIdent -> s -> String -> Doc -> Pred
+                   -> Message
+errMissingInstance m p what doc predicate = spanInfoMessage (getSpanInfo p) $ vcat
+  [ text "Missing instance for" <+> ppPred m predicate
+  , text "in" <+> text what <+> doc
+  ]
diff --git a/src/Checks/InterfaceCheck.hs b/src/Checks/InterfaceCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/InterfaceCheck.hs
@@ -0,0 +1,321 @@
+{- |
+    Module      :  $Header$
+    Description :  Checks consistency of interface files
+    Copyright   :  (c) 2000 - 2007 Wolfgang Lux
+                       2015        Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   Interface files include declarations of all entities that are exported
+   by the module, but defined in another module. Since these declarations
+   can become inconsistent if client modules are not recompiled properly,
+   the compiler checks that all imported declarations in an interface
+   agree with their original definitions.
+
+   One may ask why we include imported declarations at all, if the
+   compiler always has to compare those declarations with the original
+   definitions. The main reason for this is that it helps to avoid
+   unnecessary recompilations of client modules. As an example, consider
+   the three modules:
+
+     module A where { data T = C }
+     module B(T(..)) where { import A }
+     module C where { import B; f = C }
+
+   where module B could be considered as a public interface of module A,
+   which restricts access to type A.T and its constructor C.
+   The client module C imports this type via the public interface B.
+   If now module A is changed by adding a definition of a new global function
+
+     module A where { data T = C; f = C }
+
+   module B must be recompiled because A's interface is changed.
+   On the other hand, module C need not be recompiled because the change in
+   A does not affect B's interface. By including the declaration of type A.T
+   in B's interface, the compiler can trivially check that B's interface
+   remains unchanged and therefore the client module C is not recompiled.
+
+   Another reason for including imported declarations in interfaces is
+   that the compiler in principle could avoid loading interfaces of
+   modules that are imported only indirectly, which would save processing
+   time and allow distributing binary packages of a library with a public
+   interface module only. However, this has not been implemented yet.
+-}
+
+module Checks.InterfaceCheck (interfaceCheck) where
+
+import           Control.Monad            (unless)
+import qualified Control.Monad.State as S
+import           Data.List                (sort)
+import           Data.Maybe               (fromMaybe, isJust, isNothing)
+
+import Curry.Base.Ident
+import Curry.Base.SpanInfo
+import Curry.Base.Pretty
+import Curry.Syntax
+
+import Base.CurryKinds (toKind')
+import Base.CurryTypes
+import Base.Messages (Message, spanInfoMessage, internalError)
+import Base.TopEnv
+import Base.Types
+
+import Env.Class
+import Env.Instance
+import Env.OpPrec
+import Env.TypeConstructor
+import Env.Value
+
+data ICState = ICState
+  { moduleIdent :: ModuleIdent
+  , precEnv     :: OpPrecEnv
+  , tyConsEnv   :: TCEnv
+  , classEnv    :: ClassEnv
+  , instEnv     :: InstEnv
+  , valueEnv    :: ValueEnv
+  , errors      :: [Message]
+  }
+
+type IC = S.State ICState
+
+getModuleIdent :: IC ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+getPrecEnv :: IC OpPrecEnv
+getPrecEnv = S.gets precEnv
+
+getTyConsEnv :: IC TCEnv
+getTyConsEnv = S.gets tyConsEnv
+
+getClassEnv :: IC ClassEnv
+getClassEnv = S.gets classEnv
+
+getInstEnv :: IC InstEnv
+getInstEnv = S.gets instEnv
+
+getValueEnv :: IC ValueEnv
+getValueEnv = S.gets valueEnv
+
+-- |Report a syntax error
+report :: Message -> IC ()
+report msg = S.modify $ \s -> s { errors = msg : errors s }
+
+ok :: IC ()
+ok = return ()
+
+interfaceCheck :: OpPrecEnv -> TCEnv -> ClassEnv -> InstEnv -> ValueEnv
+               -> Interface -> [Message]
+interfaceCheck pEnv tcEnv clsEnv inEnv tyEnv (Interface m _ ds) =
+  reverse (errors s)
+  where s = S.execState (mapM_ checkImport ds) initState
+        initState = ICState m pEnv tcEnv clsEnv inEnv tyEnv []
+
+checkImport :: IDecl -> IC ()
+checkImport (IInfixDecl _ fix pr op) = checkPrecInfo check op op
+  where check (PrecInfo op' (OpPrec fix' pr')) =
+          op == op' && fix == fix' && pr == pr'
+checkImport (HidingDataDecl _ tc k tvs) =
+  checkTypeInfo "hidden data type" check tc tc
+  where check (DataType     tc' k' _)
+          | tc == tc' && toKind' k (length tvs) == k' = Just ok
+        check (RenamingType tc' k' _)
+          | tc == tc' && toKind' k (length tvs) == k' = Just ok
+        check _ = Nothing
+checkImport (IDataDecl _ tc k tvs cs _) = checkTypeInfo "data type" check tc tc
+  where check (DataType     tc' k' cs')
+          | tc == tc' && toKind' k (length tvs) == k' &&
+            (null cs || map constrId cs == map constrIdent cs')
+          = Just (mapM_ (checkConstrImport tc tvs) cs)
+        check (RenamingType tc' k'   _)
+          | tc == tc' && toKind' k (length tvs) == k' && null cs
+          = Just ok
+        check _ = Nothing
+checkImport (INewtypeDecl _ tc k tvs nc _) = checkTypeInfo "newtype" check tc tc
+  where check (RenamingType tc' k' nc')
+          | tc == tc' && toKind' k (length tvs) == k' &&
+            nconstrId nc == constrIdent nc'
+          = Just (checkNewConstrImport tc tvs nc)
+        check _ = Nothing
+checkImport (ITypeDecl _ tc k tvs ty) = do
+  m <- getModuleIdent
+  let check (AliasType tc' k' n' ty')
+        | tc == tc' && toKind' k (length tvs) == k' &&
+          length tvs == n' && toQualType m tvs ty == ty'
+        = Just ok
+      check _ = Nothing
+  checkTypeInfo "synonym type" check tc tc
+checkImport (IFunctionDecl _ f (Just tv) n ty) = do
+  m <- getModuleIdent
+  let check (Value f' cm' n' (ForAll _ ty')) =
+        f == f' && isJust cm' && n' == n &&
+        toQualPredType m [tv] ty == ty'
+      check _ = False
+  checkValueInfo "method" check f f
+checkImport (IFunctionDecl _ f Nothing n ty) = do
+  m <- getModuleIdent
+  let check (Value f' cm' n' (ForAll _ ty')) =
+        f == f' && isNothing cm' && n' == n &&
+        toQualPredType m [] ty == ty'
+      check _ = False
+  checkValueInfo "function" check f f
+checkImport (HidingClassDecl _ cx cls k _) = do
+  clsEnv <- getClassEnv
+  let check (TypeClass cls' k' _)
+        | cls == cls' && toKind' k 0 == k' &&
+          [cls'' | Constraint _ cls'' _ <- cx] == superClasses cls' clsEnv
+        = Just ok
+      check _ = Nothing
+  checkTypeInfo "hidden type class" check cls cls
+checkImport (IClassDecl _ cx cls k clsvar ms _) = do
+  clsEnv <- getClassEnv
+  let check (TypeClass cls' k' fs)
+        | cls == cls' && toKind' k 0 == k' &&
+          [cls'' | Constraint _ cls'' _ <- cx] == superClasses cls' clsEnv &&
+          map (\m -> (imethod m, imethodArity m)) ms ==
+            map (\f -> (methodName f, methodArity f)) fs
+        = Just $ mapM_ (checkMethodImport cls clsvar) ms
+      check _ = Nothing
+  checkTypeInfo "type class" check cls cls
+checkImport (IInstanceDecl _ cx cls ty is m) =
+  checkInstInfo check cls (cls, typeConstr ty) m
+  where PredType ps _ = toPredType [] $ QualTypeExpr NoSpanInfo cx ty
+        check ps' is' = ps == ps' && sort is == sort is'
+
+checkConstrImport :: QualIdent -> [Ident] -> ConstrDecl -> IC ()
+checkConstrImport tc tvs (ConstrDecl _ c tys) = do
+  m <- getModuleIdent
+  let qc = qualifyLike tc c
+      check (DataConstructor c' _ _ (ForAll uqvs pty)) =
+        qc == c' && length tvs == uqvs &&
+        qualifyPredType m (toConstrType tc tvs tys) == pty
+      check _ = False
+  checkValueInfo "data constructor" check c qc
+checkConstrImport tc tvs (ConOpDecl _ ty1 op ty2) = do
+  m <- getModuleIdent
+  let qc = qualifyLike tc op
+      check (DataConstructor c' _ _ (ForAll uqvs pty)) =
+        qc == c' && length tvs == uqvs &&
+        qualifyPredType m (toConstrType tc tvs [ty1, ty2]) == pty
+      check _ = False
+  checkValueInfo "data constructor" check op qc
+checkConstrImport tc tvs (RecordDecl _ c fs) = do
+  m <- getModuleIdent
+  let qc = qualifyLike tc c
+      (ls, tys) = unzip [(l, ty) | FieldDecl _ labels ty <- fs, l <- labels]
+      check (DataConstructor c' _ ls' (ForAll uqvs pty)) =
+        qc == c' && length tvs == uqvs && ls == ls' &&
+        qualifyPredType m (toConstrType tc tvs tys) == pty
+      check _ = False
+  checkValueInfo "data constructor" check c qc
+
+checkNewConstrImport :: QualIdent -> [Ident] -> NewConstrDecl -> IC ()
+checkNewConstrImport tc tvs (NewConstrDecl _ c ty) = do
+  m <- getModuleIdent
+  let qc = qualifyLike tc c
+      check (NewtypeConstructor c' _ (ForAll uqvs (PredType _ ty'))) =
+        qc == c' && length tvs == uqvs && toQualType m tvs ty == head (arrowArgs ty')
+      check _ = False
+  checkValueInfo "newtype constructor" check c qc
+checkNewConstrImport tc tvs (NewRecordDecl _ c (l, ty)) = do
+  m <- getModuleIdent
+  let qc = qualifyLike tc c
+      check (NewtypeConstructor c' l' (ForAll uqvs (PredType _ ty'))) =
+        qc == c' && length tvs == uqvs && l == l' &&
+        toQualType m tvs ty == head (arrowArgs ty')
+      check _ = False
+  checkValueInfo "newtype constructor" check c qc
+
+checkMethodImport :: QualIdent -> Ident -> IMethodDecl -> IC ()
+checkMethodImport qcls clsvar (IMethodDecl _ f _ qty) =
+  checkValueInfo "method" check f qf
+  where qf = qualifyLike qcls f
+        check (Value f' cm' _ (ForAll _ pty)) =
+          qf == f' && isJust cm' &&
+          toMethodType qcls clsvar qty == pty
+        check _ = False
+
+checkPrecInfo :: HasSpanInfo s => (PrecInfo -> Bool) -> s -> QualIdent -> IC ()
+checkPrecInfo check p op = do
+  pEnv <- getPrecEnv
+  let checkInfo m op' = case qualLookupTopEnv op pEnv of
+        []     -> report $ errNoPrecedence p m op'
+        [prec] -> unless (check prec)
+                         (report $ errImportConflict p "precedence" m op')
+        _      -> internalError "checkPrecInfo"
+  checkImported checkInfo op
+
+checkTypeInfo :: HasSpanInfo s => String -> (TypeInfo -> Maybe (IC ())) -> s
+              -> QualIdent -> IC ()
+checkTypeInfo what check p tc = do
+  tcEnv <- getTyConsEnv
+  let checkInfo m tc' = case qualLookupTopEnv tc tcEnv of
+        []   -> report $ errNotExported p what m tc'
+        [ti] -> fromMaybe (report $ errImportConflict p what m tc') (check ti)
+        _    -> internalError "checkTypeInfo"
+  checkImported checkInfo tc
+
+checkInstInfo :: HasSpanInfo s => (PredSet -> [(Ident, Int)] -> Bool) -> s -> InstIdent
+              -> Maybe ModuleIdent -> IC ()
+checkInstInfo check p i mm = do
+  inEnv <- getInstEnv
+  let checkInfo m _ = case lookupInstInfo i inEnv of
+        Just (m', ps, is)
+          | m /= m'   -> report $ errNoInstance p m i
+          | otherwise ->
+            unless (check ps is) $ report $ errInstanceConflict p m i
+        Nothing -> report $ errNoInstance p m i
+  checkImported checkInfo (maybe qualify qualifyWith mm anonId)
+
+checkValueInfo :: HasSpanInfo a => String -> (ValueInfo -> Bool) -> a
+               -> QualIdent -> IC ()
+checkValueInfo what check p x = do
+  tyEnv <- getValueEnv
+  let checkInfo m x' = case qualLookupTopEnv x tyEnv of
+        []   -> report $ errNotExported p' what m x'
+        [vi] -> unless (check vi)
+                  (report $ errImportConflict p' what m x')
+        _    -> internalError "checkValueInfo"
+  checkImported checkInfo x
+  where p' = getSpanInfo p
+
+checkImported :: (ModuleIdent -> Ident -> IC ()) -> QualIdent -> IC ()
+checkImported _ (QualIdent _ Nothing  _) = ok
+checkImported f (QualIdent _ (Just m) x) = f m x
+
+-- ---------------------------------------------------------------------------
+-- Error messages
+-- ---------------------------------------------------------------------------
+
+errNotExported :: HasSpanInfo s => s -> String -> ModuleIdent -> Ident -> Message
+errNotExported p what m x = spanInfoMessage p $
+  text "Inconsistent module interfaces"
+  $+$ text "Module" <+> text (moduleName m)
+  <+> text "does not export"<+> text what <+> text (escName x)
+
+errNoPrecedence :: HasSpanInfo s => s -> ModuleIdent -> Ident -> Message
+errNoPrecedence p m x = spanInfoMessage p $
+  text "Inconsistent module interfaces"
+  $+$ text "Module" <+> text (moduleName m)
+  <+> text "does not define a precedence for" <+> text (escName x)
+
+errNoInstance :: HasSpanInfo s => s -> ModuleIdent -> InstIdent -> Message
+errNoInstance p m i = spanInfoMessage p $
+  text "Inconsistent module interfaces"
+  $+$ text "Module" <+> text (moduleName m)
+  <+> text "does not define an instance for" <+> ppInstIdent i
+
+errImportConflict :: HasSpanInfo s => s -> String -> ModuleIdent -> Ident -> Message
+errImportConflict p what m x = spanInfoMessage p $
+  text "Inconsistent module interfaces"
+  $+$ text "Declaration of" <+> text what <+> text (escName x)
+  <+> text "does not match its definition in module" <+> text (moduleName m)
+
+errInstanceConflict :: HasSpanInfo s => s -> ModuleIdent -> InstIdent -> Message
+errInstanceConflict p m i = spanInfoMessage p $
+  text "Inconsistent module interfaces"
+  $+$ text "Declaration of instance" <+> ppInstIdent i
+  <+> text "does not match its definition in module" <+> text (moduleName m)
diff --git a/src/Checks/InterfaceSyntaxCheck.hs b/src/Checks/InterfaceSyntaxCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/InterfaceSyntaxCheck.hs
@@ -0,0 +1,346 @@
+{- |
+    Module      :  $Header$
+    Description :  Checks interface declarations
+    Copyright   :  (c) 2000 - 2007 Wolfgang Lux
+                       2011 - 2015 Björn Peemöller
+                       2015        Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   Similar to Curry source files, some post-processing has to be applied
+   to parsed interface files. In particular, the compiler must
+   disambiguate nullary type constructors and type variables. In
+   addition, the compiler also checks that all type constructor
+   applications are saturated. Since interface files are closed -- i.e.,
+   they include declarations of all entities which are defined in other
+   modules -- the compiler can perform this check without reference to
+   the global environments.
+-}
+
+module Checks.InterfaceSyntaxCheck (intfSyntaxCheck) where
+
+import           Control.Monad            (liftM, liftM2, unless, when)
+import qualified Control.Monad.State as S
+import           Data.List                (nub, partition)
+import           Data.Maybe               (isNothing)
+
+import Base.Expr
+import Base.Messages (Message, spanInfoMessage, internalError)
+import Base.TopEnv
+import Base.Utils    (findMultiples, findDouble)
+
+import Env.TypeConstructor
+import Env.Type
+
+import Curry.Base.Ident
+import Curry.Base.SpanInfo
+import Curry.Base.Pretty
+import Curry.Syntax
+
+data ISCState = ISCState
+  { typeEnv :: TypeEnv
+  , errors  :: [Message]
+  }
+
+type ISC = S.State ISCState
+
+getTypeEnv :: ISC TypeEnv
+getTypeEnv = S.gets typeEnv
+
+-- |Report a syntax error
+report :: Message -> ISC ()
+report msg = S.modify $ \ s -> s { errors = msg : errors s }
+
+intfSyntaxCheck :: Interface -> (Interface, [Message])
+intfSyntaxCheck (Interface n is ds) = (Interface n is ds', reverse $ errors s')
+  where (ds', s') = S.runState (mapM checkIDecl ds) (ISCState env [])
+        env = foldr bindType (fmap toTypeKind initTCEnv) ds
+
+-- The compiler requires information about the arity of each defined type
+-- constructor as well as information whether the type constructor
+-- denotes an algebraic data type, a renaming type, or a type synonym.
+-- The latter must not occur in type expressions in interfaces.
+
+bindType :: IDecl -> TypeEnv -> TypeEnv
+bindType (IInfixDecl           _ _ _ _) = id
+bindType (HidingDataDecl      _ tc _ _) = qualBindTopEnv tc (Data tc [])
+bindType (IDataDecl      _ tc _ _ cs _) =
+  qualBindTopEnv tc (Data tc (map constrId cs))
+bindType (INewtypeDecl   _ tc _ _ nc _) =
+  qualBindTopEnv tc (Data tc [nconstrId nc])
+bindType (ITypeDecl         _ tc _ _ _) = qualBindTopEnv tc (Alias tc)
+bindType (IFunctionDecl      _ _ _ _ _) = id
+bindType (HidingClassDecl  _ _ cls _ _) = qualBindTopEnv cls (Class cls [])
+bindType (IClassDecl _ _ cls _ _ ms hs) =
+  qualBindTopEnv cls (Class cls (filter (`notElem` hs) (map imethod ms)))
+bindType (IInstanceDecl    _ _ _ _ _ _) = id
+
+-- The checks applied to the interface are similar to those performed
+-- during syntax checking of type expressions.
+
+checkIDecl :: IDecl -> ISC IDecl
+checkIDecl (IInfixDecl  p fix pr op) = return (IInfixDecl p fix pr op)
+checkIDecl (HidingDataDecl p tc k tvs) = do
+  checkTypeLhs tvs
+  return (HidingDataDecl p tc k tvs)
+checkIDecl (IDataDecl p tc k tvs cs hs) = do
+  checkTypeLhs tvs
+  checkHiddenType tc (cons ++ labels) hs
+  cs' <- mapM (checkConstrDecl tvs) cs
+  return $ IDataDecl p tc k tvs cs' hs
+  where cons   = map constrId cs
+        labels = nub $ concatMap recordLabels cs
+checkIDecl (INewtypeDecl p tc k tvs nc hs) = do
+  checkTypeLhs tvs
+  checkHiddenType tc (con : labels) hs
+  nc' <- checkNewConstrDecl tvs nc
+  return $ INewtypeDecl p tc k tvs nc' hs
+  where con    = nconstrId nc
+        labels = nrecordLabels nc
+checkIDecl (ITypeDecl p tc k tvs ty) = do
+  checkTypeLhs tvs
+  liftM (ITypeDecl p tc k tvs) (checkClosedType tvs ty)
+checkIDecl (IFunctionDecl p f cm n qty) =
+  liftM (IFunctionDecl p f cm n) (checkQualType qty)
+checkIDecl (HidingClassDecl p cx qcls k clsvar) = do
+  checkTypeVars "hiding class declaration" [clsvar]
+  cx' <- checkClosedContext [clsvar] cx
+  checkSimpleContext cx'
+  return $ HidingClassDecl p cx' qcls k clsvar
+checkIDecl (IClassDecl p cx qcls k clsvar ms hs) = do
+  checkTypeVars "class declaration" [clsvar]
+  cx' <- checkClosedContext [clsvar] cx
+  checkSimpleContext cx'
+  ms' <- mapM (checkIMethodDecl clsvar) ms
+  checkHidden (errNoElement "method" "class") qcls (map imethod ms') hs
+  return $ IClassDecl p cx' qcls k clsvar ms' hs
+checkIDecl (IInstanceDecl p cx qcls inst is m) = do
+  checkClass qcls
+  QualTypeExpr _ cx' inst' <- checkQualType $ QualTypeExpr NoSpanInfo cx inst
+  checkSimpleContext cx'
+  checkInstanceType inst'
+  mapM_ (report . errMultipleImplementation . head) $ findMultiples $ map fst is
+  return $ IInstanceDecl p cx' qcls inst' is m
+
+checkHiddenType :: QualIdent -> [Ident] -> [Ident] -> ISC ()
+checkHiddenType = checkHidden $ errNoElement "constructor or label" "type"
+
+checkHidden :: (QualIdent -> Ident -> Message) -> QualIdent -> [Ident]
+            -> [Ident] -> ISC ()
+checkHidden err tc csls hs =
+  mapM_ (report . err tc) $ nub $ filter (`notElem` csls) hs
+
+checkTypeLhs :: [Ident] -> ISC ()
+checkTypeLhs = checkTypeVars "left hand side of type declaration"
+
+checkTypeVars :: String -> [Ident] -> ISC ()
+checkTypeVars what tvs = do
+  tyEnv <- getTypeEnv
+  let (tcs, tvs') = partition isTypeConstrOrClass tvs
+      isTypeConstrOrClass tv = not (null (lookupTypeKind tv tyEnv))
+  mapM_ (report . flip errNoVariable what)       (nub tcs)
+  mapM_ (report . flip errNonLinear what . head) (findMultiples tvs')
+
+checkConstrDecl :: [Ident] -> ConstrDecl -> ISC ConstrDecl
+checkConstrDecl tvs (ConstrDecl p c tys) = do
+  liftM (ConstrDecl p c) (mapM (checkClosedType tvs) tys)
+checkConstrDecl tvs (ConOpDecl p ty1 op ty2) = do
+  liftM2 (\t1 t2 -> ConOpDecl p t1 op t2)
+         (checkClosedType tvs ty1)
+         (checkClosedType tvs ty2)
+checkConstrDecl tvs (RecordDecl p c fs) = do
+  liftM (RecordDecl p c) (mapM (checkFieldDecl tvs) fs)
+
+checkFieldDecl :: [Ident] -> FieldDecl -> ISC FieldDecl
+checkFieldDecl tvs (FieldDecl p ls ty) =
+  liftM (FieldDecl p ls) (checkClosedType tvs ty)
+
+checkNewConstrDecl :: [Ident] -> NewConstrDecl -> ISC NewConstrDecl
+checkNewConstrDecl tvs (NewConstrDecl p c ty) =
+  liftM (NewConstrDecl p c) (checkClosedType tvs ty)
+checkNewConstrDecl tvs (NewRecordDecl p c (l, ty)) = do
+  ty' <- checkClosedType tvs ty
+  return $ NewRecordDecl p c (l, ty')
+
+checkSimpleContext :: Context -> ISC ()
+checkSimpleContext = mapM_ checkSimpleConstraint
+
+checkSimpleConstraint :: Constraint -> ISC ()
+checkSimpleConstraint c@(Constraint _ _ ty) =
+  unless (isVariableType ty) $ report $ errIllegalSimpleConstraint c
+
+checkIMethodDecl :: Ident -> IMethodDecl -> ISC IMethodDecl
+checkIMethodDecl tv (IMethodDecl p f a qty) = do
+  qty' <- checkQualType qty
+  unless (tv `elem` fv qty') $ report $ errAmbiguousType f tv
+  let QualTypeExpr _ cx _ = qty'
+  when (tv `elem` fv cx) $ report $ errConstrainedClassVariable f tv
+  return $ IMethodDecl p f a qty'
+
+checkInstanceType :: InstanceType -> ISC ()
+checkInstanceType inst = do
+  tEnv <- getTypeEnv
+  unless (isSimpleType inst &&
+    not (isTypeSyn (typeConstr inst) tEnv) &&
+    null (filter isAnonId $ typeVars inst) &&
+    isNothing (findDouble $ fv inst)) $
+      report $ errIllegalInstanceType inst inst
+
+checkQualType :: QualTypeExpr -> ISC QualTypeExpr
+checkQualType (QualTypeExpr spi cx ty) = do
+  ty' <- checkType ty
+  cx' <- checkClosedContext (fv ty') cx
+  return $ QualTypeExpr spi cx' ty'
+
+checkClosedContext :: [Ident] -> Context -> ISC Context
+checkClosedContext tvs cx = do
+  cx' <- checkContext cx
+  mapM_ (\(Constraint _ _ ty) -> checkClosed tvs ty) cx'
+  return cx'
+
+checkContext :: Context -> ISC Context
+checkContext = mapM checkConstraint
+
+checkConstraint :: Constraint -> ISC Constraint
+checkConstraint (Constraint spi qcls ty) = do
+  checkClass qcls
+  Constraint spi qcls `liftM` checkType ty
+
+checkClass :: QualIdent -> ISC ()
+checkClass qcls = do
+  tEnv <- getTypeEnv
+  case qualLookupTypeKind qcls tEnv of
+    [] -> report $ errUndefinedClass qcls
+    [Class _ _] -> return ()
+    [_] -> report $ errUndefinedClass qcls
+    _ -> internalError $ "Checks.InterfaceSyntaxCheck.checkClass: " ++
+           "ambiguous identifier " ++ show qcls
+
+checkClosedType :: [Ident] -> TypeExpr -> ISC TypeExpr
+checkClosedType tvs ty = do
+  ty' <- checkType ty
+  checkClosed tvs ty'
+  return ty'
+
+checkType :: TypeExpr -> ISC TypeExpr
+checkType (ConstructorType spi tc) = checkTypeConstructor spi tc
+checkType (ApplyType  spi ty1 ty2) =
+  liftM2 (ApplyType spi) (checkType ty1) (checkType ty2)
+checkType (VariableType    spi tv) =
+  checkType $ ConstructorType spi (qualify tv)
+checkType (TupleType      spi tys) = liftM (TupleType spi) (mapM checkType tys)
+checkType (ListType        spi ty) = liftM (ListType spi) (checkType ty)
+checkType (ArrowType  spi ty1 ty2) =
+  liftM2 (ArrowType spi) (checkType ty1) (checkType ty2)
+checkType (ParenType      spi  ty) = liftM (ParenType spi) (checkType ty)
+checkType (ForallType   spi vs ty) = liftM (ForallType spi vs) (checkType ty)
+
+checkClosed :: [Ident] -> TypeExpr -> ISC ()
+checkClosed _   (ConstructorType _ _) = return ()
+checkClosed tvs (ApplyType _ ty1 ty2) = mapM_ (checkClosed tvs) [ty1, ty2]
+checkClosed tvs (VariableType   _ tv) =
+  when (isAnonId tv || tv `notElem` tvs) $ report $ errUnboundVariable tv
+checkClosed tvs (TupleType     _ tys) = mapM_ (checkClosed tvs) tys
+checkClosed tvs (ListType       _ ty) = checkClosed tvs ty
+checkClosed tvs (ArrowType _ ty1 ty2) = mapM_ (checkClosed tvs) [ty1, ty2]
+checkClosed tvs (ParenType      _ ty) = checkClosed tvs ty
+checkClosed tvs (ForallType  _ vs ty) = checkClosed (tvs ++ vs) ty
+
+checkTypeConstructor :: SpanInfo -> QualIdent -> ISC TypeExpr
+checkTypeConstructor spi tc = do
+  tyEnv <- getTypeEnv
+  case qualLookupTypeKind tc tyEnv of
+    [] | not (isQualified tc) -> return $ VariableType spi $ unqualify tc
+       | otherwise            -> do
+          report $ errUndefinedType tc
+          return $ ConstructorType spi tc
+    [Data _ _] -> return $ ConstructorType spi tc
+    [Alias  _] -> do
+                  report $ errBadTypeSynonym tc
+                  return $ ConstructorType spi tc
+    _          ->
+      internalError "Checks.InterfaceSyntaxCheck.checkTypeConstructor"
+
+-- ---------------------------------------------------------------------------
+-- Auxiliary definitions
+-- ---------------------------------------------------------------------------
+
+typeVars :: TypeExpr -> [Ident]
+typeVars (ConstructorType      _ _) = []
+typeVars (ApplyType      _ ty1 ty2) = typeVars ty1 ++ typeVars ty2
+typeVars (VariableType        _ tv) = [tv]
+typeVars (TupleType          _ tys) = concatMap typeVars tys
+typeVars (ListType            _ ty) = typeVars ty
+typeVars (ArrowType      _ ty1 ty2) = typeVars ty1 ++ typeVars ty2
+typeVars (ParenType           _ ty) = typeVars ty
+typeVars (ForallType       _ vs ty) = vs ++ typeVars ty
+
+isTypeSyn :: QualIdent -> TypeEnv -> Bool
+isTypeSyn tc tEnv = case qualLookupTypeKind tc tEnv of
+  [Alias _] -> True
+  _ -> False
+
+-- ---------------------------------------------------------------------------
+-- Error messages
+-- ---------------------------------------------------------------------------
+
+errUndefined :: String -> QualIdent -> Message
+errUndefined what qident = spanInfoMessage qident $ hsep $ map text
+  ["Undefined", what, qualName qident]
+
+errUndefinedClass :: QualIdent -> Message
+errUndefinedClass = errUndefined "class"
+
+errUndefinedType :: QualIdent -> Message
+errUndefinedType = errUndefined "type"
+
+errMultipleImplementation :: Ident -> Message
+errMultipleImplementation f = spanInfoMessage f $ hsep $ map text
+  ["Arity information for method", idName f, "occurs more than once"]
+
+errAmbiguousType :: HasSpanInfo s => s -> Ident -> Message
+errAmbiguousType p ident = spanInfoMessage p $ hsep $ map text
+  [ "Method type does not mention class variable", idName ident ]
+
+errConstrainedClassVariable :: HasSpanInfo s => s -> Ident -> Message
+errConstrainedClassVariable p ident = spanInfoMessage p $ hsep $ map text
+  [ "Method context must not constrain class variable", idName ident ]
+
+errNonLinear :: Ident -> String -> Message
+errNonLinear tv what = spanInfoMessage tv $ hsep $ map text
+  [ "Type variable", escName tv, "occurs more than once in", what ]
+
+errNoVariable :: Ident -> String -> Message
+errNoVariable tv what = spanInfoMessage tv $ hsep $ map text
+  [ "Type constructor or type class identifier", escName tv, "used in", what ]
+
+errUnboundVariable :: Ident -> Message
+errUnboundVariable tv = spanInfoMessage tv $
+  text "Undefined type variable" <+> text (escName tv)
+
+errBadTypeSynonym :: QualIdent -> Message
+errBadTypeSynonym tc = spanInfoMessage tc $ text "Synonym type"
+                    <+> text (qualName tc) <+> text "in interface"
+
+errNoElement :: String -> String -> QualIdent -> Ident -> Message
+errNoElement what for tc x = spanInfoMessage x $ hsep $ map text
+  [ "Hidden", what, escName x, "is not defined for", for, qualName tc ]
+
+errIllegalSimpleConstraint :: Constraint -> Message
+errIllegalSimpleConstraint c@(Constraint _ qcls _) = spanInfoMessage qcls $ vcat
+  [ text "Illegal class constraint" <+> pPrint c
+  , text "Constraints in class and instance declarations must be of"
+  , text "the form C u, where C is a type class and u is a type variable."
+  ]
+
+errIllegalInstanceType :: HasSpanInfo s => s -> InstanceType -> Message
+errIllegalInstanceType p inst = spanInfoMessage p $ vcat
+  [ text "Illegal instance type" <+> pPrint inst
+  , text "The instance type must be of the form (T u_1 ... u_n),"
+  , text "where T is not a type synonym and u_1, ..., u_n are"
+  , text "mutually distinct, non-anonymous type variables."
+  ]
diff --git a/src/Checks/KindCheck.hs b/src/Checks/KindCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/KindCheck.hs
@@ -0,0 +1,762 @@
+{- |
+    Module      :  $Header$
+    Description :  Checks type kinds
+    Copyright   :  (c) 2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   After the type syntax has been checked und nullary type constructors and
+   type variables have been disambiguated, the compiler infers kinds for all
+   type constructors and type classes defined in the current module and
+   performs kind checking on all type definitions and type signatures.
+-}
+{-# LANGUAGE CPP #-}
+module Checks.KindCheck (kindCheck) where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative      ((<$>), (<*>))
+#endif
+import           Control.Monad            (when, foldM)
+import           Control.Monad.Fix        (mfix)
+import qualified Control.Monad.State as S (State, runState, gets, modify)
+import           Data.List                (partition, nub)
+
+import Curry.Base.Ident
+import Curry.Base.Position
+import Curry.Base.SpanInfo
+import Curry.Base.Pretty
+import Curry.Syntax
+import Curry.Syntax.Pretty
+
+import Base.CurryKinds
+import Base.Expr
+import Base.Kinds
+import Base.KindSubst
+import Base.Messages (Message, spanInfoMessage, internalError)
+import Base.SCC
+import Base.TopEnv
+import Base.Types
+import Base.TypeExpansion
+
+import Env.Class
+import Env.TypeConstructor
+
+-- In order to infer kinds for type constructors and type classes, the
+-- compiler sorts the module's type and class declarations into minimal
+-- recursive binding groups and then applies kind inference to each
+-- declaration group. Besides inferring kinds for the type constructors
+-- and type classes of a group, the compiler also checks that there are
+-- no mutually recursive type synonym definitions and that the super class
+-- hierarchy is acyclic. The former allows entering fully expanded type
+-- synonyms into the type constructor environment.
+
+kindCheck :: TCEnv -> ClassEnv -> Module a -> ((TCEnv, ClassEnv), [Message])
+kindCheck tcEnv clsEnv (Module _ _ _ m _ _ ds) = runKCM check initState
+  where
+    check = do
+      checkNonRecursiveTypes tds &&> checkAcyclicSuperClasses cds
+      errs <- S.gets errors
+      if null errs
+         then checkDecls
+         else return (tcEnv, clsEnv)
+    checkDecls = do
+      (tcEnv', clsEnv') <- kcDecls tcEnv clsEnv tcds
+      mapM_ (kcDecl tcEnv') ods
+      return (tcEnv', clsEnv')
+    tds = filter isTypeDecl tcds
+    cds = filter isClassDecl tcds
+    (tcds, ods) = partition isTypeOrClassDecl ds
+    initState  = KCState m idSubst 0 []
+
+-- Kind Check Monad
+type KCM = S.State KCState
+
+-- |Internal state of the Kind Check
+data KCState = KCState
+  { moduleIdent :: ModuleIdent -- read only
+  , kindSubst   :: KindSubst
+  , nextId      :: Int         -- automatic counter
+  , errors      :: [Message]
+  }
+
+(&&>) :: KCM () -> KCM () -> KCM ()
+pre &&> suf = do
+  errs <- pre >> S.gets errors
+  when (null errs) suf
+
+runKCM :: KCM a -> KCState -> (a, [Message])
+runKCM kcm s = let (a, s') = S.runState kcm s in (a, reverse $ errors s')
+
+getModuleIdent :: KCM ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+getKindSubst :: KCM KindSubst
+getKindSubst = S.gets kindSubst
+
+modifyKindSubst :: (KindSubst -> KindSubst) -> KCM ()
+modifyKindSubst f = S.modify $ \s -> s { kindSubst = f $ kindSubst s }
+
+getNextId :: KCM Int
+getNextId = do
+  nid <- S.gets nextId
+  S.modify $ \s -> s { nextId = succ nid }
+  return nid
+
+report :: Message -> KCM ()
+report err = S.modify (\s -> s { errors = err : errors s })
+
+ok :: KCM ()
+ok = return ()
+
+-- Minimal recursive declaration groups are computed using the sets of bound
+-- and free type constructor and type class identifiers of the declarations.
+
+bt :: Decl a -> [Ident]
+bt (DataDecl     _ tc _ _ _) = [tc]
+bt (ExternalDataDecl _ tc _) = [tc]
+bt (NewtypeDecl  _ tc _ _ _) = [tc]
+bt (TypeDecl       _ tc _ _) = [tc]
+bt (ClassDecl _ _ _ cls _ _) = [cls]
+bt _                         = []
+
+ft :: ModuleIdent -> Decl a -> [Ident]
+ft m d = fts m d []
+
+class HasType a where
+  fts :: ModuleIdent -> a -> [Ident] -> [Ident]
+
+instance HasType a => HasType [a] where
+  fts m = flip $ foldr $ fts m
+
+instance HasType a => HasType (Maybe a) where
+  fts m = maybe id $ fts m
+
+instance HasType (Decl a) where
+  fts _ (InfixDecl               _ _ _ _) = id
+  fts m (DataDecl          _ _ _ cs clss) = fts m cs . fts m clss
+  fts _ (ExternalDataDecl          _ _ _) = id
+  fts m (NewtypeDecl       _ _ _ nc clss) = fts m nc . fts m clss
+  fts m (TypeDecl               _ _ _ ty) = fts m ty
+  fts m (TypeSig                  _ _ ty) = fts m ty
+  fts m (FunctionDecl          _ _ _ eqs) = fts m eqs
+  fts _ (ExternalDecl                _ _) = id
+  fts m (PatternDecl             _ _ rhs) = fts m rhs
+  fts _ (FreeDecl                    _ _) = id
+  fts m (DefaultDecl               _ tys) = fts m tys
+  fts m (ClassDecl         _ _ cx _ _ ds) = fts m cx . fts m ds
+  fts m (InstanceDecl _ _ cx cls inst ds) =
+    fts m cx . fts m cls . fts m inst . fts m ds
+
+instance HasType ConstrDecl where
+  fts m (ConstrDecl     _ _ tys) = fts m tys
+  fts m (ConOpDecl  _ ty1 _ ty2) = fts m ty1 . fts m ty2
+  fts m (RecordDecl      _ _ fs) = fts m fs
+
+instance HasType FieldDecl where
+  fts m (FieldDecl _ _ ty) = fts m ty
+
+instance HasType NewConstrDecl where
+  fts m (NewConstrDecl      _ _ ty) = fts m ty
+  fts m (NewRecordDecl _ _ (_, ty)) = fts m ty
+
+instance HasType Constraint where
+  fts m (Constraint _ qcls _) = fts m qcls
+
+instance HasType QualTypeExpr where
+  fts m (QualTypeExpr _ cx ty) = fts m cx . fts m ty
+
+instance HasType TypeExpr where
+  fts m (ConstructorType     _ tc) = fts m tc
+  fts m (ApplyType      _ ty1 ty2) = fts m ty1 . fts m ty2
+  fts _ (VariableType         _ _) = id
+  fts m (TupleType          _ tys) = (tupleId (length tys) :) . fts m tys
+  fts m (ListType            _ ty) = (listId :) . fts m ty
+  fts m (ArrowType      _ ty1 ty2) = (arrowId :) . fts m ty1 . fts m ty2
+  fts m (ParenType           _ ty) = fts m ty
+  fts m (ForallType        _ _ ty) = fts m ty
+
+instance HasType (Equation a) where
+  fts m (Equation _ _ rhs) = fts m rhs
+
+instance HasType (Rhs a) where
+  fts m (SimpleRhs  _ _ e  ds) = fts m e . fts m ds
+  fts m (GuardedRhs _ _ es ds) = fts m es . fts m ds
+
+instance HasType (CondExpr a) where
+  fts m (CondExpr _ g e) = fts m g . fts m e
+
+instance HasType (Expression a) where
+  fts _ (Literal             _ _ _) = id
+  fts _ (Variable            _ _ _) = id
+  fts _ (Constructor         _ _ _) = id
+  fts m (Paren                 _ e) = fts m e
+  fts m (Typed              _ e ty) = fts m e . fts m ty
+  fts m (Record           _ _ _ fs) = fts m fs
+  fts m (RecordUpdate       _ e fs) = fts m e . fts m fs
+  fts m (Tuple                _ es) = fts m es
+  fts m (List               _ _ es) = fts m es
+  fts m (ListCompr        _ e stms) = fts m e . fts m stms
+  fts m (EnumFrom              _ e) = fts m e
+  fts m (EnumFromThen      _ e1 e2) = fts m e1 . fts m e2
+  fts m (EnumFromTo        _ e1 e2) = fts m e1 . fts m e2
+  fts m (EnumFromThenTo _ e1 e2 e3) = fts m e1 . fts m e2 . fts m e3
+  fts m (UnaryMinus            _ e) = fts m e
+  fts m (Apply             _ e1 e2) = fts m e1 . fts m e2
+  fts m (InfixApply      _ e1 _ e2) = fts m e1 . fts m e2
+  fts m (LeftSection         _ e _) = fts m e
+  fts m (RightSection        _ _ e) = fts m e
+  fts m (Lambda              _ _ e) = fts m e
+  fts m (Let              _ _ ds e) = fts m ds . fts m e
+  fts m (Do             _ _ stms e) = fts m stms . fts m e
+  fts m (IfThenElse     _ e1 e2 e3) = fts m e1 . fts m e2 . fts m e3
+  fts m (Case           _ _ _ e as) = fts m e . fts m as
+
+instance HasType (Statement a) where
+  fts m (StmtExpr _    e) = fts m e
+  fts m (StmtDecl _ _ ds) = fts m ds
+  fts m (StmtBind _ _  e) = fts m e
+
+instance HasType (Alt a) where
+  fts m (Alt _ _ rhs) = fts m rhs
+
+instance HasType a => HasType (Field a) where
+  fts m (Field _ _ x) = fts m x
+
+instance HasType QualIdent where
+  fts m qident = maybe id (:) (localIdent m qident)
+
+-- When types are entered into the type constructor environment, all type
+-- synonyms occuring in the definitions are fully expanded (except for
+-- record types) and all type constructors and type classes are qualified
+-- with the name of the module in which they are defined. This is possible
+-- because Curry does not allow (mutually) recursive type synonyms or
+-- newtypes, which is checked in the function 'checkNonRecursiveTypes' below.
+
+ft' :: ModuleIdent -> Decl a -> [Ident]
+ft' _ (DataDecl     _ _ _ _ _) = []
+ft' _ (ExternalDataDecl _ _ _) = []
+ft' m (NewtypeDecl _ _ _ nc _) = fts m nc []
+ft' m (TypeDecl      _ _ _ ty) = fts m ty []
+ft' _ _                        = []
+
+checkNonRecursiveTypes :: [Decl a] -> KCM ()
+checkNonRecursiveTypes ds = do
+  m <- getModuleIdent
+  mapM_ checkTypeAndNewtypeDecls $ scc bt (ft' m) ds
+
+checkTypeAndNewtypeDecls :: [Decl a] -> KCM ()
+checkTypeAndNewtypeDecls [] =
+  internalError "Checks.KindCheck.checkTypeAndNewtypeDecls: empty list"
+checkTypeAndNewtypeDecls [DataDecl _ _ _ _ _] = ok
+checkTypeAndNewtypeDecls [ExternalDataDecl _ _ _] = ok
+checkTypeAndNewtypeDecls [d] | isTypeOrNewtypeDecl d = do
+  m <- getModuleIdent
+  let tc = typeConstructor d
+  when (tc `elem` ft m d) $ report $ errRecursiveTypes [tc]
+checkTypeAndNewtypeDecls (d:ds) | isTypeOrNewtypeDecl d =
+  report $ errRecursiveTypes $
+    typeConstructor d : [typeConstructor d' | d' <- ds, isTypeOrNewtypeDecl d']
+checkTypeAndNewtypeDecls _ = internalError
+  "Checks.KindCheck.checkTypeAndNewtypeDecls: no type or newtype declarations"
+
+-- The function 'checkAcyclicSuperClasses' checks that the super class
+-- hierarchy is acyclic.
+
+fc :: ModuleIdent -> Context -> [Ident]
+fc m = foldr fc' []
+  where
+    fc' (Constraint _ qcls _) = maybe id (:) (localIdent m qcls)
+
+checkAcyclicSuperClasses :: [Decl a] -> KCM ()
+checkAcyclicSuperClasses ds = do
+  m <- getModuleIdent
+  mapM_ checkClassDecl $ scc bt (\(ClassDecl _ _ cx _ _ _) -> fc m cx) ds
+
+checkClassDecl :: [Decl a] -> KCM ()
+checkClassDecl [] =
+  internalError "Checks.KindCheck.checkClassDecl: empty list"
+checkClassDecl [ClassDecl _ _ cx cls _ _] = do
+  m <- getModuleIdent
+  when (cls `elem` fc m cx) $ report $ errRecursiveClasses [cls]
+checkClassDecl (ClassDecl _ _ _ cls _ _ : ds) =
+  report $ errRecursiveClasses $ cls : [cls' | ClassDecl _ _ _ cls' _ _ <- ds]
+checkClassDecl _ =
+  internalError "Checks.KindCheck.checkClassDecl: no class declaration"
+
+-- For each declaration group, the kind checker first enters new
+-- assumptions into the type constructor environment. For a type
+-- constructor with arity n, we enter kind k_1 -> ... -> k_n -> k,
+-- where k_i are fresh kind variables and k is * for data and newtype
+-- type constructors and a fresh kind variable for type synonym type
+-- constructors. For a type class we enter kind k, where k is a fresh
+-- kind variable. We also add a type class to the class environment.
+-- Next, the kind checker checks the declarations of the group within
+-- the extended environment, and finally the kind checker instantiates
+-- all remaining free kind variables to *.
+
+-- As noted above, type synonyms are fully expanded while types are
+-- entered into the type constructor environment. Furthermore, we uses
+-- original names for classes and super classes in the class environment.
+-- Unfortunately, both of this requires either sorting type declarations
+-- properly or using the final type constructor environment for the expansion
+-- and original names. We have chosen the latter option here, which requires
+-- recursive monadic bindings which are supported using the 'mfix' method
+-- from the 'MonadFix' type class.
+
+bindKind :: ModuleIdent -> TCEnv -> ClassEnv -> TCEnv -> Decl a -> KCM TCEnv
+bindKind m tcEnv' clsEnv tcEnv (DataDecl _ tc tvs cs _) =
+  bindTypeConstructor DataType tc tvs (Just KindStar) (map mkData cs) tcEnv
+  where
+    mkData (ConstrDecl _     c  tys) = mkData' c  tys
+    mkData (ConOpDecl  _ ty1 op ty2) = mkData' op [ty1, ty2]
+    mkData (RecordDecl _     c   fs) =
+      let (labels, tys) = unzip [(l, ty) | FieldDecl _ ls ty <- fs, l <- ls]
+      in  mkRec c labels tys
+    mkData' c tys = DataConstr c tys'
+      where qtc = qualifyWith m tc
+            PredType _ ty = expandConstrType m tcEnv' clsEnv qtc tvs tys
+            tys' = arrowArgs ty
+    mkRec c ls tys =
+      RecordConstr c ls tys'
+      where qtc = qualifyWith m tc
+            PredType _ ty = expandConstrType m tcEnv' clsEnv qtc tvs tys
+            tys' = arrowArgs ty
+bindKind _ _     _       tcEnv (ExternalDataDecl _ tc tvs) =
+  bindTypeConstructor DataType tc tvs (Just KindStar) [] tcEnv
+bindKind m tcEnv' _      tcEnv (NewtypeDecl _ tc tvs nc _) =
+  bindTypeConstructor RenamingType tc tvs (Just KindStar) (mkData nc) tcEnv
+  where
+    mkData (NewConstrDecl _ c      ty) = DataConstr c [ty']
+      where ty'  = expandMonoType m tcEnv' tvs ty
+    mkData (NewRecordDecl _ c (l, ty)) = RecordConstr c [l] [ty']
+      where ty'  = expandMonoType m tcEnv' tvs ty
+bindKind m tcEnv' _      tcEnv (TypeDecl _ tc tvs ty) =
+  bindTypeConstructor aliasType tc tvs Nothing ty' tcEnv
+  where
+    aliasType tc' k = AliasType tc' k $ length tvs
+    ty' = expandMonoType m tcEnv' tvs ty
+bindKind m tcEnv' clsEnv tcEnv (ClassDecl _ _ _ cls tv ds) =
+  bindTypeClass cls (concatMap mkMethods ds) tcEnv
+  where
+    mkMethods (TypeSig _ fs qty) = map (mkMethod qty) fs
+    mkMethods _                  = []
+    mkMethod qty f = ClassMethod f (findArity f ds) $
+                       expandMethodType m tcEnv' clsEnv (qualify cls) tv qty
+    findArity _ []                                    = Nothing
+    findArity f (FunctionDecl _ _ f' eqs:_) | f == f' =
+      Just $ eqnArity $ head eqs
+    findArity f (_:ds')                               = findArity f ds'
+bindKind _ _      _      tcEnv _                          = return tcEnv
+
+bindTypeConstructor :: (QualIdent -> Kind -> a -> TypeInfo) -> Ident
+                    -> [Ident] -> Maybe Kind -> a -> TCEnv -> KCM TCEnv
+bindTypeConstructor f tc tvs k x tcEnv = do
+  m <- getModuleIdent
+  k' <- maybe freshKindVar return k
+  ks <- mapM (const freshKindVar) tvs
+  let qtc = qualifyWith m tc
+      ti = f qtc (foldr KindArrow k' ks) x
+  return $ bindTypeInfo m tc ti tcEnv
+
+bindTypeClass :: Ident -> [ClassMethod] -> TCEnv -> KCM TCEnv
+bindTypeClass cls ms tcEnv = do
+  m <- getModuleIdent
+  k <- freshKindVar
+  let qcls = qualifyWith m cls
+      ti = TypeClass qcls k ms
+  return $ bindTypeInfo m cls ti tcEnv
+
+bindFreshKind :: TCEnv -> Ident -> KCM TCEnv
+bindFreshKind tcEnv tv = do
+  k <- freshKindVar
+  return $ bindTypeVar tv k tcEnv
+
+bindTypeVars :: Ident -> [Ident] -> TCEnv -> KCM (Kind, TCEnv)
+bindTypeVars tc tvs tcEnv = do
+  m <- getModuleIdent
+  return $ foldl (\(KindArrow k1 k2, tcEnv') tv ->
+                   (k2, bindTypeVar tv k1 tcEnv'))
+                 (tcKind m (qualifyWith m tc) tcEnv, tcEnv)
+                 tvs
+
+bindTypeVar :: Ident -> Kind -> TCEnv -> TCEnv
+bindTypeVar ident k = bindTopEnv ident (TypeVar k)
+
+bindClass :: ModuleIdent -> TCEnv -> ClassEnv -> Decl a -> ClassEnv
+bindClass m tcEnv clsEnv (ClassDecl _ _ cx cls _ ds) =
+  bindClassInfo qcls (sclss, ms) clsEnv
+  where qcls = qualifyWith m cls
+        ms = map (\f -> (f, f `elem` fs)) $ concatMap methods ds
+        fs = concatMap impls ds
+        sclss = nub $ map (\(Constraint _ cls' _) -> getOrigName m cls' tcEnv) cx
+bindClass _ _ clsEnv _ = clsEnv
+
+instantiateWithDefaultKind :: TypeInfo -> TypeInfo
+instantiateWithDefaultKind (DataType tc k cs) =
+  DataType tc (defaultKind k) cs
+instantiateWithDefaultKind (RenamingType tc k nc) =
+  RenamingType tc (defaultKind k) nc
+instantiateWithDefaultKind (AliasType tc k n ty) =
+  AliasType tc (defaultKind k) n ty
+instantiateWithDefaultKind (TypeClass cls k ms) =
+  TypeClass cls (defaultKind k) ms
+instantiateWithDefaultKind (TypeVar _) =
+  internalError "Checks.KindCheck.instantiateWithDefaultKind: type variable"
+
+kcDecls :: TCEnv -> ClassEnv -> [Decl a] -> KCM (TCEnv, ClassEnv)
+kcDecls tcEnv clsEnv ds = do
+  m <- getModuleIdent
+  foldM (uncurry kcDeclGroup) (tcEnv, clsEnv) $ scc bt (ft m) ds
+
+kcDeclGroup :: TCEnv -> ClassEnv -> [Decl a] -> KCM (TCEnv, ClassEnv)
+kcDeclGroup tcEnv clsEnv ds = do
+  m <- getModuleIdent
+  (tcEnv', clsEnv') <- mfix (\ ~(tcEnv', clsEnv') ->
+    flip (,) (foldl (bindClass m tcEnv') clsEnv ds) <$>
+      foldM (bindKind m tcEnv' clsEnv') tcEnv ds)
+  mapM_ (kcDecl tcEnv') ds
+  theta <- getKindSubst
+  return (fmap (instantiateWithDefaultKind . subst theta) tcEnv', clsEnv')
+
+-- After adding new assumptions to the environment, kind inference is
+-- applied to all declarations. The type environment may be extended
+-- temporarily with bindings for type variables occurring in the left
+-- hand side of type declarations and free type variables of type
+-- signatures. While the kinds of the former are determined already by
+-- the kinds of their type constructors and type classes, respectively,
+-- fresh kind variables are added for the latter.
+
+kcDecl :: TCEnv -> Decl a -> KCM ()
+kcDecl _     (InfixDecl _ _ _ _) = ok
+kcDecl tcEnv (DataDecl _ tc tvs cs _) = do
+  (_, tcEnv') <- bindTypeVars tc tvs tcEnv
+  mapM_ (kcConstrDecl tcEnv') cs
+kcDecl _     (ExternalDataDecl _ _ _) = ok
+kcDecl tcEnv (NewtypeDecl _ tc tvs nc _) = do
+  (_, tcEnv') <- bindTypeVars tc tvs tcEnv
+  kcNewConstrDecl tcEnv' nc
+kcDecl tcEnv t@(TypeDecl _ tc tvs ty) = do
+  (k, tcEnv') <- bindTypeVars tc tvs tcEnv
+  kcType tcEnv' "type declaration" (pPrint t) k ty
+kcDecl tcEnv (TypeSig _ _ qty) = kcTypeSig tcEnv qty
+kcDecl tcEnv (FunctionDecl _ _ _ eqs) = mapM_ (kcEquation tcEnv) eqs
+kcDecl _     (ExternalDecl _ _) = ok
+kcDecl tcEnv (PatternDecl _ _ rhs) = kcRhs tcEnv rhs
+kcDecl _     (FreeDecl _ _) = ok
+kcDecl tcEnv (DefaultDecl _ tys) = do
+  tcEnv' <- foldM bindFreshKind tcEnv $ nub $ fv tys
+  mapM_ (kcValueType tcEnv' "default declaration" empty) tys
+kcDecl tcEnv (ClassDecl _ _ cx cls tv ds) = do
+  m <- getModuleIdent
+  let tcEnv' = bindTypeVar tv (clsKind m (qualifyWith m cls) tcEnv) tcEnv
+  kcContext tcEnv' cx
+  mapM_ (kcDecl tcEnv') ds
+kcDecl tcEnv (InstanceDecl p _ cx qcls inst ds) = do
+  m <- getModuleIdent
+  tcEnv' <- foldM bindFreshKind tcEnv $ fv inst
+  kcContext tcEnv' cx
+  kcType tcEnv' what doc (clsKind m qcls tcEnv) inst
+  mapM_ (kcDecl tcEnv') ds
+    where
+      what = "instance declaration"
+      doc = pPrint (InstanceDecl p WhitespaceLayout cx qcls inst [])
+
+kcConstrDecl :: TCEnv -> ConstrDecl -> KCM ()
+kcConstrDecl tcEnv d@(ConstrDecl _ _ tys) = do
+  mapM_ (kcValueType tcEnv what doc) tys
+    where
+      what = "data constructor declaration"
+      doc = pPrint d
+kcConstrDecl tcEnv d@(ConOpDecl _ ty1 _ ty2) = do
+  kcValueType tcEnv what doc ty1
+  kcValueType tcEnv what doc ty2
+    where
+      what = "data constructor declaration"
+      doc = pPrint d
+kcConstrDecl tcEnv (RecordDecl _ _ fs) = do
+  mapM_ (kcFieldDecl tcEnv) fs
+
+kcFieldDecl :: TCEnv -> FieldDecl -> KCM ()
+kcFieldDecl tcEnv d@(FieldDecl _ _ ty) =
+  kcValueType tcEnv "field declaration" (pPrint d) ty
+
+kcNewConstrDecl :: TCEnv -> NewConstrDecl -> KCM ()
+kcNewConstrDecl tcEnv d@(NewConstrDecl _ _ ty) =
+  kcValueType tcEnv "newtype constructor declaration" (pPrint d) ty
+kcNewConstrDecl tcEnv (NewRecordDecl p _ (l, ty)) =
+  kcFieldDecl tcEnv (FieldDecl p [l] ty)
+
+kcEquation :: TCEnv -> Equation a -> KCM ()
+kcEquation tcEnv (Equation _ _ rhs) = kcRhs tcEnv rhs
+
+kcRhs :: TCEnv -> Rhs a -> KCM ()
+kcRhs tcEnv (SimpleRhs _ _ e ds) = do
+  kcExpr tcEnv e
+  mapM_ (kcDecl tcEnv) ds
+kcRhs tcEnv (GuardedRhs _ _ es ds) = do
+  mapM_ (kcCondExpr tcEnv) es
+  mapM_ (kcDecl tcEnv) ds
+
+kcCondExpr :: TCEnv -> CondExpr a -> KCM ()
+kcCondExpr tcEnv (CondExpr _ g e) = kcExpr tcEnv g >> kcExpr tcEnv e
+
+kcExpr :: TCEnv -> Expression a -> KCM ()
+kcExpr _     (Literal _ _ _) = ok
+kcExpr _     (Variable _ _ _) = ok
+kcExpr _     (Constructor _ _ _) = ok
+kcExpr tcEnv (Paren _ e) = kcExpr tcEnv e
+kcExpr tcEnv (Typed _ e qty) = do
+  kcExpr tcEnv e
+  kcTypeSig tcEnv qty
+kcExpr tcEnv (Record _ _ _ fs) = mapM_ (kcField tcEnv) fs
+kcExpr tcEnv (RecordUpdate _ e fs) = do
+  kcExpr tcEnv e
+  mapM_ (kcField tcEnv) fs
+kcExpr tcEnv (Tuple _ es) = mapM_ (kcExpr tcEnv) es
+kcExpr tcEnv (List _ _ es) = mapM_ (kcExpr tcEnv) es
+kcExpr tcEnv (ListCompr _ e stms) = do
+  kcExpr tcEnv e
+  mapM_ (kcStmt tcEnv) stms
+kcExpr tcEnv (EnumFrom _ e) = kcExpr tcEnv e
+kcExpr tcEnv (EnumFromThen _ e1 e2) = do
+  kcExpr tcEnv e1
+  kcExpr tcEnv e2
+kcExpr tcEnv (EnumFromTo _ e1 e2) = do
+  kcExpr tcEnv e1
+  kcExpr tcEnv e2
+kcExpr tcEnv (EnumFromThenTo _ e1 e2 e3) = do
+  kcExpr tcEnv e1
+  kcExpr tcEnv e2
+  kcExpr tcEnv e3
+kcExpr tcEnv (UnaryMinus _ e) = kcExpr tcEnv e
+kcExpr tcEnv (Apply _ e1 e2) = do
+  kcExpr tcEnv e1
+  kcExpr tcEnv e2
+kcExpr tcEnv (InfixApply _ e1 _ e2) = do
+  kcExpr tcEnv e1
+  kcExpr tcEnv e2
+kcExpr tcEnv (LeftSection _ e _) = kcExpr tcEnv e
+kcExpr tcEnv (RightSection _ _ e) = kcExpr tcEnv e
+kcExpr tcEnv (Lambda _ _ e) = kcExpr tcEnv e
+kcExpr tcEnv (Let _ _ ds e) = do
+  mapM_ (kcDecl tcEnv) ds
+  kcExpr tcEnv e
+kcExpr tcEnv (Do _ _ stms e) = do
+  mapM_ (kcStmt tcEnv) stms
+  kcExpr tcEnv e
+kcExpr tcEnv (IfThenElse _ e1 e2 e3) = do
+  kcExpr tcEnv e1
+  kcExpr tcEnv e2
+  kcExpr tcEnv e3
+kcExpr tcEnv (Case _ _ _ e alts) = do
+  kcExpr tcEnv e
+  mapM_ (kcAlt tcEnv) alts
+
+kcStmt :: TCEnv -> Statement a -> KCM ()
+kcStmt tcEnv (StmtExpr _ e) = kcExpr tcEnv e
+kcStmt tcEnv (StmtDecl _ _ ds) = mapM_ (kcDecl tcEnv) ds
+kcStmt tcEnv (StmtBind _ _ e) = kcExpr tcEnv e
+
+kcAlt :: TCEnv -> Alt a -> KCM ()
+kcAlt tcEnv (Alt _ _ rhs) = kcRhs tcEnv rhs
+
+kcField :: TCEnv -> Field (Expression a) -> KCM ()
+kcField tcEnv (Field _ _ e) = kcExpr tcEnv e
+
+kcContext :: TCEnv -> Context -> KCM ()
+kcContext tcEnv = mapM_ (kcConstraint tcEnv)
+
+kcConstraint :: TCEnv -> Constraint -> KCM ()
+kcConstraint tcEnv sc@(Constraint _ qcls ty) = do
+  m <- getModuleIdent
+  kcType tcEnv "class constraint" doc (clsKind m qcls tcEnv) ty
+  where
+    doc = pPrint sc
+
+kcTypeSig :: TCEnv -> QualTypeExpr -> KCM ()
+kcTypeSig tcEnv (QualTypeExpr _ cx ty) = do
+  tcEnv' <- foldM bindFreshKind tcEnv free
+  kcContext tcEnv' cx
+  kcValueType tcEnv' "type signature" doc ty
+  where
+    free = filter (null . flip lookupTypeInfo tcEnv) $ nub $ fv ty
+    doc = pPrintPrec 0 ty
+
+kcValueType :: TCEnv -> String -> Doc -> TypeExpr -> KCM ()
+kcValueType tcEnv what doc = kcType tcEnv what doc KindStar
+
+kcType :: TCEnv -> String -> Doc -> Kind -> TypeExpr -> KCM ()
+kcType tcEnv what doc k ty = do
+  k' <- kcTypeExpr tcEnv "type expression" doc' 0 ty
+  unify ty what (doc $-$ text "Type:" <+> doc') k k'
+  where
+    doc' = pPrintPrec 0 ty
+
+kcTypeExpr :: TCEnv -> String -> Doc -> Int -> TypeExpr -> KCM Kind
+kcTypeExpr tcEnv _ _ n (ConstructorType p tc) = do
+  m <- getModuleIdent
+  case qualLookupTypeInfo tc tcEnv of
+    [AliasType _ _ n' _] -> case n >= n' of
+      True -> return $ tcKind m tc tcEnv
+      False -> do
+        report $ errPartialAlias p tc n' n
+        freshKindVar
+    _ -> return $ tcKind m tc tcEnv
+kcTypeExpr tcEnv what doc n (ApplyType p ty1 ty2) = do
+  (alpha, beta) <- kcTypeExpr tcEnv what doc (n + 1) ty1 >>=
+    kcArrow p what (doc $-$ text "Type:" <+> pPrintPrec 0 ty1)
+  kcTypeExpr tcEnv what doc 0 ty2 >>=
+    unify p what (doc $-$ text "Type:" <+> pPrintPrec 0 ty2) alpha
+  return beta
+kcTypeExpr tcEnv _ _ _      (VariableType _ tv) = return (varKind tv tcEnv)
+kcTypeExpr tcEnv what doc _ (TupleType _ tys) = do
+  mapM_ (kcValueType tcEnv what doc) tys
+  return KindStar
+kcTypeExpr tcEnv what doc _ (ListType _ ty) = do
+  kcValueType tcEnv what doc ty
+  return KindStar
+kcTypeExpr tcEnv what doc _ (ArrowType _ ty1 ty2) = do
+  kcValueType tcEnv what doc ty1
+  kcValueType tcEnv what doc ty2
+  return KindStar
+kcTypeExpr tcEnv what doc n (ParenType _ ty) = kcTypeExpr tcEnv what doc n ty
+kcTypeExpr tcEnv what doc n (ForallType _ vs ty) = do
+  tcEnv' <- foldM bindFreshKind tcEnv vs
+  kcTypeExpr tcEnv' what doc n ty
+
+kcArrow :: HasSpanInfo p => p -> String -> Doc -> Kind -> KCM (Kind, Kind)
+kcArrow p what doc k = do
+  theta <- getKindSubst
+  case subst theta k of
+    KindStar -> do
+      report $ errNonArrowKind p what doc KindStar
+      (,) <$> freshKindVar <*> freshKindVar
+    KindVariable kv -> do
+      alpha <- freshKindVar
+      beta <- freshKindVar
+      modifyKindSubst $ bindVar kv $ KindArrow alpha beta
+      return (alpha, beta)
+    KindArrow k1 k2 -> return (k1, k2)
+
+-- ---------------------------------------------------------------------------
+-- Unification
+-- ---------------------------------------------------------------------------
+
+-- The unification uses Robinson's algorithm.
+unify :: HasSpanInfo p => p -> String -> Doc -> Kind -> Kind -> KCM ()
+unify p what doc k1 k2 = do
+  theta <- getKindSubst
+  let k1' = subst theta k1
+  let k2' = subst theta k2
+  case unifyKinds k1' k2' of
+    Nothing -> report $ errKindMismatch p what doc k1' k2'
+    Just sigma -> modifyKindSubst (compose sigma)
+
+unifyKinds :: Kind -> Kind -> Maybe KindSubst
+unifyKinds KindStar KindStar = Just idSubst
+unifyKinds (KindVariable kv1) (KindVariable kv2)
+  | kv1 == kv2 = Just idSubst
+  | otherwise  = Just (singleSubst kv1 (KindVariable kv2))
+unifyKinds (KindVariable kv) k
+  | kv `elem` kindVars k = Nothing
+  | otherwise            = Just (singleSubst kv k)
+unifyKinds k (KindVariable kv)
+  | kv `elem` kindVars k = Nothing
+  | otherwise            = Just (singleSubst kv k)
+unifyKinds (KindArrow k11 k12) (KindArrow k21 k22) = do
+  theta <- unifyKinds k11 k21
+  theta' <- unifyKinds (subst theta k12) (subst theta k22)
+  Just (compose theta' theta)
+unifyKinds _ _ = Nothing
+
+-- ---------------------------------------------------------------------------
+-- Fresh variables
+-- ---------------------------------------------------------------------------
+
+fresh :: (Int -> a) -> KCM a
+fresh f = f <$> getNextId
+
+freshKindVar :: KCM Kind
+freshKindVar = fresh KindVariable
+
+-- ---------------------------------------------------------------------------
+-- Auxiliary definitions
+-- ---------------------------------------------------------------------------
+
+typeConstructor :: Decl a -> Ident
+typeConstructor (DataDecl     _ tc _ _ _) = tc
+typeConstructor (ExternalDataDecl _ tc _) = tc
+typeConstructor (NewtypeDecl  _ tc _ _ _) = tc
+typeConstructor (TypeDecl     _ tc _ _  ) = tc
+typeConstructor _                        =
+  internalError "Checks.KindCheck.typeConstructor: no type declaration"
+
+isTypeOrNewtypeDecl :: Decl a -> Bool
+isTypeOrNewtypeDecl (NewtypeDecl _ _ _ _ _) = True
+isTypeOrNewtypeDecl (TypeDecl      _ _ _ _) = True
+isTypeOrNewtypeDecl _                       = False
+
+-- ---------------------------------------------------------------------------
+-- Error messages
+-- ---------------------------------------------------------------------------
+
+errRecursiveTypes :: [Ident] -> Message
+errRecursiveTypes []       = internalError
+  "KindCheck.errRecursiveTypes: empty list"
+errRecursiveTypes [tc]     = spanInfoMessage tc $ hsep $ map text
+  ["Recursive synonym or renaming type", idName tc]
+errRecursiveTypes (tc:tcs) = spanInfoMessage tc $
+  text "Mutually recursive synonym and/or renaming types" <+>
+    text (idName tc) <> types empty tcs
+  where
+    types _   []         = empty
+    types del [tc']      = del <> space <> text "and" <+> typePos tc'
+    types _   (tc':tcs') = comma <+> typePos tc' <> types comma tcs'
+    typePos tc' =
+      text (idName tc') <+> parens (text $ showLine $ getPosition tc')
+
+errRecursiveClasses :: [Ident] -> Message
+errRecursiveClasses []         = internalError
+  "KindCheck.errRecursiveClasses: empty list"
+errRecursiveClasses [cls]      = spanInfoMessage cls $ hsep $ map text
+  ["Recursive type class", idName cls]
+errRecursiveClasses (cls:clss) = spanInfoMessage cls $
+  text "Mutually recursive type classes" <+> text (idName cls) <>
+    classes empty clss
+  where
+    classes _   []           = empty
+    classes del [cls']       = del <> space <> text "and" <+> classPos cls'
+    classes _   (cls':clss') = comma <+> classPos cls' <> classes comma clss'
+    classPos cls' =
+      text (idName cls') <+> parens (text $ showLine $ getPosition cls')
+
+errNonArrowKind :: HasSpanInfo p => p -> String -> Doc -> Kind -> Message
+errNonArrowKind p what doc k = spanInfoMessage p $ vcat
+  [ text "Kind error in" <+> text what, doc
+  , text "Kind:" <+> ppKind k
+  , text "Cannot be applied"
+  ]
+
+errPartialAlias :: HasSpanInfo p => p -> QualIdent -> Int -> Int -> Message
+errPartialAlias p tc arity argc = spanInfoMessage p $ hsep
+  [ text "Type synonym", ppQIdent tc
+  , text "requires at least"
+  , int arity, text (plural arity "argument") <> comma
+  , text "but is applied to only", int argc
+  ]
+  where
+    plural n x = if n == 1 then x else x ++ "s"
+
+errKindMismatch :: HasSpanInfo p => p -> String -> Doc -> Kind -> Kind -> Message
+errKindMismatch p what doc k1 k2 = spanInfoMessage p $ vcat
+  [ text "Kind error in"  <+> text what, doc
+  , text "Inferred kind:" <+> ppKind k2
+  , text "Expected kind:" <+> ppKind k1
+  ]
diff --git a/src/Checks/PrecCheck.hs b/src/Checks/PrecCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/PrecCheck.hs
@@ -0,0 +1,515 @@
+{- |
+    Module      :  $Header$
+    Description :  Checks precedences of infix operators
+    Copyright   :  (c) 2001 - 2004 Wolfgang Lux
+                                   Martin Engelke
+                                   Björn Peemöller
+                       2015        Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   The parser does not know the relative precedences of infix operators
+   and therefore parses them as if they all associate to the right and
+   have the same precedence. After performing the definition checks,
+   the compiler is going to process the infix applications in the module
+   and rearrange infix applications according to the relative precedences
+   of the operators involved.
+-}
+{-# LANGUAGE CPP #-}
+module Checks.PrecCheck (precCheck) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative      ((<$>), (<*>))
+#endif
+import           Control.Monad            (unless, when)
+import qualified Control.Monad.State as S (State, runState, gets, modify)
+import           Data.List                (partition)
+
+import Curry.Base.Ident
+import Curry.Base.Position
+import Curry.Base.SpanInfo
+import Curry.Base.Span
+import Curry.Base.Pretty
+import Curry.Syntax
+
+import Base.Expr
+import Base.Messages (Message, spanInfoMessage, internalError)
+import Base.Utils    (findMultiples)
+
+import Env.OpPrec (OpPrecEnv, OpPrec (..), PrecInfo (..), defaultP, bindP
+  , mkPrec, qualLookupP)
+
+precCheck :: ModuleIdent -> OpPrecEnv -> [Decl a] -> ([Decl a], OpPrecEnv, [Message])
+precCheck m pEnv decls = runPCM (checkDecls decls) initState
+ where initState = PCState m pEnv []
+
+data PCState = PCState
+  { moduleIdent :: ModuleIdent
+  , precEnv     :: OpPrecEnv
+  , errors      :: [Message]
+  }
+
+type PCM = S.State PCState -- the Prec Check Monad
+
+runPCM :: PCM a -> PCState -> (a, OpPrecEnv, [Message])
+runPCM kcm s = let (a, s') = S.runState kcm s
+               in  (a, precEnv s', reverse $ errors s')
+
+getModuleIdent :: PCM ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+getPrecEnv :: PCM OpPrecEnv
+getPrecEnv = S.gets precEnv
+
+modifyPrecEnv :: (OpPrecEnv -> OpPrecEnv) -> PCM ()
+modifyPrecEnv f = S.modify $ \ s -> s { precEnv = f $ precEnv s }
+
+withLocalPrecEnv :: PCM a -> PCM a
+withLocalPrecEnv act = do
+  oldEnv <- getPrecEnv
+  res <- act
+  modifyPrecEnv $ const oldEnv
+  return res
+
+report :: Message -> PCM ()
+report err = S.modify (\ s -> s { errors = err : errors s })
+
+-- For each declaration group, including the module-level, the compiler
+-- first checks that its fixity declarations contain no duplicates and
+-- that there is a corresponding value or constructor declaration in that
+-- group. The fixity declarations are then used for extending the
+-- imported precedence environment.
+
+bindPrecs :: [Decl a] -> PCM ()
+bindPrecs ds0 = case findMultiples opFixDecls of
+  [] -> case filter (`notElem` bvs) opFixDecls of
+    []  -> do
+      m <- getModuleIdent
+      modifyPrecEnv $ \env -> foldr (bindPrec m) env fixDs
+    ops -> mapM_ (report . errUndefinedOperator) ops
+  opss -> mapM_ (report . errMultiplePrecedence) opss
+  where
+    (fixDs, nonFixDs) = partition isInfixDecl ds0
+    innerDs           = [ d | ClassDecl _ _ _ _ _ ds <- ds0, d <- ds ]
+    opFixDecls        = [ op | InfixDecl _ _ _ ops <- fixDs, op <- ops ]
+    -- Unrenaming is necessary for inner class declarations, because operators
+    -- within class declarations have been renamed during syntax checking.
+    bvs               = concatMap boundValues nonFixDs ++
+                          map unRenameIdent (concatMap boundValues innerDs)
+
+bindPrec :: ModuleIdent -> Decl a -> OpPrecEnv -> OpPrecEnv
+bindPrec m (InfixDecl _ fix mprec ops) pEnv
+  | p == defaultP = pEnv
+  | otherwise     = foldr (flip (bindP m) p) pEnv ops
+  where p = OpPrec fix (mkPrec mprec)
+bindPrec _ _                           pEnv = pEnv
+
+boundValues :: Decl a -> [Ident]
+boundValues (DataDecl     _ _ _ cs _) = [ v | c <- cs
+                                            , v <- constrId c : recordLabels c]
+boundValues (NewtypeDecl  _ _ _ nc _) = nconstrId nc : nrecordLabels nc
+boundValues (TypeSig          _ fs _) = fs
+boundValues (FunctionDecl    _ _ f _) = [f]
+boundValues (ExternalDecl       _ vs) = bv vs
+boundValues (PatternDecl       _ t _) = bv t
+boundValues (FreeDecl           _ vs) = bv vs
+boundValues _                         = []
+
+-- With the help of the precedence environment, the compiler checks all
+-- infix applications and sections in the program. This pass will modify
+-- the parse tree such that for a nested infix application the operator
+-- with the lowest precedence becomes the root and that two adjacent
+-- operators with the same precedence will not have conflicting
+-- associativities. Note that the top-level precedence environment has to
+-- be returned because it is needed for constructing the module's
+-- interface.
+
+checkDecls :: [Decl a] -> PCM [Decl a]
+checkDecls decls = bindPrecs decls >> mapM checkDecl decls
+
+checkDecl :: Decl a -> PCM (Decl a)
+checkDecl (FunctionDecl p a f           eqs) =
+  FunctionDecl p a f <$> mapM checkEquation eqs
+checkDecl (PatternDecl  p t             rhs) =
+  PatternDecl p <$> checkPattern t <*> checkRhs rhs
+checkDecl (ClassDecl p li cx cls    tv   ds) =
+  ClassDecl p li cx cls tv <$> mapM checkDecl ds
+checkDecl (InstanceDecl p li cx qcls   inst ds) =
+  InstanceDecl p li cx qcls inst <$> mapM checkDecl ds
+checkDecl d                                  = return d
+
+checkEquation :: Equation a -> PCM (Equation a)
+checkEquation (Equation p lhs rhs) =
+  Equation p <$> checkLhs lhs <*> checkRhs rhs
+
+checkLhs :: Lhs a -> PCM (Lhs a)
+checkLhs (FunLhs spi     f ts) = FunLhs spi f <$> mapM checkPattern ts
+checkLhs (OpLhs  spi t1 op t2) =
+  flip (OpLhs spi) op <$> (checkPattern t1 >>= checkOpL op)
+                      <*> (checkPattern t2 >>= checkOpR op)
+checkLhs (ApLhs  spi   lhs ts) =
+  ApLhs spi <$> checkLhs lhs <*> mapM checkPattern ts
+
+checkPattern :: Pattern a -> PCM (Pattern a)
+checkPattern l@(LiteralPattern        _ _ _) = return l
+checkPattern n@(NegativePattern       _ _ _) = return n
+checkPattern v@(VariablePattern       _ _ _) = return v
+checkPattern (ConstructorPattern spi a c ts) =
+  ConstructorPattern spi a c <$> mapM checkPattern ts
+checkPattern (InfixPattern   _ a t1 op t2) = do
+  t1' <- checkPattern t1
+  t2' <- checkPattern t2
+  fixPrecT mkInfixPattern t1' op t2'
+  where mkInfixPattern t1'' op'' t2'' =
+          InfixPattern (t1'' @+@ t2'') a t1'' op'' t2''
+checkPattern (ParenPattern              spi t) =
+  ParenPattern spi <$> checkPattern t
+checkPattern (TuplePattern             spi ts) =
+  TuplePattern spi <$> mapM checkPattern ts
+checkPattern (ListPattern            spi a ts) =
+  ListPattern spi a <$> mapM checkPattern ts
+checkPattern (AsPattern               spi v t) =
+  AsPattern spi v <$> checkPattern t
+checkPattern (LazyPattern               spi t) =
+  LazyPattern spi <$> checkPattern t
+checkPattern (FunctionPattern      spi a f ts) =
+  FunctionPattern spi a f <$> mapM checkPattern ts
+checkPattern (InfixFuncPattern _ a t1 op t2) = do
+  t1' <- checkPattern t1
+  t2' <- checkPattern t2
+  fixPrecT mkInfixFuncPattern t1' op t2'
+  where mkInfixFuncPattern t1'' op'' t2'' =
+          InfixFuncPattern (t1'' @+@ t2'') a t1'' op'' t2''
+checkPattern (RecordPattern       spi a c fs) =
+  RecordPattern spi a c <$> mapM (checkField checkPattern) fs
+
+checkRhs :: Rhs a -> PCM (Rhs a)
+checkRhs (SimpleRhs spi li e ds) = withLocalPrecEnv $
+  flip (SimpleRhs spi li) <$> checkDecls ds <*> checkExpr e
+checkRhs (GuardedRhs spi li es ds) = withLocalPrecEnv $
+  flip (GuardedRhs spi li) <$> checkDecls ds <*> mapM checkCondExpr es
+
+checkCondExpr :: CondExpr a -> PCM (CondExpr a)
+checkCondExpr (CondExpr p g e) = CondExpr p <$> checkExpr g <*> checkExpr e
+
+checkExpr :: Expression a -> PCM (Expression a)
+checkExpr l@(Literal          _ _ _) = return l
+checkExpr v@(Variable         _ _ _) = return v
+checkExpr c@(Constructor      _ _ _) = return c
+checkExpr (Paren              spi e) = Paren spi <$> checkExpr e
+checkExpr (Typed           spi e ty) = flip (Typed spi) ty <$> checkExpr e
+checkExpr (Record        spi a c fs) = Record spi a c <$> mapM (checkField checkExpr) fs
+checkExpr (RecordUpdate    spi e fs) = RecordUpdate spi <$> checkExpr e
+                                                       <*> mapM (checkField checkExpr) fs
+checkExpr (Tuple            spi es) = Tuple spi <$> mapM checkExpr es
+checkExpr (List           spi a es) = List spi a <$> mapM checkExpr es
+checkExpr (ListCompr      spi e qs) = withLocalPrecEnv $
+  flip (ListCompr spi) <$> mapM checkStmt qs <*> checkExpr e
+checkExpr (EnumFrom              spi e) = EnumFrom spi <$> checkExpr e
+checkExpr (EnumFromThen      spi e1 e2) =
+  EnumFromThen spi <$> checkExpr e1 <*> checkExpr e2
+checkExpr (EnumFromTo        spi e1 e2) =
+  EnumFromTo spi <$> checkExpr e1 <*> checkExpr e2
+checkExpr (EnumFromThenTo spi e1 e2 e3) =
+  EnumFromThenTo spi <$> checkExpr e1 <*> checkExpr e2 <*> checkExpr e3
+checkExpr (UnaryMinus            spi e) = UnaryMinus spi <$> checkExpr e
+checkExpr (Apply spi e1 e2) =
+  Apply spi <$> checkExpr e1 <*> checkExpr e2
+checkExpr (InfixApply spi e1 op e2) = do
+  e1' <- checkExpr e1
+  e2' <- checkExpr e2
+  fixPrec spi e1' op e2'
+checkExpr (LeftSection    spi   e op) = checkExpr e >>= checkLSection spi op
+checkExpr (RightSection   spi   op e) = checkExpr e >>= checkRSection spi op
+checkExpr (Lambda         spi   ts e) =
+  Lambda spi <$> mapM checkPattern ts <*> checkExpr e
+checkExpr (Let           spi li ds e) = withLocalPrecEnv $
+  Let spi li <$> checkDecls ds <*> checkExpr e
+checkExpr (Do           spi li sts e) = withLocalPrecEnv $
+  Do spi li <$>  mapM checkStmt sts <*> checkExpr e
+checkExpr (IfThenElse   spi e1 e2 e3) =
+  IfThenElse spi <$> checkExpr e1 <*> checkExpr e2 <*> checkExpr e3
+checkExpr (Case     spi li ct e alts) =
+  Case spi li ct <$> checkExpr e <*> mapM checkAlt alts
+
+checkStmt :: Statement a -> PCM (Statement a)
+checkStmt (StmtExpr spi     e) =
+  StmtExpr spi    <$> checkExpr e
+checkStmt (StmtDecl spi li ds) =
+  StmtDecl spi li <$> checkDecls ds
+checkStmt (StmtBind spi   t e) =
+  StmtBind spi    <$> checkPattern t <*> checkExpr e
+
+checkAlt :: Alt a -> PCM (Alt a)
+checkAlt (Alt p t rhs) = Alt p <$> checkPattern t <*> checkRhs rhs
+
+checkField :: (a -> PCM a) -> Field a -> PCM (Field a)
+checkField check (Field p l x) = Field p l <$> check x
+
+-- The functions 'fixPrec', 'fixUPrec', and 'fixRPrec' check the relative
+-- precedences of adjacent infix operators in nested infix applications
+-- and unary negations. The expressions will be reordered such that the
+-- infix operator with the lowest precedence becomes the root of the
+-- expression. The functions rely on the fact that the parser constructs
+-- infix applications in a right-associative fashion, i.e., the left argument
+-- of an infix application will never be an infix application. In addition,
+-- a unary negation will never have an infix application as its argument.
+
+-- The function 'fixPrec' checks whether the left argument of an
+-- infix application is a unary negation and eventually reorders the
+-- expression if the precedence of the infix operator is higher than that
+-- of the negation. This will be done with the help of the function
+-- 'fixUPrec'. In any case, the function 'fixRPrec' is used for fixing the
+-- precedence of the infix operator and that of its right argument.
+-- Note that both arguments already have been checked before 'fixPrec'
+-- is called.
+
+fixPrec :: SpanInfo -> Expression a -> InfixOp a -> Expression a -> PCM (Expression a)
+fixPrec spi (UnaryMinus spi' e1) op e2 = do
+  OpPrec fix pr <- getOpPrec op
+  if pr < 6 || pr == 6 && fix == InfixL
+    then fixRPrec spi (UnaryMinus spi' e1) op e2
+    else if pr > 6
+      then fixUPrec spi' e1 op e2
+      else do
+        report $ errAmbiguousParse "unary" (qualify minusId) (opName op)
+        return $ InfixApply spi (UnaryMinus spi' e1) op e2
+fixPrec spi e1 op e2 = fixRPrec spi e1 op e2
+
+fixUPrec :: SpanInfo -> Expression a -> InfixOp a -> Expression a
+         -> PCM (Expression a)
+fixUPrec spi e1 op e2@(UnaryMinus spi' _) = do
+  report $ errAmbiguousParse "operator" (opName op) (qualify minusId)
+  return $ UnaryMinus spi' (InfixApply spi e1 op e2)
+fixUPrec spi e1 op1 e'@(InfixApply spi' e2 op2 e3) = do
+  OpPrec fix2 pr2 <- getOpPrec op2
+  if pr2 < 6 || pr2 == 6 && fix2 == InfixL
+    then do
+      left <- fixUPrec spi e1 op1 e2
+      return $ InfixApply (left @+@ e3) left op2 e3
+    else if pr2 > 6
+      then do
+        op <- fixRPrec spi e1 op1 $ InfixApply spi' e2 op2 e3
+        return $ updateEndPos $ UnaryMinus spi' op
+      else do
+        report $ errAmbiguousParse "unary" (qualify minusId) (opName op2)
+        let left = updateEndPos (UnaryMinus spi' e1)
+        return $ InfixApply (left @+@ e') left op1 e'
+fixUPrec spi e1 op e2 = return $ updateEndPos $ UnaryMinus spi
+  (InfixApply (e1 @+@ e2) e1 op e2)
+
+fixRPrec :: SpanInfo -> Expression a -> InfixOp a -> Expression a
+         -> PCM (Expression a)
+fixRPrec spi e1 op (UnaryMinus spi' e2) = do
+  OpPrec _ pr <- getOpPrec op
+  unless (pr < 6) $ report $ errAmbiguousParse "operator" (opName op) (qualify minusId)
+  return $ InfixApply spi e1 op $ UnaryMinus spi' e2
+fixRPrec spi e1 op1 (InfixApply spi' e2 op2 e3) = do
+  OpPrec fix1 pr1 <- getOpPrec op1
+  OpPrec fix2 pr2 <- getOpPrec op2
+  if pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR
+     then return $ InfixApply spi e1 op1 $ InfixApply spi' e2 op2 e3
+     else if pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL
+       then do
+          left <- fixPrec (e1 @+@ e2) e1 op1 e2
+          return $ InfixApply (left @+@ e3) left op2 e3
+       else do
+         report $ errAmbiguousParse "operator" (opName op1) (opName op2)
+         return $ InfixApply spi e1 op1 $ InfixApply spi' e2 op2 e3
+fixRPrec spi e1 op e2 = return $ InfixApply spi e1 op e2
+
+-- The functions 'checkLSection' and 'checkRSection' are used for handling
+-- the precedences inside left and right sections.
+-- These functions only need to check that an infix operator occurring in
+-- the section has either a higher precedence than the section operator
+-- or both operators have the same precedence and are both left
+-- associative for a left section and right associative for a right
+-- section, respectively.
+
+checkLSection :: SpanInfo -> InfixOp a -> Expression a -> PCM (Expression a)
+checkLSection spi op e@(UnaryMinus _ _) = do
+  OpPrec fix pr <- getOpPrec op
+  unless (pr < 6 || pr == 6 && fix == InfixL) $
+    report $ errAmbiguousParse "unary" (qualify minusId) (opName op)
+  return $ LeftSection spi e op
+checkLSection spi op1 e@(InfixApply _ _ op2 _) = do
+  OpPrec fix1 pr1 <- getOpPrec op1
+  OpPrec fix2 pr2 <- getOpPrec op2
+  unless (pr1 < pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL) $
+    report $ errAmbiguousParse "operator" (opName op1) (opName op2)
+  return $ LeftSection spi e op1
+checkLSection spi op e = return $ LeftSection spi e op
+
+checkRSection :: SpanInfo -> InfixOp a -> Expression a -> PCM (Expression a)
+checkRSection spi op e@(UnaryMinus _ _) = do
+  OpPrec _ pr <- getOpPrec op
+  unless (pr < 6) $ report $ errAmbiguousParse "unary" (qualify minusId) (opName op)
+  return $ RightSection spi op e
+checkRSection spi op1 e@(InfixApply _ _ op2 _) = do
+  OpPrec fix1 pr1 <- getOpPrec op1
+  OpPrec fix2 pr2 <- getOpPrec op2
+  unless (pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR) $
+    report $ errAmbiguousParse "operator" (opName op1) (opName op2)
+  return $ RightSection spi op1 e
+checkRSection spi op e = return $ RightSection spi op e
+
+-- The functions 'fixPrecT' and 'fixRPrecT' check the relative precedences
+-- of adjacent infix operators in patterns. The patterns will be reordered
+-- such that the infix operator with the lowest precedence becomes the root
+-- of the term. The functions rely on the fact that the parser constructs
+-- infix patterns in a right-associative fashion, i.e., the left argument
+-- of an infix pattern will never be an infix pattern. The functions also
+-- check whether the left and right arguments of an infix pattern are negative
+-- literals. In this case, the negation must bind more tightly than the
+-- operator for the pattern to be accepted.
+
+fixPrecT :: (Pattern a -> QualIdent -> Pattern a -> Pattern a)
+         -> Pattern a -> QualIdent -> Pattern a -> PCM (Pattern a)
+fixPrecT infixpatt t1@(NegativePattern _ _ _) op t2 = do
+  OpPrec fix pr <- prec op <$> getPrecEnv
+  unless (pr < 6 || pr == 6 && fix == InfixL) $
+    report $ errInvalidParse "unary operator" minusId op
+  fixRPrecT infixpatt t1 op t2
+fixPrecT infixpatt t1 op t2 = fixRPrecT infixpatt t1 op t2
+
+fixRPrecT :: (Pattern a -> QualIdent -> Pattern a -> Pattern a)
+          -> Pattern a -> QualIdent -> Pattern a -> PCM (Pattern a)
+fixRPrecT infixpatt t1 op t2@(NegativePattern _ _ _) = do
+  OpPrec _ pr <- prec op <$> getPrecEnv
+  unless (pr < 6) $ report $ errInvalidParse "unary operator" minusId op
+  return $ infixpatt t1 op t2
+fixRPrecT infixpatt t1 op1 (InfixPattern spi a t2 op2 t3) = do
+  OpPrec fix1 pr1 <- prec op1 <$> getPrecEnv
+  OpPrec fix2 pr2 <- prec op2 <$> getPrecEnv
+  if pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR
+    then return $ infixpatt t1 op1 (InfixPattern spi a t2 op2 t3)
+    else if pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL
+      then do
+        left <- fixPrecT infixpatt t1 op1 t2
+        return $ InfixPattern (left @+@ t3) a left op2 t3
+      else do
+        report $ errAmbiguousParse "operator" op1 op2
+        return $ infixpatt t1 op1 (InfixPattern spi a t2 op2 t3)
+fixRPrecT infixpatt t1 op1 (InfixFuncPattern spi a t2 op2 t3) = do
+  OpPrec fix1 pr1 <- prec op1 <$> getPrecEnv
+  OpPrec fix2 pr2 <- prec op2 <$> getPrecEnv
+  if pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR
+    then return $ infixpatt t1 op1 (InfixFuncPattern spi a t2 op2 t3)
+    else if pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL
+      then do
+        left <- fixPrecT infixpatt t1 op1 t2
+        return $ InfixFuncPattern (left @+@ t3) a left op2 t3
+      else do
+        report $ errAmbiguousParse "operator" op1 op2
+        return $ infixpatt t1 op1 (InfixFuncPattern spi a t2 op2 t3)
+fixRPrecT infixpatt t1 op t2 = return $ infixpatt t1 op t2
+
+{-fixPrecT :: Position -> OpPrecEnv -> Pattern -> QualIdent -> Pattern
+         -> Pattern
+fixPrecT p pEnv t1@(NegativePattern uop l) op t2
+  | pr < 6 || pr == 6 && fix == InfixL = fixRPrecT p pEnv t1 op t2
+  | otherwise = errorAt p $ errInvalidParse "unary" uop op
+  where OpPrec fix pr = prec op pEnv
+fixPrecT p pEnv t1 op t2 = fixRPrecT p pEnv t1 op t2-}
+
+{-fixRPrecT :: Position -> OpPrecEnv -> Pattern -> QualIdent -> Pattern
+          -> Pattern
+fixRPrecT p pEnv t1 op t2@(NegativePattern uop l)
+  | pr < 6 = InfixPattern t1 op t2
+  | otherwise = errorAt p $ errInvalidParse "unary" uop op
+  where OpPrec _ pr = prec op pEnv
+fixRPrecT p pEnv t1 op1 (InfixPattern t2 op2 t3)
+  | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR =
+      InfixPattern t1 op1 (InfixPattern t2 op2 t3)
+  | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL =
+      InfixPattern (fixPrecT p pEnv t1 op1 t2) op2 t3
+  | otherwise = errorAt p $ errAmbiguousParse "operator" op1 op2
+  where OpPrec fix1 pr1 = prec op1 pEnv
+        OpPrec fix2 pr2 = prec op2 pEnv
+fixRPrecT _ _ t1 op t2 = InfixPattern t1 op t2-}
+
+-- The functions 'checkOpL' and 'checkOpR' check the left and right arguments
+-- of an operator declaration. If they are infix patterns they must bind
+-- more tightly than the operator, otherwise the left-hand side of the
+-- declaration is invalid.
+
+checkOpL :: Ident -> Pattern a -> PCM (Pattern a)
+checkOpL op t@(NegativePattern _ _ _) = do
+  OpPrec fix pr <- prec (qualify op) <$> getPrecEnv
+  unless (pr < 6 || pr == 6 && fix == InfixL) $
+    report $ errInvalidParse "unary operator" minusId (qualify op)
+  return t
+checkOpL op1 t@(InfixPattern _ _ _ op2 _) = do
+  OpPrec fix1 pr1 <- prec (qualify op1) <$> getPrecEnv
+  OpPrec fix2 pr2 <- prec op2 <$> getPrecEnv
+  unless (pr1 < pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL) $
+    report $ errInvalidParse "operator" op1 op2
+  return t
+checkOpL _ t = return t
+
+checkOpR :: Ident -> Pattern a -> PCM (Pattern a)
+checkOpR op t@(NegativePattern _ _ _) = do
+  OpPrec _ pr <- prec (qualify op)  <$> getPrecEnv
+  when (pr >= 6) $ report $ errInvalidParse "unary operator" minusId (qualify op)
+  return t
+checkOpR op1 t@(InfixPattern _ _ _ op2 _) = do
+  OpPrec fix1 pr1 <- prec (qualify op1)  <$> getPrecEnv
+  OpPrec fix2 pr2 <- prec op2  <$> getPrecEnv
+  unless (pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR) $
+    report $ errInvalidParse "operator" op1 op2
+  return t
+checkOpR _ t = return t
+
+-- The functions 'opPrec' and 'prec' return the fixity and operator precedence
+-- of an entity. Even though precedence checking is performed after the
+-- renaming phase, we have to be prepared to see ambiguoeus identifiers here.
+-- This may happen while checking the root of an operator definition that
+-- shadows an imported definition.
+
+getOpPrec :: InfixOp a -> PCM OpPrec
+getOpPrec op = opPrec op <$> getPrecEnv
+
+opPrec :: InfixOp a -> OpPrecEnv -> OpPrec
+opPrec op = prec (opName op)
+
+prec :: QualIdent -> OpPrecEnv -> OpPrec
+prec op env = case qualLookupP op env of
+  [] -> defaultP
+  PrecInfo _ p : _ -> p
+
+
+-- Combine two entities with SpanInfo to a new SpanInfo (discarding info points)
+(@+@) :: (HasSpanInfo a, HasSpanInfo b) => a -> b -> SpanInfo
+a @+@ b = fromSrcSpan (combineSpans (getSrcSpan a) (getSrcSpan b))
+
+-- ---------------------------------------------------------------------------
+-- Error messages
+-- ---------------------------------------------------------------------------
+
+errUndefinedOperator :: Ident -> Message
+errUndefinedOperator op = spanInfoMessage op $ hsep $ map text
+  ["No definition for", escName op, "in this scope"]
+
+errMultiplePrecedence :: [Ident] -> Message
+errMultiplePrecedence []       = internalError
+  "PrecCheck.errMultiplePrecedence: empty list"
+errMultiplePrecedence (op:ops) = spanInfoMessage op $
+  (hsep $ map text ["More than one fixity declaration for", escName op, "at"])
+  $+$ nest 2 (vcat (map (ppPosition . getPosition) (op:ops)))
+
+errInvalidParse :: String -> Ident -> QualIdent -> Message
+errInvalidParse what op1 op2 = spanInfoMessage op1 $ hsep $ map text
+  [ "Invalid use of", what, escName op1, "with", escQualName op2, "in"
+  , showLine $ getPosition op2]
+
+-- FIXME: Messages may have missing positions for minus operators
+-- TODO: Is this still true after span update for parser?
+
+errAmbiguousParse :: String -> QualIdent -> QualIdent -> Message
+errAmbiguousParse what op1 op2 = spanInfoMessage op1 $ hsep $ map text
+  ["Ambiguous use of", what, escQualName op1, "with", escQualName op2, "in"
+  , showLine $ getPosition op2]
diff --git a/src/Checks/SyntaxCheck.hs b/src/Checks/SyntaxCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/SyntaxCheck.hs
@@ -0,0 +1,1430 @@
+{- |
+    Module      :  $Header$
+    Description :  Syntax checks
+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux
+                                   Martin Engelke
+                                   Björn Peemöller
+                       2015        Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   After the type declarations have been checked, the compiler performs
+   a syntax check on the remaining declarations. This check disambiguates
+   nullary data constructors and variables which -- in contrast to Haskell --
+   is not possible on purely syntactic criteria. In addition, this pass checks
+   for undefined as well as ambiguous variables and constructors. In order to
+   allow lifting of local definitions in later phases, all local variables are
+   renamed by adding a key identifying their scope. Therefore, all variables
+   defined in the same scope share the same key so that multiple definitions
+   can be recognized. Finally, all (adjacent) equations of a function are
+   merged into a single definition.
+-}
+{-# LANGUAGE CPP #-}
+module Checks.SyntaxCheck (syntaxCheck) where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative        ((<$>), (<*>))
+#endif
+
+import           Control.Monad       (unless, when)
+import qualified Control.Monad.State as S (State, gets, modify, runState,
+                                           withState)
+import           Data.Function       (on)
+import           Data.List           (insertBy, intersect, nub, nubBy)
+import qualified Data.Map            as Map (Map, empty, findWithDefault,
+                                             fromList, insertWith, keys)
+import           Data.Maybe          (isJust, isNothing)
+import qualified Data.Set            as Set (Set, empty, insert, member,
+                                             singleton, toList, union)
+
+import           Curry.Base.Ident
+import           Curry.Base.Position
+import           Curry.Base.Pretty
+import           Curry.Base.Span
+import           Curry.Base.SpanInfo
+import           Curry.Syntax
+
+import           Base.Expr
+import           Base.Messages       (Message, internalError,
+                                      spanInfoMessage)
+import           Base.NestEnv
+import           Base.SCC            (scc)
+import           Base.Utils          (findDouble, findMultiples, (++!))
+
+import           Env.TypeConstructor (TCEnv, clsMethods, getOrigName)
+import           Env.Value           (ValueEnv, ValueInfo (..),
+                                      qualLookupValueUnique)
+
+
+-- The syntax checking proceeds as follows. First, the compiler extracts
+-- information about all imported values and data constructors from the
+-- imported (type) environments. Next, the data constructors defined in
+-- the current module are entered into this environment. After this,
+-- all record labels are entered into the environment. If a record
+-- identifier is already assigned to a constructor, then an error will be
+-- generated. Class methods defined in the current module are entered into
+-- the environment, too. Finally, all declarations are checked within the
+-- resulting environment. In addition, this process will also rename the
+-- local variables.
+
+-- TODO: use SpanInfos for errors and then stop passing down SpanInfo from the decls to the checks
+
+syntaxCheck :: [KnownExtension] -> TCEnv -> ValueEnv -> Module ()
+            -> ((Module (), [KnownExtension]), [Message])
+syntaxCheck exts tcEnv vEnv mdl@(Module _ _ _ m _ _ ds) =
+  case findMultiples cons of
+    []  -> case findMultiples (ls ++ fs ++ cons ++ cs) of
+             []  -> runSC (checkModule mdl) state
+             iss -> ((mdl, exts), map (errMultipleDeclarations m) iss)
+    css -> ((mdl, exts), map errMultipleDataConstructor css)
+  where
+    tds   = filter isTypeDecl ds
+    vds   = filter isValueDecl ds
+    cds   = filter isClassDecl ds
+    cons  = concatMap constrs tds
+    ls    = nub $ concatMap recLabels tds
+    fs    = nub $ concatMap vars vds
+    cs    = concatMap (concatMap methods) [ds' | ClassDecl _ _ _ _ _ ds' <- cds]
+    rEnv  = globalEnv $ fmap renameInfo vEnv
+    state = initState exts m tcEnv rEnv vEnv
+
+-- A global state transformer is used for generating fresh integer keys with
+-- which the variables are renamed.
+-- The state tracks the identifier of the current scope 'scopeId' as well as
+-- the next fresh identifier, which is used for introducing new scopes as well
+-- as renaming literals and underscore to disambiguate them.
+
+-- |Syntax check monad
+type SCM = S.State SCState
+
+-- |Internal state of the syntax check
+data SCState = SCState
+  { extensions       :: [KnownExtension] -- ^ Enabled language extensions
+  , moduleIdent      :: ModuleIdent      -- ^ 'ModuleIdent' of the current module
+  , tyConsEnv        :: TCEnv
+  , renameEnv        :: RenameEnv        -- ^ Information store
+  , valueEnv         :: ValueEnv         -- ^ To check instance method visibility
+  , scopeId          :: Integer          -- ^ Identifier for the current scope
+  , nextId           :: Integer          -- ^ Next fresh identifier
+  , funcDeps         :: FuncDeps         -- ^ Stores data about functions dependencies
+  , typeClassesCheck :: Bool
+  , errors           :: [Message]        -- ^ Syntactic errors in the module
+  }
+
+-- |Initial syntax check state
+initState :: [KnownExtension] -> ModuleIdent -> TCEnv -> RenameEnv -> ValueEnv
+          -> SCState
+initState exts m tcEnv rEnv vEnv =
+  SCState exts m tcEnv rEnv vEnv globalScopeId 1 noFuncDeps False []
+
+-- |Identifier for global (top-level) declarations
+globalScopeId :: Integer
+globalScopeId = idUnique (mkIdent "")
+
+-- |Run the syntax check monad
+runSC :: SCM a -> SCState -> (a, [Message])
+runSC scm s = let (a, s') = S.runState scm s in (a, reverse $ errors s')
+
+-- |Check for an enabled extension
+hasExtension :: KnownExtension -> SCM Bool
+hasExtension ext = S.gets (elem ext . extensions)
+
+-- |Enable an additional 'Extension' to avoid redundant complaints about
+-- missing extensions
+enableExtension :: KnownExtension -> SCM ()
+enableExtension e = S.modify $ \s -> s { extensions = e : extensions s }
+
+-- |Retrieve all enabled extensions
+getExtensions :: SCM [KnownExtension]
+getExtensions = S.gets extensions
+
+-- |Retrieve the 'ModuleIdent' of the current module
+getModuleIdent :: SCM ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+-- |Retrieve the 'TCEnv'
+getTyConsEnv :: SCM TCEnv
+getTyConsEnv = S.gets tyConsEnv
+
+-- |Retrieve the 'RenameEnv'
+getRenameEnv :: SCM RenameEnv
+getRenameEnv = S.gets renameEnv
+
+-- |Retrieve the 'ValueEnv'
+getValueEnv :: SCM ValueEnv
+getValueEnv = S.gets valueEnv
+
+-- |Modify the 'RenameEnv'
+modifyRenameEnv :: (RenameEnv -> RenameEnv) -> SCM ()
+modifyRenameEnv f = S.modify $ \s -> s { renameEnv = f $ renameEnv s }
+
+-- |Retrieve the current scope identifier
+getScopeId :: SCM Integer
+getScopeId = S.gets scopeId
+
+-- |Create a new identifier and return it
+newId :: SCM Integer
+newId = do
+  curId <- S.gets nextId
+  S.modify $ \s -> s { nextId = succ curId }
+  return curId
+
+-- |Checks whether a type classes check is running
+isTypeClassesCheck :: SCM Bool
+isTypeClassesCheck = S.gets typeClassesCheck
+
+-- |Performs a type classes check in a nested scope
+performTypeClassesCheck :: SCM a -> SCM a
+performTypeClassesCheck = inNestedScope .
+  S.withState (\s -> s { typeClassesCheck = True })
+
+-- |Increase the nesting of the 'RenameEnv' to introduce a new local scope.
+-- This also increases the scope identifier.
+incNesting :: SCM ()
+incNesting = do
+  newScopeId <- newId
+  S.modify $ \s -> s { scopeId = newScopeId }
+  modifyRenameEnv nestEnv
+
+withLocalEnv :: SCM a -> SCM a
+withLocalEnv act = do
+  oldEnv <- getRenameEnv
+  res    <- act
+  modifyRenameEnv $ const oldEnv
+  return res
+
+-- |Perform an action in a nested scope (by creating a nested 'RenameEnv')
+-- and discard the nested 'RenameEnv' afterwards
+inNestedScope :: SCM a -> SCM a
+inNestedScope act = withLocalEnv (incNesting >> act)
+
+-- |Modify the `FuncDeps'
+modifyFuncDeps :: (FuncDeps -> FuncDeps) -> SCM ()
+modifyFuncDeps f = S.modify $ \ s -> s { funcDeps = f $ funcDeps s }
+
+-- |Report a syntax error
+report :: Message -> SCM ()
+report msg = S.modify $ \s -> s { errors = msg : errors s }
+
+-- |Everything is checked
+ok :: SCM ()
+ok = return ()
+
+-- FuncDeps contains information to deal with dependencies between functions.
+-- This is used for checking whether functional patterns are cyclic.
+-- curGlobalFunc contains the identifier of the global function that is
+-- currently being checked, if any.
+-- data X = X
+-- f = let g = lookup 42 in g [1,2,3]
+-- While `X' is being checked `curGlobalFunc' should be `Nothing',
+-- while `lookup' is being checked is should be `f's identifier.
+-- globalDeps collects all dependencies (other functions) of global functions
+-- funcPats collects all functional patterns and the global function they're
+-- used in
+data FuncDeps = FuncDeps
+  { curGlobalFunc :: Maybe QualIdent
+  , globalDeps    :: GlobalDeps
+  , funcPats      :: [(QualIdent, QualIdent)]
+  }
+type GlobalDeps = Map.Map QualIdent (Set.Set QualIdent)
+
+-- |Initial state for FuncDeps
+noFuncDeps :: FuncDeps
+noFuncDeps = FuncDeps Nothing Map.empty []
+
+-- |Perform an action inside a function, settìng `curGlobalFunc' to that function
+inFunc :: Ident -> SCM a -> SCM a
+inFunc i scm = do
+  m      <- getModuleIdent
+  global <- isNothing <$> S.gets (curGlobalFunc . funcDeps)
+  when global $ modifyFuncDeps $ \ fd -> fd { curGlobalFunc = Just (qualifyWith m i) }
+  res    <- scm
+  when global $ modifyFuncDeps $ \ fd -> fd { curGlobalFunc = Nothing }
+  return res
+
+-- |Add a dependency to `curGlobalFunction'
+addGlobalDep :: QualIdent -> SCM ()
+addGlobalDep dep = do
+  maybeF <- S.gets (curGlobalFunc . funcDeps)
+  case maybeF of
+    Nothing -> internalError "SyntaxCheck.addFuncPat: no global function set"
+    Just  f -> modifyFuncDeps $ \ fd -> fd
+                { globalDeps = Map.insertWith Set.union f
+                              (Set.singleton dep) (globalDeps fd) }
+
+-- |Add a functional pattern to `curGlobalFunction'
+addFuncPat :: QualIdent -> SCM ()
+addFuncPat fp = do
+  maybeF <- S.gets (curGlobalFunc . funcDeps)
+  case maybeF of
+    Nothing -> internalError "SyntaxCheck.addFuncPat: no global function set"
+    Just  f -> modifyFuncDeps $ \ fd -> fd { funcPats = (fp, f) : funcPats fd }
+
+-- |Return dependencies of global functions
+getGlobalDeps :: SCM GlobalDeps
+getGlobalDeps = globalDeps <$> S.gets funcDeps
+
+-- |Return used functional patterns
+getFuncPats :: SCM [(QualIdent, QualIdent)]
+getFuncPats = funcPats <$> S.gets funcDeps
+
+
+-- A nested environment is used for recording information about the data
+-- constructors and variables in the module. For every data constructor
+-- its arity is saved. This is used for checking that all constructor
+-- applications in patterns are saturated. For local variables the
+-- environment records the new name of the variable after renaming.
+-- Global variables are recorded with qualified identifiers in order
+-- to distinguish multiply declared entities.
+
+-- Currently, records must explicitly be declared together with their labels.
+-- When constructing or updating a record, it is necessary to compute
+-- all its labels using just one of them. Thus for each label
+-- the record identifier and all its labels are entered into the environment
+
+-- Note: the function 'qualLookupVar' has been extended to allow the usage of
+-- the qualified list constructor (prelude.:).
+
+type RenameEnv = NestEnv RenameInfo
+
+data RenameInfo
+  -- |Arity of data constructor
+  = Constr      QualIdent Int
+  -- |Constructors of a record label
+  | RecordLabel QualIdent [QualIdent]
+  -- |Arity of global function
+  | GlobalVar   QualIdent Int
+  -- |Arity of local function
+  | LocalVar    Ident Int
+    deriving (Eq, Show)
+
+ppRenameInfo :: RenameInfo -> Doc
+ppRenameInfo (Constr      qn _) = text (escQualName qn)
+ppRenameInfo (RecordLabel qn _) = text (escQualName qn)
+ppRenameInfo (GlobalVar   qn _) = text (escQualName qn)
+ppRenameInfo (LocalVar     n _) = text (escName      n)
+
+-- Since record types are currently translated into data types, it is necessary
+-- to ensure that all identifiers for records and constructors are different.
+-- Furthermore, it is not allowed to declare a label more than once.
+
+renameInfo :: ValueInfo -> RenameInfo
+renameInfo (DataConstructor    qid    a _ _) = Constr      qid a
+renameInfo (NewtypeConstructor qid      _ _) = Constr      qid 1
+renameInfo (Value              qid _  a   _) = GlobalVar   qid a
+renameInfo (Label              qid cs     _) = RecordLabel qid cs
+
+bindGlobal :: Bool -> ModuleIdent -> Ident -> RenameInfo -> RenameEnv
+           -> RenameEnv
+bindGlobal tcc m c r
+  | not tcc   = bindNestEnv c r . qualBindNestEnv (qualifyWith m c) r
+  | otherwise = id
+
+bindLocal :: Ident -> RenameInfo -> RenameEnv -> RenameEnv
+bindLocal = bindNestEnv
+
+-- ------------------------------------------------------------------------------
+
+-- |Bind type constructor information and record label information
+bindTypeDecl :: Decl a -> SCM ()
+bindTypeDecl (DataDecl    _ _ _ cs _) =
+  mapM_ bindConstr cs >> bindRecordLabels cs
+bindTypeDecl (NewtypeDecl _ _ _ nc _) = bindNewConstr nc
+bindTypeDecl _                        = ok
+
+bindConstr :: ConstrDecl -> SCM ()
+bindConstr (ConstrDecl _ c tys) = do
+  m <- getModuleIdent
+  modifyRenameEnv $ bindGlobal False m c (Constr (qualifyWith m c) $ length tys)
+bindConstr (ConOpDecl _ _ op _) = do
+  m <- getModuleIdent
+  modifyRenameEnv $ bindGlobal False m op (Constr (qualifyWith m op) 2)
+bindConstr (RecordDecl _ c fs)  = do
+  m <- getModuleIdent
+  modifyRenameEnv $ bindGlobal False m c (Constr (qualifyWith m c) (length labels))
+    where labels = [l | FieldDecl _ ls _ <- fs, l <- ls]
+
+bindNewConstr :: NewConstrDecl -> SCM ()
+bindNewConstr (NewConstrDecl _ c _) = do
+  m <- getModuleIdent
+  modifyRenameEnv $ bindGlobal False m c (Constr (qualifyWith m c) 1)
+bindNewConstr (NewRecordDecl _ c (l, _)) = do
+  m <- getModuleIdent
+  bindRecordLabel (l, [c])
+  modifyRenameEnv $ bindGlobal False m c (Constr (qualifyWith m c) 1)
+
+bindRecordLabels :: [ConstrDecl] -> SCM ()
+bindRecordLabels cs =
+  mapM_ bindRecordLabel [(l, constr l) | l <- nub (concatMap recordLabels cs)]
+  where constr l = [constrId c | c <- cs, l `elem` recordLabels c]
+
+bindRecordLabel :: (Ident, [Ident]) -> SCM ()
+bindRecordLabel (l, cs) = do
+  m   <- getModuleIdent
+  new <- null . lookupVar l <$> getRenameEnv
+  unless new $ report $ errDuplicateDefinition l
+  modifyRenameEnv $ bindGlobal False m l $
+    RecordLabel (qualifyWith m l) (map (qualifyWith m) cs)
+
+-- ------------------------------------------------------------------------------
+
+-- |Bind a global function declaration in the 'RenameEnv'
+bindFuncDecl :: Bool -> ModuleIdent -> Decl a -> RenameEnv -> RenameEnv
+bindFuncDecl _   _ (FunctionDecl _ _ _ []) _
+  = internalError "SyntaxCheck.bindFuncDecl: no equations"
+bindFuncDecl tcc m (FunctionDecl _ _ f (eq:_)) env
+  = let arty = length $ snd $ getFlatLhs eq
+    in  bindGlobal tcc m f (GlobalVar (qualifyWith m f) arty) env
+bindFuncDecl tcc m (TypeSig _ fs (QualTypeExpr _ _ ty)) env
+  = foldr (bindTS . qualifyWith m) env fs
+  where
+    bindTS qf env'
+      | null $ qualLookupVar qf env'
+        = bindGlobal tcc m (unqualify qf) (GlobalVar qf (typeArity ty)) env'
+      | otherwise = env'
+bindFuncDecl _   _ _ env = env
+
+-- ------------------------------------------------------------------------------
+
+-- |Bind type class information, i.e. class methods
+bindClassDecl :: Decl a -> SCM ()
+bindClassDecl (ClassDecl _ _ _ _ _ ds) = mapM_ bindClassMethod ds
+bindClassDecl _                        = ok
+
+bindClassMethod :: Decl a -> SCM ()
+bindClassMethod ts@(TypeSig _ _ _) = do
+  m <- getModuleIdent
+  modifyRenameEnv $ bindFuncDecl False m ts
+bindClassMethod _ = ok
+
+-- ------------------------------------------------------------------------------
+
+-- |Bind a local declaration (function, variables) in the 'RenameEnv'
+bindVarDecl :: Decl a -> RenameEnv -> RenameEnv
+bindVarDecl (FunctionDecl    _ _ f eqs) env
+  | null eqs  = internalError "SyntaxCheck.bindVarDecl: no equations"
+  | otherwise = let arty = length $ snd $ getFlatLhs $ head eqs
+                in  bindLocal (unRenameIdent f) (LocalVar f arty) env
+bindVarDecl (PatternDecl         _ t _) env = foldr bindVar env (bv t)
+bindVarDecl (FreeDecl             _ vs) env = foldr (bindVar . varIdent) env vs
+bindVarDecl _                           env = env
+
+bindVar :: Ident -> RenameEnv -> RenameEnv
+bindVar v | isAnonId v = id
+          | otherwise  = bindLocal (unRenameIdent v) (LocalVar v 0)
+
+lookupVar :: Ident -> RenameEnv -> [RenameInfo]
+lookupVar v env = lookupNestEnv v env ++! lookupTupleConstr v
+
+qualLookupVar :: QualIdent -> RenameEnv -> [RenameInfo]
+qualLookupVar v env =  qualLookupNestEnv v env
+                   ++! qualLookupListCons v env
+                   ++! lookupTupleConstr (unqualify v)
+
+lookupTupleConstr :: Ident -> [RenameInfo]
+lookupTupleConstr v
+  | isTupleId v = let a = tupleArity v
+                  in  [Constr (qualifyWith preludeMIdent $ tupleId a) a]
+  | otherwise   = []
+
+qualLookupListCons :: QualIdent -> RenameEnv -> [RenameInfo]
+qualLookupListCons v env
+  | v == qualifyWith preludeMIdent consId
+  = qualLookupNestEnv (qualify $ qidIdent v) env
+  | otherwise
+  = []
+
+-- When a module is checked, the global declaration group is checked. The
+-- resulting renaming environment can be discarded. The same is true for
+-- a goal. Note that all declarations in the goal must be considered as
+-- local declarations. Class and instance declarations define their own scope,
+-- thus defined functions will be renamed as well. For class and instance
+-- declarations several checks have to be disabled (for instance, type
+-- signatures without corresponding function declaration are allowed in class
+-- declarations), while some have to be performed extra (for instance, no
+-- other functions than specified by the type signatures within a class
+-- declaration are allowed to be declared).
+
+checkModule :: Module () -> SCM (Module (), [KnownExtension])
+checkModule (Module spi li ps m es is ds) = do
+  mapM_ bindTypeDecl tds
+  mapM_ bindClassDecl cds
+  ds' <- checkTopDecls ds
+  cds' <- mapM (performTypeClassesCheck . checkClassDecl) cds
+  ids' <- mapM (performTypeClassesCheck . checkInstanceDecl) ids
+  let ds'' = updateClassAndInstanceDecls cds' ids' ds'
+  checkFuncPatDeps
+  exts <- getExtensions
+  return (Module spi li ps m es is ds'', exts)
+  where tds = filter isTypeDecl ds
+        cds = filter isClassDecl ds
+        ids = filter isInstanceDecl ds
+
+-- |Checks whether a function in a functional pattern contains cycles
+-- |(depends on its own global function)
+checkFuncPatDeps :: SCM ()
+checkFuncPatDeps = do
+  fps  <- getFuncPats
+  deps <- getGlobalDeps
+  let levels   = scc (:[])
+                     (\k -> Set.toList (Map.findWithDefault Set.empty k deps))
+                     (Map.keys deps)
+      levelMap = Map.fromList [ (f, l) | (fs, l) <- zip levels [1 ..], f <- fs ]
+      level f  = Map.findWithDefault (0 :: Int) f levelMap
+  mapM_ (checkFuncPatDep level) fps
+
+checkFuncPatDep :: Ord a => (QualIdent -> a) -> (QualIdent, QualIdent) -> SCM ()
+checkFuncPatDep level (fp, f) = unless (level fp < level f) $
+  report $ errFuncPatCyclic fp f
+
+checkTopDecls :: [Decl ()] -> SCM [Decl ()]
+checkTopDecls ds = do
+  m <- getModuleIdent
+  tcc <- isTypeClassesCheck
+  checkDeclGroup (bindFuncDecl tcc m) ds
+
+checkClassDecl :: Decl () -> SCM (Decl ())
+checkClassDecl (ClassDecl p li cx cls tv ds) = do
+  checkMethods (qualify cls) (concatMap methods ds) ds
+  ClassDecl p li cx cls tv <$> checkTopDecls ds
+checkClassDecl _ =
+  internalError "SyntaxCheck.checkClassDecl: no class declaration"
+
+checkInstanceDecl :: Decl () -> SCM (Decl ())
+checkInstanceDecl (InstanceDecl p li cx qcls ty ds) = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  tcEnv <- getTyConsEnv
+  let clsMthds = clsMethods m qcls tcEnv
+  let orig = getOrigName m qcls tcEnv
+  let mthds =
+        if isLocalIdent m orig
+          then clsMthds
+          else filter (isFromCls orig m vEnv) clsMthds
+  checkMethods qcls mthds ds
+  mapM_ checkAmbiguousMethod ds
+  InstanceDecl p li cx qcls ty <$> checkTopDecls ds
+  where
+    isFromCls orig m vEnv f = case qualLookupValueUnique m (qualify f) vEnv of
+      [Value _ (Just cls) _ _]
+        | cls == orig -> True
+      _               -> False
+
+checkInstanceDecl _ =
+  internalError "SyntaxCheck.checkInstanceDecl: no instance declaration"
+
+checkAmbiguousMethod :: Decl a -> SCM ()
+checkAmbiguousMethod (FunctionDecl _ _ f _) = do
+  m <- getModuleIdent
+  rename <- getRenameEnv
+  case lookupVar f rename of
+    rs1@(_:_:_) -> case qualLookupVar (qualifyWith m f) rename of
+      []          -> report $ errAmbiguousIdent rs1 (qualify f)
+      rs2@(_:_:_) -> report $ errAmbiguousIdent rs2 (qualify f)
+      _           -> return ()
+    _           -> return ()
+checkAmbiguousMethod _ =
+  internalError "SyntaxCheck.checkAmbiguousMethod: no function declaration"
+
+checkMethods :: QualIdent -> [Ident] -> [Decl a] -> SCM ()
+checkMethods qcls ms ds =
+  mapM_ (report . errUndefinedMethod qcls) $ filter (`notElem` ms) fs
+  where fs = [f | FunctionDecl _ _ f _ <- ds]
+
+updateClassAndInstanceDecls :: [Decl a] -> [Decl a] -> [Decl a] -> [Decl a]
+updateClassAndInstanceDecls [] [] ds = ds
+updateClassAndInstanceDecls (c:cs) is (ClassDecl _ _ _ _ _ _:ds) =
+  c : updateClassAndInstanceDecls cs is ds
+updateClassAndInstanceDecls cs (i:is) (InstanceDecl _ _ _ _ _ _:ds) =
+  i : updateClassAndInstanceDecls cs is ds
+updateClassAndInstanceDecls cs is (d:ds) =
+  d : updateClassAndInstanceDecls cs is ds
+updateClassAndInstanceDecls _ _ _ =
+  internalError "SyntaxCheck.updateClassAndInstanceDecls"
+
+-- Each declaration group opens a new scope and uses a distinct key
+-- for renaming the variables in this scope. In a declaration group,
+-- first the left hand sides of all declarations are checked, next the
+-- compiler checks that there is a definition for every type signature
+-- and evaluation annotation in this group. Finally, the right hand sides
+-- are checked and adjacent equations for the same function are merged
+-- into a single definition.
+
+-- The function 'checkDeclLhs' also handles the case where a pattern
+-- declaration is recognized as a function declaration by the parser.
+-- This happens, e.g., for the declaration
+--      where Just x = y
+-- because the parser cannot distinguish nullary constructors and functions.
+-- Note that pattern declarations are not allowed on the top-level.
+
+checkDeclGroup :: (Decl () -> RenameEnv -> RenameEnv) -> [Decl ()] -> SCM [Decl ()]
+checkDeclGroup bindDecl ds = do
+  checkedLhs <- mapM checkDeclLhs $ sortFuncDecls ds
+  joinEquations checkedLhs >>= checkDecls bindDecl
+
+checkDeclLhs :: Decl () -> SCM (Decl ())
+checkDeclLhs (InfixDecl    p fix' pr ops) =
+  InfixDecl p fix' <$> checkPrecedence p pr <*> mapM renameVar ops
+checkDeclLhs (TypeSig            p vs ty) =
+  (\vs' -> TypeSig p vs' ty) <$> mapM (checkVar "type signature") vs
+checkDeclLhs (FunctionDecl     p _ f eqs) =
+  inFunc f $ checkEquationsLhs p eqs
+checkDeclLhs (ExternalDecl          p vs) =
+  ExternalDecl p <$> mapM (checkVar' "external declaration") vs
+checkDeclLhs (PatternDecl        p t rhs) =
+  (\t' -> PatternDecl p t' rhs) <$> checkPattern p t
+checkDeclLhs (FreeDecl              p vs) =
+  FreeDecl p <$> mapM (checkVar' "free variables declaration") vs
+checkDeclLhs d                            = return d
+
+checkPrecedence :: SpanInfo -> Maybe Precedence -> SCM (Maybe Precedence)
+checkPrecedence _ Nothing  = return Nothing
+checkPrecedence p (Just i) = do
+  unless (0 <= i && i <= 9) $ report
+                            $ errPrecedenceOutOfRange p i
+  return $ Just i
+
+checkVar' :: String -> Var a -> SCM (Var a)
+checkVar' what (Var a v) = Var a <$> checkVar what v
+
+checkVar :: String -> Ident -> SCM Ident
+checkVar _what v = do
+  -- isDC <- S.gets (isDataConstr v . renameEnv)
+  -- when isDC $ report $ nonVariable what v -- TODO Why is this disabled?
+  renameVar v
+
+renameVar :: Ident -> SCM Ident
+renameVar v = renameIdent v <$> getScopeId
+
+checkEquationsLhs :: SpanInfo -> [Equation ()] -> SCM (Decl ())
+checkEquationsLhs p [Equation p' lhs rhs] = do
+  lhs' <- checkEqLhs p' lhs
+  case lhs' of
+    Left  l -> return $ funDecl' l
+    Right r -> checkDeclLhs (PatternDecl p' r rhs)
+  where funDecl' (f, lhs') = FunctionDecl p () f [Equation p' lhs' rhs]
+checkEquationsLhs _ _ = internalError "SyntaxCheck.checkEquationsLhs"
+
+checkEqLhs :: SpanInfo -> Lhs () -> SCM (Either (Ident, Lhs ()) (Pattern ()))
+checkEqLhs pspi toplhs = do
+  m   <- getModuleIdent
+  k   <- getScopeId
+  env <- getRenameEnv
+  case toplhs of
+    FunLhs spi f ts
+      | not $ isDataConstr f env -> return left
+      | k /= globalScopeId       -> return right
+      | null infos               -> return left
+      | otherwise                -> do report $ errToplevelPattern pspi
+                                       return right
+      where f'    = renameIdent f k
+            infos = qualLookupVar (qualifyWith m f) env
+            left  = Left  (f', FunLhs spi f' ts)
+            right = Right $  -- use start from the parsed FunLhs and compute end
+              updateEndPos $ ConstructorPattern spi () (qualify f) ts
+    OpLhs spi t1 op t2
+      | not $ isDataConstr op env -> return left
+      | k /= globalScopeId        -> return right
+      | null infos                -> return left
+      | otherwise                 -> do report $ errToplevelPattern pspi
+                                        return right
+      where op'   = renameIdent op k
+            infos = qualLookupVar (qualifyWith m op) env
+            left  = Left (op', OpLhs spi t1 op' t2)
+            right = checkOpLhs k env (infixPattern t1 (qualify op)) t2
+            infixPattern (InfixPattern _ a' t1' op1 t2') op2 t3 =
+              let t2'' = infixPattern t2' op2 t3
+                  sp = combineSpans (getSrcSpan t1') (getSrcSpan t2'')
+              in InfixPattern (fromSrcSpan sp) a' t1' op1 t2''
+            infixPattern t1' op1 t2' =
+              let sp = combineSpans (getSrcSpan t1') (getSrcSpan t2')
+              in InfixPattern (fromSrcSpan sp) () t1' op1 t2'
+    ApLhs spi lhs ts -> do
+      checked <- checkEqLhs pspi lhs
+      case checked of
+        Left (f', lhs') -> return $ Left (f', updateEndPos $ ApLhs spi lhs' ts)
+        r               -> do report $ errNonVariable "curried definition" f
+                              return $ r
+        where (f, _) = flatLhs lhs
+
+checkOpLhs :: Integer -> RenameEnv -> (Pattern a -> Pattern a)
+           -> Pattern a -> Either (Ident, Lhs a) (Pattern a)
+checkOpLhs k env f (InfixPattern spi a t1 op t2)
+  | isJust m || isDataConstr op' env
+  = checkOpLhs k env (f . InfixPattern spi a t1 op) t2
+  | otherwise
+  = Left (op'', OpLhs (getSpanInfo t1') t1' op'' t2)
+  where (m,op') = (qidModule op, qidIdent op)
+        op''    = renameIdent op' k
+        t1'     = f t1
+checkOpLhs _ _ f t = Right (f t)
+
+-- -- ---------------------------------------------------------------------------
+
+joinEquations :: [Decl a] -> SCM [Decl a]
+joinEquations [] = return []
+joinEquations (FunctionDecl a p f eqs : FunctionDecl _ _ f' [eq] : ds)
+  | f == f' = do
+    when (getArity (head eqs) /= getArity eq) $ report $ errDifferentArity [f, f']
+    joinEquations (updateEndPos (FunctionDecl a p f (eqs ++ [eq])) : ds)
+  where getArity = length . snd . getFlatLhs
+joinEquations (d : ds) = (d :) <$> joinEquations ds
+
+checkDecls :: (Decl () -> RenameEnv -> RenameEnv) -> [Decl ()] -> SCM [Decl ()]
+checkDecls bindDecl ds = do
+  let dblVar = findDouble bvs
+  onJust (report . errDuplicateDefinition) dblVar
+  let mulTys = findMultiples tys
+  mapM_ (report . errDuplicateTypeSig) mulTys
+  let missingTys = [v | ExternalDecl _ vs <- ds, Var _ v <- vs, v `notElem` tys]
+  mapM_ (report . errNoTypeSig) missingTys
+  if isNothing dblVar && null mulTys && null missingTys
+    then do
+      modifyRenameEnv $ \env -> foldr bindDecl env (tds ++ vds)
+      mapM (checkDeclRhs bvs) ds
+    else return ds -- skip further checking
+  where vds    = filter isValueDecl ds
+        tds    = filter isTypeSig ds
+        bvs    = concatMap vars vds
+        tys    = concatMap vars tds
+        onJust = maybe ok
+
+-- -- ---------------------------------------------------------------------------
+
+checkDeclRhs :: [Ident] -> Decl () -> SCM (Decl ())
+checkDeclRhs _   (DataDecl   p tc tvs cs clss) =
+  flip (DataDecl p tc tvs) clss <$> mapM checkDeclLabels cs
+checkDeclRhs bvs (TypeSig        p vs ty) =
+  (\vs' -> TypeSig p vs' ty) <$> mapM (checkLocalVar bvs) vs
+checkDeclRhs _   (FunctionDecl a p f eqs) =
+  FunctionDecl a p f <$> inFunc f (mapM checkEquation eqs)
+checkDeclRhs _   (PatternDecl    p t rhs) =
+  PatternDecl p t <$> checkRhs rhs
+checkDeclRhs _   d                        = return d
+
+checkDeclLabels :: ConstrDecl -> SCM ConstrDecl
+checkDeclLabels rd@(RecordDecl _ _ fs) = do
+  onJust (report . errDuplicateLabel "declaration")
+         (findDouble $ map qualify labels)
+  return rd
+  where
+    onJust = maybe ok
+    labels = [l | FieldDecl _ ls _ <- fs, l <- ls]
+checkDeclLabels d = return d
+
+checkLocalVar :: [Ident] -> Ident -> SCM Ident
+checkLocalVar bvs v = do
+  tcc <- isTypeClassesCheck
+  when (v `notElem` bvs && not tcc) $ report $ errNoBody v
+  return v
+
+checkEquation :: Equation () -> SCM (Equation ())
+checkEquation (Equation p lhs rhs) = inNestedScope $ do
+  lhs' <- checkLhs p lhs >>= addBoundVariables False
+  rhs' <- checkRhs rhs
+  return $ Equation p lhs' rhs'
+
+checkLhs :: SpanInfo -> Lhs () -> SCM (Lhs ())
+checkLhs p (FunLhs    spi f ts) = FunLhs spi f <$> mapM (checkPattern p) ts
+checkLhs p (OpLhs spi t1 op t2) = do
+  let wrongCalls = concatMap (checkParenPattern (Just $ qualify op)) [t1,t2]
+  unless (null wrongCalls) $ report $ errInfixWithoutParens
+    spi wrongCalls
+  flip (OpLhs spi) op <$> checkPattern p t1 <*> checkPattern p t2
+checkLhs p (ApLhs   spi lhs ts) =
+  ApLhs spi <$> checkLhs p lhs <*> mapM (checkPattern p) ts
+
+-- checkParen
+-- @param Aufrufende InfixFunktion
+-- @param Pattern
+-- @return Liste mit fehlerhaften Funktionsaufrufen
+
+checkParenPattern :: Maybe QualIdent -> Pattern a -> [(QualIdent, QualIdent)]
+checkParenPattern _ (LiteralPattern          _ _ _) = []
+checkParenPattern _ (NegativePattern         _ _ _) = []
+checkParenPattern _ (VariablePattern         _ _ _) = []
+checkParenPattern _ (ConstructorPattern   _ _ _ cs) =
+  concatMap (checkParenPattern Nothing) cs
+checkParenPattern o (InfixPattern     _ _ t1 op t2) =
+  maybe [] (\c -> [(c, op)]) o
+  ++ checkParenPattern Nothing t1 ++ checkParenPattern Nothing t2
+checkParenPattern _ (ParenPattern              _ t) =
+  checkParenPattern Nothing t
+checkParenPattern _ (RecordPattern        _ _ _ fs) =
+  concatMap (\(Field _ _ t) -> checkParenPattern Nothing t) fs
+checkParenPattern _ (TuplePattern             _ ts) =
+  concatMap (checkParenPattern Nothing) ts
+checkParenPattern _ (ListPattern            _ _ ts) =
+  concatMap (checkParenPattern Nothing) ts
+checkParenPattern o (AsPattern               _ _ t) =
+  checkParenPattern o t
+checkParenPattern o (LazyPattern               _ t) =
+  checkParenPattern o t
+checkParenPattern _ (FunctionPattern      _ _ _ ts) =
+  concatMap (checkParenPattern Nothing) ts
+checkParenPattern o (InfixFuncPattern _ _ t1 op t2) =
+  maybe [] (\c -> [(c, op)]) o
+  ++ checkParenPattern Nothing t1 ++ checkParenPattern Nothing t2
+
+checkPattern :: SpanInfo -> Pattern () -> SCM (Pattern ())
+checkPattern _ (LiteralPattern        spi a l) =
+  return $ LiteralPattern spi a l
+checkPattern _ (NegativePattern       spi a l) =
+  return $ NegativePattern spi a l
+checkPattern p (VariablePattern       spi a v)
+  | isAnonId v = VariablePattern spi a . renameIdent v <$> newId
+  | otherwise  = checkConstructorPattern p spi (qualify v) []
+checkPattern p (ConstructorPattern spi _ c ts) =
+  checkConstructorPattern p spi c ts
+checkPattern p (InfixPattern   spi _ t1 op t2) =
+  checkInfixPattern p spi t1 op t2
+checkPattern p (ParenPattern            spi t) =
+  ParenPattern spi <$> checkPattern p t
+checkPattern p (RecordPattern      spi _ c fs) =
+  checkRecordPattern p spi c fs
+checkPattern p (TuplePattern           spi ts) =
+  TuplePattern spi <$> mapM (checkPattern p) ts
+checkPattern p (ListPattern          spi a ts) =
+  ListPattern spi a <$> mapM (checkPattern p) ts
+checkPattern p (AsPattern             spi v t) =
+  AsPattern spi <$> checkVar "@ pattern" v <*> checkPattern p t
+checkPattern p (LazyPattern             spi t) = do
+  t' <- checkPattern p t
+  banFPTerm "lazy pattern" p t'
+  return (LazyPattern spi t')
+checkPattern _ (FunctionPattern     _ _ _ _) = internalError
+  "SyntaxCheck.checkPattern: function pattern not defined"
+checkPattern _ (InfixFuncPattern  _ _ _ _ _) = internalError
+  "SyntaxCheck.checkPattern: infix function pattern not defined"
+
+checkConstructorPattern :: SpanInfo -> SpanInfo -> QualIdent -> [Pattern ()]
+                        -> SCM (Pattern ())
+checkConstructorPattern p spi c ts = do
+  env <- getRenameEnv
+  m <- getModuleIdent
+  k <- getScopeId
+  case qualLookupVar c env of
+    [Constr _ n] -> processCons c n
+    [r]          -> processVarFun r k
+    rs -> case qualLookupVar (qualQualify m c) env of
+      [Constr _ n] -> processCons (qualQualify m c) n
+      [r]          -> processVarFun r k
+      []
+        | null ts && not (isQualified c) ->
+            return $ VariablePattern spi () $ renameIdent (unqualify c) k
+        | null rs -> do
+            ts' <- mapM (checkPattern p) ts
+            report $ errUndefinedData c
+            return $ ConstructorPattern spi () c ts'
+      _ -> do ts' <- mapM (checkPattern p) ts
+              report $ errAmbiguousData rs c
+              return $ ConstructorPattern spi () c ts'
+  where
+  n' = length ts
+  processCons qc n = do
+    when (n /= n') $ report $ errWrongArity c n n'
+    ConstructorPattern spi () qc <$> mapM (checkPattern p) ts
+  processVarFun r k
+    | null ts && not (isQualified c)
+    = return $ VariablePattern spi () $ renameIdent (unqualify c) k -- (varIdent r) k
+    | otherwise = do
+      checkFuncPatsExtension p
+      checkFuncPatCall r c
+      ts' <- mapM (checkPattern p) ts
+      mapM_ (checkFPTerm p) ts'
+      return $ FunctionPattern spi () (qualVarIdent r) ts'
+
+checkInfixPattern :: SpanInfo -> SpanInfo -> Pattern () -> QualIdent -> Pattern ()
+                  -> SCM (Pattern ())
+checkInfixPattern p spi t1 op t2 = do
+  m <- getModuleIdent
+  env <- getRenameEnv
+  case qualLookupVar op env of
+    [Constr _ n] -> infixPattern op n
+    [r]          -> funcPattern r op
+    rs           -> case qualLookupVar (qualQualify m op) env of
+      [Constr _ n] -> infixPattern (qualQualify m op) n
+      [r]          -> funcPattern r (qualQualify m op)
+      rs'          -> do if null rs && null rs'
+                            then report $ errUndefinedData op
+                            else report $ errAmbiguousData rs op
+                         flip (InfixPattern spi ()) op <$> checkPattern p t1
+                                                  <*> checkPattern p t2
+  where
+  infixPattern qop n = do
+    when (n /= 2) $ report $ errWrongArity op n 2
+    flip (InfixPattern spi ()) qop <$> checkPattern p t1 <*> checkPattern p t2
+  funcPattern r qop = do
+    checkFuncPatsExtension p
+    checkFuncPatCall r qop
+    ts' <- mapM (checkPattern p) [t1,t2]
+    let [t1',t2'] = ts'
+    mapM_ (checkFPTerm p) ts'
+    return $ InfixFuncPattern spi () t1' qop t2'
+
+checkRecordPattern :: SpanInfo -> SpanInfo -> QualIdent -> [Field (Pattern ())]
+                   -> SCM (Pattern ())
+checkRecordPattern p spi c fs = do
+  env <- getRenameEnv
+  m   <- getModuleIdent
+  case qualLookupVar c env of
+    [Constr c' _] -> processRecPat (Just c') fs
+    rs            -> case qualLookupVar (qualQualify m c) env of
+      [Constr c' _] -> processRecPat (Just c') fs
+      rs'           -> if null rs && null rs'
+                          then do report $ errUndefinedData c
+                                  processRecPat Nothing fs
+                          else do report $ errAmbiguousData rs c
+                                  processRecPat Nothing fs
+  where
+  processRecPat mcon fields = do
+    fs' <- mapM (checkField (checkPattern p)) fields
+    checkFieldLabels "pattern" p mcon fs'
+    return $ RecordPattern spi () c fs'
+
+checkFuncPatCall :: RenameInfo -> QualIdent -> SCM ()
+checkFuncPatCall r f = case r of
+  GlobalVar dep _ -> do
+    addGlobalDep dep
+    addFuncPat (dep @> f)
+  _           -> report $ errFuncPatNotGlobal f
+
+-- Note: process decls first
+checkRhs :: Rhs () -> SCM (Rhs ())
+checkRhs (SimpleRhs spi li e ds) = inNestedScope $
+  flip (SimpleRhs spi li) <$>
+    checkDeclGroup bindVarDecl ds <*>
+    checkExpr spi e
+checkRhs (GuardedRhs spi li es ds) = inNestedScope $
+  flip (GuardedRhs spi li) <$>
+    checkDeclGroup bindVarDecl ds <*>
+    mapM checkCondExpr es
+
+checkCondExpr :: CondExpr () -> SCM (CondExpr ())
+checkCondExpr (CondExpr spi g e) =  CondExpr spi <$> checkExpr spi g <*> checkExpr spi e
+
+checkExpr :: SpanInfo -> Expression () -> SCM (Expression ())
+checkExpr _ (Literal       spi a l) = return $ Literal spi a l
+checkExpr _ (Variable      spi a v) = checkVariable spi a v
+checkExpr _ (Constructor   spi a c) = checkVariable spi a c
+checkExpr p (Paren         spi   e) = Paren spi           <$> checkExpr p e
+checkExpr p (Typed        spi e ty) = flip (Typed spi) ty <$> checkExpr p e
+checkExpr p (Record     spi _ c fs) = checkRecordExpr p spi c fs
+checkExpr p (RecordUpdate spi e fs) = checkRecordUpdExpr p spi e fs
+checkExpr p (Tuple        spi   es) = Tuple spi <$> mapM (checkExpr p) es
+checkExpr p (List         spi a es) = List spi a <$> mapM (checkExpr p) es
+checkExpr p (ListCompr    spi e qs) = withLocalEnv $ flip (ListCompr spi) <$>
+  -- Note: must be flipped to insert qs into RenameEnv first
+  mapM (checkStatement "list comprehension" p) qs <*> checkExpr p e
+checkExpr p (EnumFrom              spi e) = EnumFrom spi <$> checkExpr p e
+checkExpr p (EnumFromThen      spi e1 e2) =
+  EnumFromThen spi <$> checkExpr p e1 <*> checkExpr p e2
+checkExpr p (EnumFromTo        spi e1 e2) =
+  EnumFromTo spi <$> checkExpr p e1 <*> checkExpr p e2
+checkExpr p (EnumFromThenTo spi e1 e2 e3) =
+  EnumFromThenTo spi <$> checkExpr p e1 <*> checkExpr p e2 <*> checkExpr p e3
+checkExpr p (UnaryMinus            spi e) = UnaryMinus spi <$> checkExpr p e
+checkExpr p (Apply             spi e1 e2) =
+  Apply spi <$> checkExpr p e1 <*> checkExpr p e2
+checkExpr p (InfixApply     spi e1 op e2) =
+  InfixApply spi <$> checkExpr p e1 <*> checkOp op <*> checkExpr p e2
+checkExpr p (LeftSection        spi e op) =
+  LeftSection spi <$> checkExpr p e <*> checkOp op
+checkExpr p (RightSection       spi op e) =
+  RightSection spi <$> checkOp op <*> checkExpr p e
+checkExpr p (Lambda             spi ts e) = inNestedScope $ checkLambda p spi ts e
+checkExpr p (Let             spi li ds e) = inNestedScope $
+  Let spi li <$> checkDeclGroup bindVarDecl ds <*> checkExpr p e
+checkExpr p (Do             spi li sts e) = withLocalEnv $
+  Do spi li <$> mapM (checkStatement "do sequence" p) sts <*> checkExpr p e
+checkExpr p (IfThenElse     spi e1 e2 e3) =
+  IfThenElse spi <$> checkExpr p e1 <*> checkExpr p e2 <*> checkExpr p e3
+checkExpr p (Case       spi li ct e alts) =
+  Case spi li ct <$> checkExpr p e <*> mapM checkAlt alts
+
+checkLambda :: SpanInfo -> SpanInfo -> [Pattern ()] -> Expression ()
+            -> SCM (Expression ())
+checkLambda p spi ts e = case findMultiples (bvNoAnon ts) of
+  []      -> do
+    ts' <- mapM (bindPattern "lambda expression" p) ts
+    Lambda spi ts' <$> checkExpr p e
+  errVars -> do
+    mapM_ (report . errDuplicateVariables) errVars
+    let nubTs = nubBy (\t1 t2 -> (not . null) (on intersect bvNoAnon t1 t2)) ts
+    mapM_ (bindPattern "lambda expression" p) nubTs
+    Lambda spi ts <$> checkExpr p e
+  where
+    bvNoAnon t = filter (not . isAnonId) $ bv t
+
+checkVariable :: SpanInfo -> a -> QualIdent -> SCM (Expression a)
+checkVariable spi a v
+    -- anonymous free variable
+  | isAnonId (unqualify v) = do
+    checkAnonFreeVarsExtension $ getSpanInfo v
+    (\n -> Variable spi a $ updQualIdent id (`renameIdent` n) v) <$> newId
+    -- return $ Variable v
+    -- normal variable
+  | otherwise             = do
+    env <- getRenameEnv
+    case qualLookupVar v env of
+      []              -> do report $ errUndefinedVariable v
+                            return $ Variable spi a v
+      [Constr    _ _]   -> return $ Constructor spi a v
+      [GlobalVar f _]   -> addGlobalDep f >> return (Variable spi a v)
+      [LocalVar v' _]   -> return $ Variable spi a
+                                  $ qualify
+                                  $ spanInfoLike v' (qidIdent v)
+      [RecordLabel _ _] -> return $ Variable spi a v
+      rs -> do
+        m <- getModuleIdent
+        case qualLookupVar (qualQualify m v) env of
+          []              -> do report $ errAmbiguousIdent rs v
+                                return $ Variable spi a v
+          [Constr    _ _]   -> return $ Constructor spi a v
+          [GlobalVar f _]   -> addGlobalDep f >> return (Variable spi a v)
+          [LocalVar v' _]   -> return $ Variable spi a
+                                      $ qualify
+                                      $ spanInfoLike v' (qidIdent v)
+          [RecordLabel _ _] -> return $ Variable spi a v
+          rs'               -> do report $ errAmbiguousIdent rs' v
+                                  return $ Variable spi a v
+
+checkRecordExpr :: SpanInfo -> SpanInfo -> QualIdent -> [Field (Expression ())]
+                -> SCM (Expression ())
+checkRecordExpr _ spi c [] = do
+  m   <- getModuleIdent
+  env <- getRenameEnv
+  case qualLookupVar c env of
+    [Constr _ _] -> return $ Record spi () c []
+    rs           -> case qualLookupVar (qualQualify m c) env of
+      [Constr _ _] -> return $ Record spi () c []
+      rs'          -> if null rs && null rs'
+                         then do report $ errUndefinedData c
+                                 return $ Record spi () c []
+                         else do report $ errAmbiguousData rs c
+                                 return $ Record spi () c []
+checkRecordExpr p spi c fs =
+  checkExpr p (RecordUpdate spi (Constructor (getSpanInfo c) () c)
+                fs)
+
+checkRecordUpdExpr :: SpanInfo -> SpanInfo -> Expression ()
+                   -> [Field (Expression ())] -> SCM (Expression ())
+checkRecordUpdExpr p spi e fs = do
+  e'  <- checkExpr p e
+  fs' <- mapM (checkField (checkExpr p)) fs
+  case e' of
+    Constructor _ a c -> do checkFieldLabels "construction" p (Just c) fs'
+                            return $ Record spi a c fs'
+    _                 -> do checkFieldLabels "update" p Nothing fs'
+                            return $ RecordUpdate spi e' fs'
+
+-- * Because patterns or decls eventually introduce new variables, the
+--   scope has to be nested one level.
+-- * Because statements are processed list-wise, inNestedEnv can not be
+--   used as this nesting must be visible to following statements.
+checkStatement :: String -> SpanInfo -> Statement () -> SCM (Statement ())
+checkStatement _ p (StmtExpr spi     e) = StmtExpr spi <$> checkExpr p e
+checkStatement s p (StmtBind spi   t e) =
+  flip (StmtBind spi) <$> checkExpr p e <*> (incNesting >> bindPattern s p t)
+checkStatement _ _ (StmtDecl spi li ds) =
+  StmtDecl spi li <$> (incNesting >> checkDeclGroup bindVarDecl ds)
+
+bindPattern :: String -> SpanInfo -> Pattern () -> SCM (Pattern ())
+bindPattern s p t = do
+  t' <- checkPattern p t
+  banFPTerm s p t'
+  addBoundVariables True t'
+
+banFPTerm :: String -> SpanInfo -> Pattern a -> SCM ()
+banFPTerm _ _ (LiteralPattern           _ _ _) = ok
+banFPTerm _ _ (NegativePattern          _ _ _) = ok
+banFPTerm _ _ (VariablePattern          _ _ _) = ok
+banFPTerm s p (ConstructorPattern    _ _ _ ts) = mapM_ (banFPTerm s p) ts
+banFPTerm s p (InfixPattern       _ _ t1 _ t2) = mapM_ (banFPTerm s p) [t1, t2]
+banFPTerm s p (ParenPattern               _ t) = banFPTerm s p t
+banFPTerm s p (RecordPattern         _ _ _ fs) = mapM_ banFPTermField fs
+  where banFPTermField (Field _ _ x) = banFPTerm s p x
+banFPTerm s p (TuplePattern              _ ts) = mapM_ (banFPTerm s p) ts
+banFPTerm s p (ListPattern             _ _ ts) = mapM_ (banFPTerm s p) ts
+banFPTerm s p (AsPattern                _ _ t) = banFPTerm s p t
+banFPTerm s p (LazyPattern                _ t) = banFPTerm s p t
+banFPTerm s p pat@(FunctionPattern    _ _ _ _)
+ = report $ errUnsupportedFuncPattern s p pat
+banFPTerm s p pat@(InfixFuncPattern _ _ _ _ _)
+ = report $ errUnsupportedFuncPattern s p pat
+
+checkOp :: InfixOp a -> SCM (InfixOp a)
+checkOp op = do
+  env <- getRenameEnv
+  case qualLookupVar v env of
+    []              -> report (errUndefinedVariable v) >> return op
+    [Constr _ _]    -> return $ InfixConstr a v
+    [GlobalVar f _] -> addGlobalDep f >> return (InfixOp a v)
+    [LocalVar v' _] -> return $ InfixOp a $ qualify v'
+    rs              -> do
+      m <- getModuleIdent
+      case qualLookupVar (qualQualify m v) env of
+        []              -> report (errAmbiguousIdent rs v) >> return op
+        [Constr _ _]    -> return $ InfixConstr a v
+        [GlobalVar f _] -> addGlobalDep f >> return (InfixOp a v)
+        [LocalVar v' _] -> return $ InfixOp a $ qualify v'
+        rs'             -> report (errAmbiguousIdent rs' v) >> return op
+  where v = opName op
+        a = opAnnotation op
+
+checkAlt :: Alt () -> SCM (Alt ())
+checkAlt (Alt spi t rhs) = inNestedScope $
+  Alt spi <$> bindPattern "case expression" spi t <*> checkRhs rhs
+
+addBoundVariables :: (QuantExpr t) => Bool -> t -> SCM t
+addBoundVariables checkDuplicates ts = do
+  when checkDuplicates $ mapM_ (report . errDuplicateVariables)
+                               (findMultiples bvs)
+  modifyRenameEnv $ \ env -> foldr bindVar env (nub bvs)
+  return ts
+  where bvs = bv ts
+
+-- For record patterns and expressions the compiler checks that all field
+-- labels belong to the pattern or expression's constructor. For record
+-- update expressions, the compiler checks that there is at least one
+-- constructor which has all the specified field labels. In addition, the
+-- compiler always checks that no field label occurs twice. Field labels
+-- are always looked up in the global environment since they cannot be
+-- shadowed by local variables (cf.\ Sect.~3.15.1 of the revised
+-- Haskell'98 report~\cite{PeytonJones03:Haskell}).
+
+checkFieldLabels :: String -> SpanInfo -> Maybe QualIdent -> [Field a] -> SCM ()
+checkFieldLabels what p c fs = do
+  mapM checkFieldLabel ls' >>= checkLabels p c ls'
+  onJust (report . errDuplicateLabel what) (findDouble ls)
+  where ls  = [l | Field _ l _ <- fs]
+        ls' = nub ls
+        onJust = maybe ok
+
+checkFieldLabel :: QualIdent -> SCM [QualIdent]
+checkFieldLabel l = do
+  m   <- getModuleIdent
+  env <- getRenameEnv
+  case qualLookupVar l env of
+    [RecordLabel _ cs] -> processLabel cs
+    rs                 -> case qualLookupVar (qualQualify m l) env of
+      [RecordLabel _ cs] -> processLabel cs
+      rs'                -> if (null rs && null rs')
+                               then do report $ errUndefinedLabel l
+                                       return []
+                               else do report $
+                                         errAmbiguousIdent rs (qualQualify m l)
+                                       return []
+  where
+  processLabel cs' = do
+    when (null cs') $ report $ errUndefinedLabel l
+    return cs'
+
+checkLabels :: SpanInfo -> Maybe QualIdent -> [QualIdent] -> [[QualIdent]]
+            -> SCM ()
+checkLabels _ (Just c) ls css = do
+  env <- getRenameEnv
+  case qualLookupVar c env of
+    [Constr c' _] -> mapM_ (report . errNoLabel c)
+                           [l | (l, cs) <- zip ls css, c' `notElem` cs]
+    _             -> internalError $
+                       "Checks.SyntaxCheck.checkLabels: " ++ show c
+checkLabels p Nothing ls css
+  | not (null (foldr1 intersect css)) ||
+    any null css = ok
+  | otherwise    = report $ errNoCommonCons p ls
+
+checkField :: (a -> SCM a) -> Field a -> SCM (Field a)
+checkField check (Field p l x) = Field p l <$> check x
+
+-- ---------------------------------------------------------------------------
+-- Auxiliary definitions
+-- ---------------------------------------------------------------------------
+
+constrs :: Decl a -> [Ident]
+constrs (DataDecl    _ _ _ cs _) = map constrId cs
+constrs (NewtypeDecl _ _ _ nc _) = [nconstrId nc]
+constrs _                        = []
+
+vars :: Decl a -> [Ident]
+vars (TypeSig          _ fs _) = fs
+vars (FunctionDecl    _ _ f _) = [f]
+vars (ExternalDecl       _ vs) = bv vs
+vars (PatternDecl       _ t _) = bv t
+vars (FreeDecl           _ vs) = bv vs
+vars _                         = []
+
+recLabels :: Decl a -> [Ident]
+recLabels (DataDecl    _ _ _ cs _) = concatMap recordLabels cs
+recLabels (NewtypeDecl _ _ _ nc _) = nrecordLabels nc
+recLabels _                        = []
+
+-- Since the compiler expects all rules of the same function to be together,
+-- it is necessary to sort the list of declarations.
+
+sortFuncDecls :: [Decl a] -> [Decl a]
+sortFuncDecls = sortFD Set.empty []
+ where
+ sortFD _   res []              = reverse res
+ sortFD env res (decl : decls') = case decl of
+   FunctionDecl _ _ ident _
+    | ident `Set.member` env
+    -> sortFD env (insertBy cmpFuncDecl decl res) decls'
+    | otherwise
+    -> sortFD (Set.insert ident env) (decl:res) decls'
+   _    -> sortFD env (decl:res) decls'
+
+cmpFuncDecl :: Decl a -> Decl a -> Ordering
+cmpFuncDecl (FunctionDecl _ _ id1 _) (FunctionDecl _ _ id2 _)
+   | id1 == id2 = EQ
+   | otherwise  = GT
+cmpFuncDecl _ _ = GT
+
+-- Due to the lack of a capitalization convention in Curry, it is
+-- possible that an identifier may ambiguously refer to a data
+-- constructor and a function provided that both are imported from some
+-- other module. When checking whether an identifier denotes a
+-- constructor there are two options with regard to ambiguous
+-- identifiers:
+--   * Handle the identifier as a data constructor if at least one of
+--     the imported names is a data constructor.
+--   * Handle the identifier as a data constructor only if all imported
+--     entities are data constructors.
+-- We choose the first possibility here because in the second case a
+-- redefinition of a constructor can magically become possible if a
+-- function with the same name is imported. It seems better to warn
+-- the user about the fact that the identifier is ambiguous.
+
+isDataConstr :: Ident -> RenameEnv -> Bool
+isDataConstr v = any isConstr . lookupVar v . globalEnv . toplevelEnv
+
+isConstr :: RenameInfo -> Bool
+isConstr (Constr      _ _) = True
+isConstr (GlobalVar   _ _) = False
+isConstr (LocalVar    _ _) = False
+isConstr (RecordLabel _ _) = False
+
+isLabel :: RenameInfo -> Bool
+isLabel (Constr      _ _) = False
+isLabel (GlobalVar   _ _) = False
+isLabel (LocalVar    _ _) = False
+isLabel (RecordLabel _ _) = True
+
+-- varIdent :: RenameInfo -> Ident
+-- varIdent (GlobalVar _ v) = unqualify v
+-- varIdent (LocalVar  _ v) = v
+-- varIdent _ = internalError "SyntaxCheck.varIdent: no variable"
+
+qualVarIdent :: RenameInfo -> QualIdent
+qualVarIdent (GlobalVar v _) = v
+qualVarIdent (LocalVar  v _) = qualify v
+qualVarIdent _ = internalError "SyntaxCheck.qualVarIdent: no variable"
+
+checkFPTerm :: SpanInfo -> Pattern a -> SCM ()
+checkFPTerm _ (LiteralPattern        _ _ _) = ok
+checkFPTerm _ (NegativePattern       _ _ _) = ok
+checkFPTerm _ (VariablePattern       _ _ _) = ok
+checkFPTerm p (ConstructorPattern _ _ _ ts) = mapM_ (checkFPTerm p) ts
+checkFPTerm p (InfixPattern    _ _ t1 _ t2) = mapM_ (checkFPTerm p) [t1, t2]
+checkFPTerm p (ParenPattern            _ t) = checkFPTerm p t
+checkFPTerm p (TuplePattern           _ ts) = mapM_ (checkFPTerm p) ts
+checkFPTerm p (ListPattern          _ _ ts) = mapM_ (checkFPTerm p) ts
+checkFPTerm p (AsPattern             _ _ t) = checkFPTerm p t
+checkFPTerm p t@(LazyPattern           _ _) =
+  report $ errUnsupportedFPTerm "Lazy" p t
+checkFPTerm p (RecordPattern      _ _ _ fs) = mapM_ (checkFPTerm p)
+                                            [ t | Field _ _ t <- fs ]
+checkFPTerm _ (FunctionPattern     _ _ _ _) = ok -- do not check again
+checkFPTerm _ (InfixFuncPattern  _ _ _ _ _) = ok -- do not check again
+
+-- ---------------------------------------------------------------------------
+-- Miscellaneous functions
+-- ---------------------------------------------------------------------------
+
+checkFuncPatsExtension :: SpanInfo -> SCM ()
+checkFuncPatsExtension spi = checkUsedExtension spi
+  "Functional Patterns" FunctionalPatterns
+
+checkAnonFreeVarsExtension :: SpanInfo -> SCM ()
+checkAnonFreeVarsExtension spi = checkUsedExtension spi
+  "Anonymous free variables" AnonFreeVars
+
+checkUsedExtension :: SpanInfo -> String -> KnownExtension -> SCM ()
+checkUsedExtension spi msg ext = do
+  enabled <- hasExtension ext
+  unless enabled $ do
+    report $ errMissingLanguageExtension spi msg ext
+    enableExtension ext -- to avoid multiple warnings
+
+typeArity :: TypeExpr -> Int
+typeArity (ArrowType _ _ t2) = 1 + typeArity t2
+typeArity _                  = 0
+
+getFlatLhs :: Equation a -> (Ident, [Pattern a])
+getFlatLhs (Equation  _ lhs _) = flatLhs lhs
+
+opAnnotation :: InfixOp a -> a
+opAnnotation (InfixOp     a _) = a
+opAnnotation (InfixConstr a _) = a
+
+-- ---------------------------------------------------------------------------
+-- Error messages
+-- ---------------------------------------------------------------------------
+
+errUnsupportedFPTerm :: String -> SpanInfo -> Pattern a -> Message
+errUnsupportedFPTerm s spi pat = spanInfoMessage spi $ text s
+  <+> text "patterns are not supported inside a functional pattern."
+  $+$ pPrintPrec 0 pat
+
+errUnsupportedFuncPattern :: String -> SpanInfo -> Pattern a -> Message
+errUnsupportedFuncPattern s spi pat = spanInfoMessage spi $
+  text "Functional patterns are not supported inside a" <+> text s <> dot
+  $+$ pPrintPrec 0 pat
+
+errFuncPatNotGlobal :: QualIdent -> Message
+errFuncPatNotGlobal f = spanInfoMessage f $ hsep $ map text
+  ["Function", escQualName f, "in functional pattern is not global"]
+
+errFuncPatCyclic :: QualIdent -> QualIdent -> Message
+errFuncPatCyclic fp f = spanInfoMessage fp $ hsep $ map text
+  [ "Function", escName $ unqualify fp, "used in functional pattern depends on"
+  , escName $ unqualify f, " causing a cyclic dependency"]
+
+errPrecedenceOutOfRange :: SpanInfo -> Integer -> Message
+errPrecedenceOutOfRange spi i = spanInfoMessage spi $ hsep $ map text
+  ["Precedence out of range:", show i]
+
+errUndefinedVariable :: QualIdent -> Message
+errUndefinedVariable v = spanInfoMessage v $ hsep $ map text
+  [escQualName v, "is undefined"]
+
+errUndefinedData :: QualIdent -> Message
+errUndefinedData c = spanInfoMessage c $ hsep $ map text
+  ["Undefined data constructor", escQualName c]
+
+errUndefinedLabel :: QualIdent -> Message
+errUndefinedLabel l = spanInfoMessage l $  hsep $ map text
+  ["Undefined record label", escQualName l]
+
+errUndefinedMethod :: QualIdent -> Ident -> Message
+errUndefinedMethod qcls f = spanInfoMessage f $ hsep $ map text
+  [escName f, "is not a (visible) method of class", escQualName qcls]
+
+errAmbiguousIdent :: [RenameInfo] -> QualIdent -> Message
+errAmbiguousIdent rs qn | any isConstr rs = errAmbiguousData rs qn
+                        | any isLabel  rs = errAmbiguousLabel rs qn
+                        | otherwise       = errAmbiguous "variable" rs qn
+
+errAmbiguousData :: [RenameInfo] -> QualIdent -> Message
+errAmbiguousData = errAmbiguous "data constructor"
+
+errAmbiguousLabel :: [RenameInfo] -> QualIdent -> Message
+errAmbiguousLabel = errAmbiguous "field label"
+
+errAmbiguous :: String -> [RenameInfo] -> QualIdent -> Message
+errAmbiguous what rs qn = spanInfoMessage qn
+  $   text "Ambiguous" <+> text what <+> text (escQualName qn)
+  $+$ text "It could refer to:"
+  $+$ nest 2 (vcat (map ppRenameInfo rs))
+
+errDuplicateDefinition :: Ident -> Message
+errDuplicateDefinition v = spanInfoMessage v $ hsep $ map text
+  ["More than one definition for", escName v]
+
+errDuplicateVariables :: [Ident] -> Message
+errDuplicateVariables [] = internalError
+  "SyntaxCheck.errDuplicateVariables: empty list"
+errDuplicateVariables (v:vs) = spanInfoMessage v $
+  text (escName v) <+> text "occurs more than one in pattern at:" $+$
+  nest 2 (vcat (map (ppPosition . getPosition) (v:vs)))
+
+errMultipleDataConstructor :: [Ident] -> Message
+errMultipleDataConstructor [] = internalError
+  "SyntaxCheck.errMultipleDataDeclaration: empty list"
+errMultipleDataConstructor (i:is) = spanInfoMessage i $
+  text "Multiple definitions for data/record constructor" <+> text (escName i)
+  <+> text "at:" $+$
+  nest 2 (vcat (map (ppPosition . getPosition) (i:is)))
+
+errMultipleDeclarations :: ModuleIdent -> [Ident] -> Message
+errMultipleDeclarations _ [] = internalError
+  "SyntaxCheck.errMultipleDeclarations: empty list"
+errMultipleDeclarations m (i:is) = spanInfoMessage i $
+  text "Multiple declarations of" <+> text (escQualName (qualifyWith m i))
+  $+$ text "Declared at:" $+$
+  nest 2 (vcat (map (ppPosition . getPosition) (i:is)))
+
+errDuplicateTypeSig :: [Ident] -> Message
+errDuplicateTypeSig [] = internalError
+  "SyntaxCheck.errDuplicateTypeSig: empty list"
+errDuplicateTypeSig (v:vs) = spanInfoMessage v $
+  text "More than one type signature for" <+> text (escName v)
+  <+> text "at:" $+$
+  nest 2 (vcat (map (ppPosition . getPosition) (v:vs)))
+
+errDuplicateLabel :: String -> QualIdent -> Message
+errDuplicateLabel what l = spanInfoMessage l $ hsep $ map text
+  ["Field label", escQualName l, "occurs more than once in record", what]
+
+errNonVariable :: String -> Ident -> Message
+errNonVariable what c = spanInfoMessage c $ hsep $ map text
+  ["Data constructor", escName c, "in left hand side of", what]
+
+errNoBody :: Ident -> Message
+errNoBody v = spanInfoMessage v $  hsep $ map text ["No body for", escName v]
+
+errNoCommonCons :: SpanInfo -> [QualIdent] -> Message
+errNoCommonCons spi ls = spanInfoMessage spi $
+  text "No constructor has all of these fields:"
+  $+$ nest 2 (vcat (map (text . escQualName) ls))
+
+errNoLabel :: QualIdent -> QualIdent -> Message
+errNoLabel c l = spanInfoMessage l $ hsep $ map text
+  [escQualName l, "is not a field label of constructor", escQualName c]
+
+errNoTypeSig :: Ident -> Message
+errNoTypeSig f = spanInfoMessage f $ hsep $ map text
+  ["No type signature for external function", escName f]
+
+errToplevelPattern :: SpanInfo -> Message
+errToplevelPattern spi = spanInfoMessage spi $ text
+  "Pattern declaration not allowed at top-level"
+
+errDifferentArity :: [Ident] -> Message
+errDifferentArity [] = internalError
+  "SyntaxCheck.errDifferentArity: empty list"
+errDifferentArity (i:is) = spanInfoMessage i $
+  text "Equations for" <+> text (escName i) <+> text "have different arities"
+  <+> text "at:" $+$
+  nest 2 (vcat (map (ppPosition . getPosition) (i:is)))
+
+errWrongArity :: QualIdent -> Int -> Int -> Message
+errWrongArity c arity' argc = spanInfoMessage c $ hsep (map text
+  ["Data constructor", escQualName c, "expects", arguments arity'])
+  <> comma <+> text "but is applied to" <+> text (show argc)
+  where arguments 0 = "no arguments"
+        arguments 1 = "1 argument"
+        arguments n = show n ++ " arguments"
+
+errMissingLanguageExtension :: SpanInfo -> String -> KnownExtension -> Message
+errMissingLanguageExtension spi what ext = spanInfoMessage spi $
+  text what <+> text "are not supported in standard Curry." $+$
+  nest 2 (text "Use flag or -X" <+> text (show ext)
+          <+> text "to enable this extension.")
+
+errInfixWithoutParens :: SpanInfo -> [(QualIdent, QualIdent)] -> Message
+errInfixWithoutParens spi calls = spanInfoMessage spi $
+  text "Missing parens in infix patterns:" $+$
+  vcat (map showCall calls)
+  where
+  showCall (q1, q2) = showWithPos q1 <+> text "calls" <+> showWithPos q2
+  showWithPos q =  text (qualName q)
+               <+> parens (text $ showLine $ getPosition q)
diff --git a/src/Checks/TypeCheck.hs b/src/Checks/TypeCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/TypeCheck.hs
@@ -0,0 +1,1874 @@
+{- |
+    Module      :  $Header$
+    Description :  Type checking Curry programs
+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux
+                                   Martin Engelke
+                       2011 - 2015 Björn Peemöller
+                       2014 - 2015 Jan Tikovsky
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   This module implements the type checker of the Curry compiler. The
+   type checker is invoked after the syntactic correctness of the program
+   has been verified and kind checking has been applied to all type
+   expressions. Local variables have been renamed already. Thus the
+   compiler can maintain a flat type environment. The type checker now
+   checks the correct typing of all expressions and also verifies that
+   the type signatures given by the user match the inferred types. The
+   type checker uses the algorithm by Damas and Milner (1982) for inferring
+   the types of unannotated declarations, but allows for polymorphic
+   recursion when a type annotation is present.
+
+   The result of type checking is a (flat) top-level environment
+   containing the types of all constructors, variables, and functions
+   defined at the top level of a module. In addition, a type annotated
+   source module is returned. Note that type annotations on the
+   left hand side of a declaration hold the function or variable's
+   generalized type with the type scheme's universal quantifier left
+   implicit. Type annotations on the right hand side of a declaration
+   hold the particular instance at which a polymorphic function or
+   variable is used.
+-}
+{-# LANGUAGE CPP #-}
+module Checks.TypeCheck (typeCheck) where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative        ((<$>), (<*>))
+#endif
+import           Control.Monad.Trans (lift)
+import           Control.Monad.Extra (allM, filterM, foldM, liftM, (&&^),
+                                      notM, replicateM, when, unless, unlessM)
+import qualified Control.Monad.State as S
+                                     (State, StateT, get, gets, put, modify,
+                                      runState, evalStateT)
+import           Data.Function       (on)
+import           Data.List           (nub, nubBy, partition, sortBy, (\\))
+import qualified Data.Map            as Map (Map, empty, insert, lookup)
+import           Data.Maybe                 (fromJust, fromMaybe, isJust)
+import qualified Data.Set.Extra      as Set ( Set, concatMap, deleteMin, empty
+                                            , fromList, insert, member
+                                            , notMember, partition, singleton
+                                            , toList, union, unions )
+
+import Curry.Base.Ident
+import Curry.Base.Pretty
+import Curry.Base.SpanInfo
+import Curry.Syntax
+import Curry.Syntax.Pretty
+
+import Base.CurryTypes
+import Base.Expr
+import Base.Kinds
+import Base.Messages (Message, spanInfoMessage, internalError)
+import Base.SCC
+import Base.TopEnv
+import Base.TypeExpansion
+import Base.Types
+import Base.TypeSubst
+import Base.Utils (foldr2, fst3, snd3, thd3, uncurry3, mapAccumM)
+
+import Env.Class
+import Env.Instance
+import Env.TypeConstructor
+import Env.Value
+
+-- Type checking proceeds as follows. First, the types of all data
+-- constructors, field labels and class methods are entered into the
+-- value environment and then a type inference for all function and
+-- value definitions is performed.
+
+typeCheck :: ModuleIdent -> TCEnv -> ValueEnv -> ClassEnv -> InstEnv -> [Decl a]
+          -> ([Decl PredType], ValueEnv, [Message])
+typeCheck m tcEnv vEnv clsEnv inEnv ds = runTCM (checkDecls ds) initState
+  where initState = TcState m tcEnv vEnv clsEnv (inEnv, Map.empty)
+                            [intType, floatType] idSubst emptySigEnv 1 []
+
+checkDecls :: [Decl a] -> TCM [Decl PredType]
+checkDecls ds = do
+  bindConstrs
+  mapM_ checkFieldLabel (filter isTypeDecl ds) &&> bindLabels
+  bindClassMethods
+  mapM_ setDefaults $ filter isDefaultDecl ds
+  (_, bpds') <- tcPDecls bpds
+  tpds' <- mapM tcTopPDecl tpds
+  theta <- getTypeSubst
+  return $ map (fmap $ subst theta) $ fromPDecls $ tpds' ++ bpds'
+  where (bpds, tpds) = partition (isBlockDecl . snd) $ toPDecls ds
+
+-- The type checker makes use of a state monad in order to maintain the value
+-- environment, the current substitution, and a counter which is used for
+-- generating fresh type variables.
+
+-- Additionally, an extended instance environment is used in order to handle
+-- the introduction of local instances when matching a data constructor with a
+-- non-empty context. This extended instance environment is composed of the
+-- static top-level environment and a dynamic environment that maps each class
+-- on the instances which are in scope for it. The rationale behind using this
+-- representation is that it makes it easy to apply the current substitution to
+-- the dynamic part of the environment.
+
+type TCM = S.State TcState
+
+type InstEnv' = (InstEnv, Map.Map QualIdent [Type])
+
+data TcState = TcState
+  { moduleIdent  :: ModuleIdent -- read only
+  , tyConsEnv    :: TCEnv
+  , valueEnv     :: ValueEnv
+  , classEnv     :: ClassEnv
+  , instEnv      :: InstEnv'    -- instances (static and dynamic)
+  , defaultTypes :: [Type]
+  , typeSubst    :: TypeSubst
+  , sigEnv       :: SigEnv
+  , nextId       :: Int         -- automatic counter
+  , errors       :: [Message]
+  }
+
+(&&>) :: TCM () -> TCM () -> TCM ()
+pre &&> suf = do
+  errs <- pre >> S.gets errors
+  when (null errs) suf
+
+(>>-) :: Monad m => m (a, b, c) -> (a -> b -> m a) -> m (a, c)
+m >>- f = do
+  (u, v, w) <- m
+  u' <- f u v
+  return (u', w)
+
+(>>=-) :: TCM (a, b, d) -> (b -> TCM c) -> TCM (a, c, d)
+m >>=- f = do
+  (u, v, x) <- m
+  w <- f v
+  return (u, w, x)
+
+runTCM :: TCM a -> TcState -> (a, ValueEnv, [Message])
+runTCM tcm ts = let (a, s') = S.runState tcm ts
+               in  (a, typeSubst s' `subst` valueEnv s', reverse $ errors s')
+
+getModuleIdent :: TCM ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+getTyConsEnv :: TCM TCEnv
+getTyConsEnv = S.gets tyConsEnv
+
+getValueEnv :: TCM ValueEnv
+getValueEnv = S.gets valueEnv
+
+modifyValueEnv :: (ValueEnv -> ValueEnv) -> TCM ()
+modifyValueEnv f = S.modify $ \s -> s { valueEnv = f $ valueEnv s }
+
+withLocalValueEnv :: TCM a -> TCM a
+withLocalValueEnv act = do
+  oldEnv <- getValueEnv
+  res <- act
+  modifyValueEnv $ const oldEnv
+  return res
+
+getClassEnv :: TCM ClassEnv
+getClassEnv = S.gets classEnv
+
+getInstEnv :: TCM InstEnv'
+getInstEnv = S.gets instEnv
+
+modifyInstEnv :: (InstEnv' -> InstEnv') -> TCM ()
+modifyInstEnv f = S.modify $ \s -> s { instEnv = f $ instEnv s }
+
+getDefaultTypes :: TCM [Type]
+getDefaultTypes = S.gets defaultTypes
+
+setDefaultTypes :: [Type] -> TCM ()
+setDefaultTypes tys = S.modify $ \s -> s { defaultTypes = tys }
+
+getTypeSubst :: TCM TypeSubst
+getTypeSubst = S.gets typeSubst
+
+modifyTypeSubst :: (TypeSubst -> TypeSubst) -> TCM ()
+modifyTypeSubst f = S.modify $ \s -> s { typeSubst = f $ typeSubst s }
+
+getSigEnv :: TCM SigEnv
+getSigEnv = S.gets sigEnv
+
+setSigEnv :: SigEnv -> TCM ()
+setSigEnv sigs = S.modify $ \s -> s { sigEnv = sigs }
+
+withLocalSigEnv :: TCM a -> TCM a
+withLocalSigEnv act = do
+  oldSigs <- getSigEnv
+  res <- act
+  setSigEnv oldSigs
+  return res
+
+getNextId :: TCM Int
+getNextId = do
+  nid <- S.gets nextId
+  S.modify $ \s -> s { nextId = succ nid }
+  return nid
+
+report :: Message -> TCM ()
+report err = S.modify $ \s -> s { errors = err : errors s }
+
+ok :: TCM ()
+ok = return ()
+
+-- Because the type check may mess up the order of the declarations, we
+-- associate each declaration with a number. At the end of the type check,
+-- we can use these numbers to restore the original declaration order.
+
+type PDecl a = (Int, Decl a)
+
+toPDecls :: [Decl a] -> [PDecl a]
+toPDecls = zip [0 ..]
+
+fromPDecls :: [PDecl a] -> [Decl a]
+fromPDecls = map snd . sortBy (compare `on` fst)
+
+-- During the type check we also have to convert the type of declarations
+-- without annotations which is done by the function 'untyped' below.
+
+untyped :: PDecl a -> PDecl b
+untyped = fmap $ fmap $ internalError "TypeCheck.untyped"
+
+-- Defining Data Constructors:
+-- In the next step, the types of all data constructors are entered into
+-- the value environment using the information entered into the type constructor
+-- environment before.
+
+bindConstrs :: TCM ()
+bindConstrs = do
+  m <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  modifyValueEnv $ bindConstrs' m tcEnv
+
+bindConstrs' :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv
+bindConstrs' m tcEnv vEnv = foldr (bindData . snd) vEnv $ localBindings tcEnv
+  where
+    bindData (DataType tc k cs) vEnv' =
+      let n = kindArity k in foldr (bindConstr m n (constrType' tc n)) vEnv' cs
+    bindData (RenamingType tc k c) vEnv' =
+      let n = kindArity k in bindNewConstr m n (constrType' tc n) c vEnv'
+    bindData _ vEnv' = vEnv'
+
+bindConstr :: ModuleIdent -> Int -> Type -> DataConstr -> ValueEnv -> ValueEnv
+bindConstr m n ty (DataConstr c tys) =
+  bindGlobalInfo (\qc tyScheme -> DataConstructor qc arity ls tyScheme) m c
+                 (ForAll n (PredType emptyPredSet (foldr TypeArrow ty tys)))
+  where arity = length tys
+        ls    = replicate arity anonId
+bindConstr m n ty (RecordConstr c ls tys) =
+  bindGlobalInfo (\qc tyScheme -> DataConstructor qc arity ls tyScheme) m c
+                 (ForAll n (PredType emptyPredSet (foldr TypeArrow ty tys)))
+  where arity = length tys
+
+bindNewConstr :: ModuleIdent -> Int -> Type -> DataConstr -> ValueEnv
+              -> ValueEnv
+bindNewConstr m n cty (DataConstr c [lty]) =
+  bindGlobalInfo (\qc tyScheme -> NewtypeConstructor qc anonId tyScheme) m c
+                 (ForAll n (predType (TypeArrow lty cty)))
+bindNewConstr m n cty (RecordConstr c [l] [lty]) =
+  bindGlobalInfo (\qc tyScheme -> NewtypeConstructor qc l tyScheme) m c
+                 (ForAll n (predType (TypeArrow lty cty)))
+bindNewConstr _ _ _ _ = internalError
+  "TypeCheck.bindConstrs'.bindNewConstr: newtype with illegal constructors"
+
+constrType' :: QualIdent -> Int -> Type
+constrType' tc n =
+  applyType (TypeConstructor tc) $ map TypeVariable [0 .. n - 1]
+
+-- When a field label occurs in more than one constructor declaration of
+-- a data type, the compiler ensures that the label is defined
+-- consistently, i.e. both occurrences have the same type. In addition,
+-- the compiler ensures that no existentially quantified type variable occurs
+-- in the type of a field label because such type variables necessarily escape
+-- their scope with the type of the record selection function associated with
+-- the field label.
+
+checkFieldLabel :: Decl a -> TCM ()
+checkFieldLabel (DataDecl _ _ tvs cs _) = do
+  ls' <- mapM (tcFieldLabel tvs) labels
+  mapM_ tcFieldLabels (groupLabels ls')
+  where labels = [(l, p, ty) | RecordDecl _ _ fs <- cs,
+                               FieldDecl p ls ty <- fs, l <- ls]
+checkFieldLabel (NewtypeDecl _ _ tvs (NewRecordDecl p _ (l, ty)) _) = do
+  _ <- tcFieldLabel tvs (l, p, ty)
+  ok
+checkFieldLabel _ = ok
+
+tcFieldLabel :: HasSpanInfo p => [Ident] -> (Ident, p, TypeExpr)
+             -> TCM (Ident, p, Type)
+tcFieldLabel tvs (l, p, ty) = do
+  m <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  let ForAll n (PredType _ ty') = polyType $ expandMonoType m tcEnv tvs ty
+  unless (n <= length tvs) $ report $ errSkolemFieldLabel p l
+  return (l, p, ty')
+
+groupLabels :: Eq a => [(a, b, c)] -> [(a, b, [c])]
+groupLabels []               = []
+groupLabels ((x, y, z):xyzs) =
+  (x, y, z : map thd3 xyzs') : groupLabels xyzs''
+  where (xyzs', xyzs'') = partition ((x ==) . fst3) xyzs
+
+tcFieldLabels :: HasSpanInfo p => (Ident, p, [Type]) -> TCM ()
+tcFieldLabels (_, _, [])     = return ()
+tcFieldLabels (l, p, ty:tys) = unless (not (any (ty /=) tys)) $ do
+  m <- getModuleIdent
+  report $ errIncompatibleLabelTypes p m l ty (head tys)
+
+-- Defining Field Labels:
+-- Next the types of all field labels are added to the value environment.
+
+bindLabels :: TCM ()
+bindLabels = do
+  m <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  modifyValueEnv $ bindLabels' m tcEnv
+
+bindLabels' :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv
+bindLabels' m tcEnv vEnv = foldr (bindData . snd) vEnv $ localBindings tcEnv
+  where
+    bindData (DataType tc k cs) vEnv' =
+      foldr (bindLabel m n (constrType' tc n)) vEnv' $ nubBy sameLabel clabels
+      where
+        n = kindArity k
+        labels = zip (concatMap recLabels cs) (concatMap recLabelTypes cs)
+        clabels = [(l, constr l, ty) | (l, ty) <- labels]
+        constr l = [qualifyLike tc (constrIdent c)
+                     | c <- cs, l `elem` recLabels c]
+        sameLabel (l1, _, _) (l2, _, _) = l1 == l2
+    bindData (RenamingType tc k (RecordConstr c [l] [lty])) vEnv'
+      = bindLabel m n (constrType' tc n) (l, [qc], lty) vEnv'
+      where
+        n = kindArity k
+        qc = qualifyLike tc c
+    bindData (RenamingType _ _ (RecordConstr _ _ _)) _ =
+      internalError $ "Checks.TypeCheck.bindLabels'.bindData: " ++
+        "RenamingType with more than one record label"
+    bindData _ vEnv' = vEnv'
+
+bindLabel :: ModuleIdent -> Int -> Type -> (Ident, [QualIdent], Type)
+          -> ValueEnv -> ValueEnv
+bindLabel m n ty (l, lcs, lty) =
+  bindGlobalInfo (\qc tyScheme -> Label qc lcs tyScheme) m l
+                 (ForAll n (predType (TypeArrow ty lty)))
+
+-- Defining class methods:
+-- Last, the types of all class methods are added to the value environment.
+
+bindClassMethods :: TCM ()
+bindClassMethods = do
+  m <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  modifyValueEnv $ bindClassMethods' m tcEnv
+
+bindClassMethods' :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv
+bindClassMethods' m tcEnv vEnv =
+  foldr (bindMethods . snd) vEnv $ localBindings tcEnv
+  where
+    bindMethods (TypeClass cls _ ms) vEnv' =
+      foldr (bindClassMethod m cls) vEnv' ms
+    bindMethods _                    vEnv' =
+      vEnv'
+
+-- Since the implementations of class methods can differ in their arity,
+-- we assume an arity of 0 when we enter one into the value environment.
+
+bindClassMethod :: ModuleIdent -> QualIdent -> ClassMethod -> ValueEnv
+                -> ValueEnv
+bindClassMethod m cls (ClassMethod f _ ty) =
+  bindGlobalInfo (\qc tySc -> Value qc (Just cls) 0 tySc) m f (typeScheme ty)
+
+-- -----------------------------------------------------------------------------
+-- Default Types
+-- -----------------------------------------------------------------------------
+
+-- Default Types:
+-- The list of default types is given either by a default declaration in
+-- the source code or defaults to the predefined list of numeric data types.
+
+setDefaults :: Decl a -> TCM ()
+setDefaults (DefaultDecl _ tys) = mapM toDefaultType tys >>= setDefaultTypes
+  where
+    toDefaultType =
+      liftM snd . (inst =<<) . liftM typeScheme
+                . expandPoly . QualTypeExpr NoSpanInfo []
+setDefaults _ = ok
+
+-- Type Signatures:
+-- The type checker collects type signatures in a flat environment.
+-- The types are not expanded so that the signature is available for
+-- use in the error message that is printed when the inferred type is
+-- less general than the signature.
+
+type SigEnv = Map.Map Ident QualTypeExpr
+
+emptySigEnv :: SigEnv
+emptySigEnv = Map.empty
+
+bindTypeSig :: Ident -> QualTypeExpr -> SigEnv -> SigEnv
+bindTypeSig = Map.insert
+
+bindTypeSigs :: Decl a -> SigEnv -> SigEnv
+bindTypeSigs (TypeSig _ vs ty) env = foldr (`bindTypeSig` ty) env vs
+bindTypeSigs _                 env = env
+
+lookupTypeSig :: Ident -> SigEnv -> Maybe QualTypeExpr
+lookupTypeSig = Map.lookup
+
+-- Declaration groups:
+-- Before type checking a group of declarations, a dependency analysis is
+-- performed and the declaration group is eventually transformed into nested
+-- declaration groups which are checked separately. Within each declaration
+-- group, first the value environment is extended with new bindings for all
+-- variables and functions defined in the group. Next, types are inferred for
+-- all declarations without an explicit type signature and the inferred types
+-- are then generalized. Finally, the types of all explicitly typed declarations
+-- are checked.
+
+-- Within a group of mutually recursive declarations, all type variables that
+-- appear in the types of the variables defined in the group and whose type
+-- cannot be generalized must not be generalized in the other declarations of
+-- that group as well.
+
+tcDecls :: [Decl a] -> TCM (PredSet, [Decl PredType])
+tcDecls = fmap (fmap fromPDecls) . tcPDecls . toPDecls
+
+tcPDecls :: [PDecl a] -> TCM (PredSet, [PDecl PredType])
+tcPDecls pds = withLocalSigEnv $ do
+  let (vpds, opds) = partition (isValueDecl . snd) pds
+  setSigEnv $ foldr (bindTypeSigs . snd) emptySigEnv $ opds
+  m <- getModuleIdent
+  (ps, vpdss') <-
+    mapAccumM tcPDeclGroup emptyPredSet $ scc (bv . snd) (qfv m . snd) vpds
+  return (ps, map untyped opds ++ concat (vpdss' :: [[PDecl PredType]]))
+
+tcPDeclGroup :: PredSet -> [PDecl a] -> TCM (PredSet, [PDecl PredType])
+tcPDeclGroup ps [(i, ExternalDecl p fs)] = do
+  tys <- mapM (tcExternal . varIdent) fs
+  return (ps, [(i, ExternalDecl p (zipWith (fmap . const . predType) tys fs))])
+tcPDeclGroup ps [(i, FreeDecl p fvs)] = do
+  vs <- mapM (tcDeclVar False) (bv fvs)
+  m <- getModuleIdent
+  (vs', ps') <- unzip <$> mapM addDataPred vs
+  modifyValueEnv $ flip (bindVars m) vs'
+  let d = FreeDecl p (map (\(v, _, ForAll _ ty) -> Var ty v) vs')
+  return (ps `Set.union` Set.unions ps', [(i, d)])
+  where
+    addDataPred (idt, n, ForAll ids ty1) = do
+      (ps2, ty2) <- freshDataType
+      ps' <- unify idt "free variable" (ppIdent idt) emptyPredSet (unpredType ty1) ps2 ty2
+      return ((idt, n, ForAll ids ty1), ps')
+tcPDeclGroup ps pds = do
+  vEnv <- getValueEnv
+  vss <- mapM (tcDeclVars . snd) pds
+  m <- getModuleIdent
+  modifyValueEnv $ flip (bindVars m) $ concat vss
+  sigs <- getSigEnv
+  let (impPds, expPds) = partitionPDecls sigs pds
+  (ps', impPds') <- mapAccumM tcPDecl ps impPds
+  theta <- getTypeSubst
+  tvs <- concatMap (typeVars . subst theta . fst) <$>
+           filterM (notM . isNonExpansive . snd . snd) impPds'
+  let fvs = foldr Set.insert (fvEnv (subst theta vEnv)) tvs
+      (gps, lps) = splitPredSet fvs ps'
+  lps' <- foldM (uncurry . defaultPDecl fvs) lps impPds'
+  theta' <- getTypeSubst
+  let impPds'' = map (uncurry (fixType . gen fvs lps' . subst theta')) impPds'
+  modifyValueEnv $ flip (rebindVars m) (concatMap (declVars . snd) impPds'')
+  (ps'', expPds') <- mapAccumM (uncurry . tcCheckPDecl) gps expPds
+  return (ps'', impPds'' ++ expPds')
+
+partitionPDecls :: SigEnv -> [PDecl a] -> ([PDecl a], [(QualTypeExpr, PDecl a)])
+partitionPDecls sigs =
+  foldr (\pd -> maybe (implicit pd) (explicit pd) (typeSig $ snd pd)) ([], [])
+  where implicit pd ~(impPds, expPds) = (pd : impPds, expPds)
+        explicit pd qty ~(impPds, expPds) = (impPds, (qty, pd) : expPds)
+        typeSig (FunctionDecl _ _ f _) = lookupTypeSig f sigs
+        typeSig (PatternDecl _ (VariablePattern _ _ v) _) = lookupTypeSig v sigs
+        typeSig _ = Nothing
+
+bindVars :: ModuleIdent -> ValueEnv -> [(Ident, Int, TypeScheme)] -> ValueEnv
+bindVars m = foldr $ uncurry3 $ flip (bindFun m) Nothing
+
+rebindVars :: ModuleIdent -> ValueEnv -> [(Ident, Int, TypeScheme)] -> ValueEnv
+rebindVars m = foldr $ uncurry3 $ flip (rebindFun m) Nothing
+
+tcDeclVars :: Decl a -> TCM [(Ident, Int, TypeScheme)]
+tcDeclVars (FunctionDecl _ _ f eqs) = do
+  sigs <- getSigEnv
+  let n = eqnArity $ head eqs
+  case lookupTypeSig f sigs of
+    Just qty -> do
+      pty <- expandPoly qty
+      return [(f, n, typeScheme pty)]
+    Nothing -> do
+      tys <- replicateM (n + 1) freshTypeVar
+      return [(f, n, monoType $ foldr1 TypeArrow tys)]
+tcDeclVars (PatternDecl _ t _) = case t of
+  VariablePattern _ _ v -> return <$> tcDeclVar True v
+  _ -> mapM (tcDeclVar False) (bv t)
+tcDeclVars _ = internalError "TypeCheck.tcDeclVars"
+
+tcDeclVar :: Bool -> Ident -> TCM (Ident, Int, TypeScheme)
+tcDeclVar poly v = do
+  sigs <- getSigEnv
+  case lookupTypeSig v sigs of
+    Just qty
+      | poly || null (fv qty) -> do
+        pty <- expandPoly qty
+        return (v, 0, typeScheme pty)
+      | otherwise -> do
+        report $ errPolymorphicVar v
+        lambdaVar v
+    Nothing -> lambdaVar v
+
+tcPDecl :: PredSet -> PDecl a -> TCM (PredSet, (Type, PDecl PredType))
+tcPDecl ps (i, FunctionDecl p _ f eqs) = do
+  vEnv <- getValueEnv
+  tcFunctionPDecl i ps (varType f vEnv) p f eqs
+tcPDecl ps (i, d@(PatternDecl p t rhs)) = do
+  (ps', ty', t') <- tcPattern p t
+  (ps'', rhs') <- tcRhs rhs >>-
+    unifyDecl p "pattern declaration" (pPrint d) (ps `Set.union` ps') ty'
+  return (ps'', (ty', (i, PatternDecl p t' rhs')))
+tcPDecl _ _ = internalError "TypeCheck.tcPDecl"
+
+-- The function 'tcFunctionPDecl' ignores the context of a function's type
+-- signature. This prevents missing instance errors when the inferred type
+-- of a function is less general than the declared type.
+
+tcFunctionPDecl :: Int -> PredSet -> TypeScheme -> SpanInfo -> Ident
+                -> [Equation a] -> TCM (PredSet, (Type, PDecl PredType))
+tcFunctionPDecl i ps tySc@(ForAll _ pty) p f eqs = do
+  (_, ty) <- inst tySc
+  (ps', eqs') <- mapAccumM (tcEquation ty) ps eqs
+  return (ps', (ty, (i, FunctionDecl p pty f eqs')))
+
+tcEquation :: Type -> PredSet -> Equation a
+           -> TCM (PredSet, Equation PredType)
+tcEquation ty ps eqn@(Equation p lhs rhs) =
+  tcEqn p lhs rhs >>- unifyDecl p "equation" (pPrint eqn) ps ty
+
+tcEqn :: SpanInfo -> Lhs a -> Rhs a
+      -> TCM (PredSet, Type, Equation PredType)
+tcEqn p lhs rhs = do
+  (ps, tys, lhs', ps', ty, rhs') <- withLocalValueEnv $ do
+    bindLambdaVars lhs
+    (ps, tys, lhs') <- S.evalStateT (tcLhs p lhs) Set.empty
+    (ps', ty, rhs') <- tcRhs rhs
+    return (ps, tys, lhs', ps', ty, rhs')
+  ps'' <- reducePredSet p "equation" (pPrint (Equation p lhs' rhs'))
+                        (ps `Set.union` ps')
+  return (ps'', foldr TypeArrow ty tys, Equation p lhs' rhs')
+
+bindLambdaVars :: QuantExpr t => t -> TCM ()
+bindLambdaVars t = do
+  m <- getModuleIdent
+  vs <- mapM lambdaVar (nub $ bv t)
+  modifyValueEnv $ flip (bindVars m) vs
+
+lambdaVar :: Ident -> TCM (Ident, Int, TypeScheme)
+lambdaVar v = do
+  ty <- freshTypeVar
+  return (v, 0, monoType ty)
+
+unifyDecl :: HasSpanInfo p => p -> String -> Doc -> PredSet -> Type -> PredSet
+          -> Type
+          -> TCM PredSet
+unifyDecl p what doc psLhs tyLhs psRhs tyRhs = do
+  ps <- unify p what doc psLhs tyLhs psRhs tyRhs
+  fvs <- computeFvEnv
+  applyDefaultsDecl p what doc fvs ps tyLhs
+
+-- After inferring types for a group of mutually recursive declarations
+-- and computing the set of its constrained type variables, the compiler
+-- has to be prepared for some of the constrained type variables to not
+-- appear in some of the inferred types, i.e., there may be ambiguous
+-- types that have not been reported by 'unifyDecl' above at the level
+-- of individual function equations and pattern declarations.
+
+defaultPDecl :: Set.Set Int -> PredSet -> Type -> PDecl a -> TCM PredSet
+defaultPDecl fvs ps ty (_, FunctionDecl p _ f _) =
+  applyDefaultsDecl p ("function " ++ escName f) empty fvs ps ty
+defaultPDecl fvs ps ty (_, PatternDecl p t _) = case t of
+  VariablePattern _ _ v ->
+    applyDefaultsDecl p ("variable " ++ escName v) empty fvs ps ty
+  _ -> return ps
+defaultPDecl _ _ _ _ = internalError "TypeCheck.defaultPDecl"
+
+applyDefaultsDecl :: HasSpanInfo p => p -> String -> Doc -> Set.Set Int
+                  -> PredSet -> Type -> TCM PredSet
+applyDefaultsDecl p what doc fvs ps ty = do
+  theta <- getTypeSubst
+  let ty' = subst theta ty
+      fvs' = foldr Set.insert fvs $ typeVars ty'
+  applyDefaults p what doc fvs' ps ty'
+
+-- After 'tcDeclGroup' has generalized the types of the implicitly
+-- typed declarations of a declaration group it must update their left
+-- hand side type annotations and the type environment accordingly.
+-- Recall that the compiler generalizes only the types of variable and
+-- function declarations.
+
+fixType :: TypeScheme -> PDecl PredType -> PDecl PredType
+fixType ~(ForAll _ pty) (i, FunctionDecl p _ f eqs) =
+  (i, FunctionDecl p pty f eqs)
+fixType ~(ForAll _ pty) pd@(i, PatternDecl p t rhs) = case t of
+  VariablePattern spi _ v
+    -> (i, PatternDecl p (VariablePattern spi pty v) rhs)
+  _ -> pd
+fixType _ _ = internalError "TypeCheck.fixType"
+
+declVars :: Decl PredType -> [(Ident, Int, TypeScheme)]
+declVars (FunctionDecl _ pty f eqs) = [(f, eqnArity $ head eqs, typeScheme pty)]
+declVars (PatternDecl _ t _) = case t of
+  VariablePattern _ pty v -> [(v, 0, typeScheme pty)]
+  _ -> []
+declVars _ = internalError "TypeCheck.declVars"
+
+-- The function 'tcCheckPDecl' checks the type of an explicitly typed function
+-- or variable declaration. After inferring a type for the declaration, the
+-- inferred type is compared with the type signature. Since the inferred type
+-- of an explicitly typed function or variable declaration is automatically an
+-- instance of its type signature, the type signature is correct only if the
+-- inferred type matches the type signature exactly except for the inferred
+-- predicate set, which may contain only a subset of the declared context
+-- because the context of a function's type signature is ignored in the
+-- function 'tcFunctionPDecl' above.
+
+tcCheckPDecl :: PredSet -> QualTypeExpr -> PDecl a
+             -> TCM (PredSet, PDecl PredType)
+tcCheckPDecl ps qty pd = do
+  (ps', (ty, pd')) <- tcPDecl ps pd
+  fvs <- computeFvEnv
+  theta <- getTypeSubst
+  poly <- isNonExpansive $ snd pd
+  let (gps, lps) = splitPredSet fvs ps'
+      ty' = subst theta ty
+      tySc = if poly then gen fvs lps ty' else monoType ty'
+  checkPDeclType qty gps tySc pd'
+
+checkPDeclType :: QualTypeExpr -> PredSet -> TypeScheme -> PDecl PredType
+               -> TCM (PredSet, PDecl PredType)
+checkPDeclType qty ps tySc (i, FunctionDecl p _ f eqs) = do
+  pty <- expandPoly qty
+  unlessM (checkTypeSig pty tySc) $ do
+    m <- getModuleIdent
+    report $ errTypeSigTooGeneral m (text "Function:" <+> ppIdent f) qty tySc
+  return (ps, (i, FunctionDecl p pty f eqs))
+checkPDeclType qty ps tySc (i, PatternDecl p (VariablePattern spi _ v) rhs) = do
+  pty <- expandPoly qty
+  unlessM (checkTypeSig pty tySc) $ do
+    m <- getModuleIdent
+    report $ errTypeSigTooGeneral m (text "Variable:" <+> ppIdent v) qty tySc
+  return (ps, (i, PatternDecl p (VariablePattern spi pty v) rhs))
+checkPDeclType _ _ _ _ = internalError "TypeCheck.checkPDeclType"
+
+checkTypeSig :: PredType -> TypeScheme -> TCM Bool
+checkTypeSig (PredType sigPs sigTy) (ForAll _ (PredType ps ty)) = do
+  clsEnv <- getClassEnv
+  return $
+    ty `eqTypes` sigTy &&
+    all (`Set.member` maxPredSet clsEnv sigPs) (Set.toList ps)
+
+-- The function 'equTypes' computes whether two types are equal modulo
+-- renaming of type variables.
+-- WARNING: This operation is not reflexive and expects the second type to be
+-- the type signature provided by the programmer.
+eqTypes :: Type -> Type -> Bool
+eqTypes t1 t2 = fst (eq [] t1 t2)
+ where
+ -- @is@ is an AssocList of type variable indices
+ eq is (TypeConstructor   qid1) (TypeConstructor   qid2) = (qid1 == qid2, is)
+ eq is (TypeVariable        i1) (TypeVariable        i2)
+   | i1 < 0    = (False, is)
+   | otherwise = eqVar is i1 i2
+ eq is (TypeConstrained ts1 i1) (TypeConstrained ts2 i2)
+   = let (res1, is1) = eqs   is  ts1 ts2
+         (res2, is2) = eqVar is1 i1  i2
+     in  (res1 && res2, is2)
+ eq is (TypeApply      ta1 tb1) (TypeApply      ta2 tb2)
+   = let (res1, is1) = eq is  ta1 ta2
+         (res2, is2) = eq is1 tb1 tb2
+     in  (res1 && res2, is2)
+ eq is (TypeArrow      tf1 tt1) (TypeArrow      tf2 tt2)
+   = let (res1, is1) = eq is  tf1 tf2
+         (res2, is2) = eq is1 tt1 tt2
+     in  (res1 && res2, is2)
+ eq is (TypeForall     is1 t1') (TypeForall     is2 t2')
+   = let (res1, is') = eqs [] (map TypeVariable is1) (map TypeVariable is2)
+         (res2, _  ) = eq is' t1' t2'
+     in  (res1 && res2, is)
+ eq is _                        _                        = (False, is)
+
+ eqVar is i1 i2 = case lookup i1 is of
+   Nothing  -> (True, (i1, i2) : is)
+   Just i2' -> (i2 == i2', is)
+
+ eqs is []        []        = (True , is)
+ eqs is (t1':ts1) (t2':ts2)
+    = let (res1, is1) = eq  is t1'  t2'
+          (res2, is2) = eqs is1 ts1 ts2
+      in  (res1 && res2, is2)
+ eqs is _         _         = (False, is)
+
+-- In Curry, a non-expansive expression is either
+--
+-- * a literal,
+-- * a variable,
+-- * an application of a constructor with arity n to at most n
+--   non-expansive expressions,
+-- * an application of a function with arity n to at most n-1
+--   non-expansive expressions, or
+-- * a let expression whose body is a non-expansive expression and
+--   whose local declarations are either function declarations or
+--   variable declarations of the form x=e where e is a non-expansive
+--   expression, or
+-- * an expression whose desugared form is one of the above.
+--
+-- At first it may seem strange that variables are included in the list
+-- above because a variable may be bound to a logical variable. However,
+-- this is no problem because type variables that are present among the
+-- typing assumptions of the environment enclosing a let expression
+-- cannot be generalized.
+
+class Binding a where
+  isNonExpansive :: a -> TCM Bool
+
+instance Binding a => Binding [a] where
+  isNonExpansive = allM isNonExpansive
+
+instance Binding (Decl a) where
+  isNonExpansive (InfixDecl       _ _ _ _) = return True
+  isNonExpansive (TypeSig           _ _ _) = return True
+  isNonExpansive (FunctionDecl    _ _ _ _) = return True
+  isNonExpansive (ExternalDecl        _ _) = return True
+  isNonExpansive (PatternDecl       _ _ _) = return False
+    -- TODO: Uncomment when polymorphic let declarations are fully supported
+  {-isNonExpansive (PatternDecl     _ t rhs) = case t of
+    VariablePattern _ _ -> isNonExpansive rhs
+    _                   -> return False-}
+  isNonExpansive (FreeDecl            _ _) = return False
+  isNonExpansive _                         =
+    internalError "TypeCheck.isNonExpansive: declaration"
+
+instance Binding (Rhs a) where
+  isNonExpansive (GuardedRhs _ _ _ _) = return False
+  isNonExpansive (SimpleRhs _ _ e ds) = withLocalValueEnv $ do
+    m <- getModuleIdent
+    tcEnv <- getTyConsEnv
+    clsEnv <- getClassEnv
+    sigs <- getSigEnv
+    modifyValueEnv $ flip (foldr (bindDeclArity m tcEnv clsEnv sigs)) ds
+    isNonExpansive e &&^ isNonExpansive ds
+
+-- A record construction is non-expansive only if all field labels are present.
+
+instance Binding (Expression a) where
+  isNonExpansive = isNonExpansive' 0
+
+isNonExpansive' :: Int -> Expression a -> TCM Bool
+isNonExpansive' _ (Literal         _ _ _) = return True
+isNonExpansive' n (Variable        _ _ v)
+  | v' == anonId = return False
+  | isRenamed v' = do
+    vEnv <- getValueEnv
+    return $ n == 0 || n < varArity v vEnv
+  | otherwise = do
+    vEnv <- getValueEnv
+    return $ n < varArity v vEnv
+  where v' = unqualify v
+isNonExpansive' _ (Constructor     _ _ _) = return True
+isNonExpansive' n (Paren             _ e) = isNonExpansive' n e
+isNonExpansive' n (Typed           _ e _) = isNonExpansive' n e
+isNonExpansive' _ (Record       _ _ c fs) = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  fmap ((length (constrLabels m c vEnv) == length fs) &&) (isNonExpansive fs)
+isNonExpansive' _ (Tuple _ es)            = isNonExpansive es
+isNonExpansive' _ (List _ _ es)           = isNonExpansive es
+isNonExpansive' n (Apply _ f e)           = isNonExpansive' (n + 1) f
+                                              &&^ isNonExpansive e
+isNonExpansive' n (InfixApply _ e1 op e2)
+  = isNonExpansive' (n + 2) (infixOp op) &&^ isNonExpansive e1
+                                         &&^ isNonExpansive e2
+isNonExpansive' n (LeftSection _ e op)    = isNonExpansive' (n + 1) (infixOp op)
+                                              &&^ isNonExpansive e
+isNonExpansive' n (Lambda _ ts e)         = withLocalValueEnv $ do
+  modifyValueEnv $ flip (foldr bindVarArity) (bv ts)
+  fmap (((n < length ts) ||) . (all isVariablePattern ts &&))
+    (isNonExpansive' (n - length ts) e)
+isNonExpansive' n (Let _ _ ds e)            = withLocalValueEnv $ do
+  m <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  clsEnv <- getClassEnv
+  sigs <- getSigEnv
+  modifyValueEnv $ flip (foldr (bindDeclArity m tcEnv clsEnv sigs)) ds
+  isNonExpansive ds &&^ isNonExpansive' n e
+isNonExpansive' _ _                     = return False
+
+instance Binding a => Binding (Field a) where
+  isNonExpansive (Field _ _ e) = isNonExpansive e
+
+bindDeclArity :: ModuleIdent -> TCEnv -> ClassEnv -> SigEnv ->  Decl a
+              -> ValueEnv -> ValueEnv
+bindDeclArity _ _     _      _    (InfixDecl        _ _ _ _) = id
+bindDeclArity _ _     _      _    (TypeSig            _ _ _) = id
+bindDeclArity _ _     _      _    (FunctionDecl   _ _ f eqs) =
+  bindArity f (eqnArity $ head eqs)
+bindDeclArity m tcEnv clsEnv sigs (ExternalDecl        _ fs) =
+  flip (foldr $ \(Var _ f) -> bindArity f $ arrowArity $ ty f) fs
+  where ty = unpredType . expandPolyType m tcEnv clsEnv . fromJust .
+               flip lookupTypeSig sigs
+bindDeclArity _ _     _      _    (PatternDecl        _ t _) =
+  flip (foldr bindVarArity) (bv t)
+bindDeclArity _ _     _      _    (FreeDecl            _ vs) =
+  flip (foldr bindVarArity) (bv vs)
+bindDeclArity _ _     _      _    _                          =
+  internalError "TypeCheck.bindDeclArity"
+
+bindVarArity :: Ident -> ValueEnv -> ValueEnv
+bindVarArity v = bindArity v 0
+
+bindArity :: Ident -> Int -> ValueEnv -> ValueEnv
+bindArity v n = bindTopEnv v (Value (qualify v) Nothing n undefined)
+
+-- Class and instance declarations:
+-- When checking method implementations in class and instance
+-- declarations, the compiler must check that the inferred type matches
+-- the method's declared type. This is straight forward in class
+-- declarations (the only difference with respect to an overloaded
+-- function with an explicit type signature is that a class method's type
+-- signature is composed of its declared type signature and the context
+-- from the class declaration), but a little bit more complicated for
+-- instance declarations because the instance type must be substituted
+-- for the type variable used in the type class declaration.
+--
+-- When checking inferred method types against their expected types, we have to
+-- be careful because the class' type variable is always assigned index 0 in
+-- the method types recorded in the value environment. However, in the inferred
+-- type scheme returned from 'tcMethodDecl', type variables are assigned
+-- indices in the order of their occurrence. In order to avoid incorrectly
+-- reporting errors when the type class variable is not the first variable that
+-- appears in a method's type, 'tcInstanceMethodPDecl' normalizes the expected
+-- method type before applying 'checkInstMethodType' to it. Unfortunately, this
+-- means that the compiler has to add the class constraint explicitly to the
+-- type signature.
+
+tcTopPDecl :: PDecl a -> TCM (PDecl PredType)
+tcTopPDecl (i, DataDecl p tc tvs cs clss)
+  = return (i, DataDecl p tc tvs cs clss)
+tcTopPDecl (i, ExternalDataDecl p tc tvs)
+  = return (i, ExternalDataDecl p tc tvs)
+tcTopPDecl (i, NewtypeDecl p tc tvs nc clss)
+  = return (i, NewtypeDecl p tc tvs nc clss)
+tcTopPDecl (i, TypeDecl p tc tvs ty)
+  = return (i, TypeDecl p tc tvs ty)
+tcTopPDecl (i, DefaultDecl p tys)
+  = return (i, DefaultDecl p tys)
+tcTopPDecl (i, ClassDecl p li cx cls tv ds)     = withLocalSigEnv $ do
+  let (vpds, opds) = partition (isValueDecl . snd) $ toPDecls ds
+  setSigEnv $ foldr (bindTypeSigs . snd) emptySigEnv opds
+  vpds' <- mapM (tcClassMethodPDecl (qualify cls) tv) vpds
+  return (i, ClassDecl p li cx cls tv $ fromPDecls $ map untyped opds ++ vpds')
+tcTopPDecl (i, InstanceDecl p li cx qcls ty ds) = do
+  tcEnv <- getTyConsEnv
+  pty <- expandPoly $ QualTypeExpr NoSpanInfo cx ty
+  mid <- getModuleIdent
+  let origCls = getOrigName mid qcls tcEnv
+      clsQual = head $ filter isQualified $ reverseLookupByOrigName origCls tcEnv
+      qQualCls = qualQualify (fromJust $ qidModule clsQual) qcls
+  vpds' <- mapM (tcInstanceMethodPDecl qQualCls pty) vpds
+  return (i,InstanceDecl p li cx qcls ty $ fromPDecls $ map untyped opds++vpds')
+  where (vpds, opds) = partition (isValueDecl . snd) $ toPDecls ds
+tcTopPDecl _ = internalError "TypeCheck.tcTopDecl"
+
+tcClassMethodPDecl :: QualIdent -> Ident -> PDecl a -> TCM (PDecl PredType)
+tcClassMethodPDecl qcls tv pd@(_, FunctionDecl _ _ f _) = do
+  methTy <- classMethodType qualify f
+  (tySc, pd') <- tcMethodPDecl qcls methTy pd
+  sigs <- getSigEnv
+  let QualTypeExpr spi cx ty = fromJust $ lookupTypeSig f sigs
+      qty = QualTypeExpr spi
+              (Constraint NoSpanInfo qcls (VariableType NoSpanInfo tv) : cx) ty
+  checkClassMethodType qty tySc pd'
+tcClassMethodPDecl _ _ _ = internalError "TypeCheck.tcClassMethodPDecl"
+
+tcInstanceMethodPDecl :: QualIdent -> PredType -> PDecl a
+                      -> TCM (PDecl PredType)
+tcInstanceMethodPDecl qcls pty pd@(_, FunctionDecl _ _ f _) = do
+  methTy <- instMethodType (qualifyLike qcls) pty f
+  (tySc, pd') <- tcMethodPDecl qcls (typeScheme methTy) pd
+  checkInstMethodType (normalize 0 methTy) tySc pd'
+tcInstanceMethodPDecl _ _ _ = internalError "TypeCheck.tcInstanceMethodPDecl"
+
+tcMethodPDecl :: QualIdent -> TypeScheme -> PDecl a -> TCM (TypeScheme, PDecl PredType)
+tcMethodPDecl qcls tySc (i, FunctionDecl p _ f eqs) = withLocalValueEnv $ do
+  m <- getModuleIdent
+  modifyValueEnv $ bindFun m f (Just qcls) (eqnArity $ head eqs) tySc
+  (ps, (ty, pd)) <- tcFunctionPDecl i emptyPredSet tySc p f eqs
+  theta <- getTypeSubst
+  return (gen Set.empty ps $ subst theta ty, pd)
+tcMethodPDecl _ _ _ = internalError "TypeCheck.tcMethodPDecl"
+
+checkClassMethodType :: QualTypeExpr -> TypeScheme -> PDecl PredType
+                     -> TCM (PDecl PredType)
+checkClassMethodType qty tySc pd@(_, FunctionDecl _ _ f _) = do
+  pty <- expandPoly qty
+  unlessM (checkTypeSig pty tySc) $ do
+    m <- getModuleIdent
+    report $ errTypeSigTooGeneral m (text "Method:" <+> ppIdent f) qty tySc
+  return pd
+checkClassMethodType _ _ _ = internalError "TypeCheck.checkClassMethodType"
+
+checkInstMethodType :: PredType -> TypeScheme -> PDecl PredType
+                    -> TCM (PDecl PredType)
+checkInstMethodType pty tySc pd@(_, FunctionDecl _ _ f _) = do
+  unlessM (checkTypeSig pty tySc) $ do
+    m <- getModuleIdent
+    report $
+      errMethodTypeTooSpecific f m (text "Method:" <+> ppIdent f) pty tySc
+  return pd
+checkInstMethodType _ _ _ = internalError "TypeCheck.checkInstMethodType"
+
+classMethodType :: (Ident -> QualIdent) -> Ident -> TCM TypeScheme
+classMethodType qual f = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  return $ funType m (qual $ unRenameIdent f) vEnv
+
+-- Due to the sorting of the predicate set, we can simply remove the minimum
+-- element as this is guaranteed to be the class constraint (see module 'Types'
+-- for more information).
+
+instMethodType :: (Ident -> QualIdent) -> PredType -> Ident -> TCM PredType
+instMethodType qual (PredType ps ty) f = do
+  ForAll _ (PredType ps' ty') <- classMethodType qual f
+  let PredType ps'' ty'' = instanceType ty (PredType (Set.deleteMin ps') ty')
+  return $ PredType (ps `Set.union` ps'') ty''
+
+-- External functions:
+
+tcExternal :: Ident -> TCM Type
+tcExternal f = do
+  sigs <- getSigEnv
+  case lookupTypeSig f sigs of
+    Nothing -> internalError "TypeCheck.tcExternal: type signature not found"
+    Just (QualTypeExpr _ _ ty) -> do
+      m <- getModuleIdent
+      PredType _ ty' <- expandPoly $ QualTypeExpr NoSpanInfo [] ty
+      modifyValueEnv $ bindFun m f Nothing (arrowArity ty') (polyType ty')
+      return ty'
+
+-- Patterns and Expressions:
+-- Note that the type attribute associated with a constructor or infix
+-- pattern is the type of the whole pattern and not the type of the
+-- constructor itself. Overloaded (numeric) literals are not supported in
+-- patterns.
+
+tcLiteral :: Bool -> Literal -> TCM (PredSet, Type)
+tcLiteral _ (Char _) = return (emptyPredSet, charType)
+tcLiteral poly (Int _)
+  | poly      = freshNumType
+  | otherwise = fmap ((,) emptyPredSet) (freshConstrained numTypes)
+tcLiteral poly (Float _)
+  | poly      = freshFractionalType
+  | otherwise = fmap ((,) emptyPredSet) (freshConstrained fractionalTypes)
+tcLiteral _    (String _) = return (emptyPredSet, stringType)
+
+tcLhs :: HasSpanInfo p => p -> Lhs a -> PTCM (PredSet, [Type], Lhs PredType)
+tcLhs p (FunLhs spi f ts) = do
+  (pss, tys, ts') <- unzip3 <$> mapM (tcPatternHelper p) ts
+  return (Set.unions pss, tys, FunLhs spi f ts')
+tcLhs p (OpLhs spi t1 op t2) = do
+  (ps1, ty1, t1') <- tcPatternHelper p t1
+  (ps2, ty2, t2') <- tcPatternHelper p t2
+  return (ps1 `Set.union` ps2, [ty1, ty2], OpLhs spi t1' op t2')
+tcLhs p (ApLhs spi lhs ts) = do
+  (ps, tys1, lhs') <- tcLhs p lhs
+  (pss, tys2, ts') <- unzip3 <$> mapM (tcPatternHelper p) ts
+  return (Set.unions (ps:pss), tys1 ++ tys2, ApLhs spi lhs' ts')
+
+-- When computing the type of a variable in a pattern, we ignore the
+-- predicate set of the variable's type (which can only be due to a type
+-- signature in the same declaration group) for just the same reason as
+-- in 'tcFunctionPDecl'. Infix and infix functional patterns are currently
+-- checked as constructor and functional patterns, respectively, resulting
+-- in slighty misleading error messages if the type check fails.
+
+-- We also keep track of already used variables,
+-- in order to add a Data constraint for non-linear patterns
+
+tcPattern :: HasSpanInfo p => p -> Pattern a
+          -> TCM (PredSet, Type, Pattern PredType)
+tcPattern = tcPatternWith Set.empty
+
+tcPatternWith :: HasSpanInfo p => Set.Set Ident -> p -> Pattern a
+              -> TCM (PredSet, Type, Pattern PredType)
+tcPatternWith s p pt = S.evalStateT (tcPatternHelper p pt) s
+
+type PTCM a = S.StateT (Set.Set Ident) TCM a
+
+tcPatternHelper :: HasSpanInfo p => p -> Pattern a
+                -> PTCM (PredSet, Type, Pattern PredType)
+tcPatternHelper _ (LiteralPattern spi _ l) = do
+  (ps, ty) <- lift $ tcLiteral False l
+  return (ps, ty, LiteralPattern spi (predType ty) l)
+tcPatternHelper _ (NegativePattern spi _ l) = do
+  (ps, ty) <- lift $ tcLiteral False l
+  return (ps, ty, NegativePattern spi (predType ty) l)
+tcPatternHelper _ (VariablePattern spi _ v) = do
+  vEnv <- lift getValueEnv
+  (_, ty) <- lift $ inst (varType v vEnv)
+  used <- S.get
+  ps <- if Set.member v used
+          then return (Set.singleton (Pred qDataId ty))
+          else S.put (Set.insert v used) >> return Set.empty
+  return (ps, ty, VariablePattern spi (predType ty) v)
+tcPatternHelper p t@(ConstructorPattern spi _ c ts) = do
+  m <- lift getModuleIdent
+  vEnv <- lift getValueEnv
+  (ps, (tys, ty')) <- fmap arrowUnapply <$> lift (skol (constrType m c vEnv))
+  (ps', ts') <- mapAccumM (uncurry . ptcPatternArg p "pattern" (pPrintPrec 0 t))
+                          ps (zip tys ts)
+  return (ps', ty', ConstructorPattern spi (predType ty') c ts')
+tcPatternHelper p (InfixPattern spi a t1 op t2) = do
+  (ps, ty, t') <- tcPatternHelper p (ConstructorPattern NoSpanInfo a op [t1,t2])
+  let ConstructorPattern _ a' op' [t1', t2'] = t'
+  return (ps, ty, InfixPattern spi a' t1' op' t2')
+tcPatternHelper p (ParenPattern spi t) = do
+  (ps, ty, t') <- tcPatternHelper p t
+  return (ps, ty, ParenPattern spi t')
+tcPatternHelper _ t@(RecordPattern spi _ c fs) = do
+  m <- lift getModuleIdent
+  vEnv <- lift getValueEnv
+  (ps, ty) <- fmap arrowBase <$> lift (skol (constrType m c vEnv))
+  -- tcField does not support passing "used" variables, thus we do it by hand
+  used <- S.get
+  (ps', fs') <- lift $ mapAccumM (tcField (tcPatternWith used) "pattern"
+    (\t' -> pPrintPrec 0 t $-$ text "Term:" <+> pPrintPrec 0 t') ty) ps fs
+  S.put $ foldr Set.insert used $ concatMap bv fs
+  return (ps', ty, RecordPattern spi (predType ty) c fs')
+tcPatternHelper p (TuplePattern spi ts) = do
+  (pss, tys, ts') <- unzip3 <$> mapM (tcPatternHelper p) ts
+  return (Set.unions pss, tupleType tys, TuplePattern spi ts')
+tcPatternHelper p t@(ListPattern spi _ ts) = do
+  ty <- lift freshTypeVar
+  (ps, ts') <- mapAccumM (flip (ptcPatternArg p "pattern" (pPrintPrec 0 t)) ty)
+                         emptyPredSet ts
+  return (ps, listType ty, ListPattern spi (predType $ listType ty) ts')
+tcPatternHelper p t@(AsPattern spi v t') = do
+  vEnv <- lift getValueEnv
+  (_, ty) <- lift $ inst (varType v vEnv)
+  used <- S.get
+  ps <- if Set.member v used
+          then return (Set.singleton (Pred qDataId ty))
+          else S.put (Set.insert v used) >> return Set.empty
+  (ps'', t'') <- tcPatternHelper p t' >>-
+    (\ps' ty' -> lift $ unify p "pattern" (pPrintPrec 0 t) ps ty ps' ty')
+  return (ps'', ty, AsPattern spi v t'')
+tcPatternHelper p (LazyPattern spi t) = do
+  (ps, ty, t') <- tcPatternHelper p t
+  return (ps, ty, LazyPattern spi t')
+tcPatternHelper p t@(FunctionPattern spi _ f ts) = do
+  m <- lift getModuleIdent
+  vEnv <- lift getValueEnv
+  (ps, ty) <- lift $ inst (funType m f vEnv)
+  -- insert all
+  S.modify (flip (foldr Set.insert) (bv t))
+  tcFuncPattern p spi (pPrintPrec 0 t) f id ps ty ts
+tcPatternHelper p (InfixFuncPattern spi a t1 op t2) = do
+  (ps, ty, t') <- tcPatternHelper p (FunctionPattern spi a op [t1, t2])
+  let FunctionPattern _ a' op' [t1', t2'] = t'
+  return (ps, ty, InfixFuncPattern spi a' t1' op' t2')
+
+tcFuncPattern :: HasSpanInfo p => p -> SpanInfo -> Doc -> QualIdent
+              -> ([Pattern PredType] -> [Pattern PredType])
+              -> PredSet -> Type -> [Pattern a]
+              -> PTCM (PredSet, Type, Pattern PredType)
+tcFuncPattern _ spi _ f ts ps ty [] =
+  return (Set.insert (Pred qDataId ty) ps, ty, FunctionPattern spi (predType ty) f (ts []))
+tcFuncPattern p spi doc f ts ps ty (t':ts') = do
+  (alpha, beta) <- lift $
+    tcArrow p "functional pattern" (doc $-$ text "Term:" <+> pPrintPrec 0 t) ty
+  (ps', t'') <- ptcPatternArg p "functional pattern" doc ps alpha t'
+  tcFuncPattern p spi doc f (ts . (t'' :)) ps' beta ts'
+  where t = FunctionPattern spi (predType ty) f (ts [])
+
+ptcPatternArg :: HasSpanInfo p => p -> String -> Doc -> PredSet -> Type
+             -> Pattern a -> PTCM (PredSet, Pattern PredType)
+ptcPatternArg p what doc ps ty t =
+  tcPatternHelper p t >>-
+    (\ps' ty' -> lift $
+      unify p what (doc $-$ text "Term:" <+> pPrintPrec 0 t) ps ty ps' ty')
+
+tcPatternArg :: HasSpanInfo p => p -> String -> Doc -> PredSet -> Type
+             -> Pattern a -> TCM (PredSet, Pattern PredType)
+tcPatternArg p what doc ps ty t =
+  tcPattern p t >>-
+    unify p what (doc $-$ text "Term:" <+> pPrintPrec 0 t) ps ty
+
+tcRhs :: Rhs a -> TCM (PredSet, Type, Rhs PredType)
+tcRhs (SimpleRhs p li e ds) = do
+  (ps, ds', ps', ty, e') <- withLocalValueEnv $ do
+    (ps, ds') <- tcDecls ds
+    (ps', ty, e') <- tcExpr e
+    return (ps, ds', ps', ty, e')
+  ps'' <- reducePredSet p "expression" (pPrintPrec 0 e') (ps `Set.union` ps')
+  return (ps'', ty, SimpleRhs p li e' ds')
+tcRhs (GuardedRhs spi li es ds) = withLocalValueEnv $ do
+  (ps, ds') <- tcDecls ds
+  ty <- freshTypeVar
+  (ps', es') <- mapAccumM (tcCondExpr ty) ps es
+  return (ps', ty, GuardedRhs spi li es' ds')
+
+tcCondExpr :: Type -> PredSet -> CondExpr a -> TCM (PredSet, CondExpr PredType)
+tcCondExpr ty ps (CondExpr p g e) = do
+  (ps', g') <- tcExpr g >>- unify p "guard" (pPrintPrec 0 g) ps boolType
+  (ps'', e') <- tcExpr e >>- unify p "guarded expression" (pPrintPrec 0 e) ps' ty
+  return (ps'', CondExpr p g' e')
+
+tcExpr :: Expression a -> TCM (PredSet, Type, Expression PredType)
+tcExpr (Literal spi _ l) = do
+  (ps, ty) <- tcLiteral True l
+  return (ps, ty, Literal spi (predType ty) l)
+tcExpr (Variable spi _ v) = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  (ps, ty) <- if isAnonId (unqualify v) then freshPredType [qDataId]
+                                        else inst (funType m v vEnv)
+  return (ps, ty, Variable spi (predType ty) v)
+tcExpr (Constructor spi _ c) = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  (ps, ty) <- inst (constrType m c vEnv)
+  return (ps, ty, Constructor spi (predType ty) c)
+tcExpr (Paren spi e) = do
+  (ps, ty, e') <- tcExpr e
+  return (ps, ty, Paren spi e')
+tcExpr (Typed spi e qty) = do
+  pty <- expandPoly qty
+  (ps, ty) <- inst (typeScheme pty)
+  (ps', e') <- tcExpr e >>-
+    unifyDecl spi "explicitly typed expression" (pPrintPrec 0 e) emptyPredSet ty
+  fvs <- computeFvEnv
+  theta <- getTypeSubst
+  let (gps, lps) = splitPredSet fvs ps'
+      tySc = gen fvs lps (subst theta ty)
+  unlessM (checkTypeSig pty tySc) $ do
+    m <- getModuleIdent
+    report $
+      errTypeSigTooGeneral m (text "Expression:" <+> pPrintPrec 0 e) qty tySc
+  return (ps `Set.union` gps, ty, Typed spi e' qty)
+tcExpr e@(Record spi _ c fs) = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  (ps, ty) <- fmap arrowBase <$> inst (constrType m c vEnv)
+  (ps', fs') <- mapAccumM (tcField (const tcExpr) "construction"
+    (\e' -> pPrintPrec 0 e $-$ text "Term:" <+> pPrintPrec 0 e') ty) ps fs
+  let missing = map (qualifyLike c) (constrLabels m c vEnv)
+                  \\ map (\(Field _ qid _) -> qid) fs'
+  pss <- mapM (tcMissingField spi ty) missing
+  return (Set.unions (ps':pss), ty, Record spi (predType ty) c fs')
+tcExpr e@(RecordUpdate spi e1 fs) = do
+  (ps, ty, e1') <- tcExpr e1
+  (ps', fs') <- mapAccumM (tcField (const tcExpr) "update"
+    (\e' -> pPrintPrec 0 e $-$ text "Term:" <+> pPrintPrec 0 e') ty) ps fs
+  return (ps', ty, RecordUpdate spi e1' fs')
+tcExpr (Tuple spi es) = do
+  (pss, tys, es') <- liftM unzip3 $ mapM (tcExpr) es
+  return (Set.unions pss, tupleType tys, Tuple spi es')
+tcExpr e@(List spi _ es) = do
+  ty <- freshTypeVar
+  (ps, es') <-
+    mapAccumM (flip (tcArg spi "expression" (pPrintPrec 0 e)) ty) emptyPredSet es
+  return (ps, listType ty, List spi (predType $ listType ty) es')
+tcExpr (ListCompr spi e qs) = do
+  (ps, qs', ps', ty, e') <- withLocalValueEnv $ do
+    (ps, qs') <- mapAccumM (tcQual spi) emptyPredSet qs
+    (ps', ty, e') <- tcExpr e
+    return (ps, qs', ps', ty, e')
+  ps'' <- reducePredSet spi "expression" (pPrintPrec 0 e') (ps `Set.union` ps')
+  return (ps'', listType ty, ListCompr spi e' qs')
+tcExpr e@(EnumFrom spi e1) = do
+  (ps, ty) <- freshEnumType
+  (ps', e1') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps ty e1
+  return (ps', listType ty, EnumFrom spi e1')
+tcExpr e@(EnumFromThen spi e1 e2) = do
+  (ps, ty) <- freshEnumType
+  (ps', e1') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps ty e1
+  (ps'', e2') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps' ty e2
+  return (ps'', listType ty, EnumFromThen spi e1' e2')
+tcExpr e@(EnumFromTo spi e1 e2) = do
+  (ps, ty) <- freshEnumType
+  (ps', e1') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps ty e1
+  (ps'', e2') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps' ty e2
+  return (ps'', listType ty, EnumFromTo spi e1' e2')
+tcExpr e@(EnumFromThenTo spi e1 e2 e3) = do
+  (ps, ty) <- freshEnumType
+  (ps', e1') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps ty e1
+  (ps'', e2') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps' ty e2
+  (ps''', e3') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps'' ty e3
+  return (ps''', listType ty, EnumFromThenTo spi e1' e2' e3')
+tcExpr e@(UnaryMinus spi e1) = do
+  (ps, ty) <- freshNumType
+  (ps', e1') <- tcArg spi "unary negation" (pPrintPrec 0 e) ps ty e1
+  return (ps', ty, UnaryMinus spi e1')
+tcExpr e@(Apply spi e1 e2) = do
+  (ps, (alpha, beta), e1') <- tcExpr e1 >>=-
+    tcArrow spi "application" (pPrintPrec 0 e $-$ text "Term:" <+> pPrintPrec 0 e1)
+  (ps', e2') <- tcArg spi "application" (pPrintPrec 0 e) ps alpha e2
+  return (ps', beta, Apply spi e1' e2')
+tcExpr e@(InfixApply spi e1 op e2) = do
+  (ps, (alpha, beta, gamma), op') <- tcInfixOp op >>=-
+    tcBinary spi "infix application" (pPrintPrec 0 e $-$ text "Operator:" <+> pPrint op)
+  (ps', e1') <- tcArg spi "infix application" (pPrintPrec 0 e) ps alpha e1
+  (ps'', e2') <- tcArg spi "infix application" (pPrintPrec 0 e) ps' beta e2
+  return (ps'', gamma, InfixApply spi e1' op' e2')
+tcExpr e@(LeftSection spi e1 op) = do
+  (ps, (alpha, beta), op') <- tcInfixOp op >>=-
+    tcArrow spi "left section" (pPrintPrec 0 e $-$ text "Operator:" <+> pPrint op)
+  (ps', e1') <- tcArg spi "left section" (pPrintPrec 0 e) ps alpha e1
+  return (ps', beta, LeftSection spi e1' op')
+tcExpr e@(RightSection spi op e1) = do
+  (ps, (alpha, beta, gamma), op') <- tcInfixOp op >>=-
+    tcBinary spi "right section" (pPrintPrec 0 e $-$ text "Operator:" <+> pPrint op)
+  (ps', e1') <- tcArg spi "right section" (pPrintPrec 0 e) ps beta e1
+  return (ps', TypeArrow alpha gamma, RightSection spi op' e1')
+tcExpr (Lambda spi ts e) = do
+  (pss, tys, ts', ps, ty, e')<- withLocalValueEnv $ do
+    bindLambdaVars ts
+    (pss, tys, ts') <- liftM unzip3 $ mapM (tcPattern spi) ts
+    (ps, ty, e') <- tcExpr e
+    return (pss, tys, ts', ps, ty, e')
+  ps' <- reducePredSet spi "expression" (pPrintPrec 0 e') (Set.unions $ ps : pss)
+  return (ps', foldr TypeArrow ty tys, Lambda spi ts' e')
+tcExpr (Let spi li ds e) = do
+  (ps, ds', ps', ty, e') <- withLocalValueEnv $ do
+    (ps, ds') <- tcDecls ds
+    (ps', ty, e') <- tcExpr e
+    return (ps, ds', ps', ty, e')
+  ps'' <- reducePredSet spi "expression" (pPrintPrec 0 e') (ps `Set.union` ps')
+  return (ps'', ty, Let spi li ds' e')
+tcExpr (Do spi li sts e) = do
+  (sts', ty, ps', e') <- withLocalValueEnv $ do
+    ((ps, mTy), sts') <-
+      mapAccumM (uncurry (tcStmt spi)) (emptyPredSet, Nothing) sts
+    ty <- liftM (maybe id TypeApply mTy) freshTypeVar
+    (ps', e') <- tcExpr e >>- unify spi "statement" (pPrintPrec 0 e) ps ty
+    return (sts', ty, ps', e')
+  return (ps', ty, Do spi li sts' e')
+tcExpr e@(IfThenElse spi e1 e2 e3) = do
+  (ps, e1') <- tcArg spi "expression" (pPrintPrec 0 e) emptyPredSet boolType e1
+  (ps', ty, e2') <- tcExpr e2
+  (ps'', e3') <- tcArg spi "expression" (pPrintPrec 0 e) (ps `Set.union` ps') ty e3
+  return (ps'', ty, IfThenElse spi e1' e2' e3')
+tcExpr (Case spi li ct e as) = do
+  (ps, tyLhs, e') <- tcExpr e
+  tyRhs <- freshTypeVar
+  (ps', as') <- mapAccumM (tcAlt tyLhs tyRhs) ps as
+  return (ps', tyRhs, Case spi li ct e' as')
+
+tcArg :: HasSpanInfo p => p -> String -> Doc -> PredSet -> Type -> Expression a
+      -> TCM (PredSet, Expression PredType)
+tcArg p what doc ps ty e =
+  tcExpr e >>- unify p what (doc $-$ text "Term:" <+> pPrintPrec 0 e) ps ty
+
+tcAlt :: Type -> Type -> PredSet -> Alt a
+      -> TCM (PredSet, Alt PredType)
+tcAlt tyLhs tyRhs ps a@(Alt p t rhs) =
+  tcAltern tyLhs p t rhs >>-
+    unify p "case alternative" (pPrint a) ps tyRhs
+
+tcAltern :: Type -> SpanInfo -> Pattern a
+         -> Rhs a -> TCM (PredSet, Type, Alt PredType)
+tcAltern tyLhs p t rhs = do
+  (ps, t', ps', ty', rhs') <- withLocalValueEnv $ do
+    bindLambdaVars t
+    (ps, t') <-
+      tcPatternArg p "case pattern" (pPrint (Alt p t rhs)) emptyPredSet tyLhs t
+    (ps', ty', rhs') <- tcRhs rhs
+    return (ps, t', ps', ty', rhs')
+  ps'' <- reducePredSet p "alternative" (pPrint (Alt p t' rhs'))
+                        (ps `Set.union` ps')
+  return (ps'', ty', Alt p t' rhs')
+
+tcQual :: HasSpanInfo p => p -> PredSet -> Statement a
+       -> TCM (PredSet, Statement PredType)
+tcQual p ps (StmtExpr spi e) = do
+  (ps', e') <- tcExpr e >>- unify p "guard" (pPrintPrec 0 e) ps boolType
+  return (ps', StmtExpr spi e')
+tcQual _ ps (StmtDecl spi li ds) = do
+  (ps', ds') <- tcDecls ds
+  return (ps `Set.union` ps', StmtDecl spi li ds')
+tcQual p ps q@(StmtBind spi t e) = do
+  alpha <- freshTypeVar
+  (ps', e') <- tcArg p "generator" (pPrint q) ps (listType alpha) e
+  bindLambdaVars t
+  (ps'', t') <- tcPatternArg p "generator" (pPrint q) ps' alpha t
+  return (ps'', StmtBind spi t' e')
+
+tcStmt :: HasSpanInfo p => p -> PredSet -> Maybe Type -> Statement a
+       -> TCM ((PredSet, Maybe Type), Statement PredType)
+tcStmt p ps mTy (StmtExpr spi e) = do
+  (ps', ty) <- maybe freshMonadType (return . (,) emptyPredSet) mTy
+  alpha <- freshTypeVar
+  (ps'', e') <- tcExpr e >>-
+    unify p "statement" (pPrintPrec 0 e) (ps `Set.union` ps') (applyType ty [alpha])
+  return ((ps'', Just ty), StmtExpr spi e')
+tcStmt _ ps mTy (StmtDecl spi li ds) = do
+  (ps', ds') <- tcDecls ds
+  return ((ps `Set.union` ps', mTy), StmtDecl spi li ds')
+tcStmt p ps mTy st@(StmtBind spi t e) = do
+  failable <- checkFailableBind t
+  let freshMType = if failable then freshMonadFailType else freshMonadType
+  (ps', ty) <- maybe freshMType (return . (,) emptyPredSet) mTy
+  alpha <- freshTypeVar
+  (ps'', e') <-
+    tcArg p "statement" (pPrint st) (ps `Set.union` ps') (applyType ty [alpha]) e
+  bindLambdaVars t
+  (ps''', t') <- tcPatternArg p "statement" (pPrint st) ps'' alpha t
+  return ((ps''', Just ty), StmtBind spi t' e')
+
+checkFailableBind :: Pattern a -> TCM Bool
+checkFailableBind (ConstructorPattern _ _ idt ps   ) = do
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfo idt tcEnv of
+    [RenamingType _ _ _ ] -> or <$> mapM checkFailableBind ps -- or [] == False
+    [DataType     _ _ cs]
+      | length cs == 1    -> or <$> mapM checkFailableBind ps
+      | otherwise         -> return True
+    _                     -> return True
+checkFailableBind (InfixPattern       _ _ p1 idt p2) = do
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfo idt tcEnv of
+    [RenamingType _ _ _ ] -> (||) <$> checkFailableBind p1
+                                  <*> checkFailableBind p2
+    [DataType     _ _ cs]
+      | length cs == 1    -> (||) <$> checkFailableBind p1
+                                  <*> checkFailableBind p2
+      | otherwise         -> return True
+    _                     -> return True
+checkFailableBind (RecordPattern      _ _ idt fs   ) = do
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfo idt tcEnv of
+    [RenamingType _ _ _ ] -> or <$> mapM (checkFailableBind . fieldContent) fs
+    [DataType     _ _ cs]
+      | length cs == 1    -> or <$> mapM (checkFailableBind . fieldContent) fs
+      | otherwise         -> return True
+    _                     -> return True
+  where fieldContent (Field _ _ c) = c
+checkFailableBind (TuplePattern       _       ps   ) =
+  or <$> mapM checkFailableBind ps
+checkFailableBind (AsPattern          _   _   p    ) = checkFailableBind p
+checkFailableBind (ParenPattern       _       p    ) = checkFailableBind p
+checkFailableBind (LazyPattern        _       _    ) = return False
+checkFailableBind (VariablePattern    _ _ _        ) = return False
+checkFailableBind _                                  = return True
+
+tcInfixOp :: InfixOp a -> TCM (PredSet, Type, InfixOp PredType)
+tcInfixOp (InfixOp _ op) = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  (ps, ty) <- inst (funType m op vEnv)
+  return (ps, ty, InfixOp (predType ty) op)
+tcInfixOp (InfixConstr _ op) = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  (ps, ty) <- inst (constrType m op vEnv)
+  return (ps, ty, InfixConstr (predType ty) op)
+
+-- The first unification in 'tcField' cannot fail; it serves only for
+-- instantiating the type variables in the field label's type.
+
+tcField :: (SpanInfo -> a b -> TCM (PredSet, Type, a PredType))
+        -> String -> (a b -> Doc) -> Type -> PredSet -> Field (a b)
+        -> TCM (PredSet, Field (a PredType))
+tcField check what doc ty ps (Field p l x) = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  (ps', ty') <- inst (labelType m l vEnv)
+  let TypeArrow ty1 ty2 = ty'
+  _ <- unify p "field label" empty emptyPredSet ty emptyPredSet ty1
+  (ps'', x') <- check p x >>-
+    unify p ("record " ++ what) (doc x) (ps `Set.union` ps') ty2
+  return (ps'', Field p l x')
+
+tcMissingField :: HasSpanInfo p => p -> Type -> QualIdent -> TCM PredSet
+tcMissingField p ty l = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  (ps, ty') <- inst (labelType m l vEnv)
+  let TypeArrow _ ty2 = ty'
+  let ps' = Set.singleton (Pred qDataId ty2)
+  unify p "field label" empty ps ty' ps' (TypeArrow ty ty2)
+
+-- | Checks that it's argument can be used as an arrow type @a -> b@ and returns
+-- the pair @(a, b)@.
+tcArrow :: HasSpanInfo p => p -> String -> Doc -> Type -> TCM (Type, Type)
+tcArrow p what doc ty = do
+  theta <- getTypeSubst
+  unaryArrow (subst theta ty)
+  where
+  unaryArrow (TypeArrow ty1 ty2) = return (ty1, ty2)
+  unaryArrow (TypeVariable   tv) = do
+    alpha <- freshTypeVar
+    beta  <- freshTypeVar
+    modifyTypeSubst $ bindVar tv $ TypeArrow alpha beta
+    return (alpha, beta)
+  unaryArrow ty'                 = do
+    m <- getModuleIdent
+    report $ errNonFunctionType p what doc m ty'
+    (,) <$> freshTypeVar <*> freshTypeVar
+
+-- The function 'tcBinary' checks that its argument can be used as an arrow type
+-- a -> b -> c and returns the triple (a,b,c).
+
+tcBinary :: HasSpanInfo p => p -> String -> Doc -> Type
+         -> TCM (Type, Type, Type)
+tcBinary p what doc ty = tcArrow p what doc ty >>= uncurry binaryArrow
+  where
+  binaryArrow ty1 (TypeArrow ty2 ty3) = return (ty1, ty2, ty3)
+  binaryArrow ty1 (TypeVariable   tv) = do
+    beta  <- freshTypeVar
+    gamma <- freshTypeVar
+    modifyTypeSubst $ bindVar tv $ TypeArrow beta gamma
+    return (ty1, beta, gamma)
+  binaryArrow ty1 ty2                 = do
+    m <- getModuleIdent
+    report $ errNonBinaryOp p what doc m (TypeArrow ty1 ty2)
+    (,,) <$> return ty1 <*> freshTypeVar <*> freshTypeVar
+
+-- Unification: The unification uses Robinson's algorithm.
+
+unify :: HasSpanInfo p => p -> String -> Doc -> PredSet -> Type -> PredSet
+      -> Type -> TCM PredSet
+unify p what doc ps1 ty1 ps2 ty2 = do
+  theta <- getTypeSubst
+  let ty1' = subst theta ty1
+      ty2' = subst theta ty2
+  m <- getModuleIdent
+  case unifyTypes m ty1' ty2' of
+    Left reason -> report $ errTypeMismatch p what doc m ty1' ty2' reason
+    Right sigma -> modifyTypeSubst (compose sigma)
+  reducePredSet p what doc $ ps1 `Set.union` ps2
+
+unifyTypes :: ModuleIdent -> Type -> Type -> Either Doc TypeSubst
+unifyTypes _ (TypeVariable tv1) (TypeVariable tv2)
+  | tv1 == tv2            = Right idSubst
+  | otherwise             = Right (singleSubst tv1 (TypeVariable tv2))
+unifyTypes m (TypeVariable tv) ty
+  | tv `elem` typeVars ty = Left  (errRecursiveType m tv ty)
+  | otherwise             = Right (singleSubst tv ty)
+unifyTypes m ty (TypeVariable tv)
+  | tv `elem` typeVars ty = Left  (errRecursiveType m tv ty)
+  | otherwise             = Right (singleSubst tv ty)
+unifyTypes _ (TypeConstrained tys1 tv1) (TypeConstrained tys2 tv2)
+  | tv1  == tv2           = Right idSubst
+  | tys1 == tys2          = Right (singleSubst tv1 (TypeConstrained tys2 tv2))
+unifyTypes m (TypeConstrained tys tv) ty =
+  foldr (choose . unifyTypes m ty) (Left (errIncompatibleTypes m ty (head tys)))
+        tys
+  where choose (Left _) theta' = theta'
+        choose (Right theta) _ = Right (bindSubst tv ty theta)
+unifyTypes m ty (TypeConstrained tys tv) =
+  foldr (choose . unifyTypes m ty) (Left (errIncompatibleTypes m ty (head tys)))
+        tys
+  where choose (Left _) theta' = theta'
+        choose (Right theta) _ = Right (bindSubst tv ty theta)
+unifyTypes _ (TypeConstructor tc1) (TypeConstructor tc2)
+  | tc1 == tc2 = Right idSubst
+unifyTypes m (TypeApply ty11 ty12) (TypeApply ty21 ty22) =
+  unifyTypeLists m [ty11, ty12] [ty21, ty22]
+unifyTypes m ty1@(TypeApply _ _) (TypeArrow ty21 ty22) =
+  unifyTypes m ty1 (TypeApply (TypeApply (TypeConstructor qArrowId) ty21) ty22)
+unifyTypes m (TypeArrow ty11 ty12) ty2@(TypeApply _ _) =
+  unifyTypes m (TypeApply (TypeApply (TypeConstructor qArrowId) ty11) ty12) ty2
+unifyTypes m (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) =
+  unifyTypeLists m [ty11, ty12] [ty21, ty22]
+unifyTypes m ty1 ty2 = Left (errIncompatibleTypes m ty1 ty2)
+
+unifyTypeLists :: ModuleIdent -> [Type] -> [Type] -> Either Doc TypeSubst
+unifyTypeLists _ []           _            = Right idSubst
+unifyTypeLists _ _            []           = Right idSubst
+unifyTypeLists m (ty1 : tys1) (ty2 : tys2) =
+  either Left unifyTypesTheta (unifyTypeLists m tys1 tys2)
+  where
+    unifyTypesTheta theta =
+      either Left (Right . flip compose theta)
+                  (unifyTypes m (subst theta ty1) (subst theta ty2))
+
+-- After performing a unification, the resulting substitution is applied
+-- to the current predicate set and the resulting predicate set is subject
+-- to a reduction. This predicate set reduction retains all predicates whose
+-- types are simple variables and which are not implied but other
+-- predicates in the predicate set. For all other predicates, the compiler
+-- checks whether an instance exists and replaces them by applying the
+-- instances' predicate set to the respective types. A minor complication
+-- arises due to constrained types, which at present are used to
+-- implement overloading of guard expressions and of numeric literals in
+-- patterns. The set of admissible types of a constrained type may be
+-- restricted by the current predicate set after the reduction and thus
+-- may cause a further extension of the current type substitution.
+
+reducePredSet :: HasSpanInfo p => p -> String -> Doc -> PredSet -> TCM PredSet
+reducePredSet p what doc ps = do
+  m <- getModuleIdent
+  clsEnv <- getClassEnv
+  theta <- getTypeSubst
+  inEnv <- fmap (fmap (subst theta)) <$> getInstEnv
+  let ps' = subst theta ps
+      (ps1, ps2) = partitionPredSet $ minPredSet clsEnv $ reducePreds inEnv ps'
+  theta' <-
+    foldM (reportMissingInstance m p what doc inEnv) idSubst $ Set.toList ps2
+  modifyTypeSubst $ compose theta'
+  return ps1
+  where
+    reducePreds inEnv = Set.concatMap $ reducePred inEnv
+    reducePred inEnv pr@(Pred qcls ty) =
+      maybe (Set.singleton pr) (reducePreds inEnv) (instPredSet inEnv qcls ty)
+
+instPredSet :: InstEnv' -> QualIdent -> Type -> Maybe PredSet
+instPredSet inEnv qcls ty = case Map.lookup qcls $ snd inEnv of
+  Just tys | ty `elem` tys -> Just emptyPredSet
+  _ -> case unapplyType False ty of
+    (TypeConstructor tc, tys) ->
+      fmap (expandAliasType tys . snd3) (lookupInstInfo (qcls, tc) $ fst inEnv)
+    _ -> Nothing
+
+reportMissingInstance :: HasSpanInfo p => ModuleIdent -> p -> String -> Doc
+                      -> InstEnv' -> TypeSubst -> Pred -> TCM TypeSubst
+reportMissingInstance m p what doc inEnv theta (Pred qcls ty) =
+  case subst theta ty of
+    ty'@(TypeConstrained tys tv) ->
+      case filter (hasInstance inEnv qcls) tys of
+        [] -> do
+          report $ errMissingInstance m p what doc (Pred qcls ty')
+          return theta
+        [ty''] -> return (bindSubst tv ty'' theta)
+        tys'
+          | length tys == length tys' -> return theta
+          | otherwise ->
+              liftM (flip (bindSubst tv) theta) (freshConstrained tys')
+    ty'
+      | hasInstance inEnv qcls ty' -> return theta
+      | otherwise -> do
+        report $ errMissingInstance m p what doc (Pred qcls ty')
+        return theta
+
+hasInstance :: InstEnv' -> QualIdent -> Type -> Bool
+hasInstance inEnv qcls = isJust . instPredSet inEnv qcls
+
+-- When a constrained type variable that is not free in the type environment
+-- disappears from the current type, the type becomes ambiguous. For instance,
+-- the type of the expression
+--
+-- let x = read "" in show x
+--
+-- is ambiguous assuming that 'read' and 'show' have types
+--
+-- read :: Read a => String -> a
+-- show :: Show a => a -> String
+--
+-- because the compiler cannot determine which 'Read' and 'Show' instances to
+-- use.
+--
+-- In the case of expressions with an ambiguous numeric type, i.e., a type that
+-- must be an instance of 'Num' or one of its subclasses, the compiler tries to
+-- resolve the ambiguity by choosing the first type from the list of default
+-- types that satisfies all constraints for the ambiguous type variable. An
+-- error is reported if no such type exists.
+
+applyDefaults :: HasSpanInfo p => p -> String -> Doc -> Set.Set Int -> PredSet
+              -> Type -> TCM PredSet
+applyDefaults p what doc fvs ps ty = do
+  m <- getModuleIdent
+  clsEnv <- getClassEnv
+  inEnv <- getInstEnv
+  defs <- getDefaultTypes
+  let theta = foldr (bindDefault defs inEnv ps) idSubst $ nub
+                [ tv | Pred qcls (TypeVariable tv) <- Set.toList ps
+                     , tv `Set.notMember` fvs, isNumClass clsEnv qcls ]
+      ps'   = fst (partitionPredSet (subst theta ps))
+      ty'   = subst theta ty
+      tvs'  = nub $ filter (`Set.notMember` fvs) (typeVars ps')
+  mapM_ (report . errAmbiguousTypeVariable m p what doc ps' ty') tvs'
+  modifyTypeSubst $ compose theta
+  return ps'
+
+bindDefault :: [Type] -> InstEnv' -> PredSet -> Int -> TypeSubst -> TypeSubst
+bindDefault defs inEnv ps tv =
+  case foldr (defaultType inEnv tv) defs (Set.toList ps) of
+    [] -> id
+    ty:_ -> bindSubst tv ty
+
+defaultType :: InstEnv' -> Int -> Pred -> [Type] -> [Type]
+defaultType inEnv tv (Pred qcls (TypeVariable tv'))
+  | tv == tv' = filter (hasInstance inEnv qcls)
+  | otherwise = id
+defaultType _ _ _ = id
+
+isNumClass :: ClassEnv -> QualIdent -> Bool
+isNumClass = (elem qNumId .) . flip allSuperClasses
+
+-- Instantiation and Generalization:
+-- We use negative offsets for fresh type variables.
+
+fresh :: (Int -> a) -> TCM a
+fresh f = f <$> getNextId
+
+freshVar :: (Int -> a) -> TCM a
+freshVar f = fresh $ \n -> f (- n)
+
+freshTypeVar :: TCM Type
+freshTypeVar = freshVar TypeVariable
+
+freshPredType :: [QualIdent] -> TCM (PredSet, Type)
+freshPredType qclss = do
+  ty <- freshTypeVar
+  return (foldr (\qcls -> Set.insert $ Pred qcls ty) emptyPredSet qclss, ty)
+
+freshEnumType :: TCM (PredSet, Type)
+freshEnumType = freshPredType [qEnumId]
+
+freshNumType :: TCM (PredSet, Type)
+freshNumType = freshPredType [qNumId]
+
+freshFractionalType :: TCM (PredSet, Type)
+freshFractionalType = freshPredType [qFractionalId]
+
+freshMonadType :: TCM (PredSet, Type)
+freshMonadType = freshPredType [qMonadId]
+
+freshMonadFailType :: TCM (PredSet, Type)
+freshMonadFailType = freshPredType [qMonadFailId]
+
+freshDataType :: TCM (PredSet, Type)
+freshDataType = freshPredType [qDataId]
+
+freshConstrained :: [Type] -> TCM Type
+freshConstrained = freshVar . TypeConstrained
+
+inst :: TypeScheme -> TCM (PredSet, Type)
+inst (ForAll n (PredType ps ty)) = do
+  tys <- replicateM n freshTypeVar
+  return (expandAliasType tys ps, expandAliasType tys ty)
+
+-- The function 'skol' instantiates the type of data and newtype
+-- constructors in patterns. All universally quantified type variables
+-- are instantiated with fresh type variables and all existentially
+-- quantified type variables are instantiated with fresh skolem types.
+-- All constraints that appear on the right hand side of the
+-- constructor's declaration are added to the dynamic instance
+-- environment.
+
+skol :: TypeScheme -> TCM (PredSet, Type)
+skol (ForAll n (PredType ps ty)) = do
+  tys <- replicateM n freshTypeVar
+  clsEnv <- getClassEnv
+  modifyInstEnv $
+    fmap $ bindSkolemInsts $ expandAliasType tys $ maxPredSet clsEnv ps
+  return (emptyPredSet, expandAliasType tys ty)
+  where bindSkolemInsts = flip (foldr bindSkolemInst) . Set.toList
+        bindSkolemInst (Pred qcls ty') dInEnv =
+          Map.insert qcls (ty' : fromMaybe [] (Map.lookup qcls dInEnv)) dInEnv
+
+-- The function 'gen' generalizes a predicate set ps and a type tau into
+-- a type scheme forall alpha . ps -> tau by universally quantifying all
+-- type variables that are free in tau and not fixed by the environment.
+-- The set of the latter is given by gvs.
+
+gen :: Set.Set Int -> PredSet -> Type -> TypeScheme
+gen gvs ps ty = ForAll (length tvs) (subst theta (PredType ps ty))
+  where tvs = [tv | tv <- nub (typeVars ty), tv `Set.notMember` gvs]
+        tvs' = map TypeVariable [0 ..]
+        theta = foldr2 bindSubst idSubst tvs tvs'
+
+-- Auxiliary Functions:
+-- The functions 'constrType', 'varType', 'funType' and 'labelType' are used
+-- to retrieve the type of constructors, pattern variables, variables and
+-- labels in expressions, respectively, from the value environment. Because
+-- the syntactical correctness has already been verified by the syntax checker,
+-- none of these functions should fail.
+
+-- Note that 'varType' can handle ambiguous identifiers and returns the first
+-- available type. This function is used for looking up the type of an
+-- identifier on the left hand side of a rule where it unambiguously refers
+-- to the local definition.
+
+-- The function 'constrLabels' returns a list of all labels belonging to a
+-- data constructor. The function 'varArity' works like 'varType' but returns
+-- a variable's arity instead of its type.
+
+constrType :: ModuleIdent -> QualIdent -> ValueEnv -> TypeScheme
+constrType m c vEnv = case qualLookupValue c vEnv of
+  [DataConstructor  _ _ _ tySc] -> tySc
+  [NewtypeConstructor _ _ tySc] -> tySc
+  _ -> case qualLookupValue (qualQualify m c) vEnv of
+    [DataConstructor  _ _ _ tySc] -> tySc
+    [NewtypeConstructor _ _ tySc] -> tySc
+    _ -> internalError $ "TypeCheck.constrType: " ++ show c
+
+constrLabels :: ModuleIdent -> QualIdent -> ValueEnv -> [Ident]
+constrLabels m c vEnv = case qualLookupValue c vEnv of
+  [DataConstructor _ _ ls _] -> ls
+  [NewtypeConstructor _ l _] -> [l]
+  _ -> case qualLookupValue (qualQualify m c) vEnv of
+    [DataConstructor _ _ ls _] -> ls
+    [NewtypeConstructor _ l _] -> [l]
+    _ -> internalError $ "TypeCheck.constrLabels: " ++ show c
+
+varType :: Ident -> ValueEnv -> TypeScheme
+varType v vEnv = case lookupValue v vEnv of
+  Value _ _ _ tySc : _ -> tySc
+  _ -> internalError $ "TypeCheck.varType: " ++ show v
+
+varArity :: QualIdent -> ValueEnv -> Int
+varArity v vEnv = case qualLookupValue v vEnv of
+  Value _ _ n _ : _ -> n
+  Label   _ _ _ : _ -> 1
+  _ -> internalError $ "TypeCheck.varArity: " ++ show v
+
+funType :: ModuleIdent -> QualIdent -> ValueEnv -> TypeScheme
+funType m f vEnv = case qualLookupValue f vEnv of
+  [Value _ _ _ tySc] -> tySc
+  [Label _ _ tySc] -> tySc
+  _ -> case qualLookupValue (qualQualify m f) vEnv of
+    [Value _ _ _ tySc] -> tySc
+    [Label _ _ tySc] -> tySc
+    _ -> internalError $ "TypeCheck.funType: " ++ show f
+
+labelType :: ModuleIdent -> QualIdent -> ValueEnv -> TypeScheme
+labelType m l vEnv = case qualLookupValue l vEnv of
+  [Label _ _ tySc] -> tySc
+  _ -> case qualLookupValue (qualQualify m l) vEnv of
+    [Label _ _ tySc] -> tySc
+    _ -> internalError $ "TypeCheck.labelType: " ++ show l
+
+-- The function 'expandPoly' handles the expansion of type aliases.
+
+expandPoly :: QualTypeExpr -> TCM PredType
+expandPoly qty = do
+  m <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  clsEnv <- getClassEnv
+  return $ expandPolyType m tcEnv clsEnv qty
+
+-- The function 'splitPredSet' splits a predicate set into a pair of predicate
+-- set such that all type variables that appear in the types of the predicates
+-- in the first predicate set are elements of a given set of type variables.
+
+splitPredSet :: Set.Set Int -> PredSet -> (PredSet, PredSet)
+splitPredSet fvs = Set.partition (all (`Set.member` fvs) . typeVars)
+
+-- The functions 'fvEnv' and 'fsEnv' compute the set of free type variables
+-- and free skolems of a type environment, respectively. We ignore the types
+-- of data constructors here because we know that they are closed.
+
+fvEnv :: ValueEnv -> Set.Set Int
+fvEnv vEnv =
+  Set.fromList [tv | tySc <- localTypes vEnv, tv <- typeVars tySc, tv < 0]
+
+computeFvEnv :: TCM (Set.Set Int)
+computeFvEnv = do
+  theta <- getTypeSubst
+  vEnv <- getValueEnv
+  return $ fvEnv (subst theta vEnv)
+
+localTypes :: ValueEnv -> [TypeScheme]
+localTypes vEnv = [tySc | (_, Value _ _ _ tySc) <- localBindings vEnv]
+
+-- ---------------------------------------------------------------------------
+-- Error functions
+-- ---------------------------------------------------------------------------
+
+errPolymorphicVar :: Ident -> Message
+errPolymorphicVar v = spanInfoMessage v $ hsep $ map text
+  ["Variable", idName v, "has a polymorphic type"]
+
+errTypeSigTooGeneral :: ModuleIdent -> Doc -> QualTypeExpr
+                     -> TypeScheme -> Message
+errTypeSigTooGeneral m what qty tySc = spanInfoMessage qty $ vcat
+  [ text "Type signature too general", what
+  , text "Inferred type:"  <+> ppTypeScheme m tySc
+  , text "Type signature:" <+> pPrint qty
+  ]
+
+errMethodTypeTooSpecific :: HasSpanInfo a => a -> ModuleIdent -> Doc -> PredType
+                         -> TypeScheme -> Message
+errMethodTypeTooSpecific p m what pty tySc = spanInfoMessage p $ vcat
+  [ text "Method type too specific", what
+  , text "Inferred type:" <+> ppTypeScheme m tySc
+  , text "Expected type:" <+> ppPredType m pty
+  ]
+
+errNonFunctionType :: HasSpanInfo a => a -> String -> Doc -> ModuleIdent -> Type
+                   -> Message
+errNonFunctionType p what doc m ty = spanInfoMessage p $ vcat
+  [ text "Type error in" <+> text what, doc
+  , text "Type:" <+> ppType m ty
+  , text "Cannot be applied"
+  ]
+
+errNonBinaryOp :: HasSpanInfo a => a -> String -> Doc -> ModuleIdent -> Type
+               -> Message
+errNonBinaryOp p what doc m ty = spanInfoMessage p $ vcat
+  [ text "Type error in" <+> text what, doc
+  , text "Type:" <+> ppType m ty
+  , text "Cannot be used as binary operator"
+  ]
+
+errTypeMismatch :: HasSpanInfo a => a -> String -> Doc -> ModuleIdent -> Type
+                -> Type -> Doc -> Message
+errTypeMismatch p what doc m ty1 ty2 reason = spanInfoMessage p $ vcat
+  [ text "Type error in"  <+> text what, doc
+  , text "Inferred type:" <+> ppType m ty2
+  , text "Expected type:" <+> ppType m ty1
+  , reason
+  ]
+
+errSkolemFieldLabel :: HasSpanInfo a => a -> Ident -> Message
+errSkolemFieldLabel p l = spanInfoMessage p $ hsep $ map text
+  ["Existential type escapes with type of record selector", escName l]
+
+errRecursiveType :: ModuleIdent -> Int -> Type -> Doc
+errRecursiveType m tv ty = errIncompatibleTypes m (TypeVariable tv) ty
+
+errIncompatibleTypes :: ModuleIdent -> Type -> Type -> Doc
+errIncompatibleTypes m ty1 ty2 = sep
+  [ text "Types" <+> ppType m ty1
+  , nest 2 $ text "and" <+> ppType m ty2
+  , text "are incompatible"
+  ]
+
+errIncompatibleLabelTypes :: HasSpanInfo a => a -> ModuleIdent -> Ident -> Type
+                          -> Type -> Message
+errIncompatibleLabelTypes p m l ty1 ty2 = spanInfoMessage p $ sep
+  [ text "Labeled types" <+> ppIdent l <+> text "::" <+> ppType m ty1
+  , nest 10 $ text "and" <+> ppIdent l <+> text "::" <+> ppType m ty2
+  , text "are incompatible"
+  ]
+
+errMissingInstance :: HasSpanInfo a => ModuleIdent -> a -> String -> Doc -> Pred
+                   -> Message
+errMissingInstance m p what doc pr = spanInfoMessage p $ vcat
+  [ text "Missing instance for" <+> ppPred m pr
+  , text "in" <+> text what
+  , doc
+  ]
+
+errAmbiguousTypeVariable :: HasSpanInfo a => ModuleIdent -> a -> String -> Doc
+                         -> PredSet -> Type -> Int -> Message
+errAmbiguousTypeVariable m p what doc ps ty tv = spanInfoMessage p $ vcat
+  [ text "Ambiguous type variable" <+> ppType m (TypeVariable tv)
+  , text "in type" <+> ppPredType m (PredType ps ty)
+  , text "inferred for" <+> text what
+  , doc
+  ]
diff --git a/src/Checks/TypeSyntaxCheck.hs b/src/Checks/TypeSyntaxCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/TypeSyntaxCheck.hs
@@ -0,0 +1,498 @@
+{- |
+    Module      :  $Header$
+    Description :  Checks type syntax
+    Copyright   :  (c) 2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   After the source file has been parsed and all modules have been
+   imported, the compiler first checks all type definitions and
+   signatures. In particular, this module disambiguates nullary type
+   constructors and type variables, which -- in contrast to Haskell -- is
+   not possible on purely syntactic criteria. In addition it is checked
+   that all type constructors and type variables occurring on the right
+   hand side of a type declaration are actually defined and no identifier
+   is defined more than once.
+-}
+{-# LANGUAGE CPP #-}
+module Checks.TypeSyntaxCheck (typeSyntaxCheck) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative      ((<$>), (<*>), pure)
+#endif
+import           Control.Monad            (unless, when)
+import qualified Control.Monad.State as S (State, runState, gets, modify)
+import           Data.List                (nub)
+import           Data.Maybe               (isNothing)
+
+import Curry.Base.Ident
+import Curry.Base.Position
+import Curry.Base.SpanInfo
+import Curry.Base.Pretty
+import Curry.Syntax
+import Curry.Syntax.Pretty
+
+import Base.Expr (Expr (fv))
+import Base.Messages (Message, spanInfoMessage, internalError)
+import Base.TopEnv
+import Base.Utils (findMultiples, findDouble)
+
+import Env.TypeConstructor (TCEnv)
+import Env.Type
+
+-- TODO Use span info for err messages
+
+-- In order to check type constructor applications, the compiler
+-- maintains an environment containing all known type constructors and
+-- type classes. The function 'typeSyntaxCheck' expects a type constructor
+-- environment that is already initialized with the imported type constructors
+-- and type classes. The type constructor environment is converted to a type
+-- identifier environment, before all locally defined type constructors and
+-- type classes are added to this environment and the declarations are checked
+-- within this environment.
+
+typeSyntaxCheck :: TCEnv -> Module a -> (Module a, [Message])
+typeSyntaxCheck tcEnv mdl@(Module _ _ _ m _ _ ds) =
+  case findMultiples $ map getIdent tcds of
+    [] -> if length dfds <= 1
+            then runTSCM (checkModule mdl) state
+            else (mdl, [errMultipleDefaultDeclarations dfps])
+    tss -> (mdl, map errMultipleDeclarations tss)
+  where
+    tcds = filter isTypeOrClassDecl ds
+    dfds = filter isDefaultDecl ds
+    dfps = map (\(DefaultDecl p _) -> p) dfds
+    tEnv = foldr (bindType m) (fmap toTypeKind tcEnv) tcds
+    state = TSCState m tEnv 1 []
+
+-- Type Syntax Check Monad
+type TSCM = S.State TSCState
+
+-- |Internal state of the Type Syntax Check
+data TSCState = TSCState
+  { moduleIdent :: ModuleIdent
+  , typeEnv     :: TypeEnv
+  , nextId      :: Integer
+  , errors      :: [Message]
+  }
+
+runTSCM :: TSCM a -> TSCState -> (a, [Message])
+runTSCM tscm s = let (a, s') = S.runState tscm s in (a, reverse $ errors s')
+
+getModuleIdent :: TSCM ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+getTypeEnv :: TSCM TypeEnv
+getTypeEnv = S.gets typeEnv
+
+newId :: TSCM Integer
+newId = do
+  curId <- S.gets nextId
+  S.modify $ \s -> s { nextId = succ curId }
+  return curId
+
+report :: Message -> TSCM ()
+report err = S.modify (\s -> s { errors = err : errors s })
+
+ok :: TSCM ()
+ok = return ()
+
+bindType :: ModuleIdent -> Decl a -> TypeEnv -> TypeEnv
+bindType m (DataDecl _ tc _ cs _) = bindTypeKind m tc (Data qtc ids)
+  where
+    qtc = qualifyWith m tc
+    ids = map constrId cs ++ nub (concatMap recordLabels cs)
+bindType m (ExternalDataDecl _ tc _) = bindTypeKind m tc (Data qtc [])
+  where
+    qtc = qualifyWith m tc
+bindType m (NewtypeDecl _ tc _ nc _) = bindTypeKind m tc (Data qtc ids)
+  where
+    qtc = qualifyWith m tc
+    ids = nconstrId nc : nrecordLabels nc
+bindType m (TypeDecl _ tc _ _) = bindTypeKind m tc (Alias qtc)
+  where
+    qtc = qualifyWith m tc
+bindType m (ClassDecl _ _ _ cls _ ds)  = bindTypeKind m cls (Class qcls ms)
+  where
+    qcls = qualifyWith m cls
+    ms = concatMap methods ds
+bindType _ _ = id
+
+-- When type declarations are checked, the compiler will allow anonymous
+-- type variables on the left hand side of the declaration, but not on
+-- the right hand side. Function and pattern declarations must be
+-- traversed because they can contain local type signatures.
+
+checkModule :: Module a -> TSCM (Module a)
+checkModule (Module spi li ps m es is ds) = do
+  ds' <- mapM checkDecl ds
+  return $ Module spi li ps m es is ds'
+
+checkDecl :: Decl a -> TSCM (Decl a)
+checkDecl (DataDecl p tc tvs cs clss)         = do
+  checkTypeLhs tvs
+  cs' <- mapM (checkConstrDecl tvs) cs
+  mapM_ (checkClass False) clss
+  return $ DataDecl p tc tvs cs' clss
+checkDecl (NewtypeDecl p tc tvs nc clss)      = do
+  checkTypeLhs tvs
+  nc' <- checkNewConstrDecl tvs nc
+  mapM_ (checkClass False) clss
+  return $ NewtypeDecl p tc tvs nc' clss
+checkDecl (TypeDecl p tc tvs ty)              = do
+  checkTypeLhs tvs
+  ty' <- checkClosedType tvs ty
+  return $ TypeDecl p tc tvs ty'
+checkDecl (TypeSig p vs qty)                   =
+  TypeSig p vs <$> checkQualType qty
+checkDecl (FunctionDecl a p f eqs)            = FunctionDecl a p f <$>
+  mapM checkEquation eqs
+checkDecl (PatternDecl p t rhs)               = PatternDecl p t <$> checkRhs rhs
+checkDecl (DefaultDecl p tys)                 = DefaultDecl p <$>
+  mapM (checkClosedType []) tys
+checkDecl (ClassDecl p li cx cls clsvar ds)   = do
+  checkTypeVars "class declaration" [clsvar]
+  cx' <- checkClosedContext [clsvar] cx
+  checkSimpleContext cx'
+  ds' <- mapM checkDecl ds
+  mapM_ (checkClassMethod clsvar) ds'
+  return $ ClassDecl p li cx' cls clsvar ds'
+checkDecl (InstanceDecl p li cx qcls inst ds) = do
+  checkClass True qcls
+  QualTypeExpr _ cx' inst' <- checkQualType $ QualTypeExpr NoSpanInfo cx inst
+  checkSimpleContext cx'
+  checkInstanceType p inst'
+  InstanceDecl p li cx' qcls inst' <$> mapM checkDecl ds
+checkDecl d                                   = return d
+
+checkConstrDecl :: [Ident] -> ConstrDecl -> TSCM ConstrDecl
+checkConstrDecl tvs (ConstrDecl p c tys) = do
+  tys' <- mapM (checkClosedType tvs) tys
+  return $ ConstrDecl p c tys'
+checkConstrDecl tvs (ConOpDecl p ty1 op ty2) = do
+  tys' <- mapM (checkClosedType tvs) [ty1, ty2]
+  let [ty1', ty2'] = tys'
+  return $ ConOpDecl p ty1' op ty2'
+checkConstrDecl tvs (RecordDecl p c fs) = do
+  fs' <- mapM (checkFieldDecl tvs) fs
+  return $ RecordDecl p c fs'
+
+checkFieldDecl :: [Ident] -> FieldDecl -> TSCM FieldDecl
+checkFieldDecl tvs (FieldDecl p ls ty) =
+  FieldDecl p ls <$> checkClosedType tvs ty
+
+checkNewConstrDecl :: [Ident] -> NewConstrDecl -> TSCM NewConstrDecl
+checkNewConstrDecl tvs (NewConstrDecl p c ty) = do
+  ty'  <- checkClosedType tvs ty
+  return $ NewConstrDecl p c ty'
+checkNewConstrDecl tvs (NewRecordDecl p c (l, ty)) = do
+  ty'  <- checkClosedType tvs ty
+  return $ NewRecordDecl p c (l, ty')
+
+checkSimpleContext :: Context -> TSCM ()
+checkSimpleContext = mapM_ checkSimpleConstraint
+
+checkSimpleConstraint :: Constraint -> TSCM ()
+checkSimpleConstraint c@(Constraint _ _ ty) =
+  unless (isVariableType ty) $ report $ errIllegalSimpleConstraint c
+
+-- Class method's type signatures have to obey a few additional restrictions.
+-- The class variable must appear in the method's type and the method's
+-- context must not contain any additional constraints for that class variable.
+
+checkClassMethod :: Ident -> Decl a -> TSCM ()
+checkClassMethod tv (TypeSig spi _ qty) = do
+  unless (tv `elem` fv qty) $ report $ errAmbiguousType spi tv
+  let QualTypeExpr _ cx _ = qty
+  when (tv `elem` fv cx) $ report $ errConstrainedClassVariable spi tv
+checkClassMethod _ _ = ok
+
+checkInstanceType :: SpanInfo -> InstanceType -> TSCM ()
+checkInstanceType p inst = do
+  tEnv <- getTypeEnv
+  unless (isSimpleType inst &&
+    not (isTypeSyn (typeConstr inst) tEnv) &&
+    not (any isAnonId $ typeVariables inst) &&
+    isNothing (findDouble $ fv inst)) $
+      report $ errIllegalInstanceType p inst
+
+checkTypeLhs :: [Ident] -> TSCM ()
+checkTypeLhs = checkTypeVars "left hand side of type declaration"
+
+-- |Checks a list of type variables for
+-- * Anonymous type variables are allowed
+-- * only type variables (no type constructors)
+-- * linearity
+checkTypeVars :: String -> [Ident] -> TSCM ()
+checkTypeVars _    []         = ok
+checkTypeVars what (tv : tvs) = do
+  unless (isAnonId tv) $ do
+    isTypeConstrOrClass <- not . null . lookupTypeKind tv <$> getTypeEnv
+    when isTypeConstrOrClass $ report $ errNoVariable tv what
+    when (tv `elem` tvs) $ report $ errNonLinear tv what
+  checkTypeVars what tvs
+
+-- Checking expressions is rather straight forward. The compiler must
+-- only traverse the structure of expressions in order to find local
+-- declaration groups.
+
+checkEquation :: Equation a -> TSCM (Equation a)
+checkEquation (Equation p lhs rhs) = Equation p lhs <$> checkRhs rhs
+
+checkRhs :: Rhs a -> TSCM (Rhs a)
+checkRhs (SimpleRhs spi li e ds)   =
+  SimpleRhs spi li <$> checkExpr e <*> mapM checkDecl ds
+checkRhs (GuardedRhs spi li es ds) =
+  GuardedRhs spi li <$> mapM checkCondExpr es <*> mapM checkDecl ds
+
+checkCondExpr :: CondExpr a -> TSCM (CondExpr a)
+checkCondExpr (CondExpr spi g e) = CondExpr spi <$> checkExpr g <*> checkExpr e
+
+checkExpr :: Expression a -> TSCM (Expression a)
+checkExpr l@(Literal             _ _ _) = return l
+checkExpr v@(Variable            _ _ _) = return v
+checkExpr c@(Constructor         _ _ _) = return c
+checkExpr (Paren                 spi e) = Paren spi <$> checkExpr e
+checkExpr (Typed             spi e qty) = Typed spi <$> checkExpr e
+                                                    <*> checkQualType qty
+checkExpr (Record           spi a c fs) =
+  Record spi a c <$> mapM checkFieldExpr fs
+checkExpr (RecordUpdate       spi e fs) =
+  RecordUpdate spi <$> checkExpr e <*> mapM checkFieldExpr fs
+checkExpr (Tuple                spi es) = Tuple spi <$> mapM checkExpr es
+checkExpr (List               spi a es) = List spi a <$> mapM checkExpr es
+checkExpr (ListCompr          spi e qs) = ListCompr spi <$> checkExpr e
+                                                        <*> mapM checkStmt qs
+checkExpr (EnumFrom              spi e) = EnumFrom spi <$> checkExpr e
+checkExpr (EnumFromThen      spi e1 e2) = EnumFromThen spi <$> checkExpr e1
+                                                           <*> checkExpr e2
+checkExpr (EnumFromTo        spi e1 e2) = EnumFromTo spi <$> checkExpr e1
+                                                         <*> checkExpr e2
+checkExpr (EnumFromThenTo spi e1 e2 e3) = EnumFromThenTo spi <$> checkExpr e1
+                                                             <*> checkExpr e2
+                                                             <*> checkExpr e3
+checkExpr (UnaryMinus            spi e) = UnaryMinus spi <$> checkExpr e
+checkExpr (Apply             spi e1 e2) = Apply spi <$> checkExpr e1
+                                                    <*> checkExpr e2
+checkExpr (InfixApply     spi e1 op e2) = InfixApply spi <$> checkExpr e1
+                                                         <*> return op
+                                                         <*> checkExpr e2
+checkExpr (LeftSection spi e op)        = flip (LeftSection spi) op <$>
+  checkExpr e
+checkExpr (RightSection spi op e)       = RightSection spi op <$> checkExpr e
+checkExpr (Lambda spi ts e)             = Lambda spi ts <$> checkExpr e
+checkExpr (Let spi li ds e)             = Let spi li <$> mapM checkDecl ds
+                                                     <*> checkExpr e
+checkExpr (Do spi li sts e)             = Do spi li <$> mapM checkStmt sts
+                                                    <*> checkExpr e
+checkExpr (IfThenElse spi e1 e2 e3)     = IfThenElse spi <$> checkExpr e1
+                                                         <*> checkExpr e2
+                                                         <*> checkExpr e3
+checkExpr (Case spi li ct e alts)       = Case spi li ct <$> checkExpr e
+                                                         <*> mapM checkAlt alts
+
+checkStmt :: Statement a -> TSCM (Statement a)
+checkStmt (StmtExpr spi e)     = StmtExpr spi    <$> checkExpr e
+checkStmt (StmtBind spi t e)   = StmtBind spi t  <$> checkExpr e
+checkStmt (StmtDecl spi li ds) = StmtDecl spi li <$> mapM checkDecl ds
+
+checkAlt :: Alt a -> TSCM (Alt a)
+checkAlt (Alt spi t rhs) = Alt spi t <$> checkRhs rhs
+
+checkFieldExpr :: Field (Expression a) -> TSCM (Field (Expression a))
+checkFieldExpr (Field spi l e) = Field spi l <$> checkExpr e
+
+-- The parser cannot distinguish unqualified nullary type constructors
+-- and type variables. Therefore, if the compiler finds an unbound
+-- identifier in a position where a type variable is admissible, it will
+-- interpret the identifier as such.
+
+checkQualType :: QualTypeExpr -> TSCM QualTypeExpr
+checkQualType (QualTypeExpr spi cx ty) = do
+  ty' <- checkType ty
+  cx' <- checkClosedContext (fv ty') cx
+  return $ QualTypeExpr spi cx' ty'
+
+checkClosedContext :: [Ident] -> Context -> TSCM Context
+checkClosedContext tvs cx = do
+  cx' <- checkContext cx
+  mapM_ (\(Constraint _ _ ty) -> checkClosed tvs ty) cx'
+  return cx'
+
+checkContext :: Context -> TSCM Context
+checkContext = mapM checkConstraint
+
+checkConstraint :: Constraint -> TSCM Constraint
+checkConstraint c@(Constraint spi qcls ty) = do
+  checkClass False qcls
+  ty' <- checkType ty
+  unless (isVariableType $ rootType ty') $ report $ errIllegalConstraint c
+  return $ Constraint spi qcls ty'
+  where
+    rootType (ApplyType _ ty' _) = ty'
+    rootType ty'                 = ty'
+
+checkClass :: Bool -> QualIdent -> TSCM ()
+checkClass isInstDecl qcls = do
+  m <- getModuleIdent
+  tEnv <- getTypeEnv
+  case qualLookupTypeKind qcls tEnv of
+    [] -> report $ errUndefinedClass qcls
+    [Class c _]
+      | c == qDataId -> when (isInstDecl && m /= preludeMIdent) $ report $
+                          errIllegalDataInstance qcls
+      | otherwise    -> ok
+    [_] -> report $ errUndefinedClass qcls
+    tks -> case qualLookupTypeKind (qualQualify m qcls) tEnv of
+      [Class c _]
+        | c == qDataId -> when (isInstDecl && m /= preludeMIdent) $ report $
+                            errIllegalDataInstance qcls
+        | otherwise    -> ok
+      [_] -> report $ errUndefinedClass qcls
+      _ -> report $ errAmbiguousIdent qcls $ map origName tks
+
+checkClosedType :: [Ident] -> TypeExpr -> TSCM TypeExpr
+checkClosedType tvs ty = do
+  ty' <- checkType ty
+  checkClosed tvs ty'
+  return ty'
+
+checkType :: TypeExpr -> TSCM TypeExpr
+checkType c@(ConstructorType spi tc) = do
+  m <- getModuleIdent
+  tEnv <- getTypeEnv
+  case qualLookupTypeKind tc tEnv of
+    []
+      | isQTupleId tc -> return c
+      | not (isQualified tc) -> return $ VariableType spi $ unqualify tc
+      | otherwise -> report (errUndefinedType tc) >> return c
+    [Class _ _] -> report (errUndefinedType tc) >> return c
+    [_] -> return c
+    tks -> case qualLookupTypeKind (qualQualify m tc) tEnv of
+      [Class _ _] -> report (errUndefinedType tc) >> return c
+      [_] -> return c
+      _ -> report (errAmbiguousIdent tc $ map origName tks) >> return c
+checkType (ApplyType spi ty1 ty2) = ApplyType spi <$> checkType ty1
+                                                  <*> checkType ty2
+checkType (VariableType spi tv)
+  | isAnonId tv = (VariableType spi . renameIdent tv) <$> newId
+  | otherwise   = checkType $ ConstructorType spi (qualify tv)
+checkType (TupleType     spi tys) = TupleType  spi    <$> mapM checkType tys
+checkType (ListType       spi ty) = ListType   spi    <$> checkType ty
+checkType (ArrowType spi ty1 ty2) = ArrowType  spi    <$> checkType ty1
+                                                      <*> checkType ty2
+checkType (ParenType      spi ty) = ParenType  spi    <$> checkType ty
+checkType (ForallType  spi vs ty) = ForallType spi vs <$> checkType ty
+
+checkClosed :: [Ident] -> TypeExpr -> TSCM ()
+checkClosed _   (ConstructorType _ _) = ok
+checkClosed tvs (ApplyType _ ty1 ty2) = mapM_ (checkClosed tvs) [ty1, ty2]
+checkClosed tvs (VariableType   _ tv) =
+  when (isAnonId tv || tv `notElem` tvs) $ report $ errUnboundVariable tv
+checkClosed tvs (TupleType     _ tys) = mapM_ (checkClosed tvs) tys
+checkClosed tvs (ListType       _ ty) = checkClosed tvs ty
+checkClosed tvs (ArrowType _ ty1 ty2) = mapM_ (checkClosed tvs) [ty1, ty2]
+checkClosed tvs (ParenType      _ ty) = checkClosed tvs ty
+checkClosed tvs (ForallType  _ vs ty) = checkClosed (tvs ++ vs) ty
+
+-- ---------------------------------------------------------------------------
+-- Auxiliary definitions
+-- ---------------------------------------------------------------------------
+
+getIdent :: Decl a -> Ident
+getIdent (DataDecl     _ tc _ _ _) = tc
+getIdent (ExternalDataDecl _ tc _) = tc
+getIdent (NewtypeDecl _ tc _ _ _)  = tc
+getIdent (TypeDecl _ tc _ _)       = tc
+getIdent (ClassDecl _ _ _ cls _ _) = cls
+getIdent _                         = internalError
+  "Checks.TypeSyntaxCheck.getIdent: no type or class declaration"
+
+isTypeSyn :: QualIdent -> TypeEnv -> Bool
+isTypeSyn tc tEnv = case qualLookupTypeKind tc tEnv of
+  [Alias _] -> True
+  _ -> False
+
+-- ---------------------------------------------------------------------------
+-- Error messages
+-- ---------------------------------------------------------------------------
+
+errMultipleDefaultDeclarations :: [SpanInfo] -> Message
+errMultipleDefaultDeclarations spis = spanInfoMessage (head spis) $
+  text "More than one default declaration:" $+$
+    nest 2 (vcat $ map showPos spis)
+  where showPos = text . showLine . getPosition
+
+errMultipleDeclarations :: [Ident] -> Message
+errMultipleDeclarations is = spanInfoMessage i $
+  text "Multiple declarations of" <+> text (escName i) <+> text "at:" $+$
+    nest 2 (vcat $ map showPos is)
+  where i = head is
+        showPos = text . showLine . getPosition
+
+errUndefined :: String -> QualIdent -> Message
+errUndefined what qident = spanInfoMessage qident $ hsep $ map text
+  ["Undefined", what, qualName qident]
+
+errUndefinedClass :: QualIdent -> Message
+errUndefinedClass = errUndefined "class"
+
+errUndefinedType :: QualIdent -> Message
+errUndefinedType = errUndefined "type"
+
+errAmbiguousIdent :: QualIdent -> [QualIdent] -> Message
+errAmbiguousIdent qident qidents = spanInfoMessage qident $
+  text "Ambiguous identifier" <+> text (escQualName qident) $+$
+    text "It could refer to:" $+$ nest 2 (vcat (map (text . qualName) qidents))
+
+errAmbiguousType :: SpanInfo -> Ident -> Message
+errAmbiguousType spi ident = spanInfoMessage spi $ hsep $ map text
+  [ "Method type does not mention class variable", idName ident ]
+
+errConstrainedClassVariable :: SpanInfo -> Ident -> Message
+errConstrainedClassVariable spi ident = spanInfoMessage spi $ hsep $ map text
+  [ "Method context must not constrain class variable", idName ident ]
+
+errNonLinear :: Ident -> String -> Message
+errNonLinear tv what = spanInfoMessage tv $ hsep $ map text
+  [ "Type variable", idName tv, "occurs more than once in", what ]
+
+errNoVariable :: Ident -> String -> Message
+errNoVariable tv what = spanInfoMessage tv $ hsep $ map text
+  ["Type constructor or type class identifier", idName tv, "used in", what]
+
+errUnboundVariable :: Ident -> Message
+errUnboundVariable tv = spanInfoMessage tv $ hsep $ map text
+  [ "Unbound type variable", idName tv ]
+
+errIllegalConstraint :: Constraint -> Message
+errIllegalConstraint c@(Constraint _ qcls _) = spanInfoMessage qcls $ vcat
+  [ text "Illegal class constraint" <+> pPrint c
+  , text "Constraints must be of the form C u or C (u t1 ... tn),"
+  , text "where C is a type class, u is a type variable and t1, ..., tn are types."
+  ]
+
+errIllegalSimpleConstraint :: Constraint -> Message
+errIllegalSimpleConstraint c@(Constraint _ qcls _) = spanInfoMessage qcls $ vcat
+  [ text "Illegal class constraint" <+> pPrint c
+  , text "Constraints in class and instance declarations must be of"
+  , text "the form C u, where C is a type class and u is a type variable."
+  ]
+
+errIllegalInstanceType :: SpanInfo -> InstanceType -> Message
+errIllegalInstanceType spi inst = spanInfoMessage spi $ vcat
+  [ text "Illegal instance type" <+> ppInstanceType inst
+  , text "The instance type must be of the form (T u_1 ... u_n),"
+  , text "where T is not a type synonym and u_1, ..., u_n are"
+  , text "mutually distinct, non-anonymous type variables."
+  ]
+
+errIllegalDataInstance :: QualIdent -> Message
+errIllegalDataInstance qcls = spanInfoMessage qcls $ vcat
+  [ text "Illegal instance of" <+> ppQIdent qcls
+  , text "Instances of this class cannot be defined."
+  , text "Instead, they are automatically derived if possible."
+  ]
diff --git a/src/Checks/WarnCheck.hs b/src/Checks/WarnCheck.hs
new file mode 100644
--- /dev/null
+++ b/src/Checks/WarnCheck.hs
@@ -0,0 +1,1641 @@
+{- |
+    Module      :  $Header$
+    Description :  Checks for irregular code
+    Copyright   :  (c) 2006        Martin Engelke
+                       2011 - 2014 Björn Peemöller
+                       2014 - 2015 Jan Tikovsky
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module searches for potentially irregular code and generates
+    warning messages.
+-}
+{-# LANGUAGE CPP #-}
+module Checks.WarnCheck (warnCheck) where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+import           Control.Applicative
+  ((<|>))
+import           Control.Monad
+  (filterM, foldM_, guard, liftM, liftM2, when, unless, void)
+import           Control.Monad.State.Strict    (State, execState, gets, modify)
+import qualified Data.IntSet         as IntSet
+  (IntSet, empty, insert, notMember, singleton, union, unions)
+import qualified Data.Map            as Map    (empty, insert, lookup, (!))
+import           Data.Maybe
+  (catMaybes, fromMaybe, listToMaybe)
+import           Data.List
+  ((\\), intersect, intersectBy, nub, sort, unionBy)
+import           Data.Char
+  (isLower, isUpper, toLower, toUpper, isAlpha)
+import qualified Data.Set.Extra as Set
+import           Data.Tuple.Extra
+  (snd3)
+
+import Curry.Base.Ident
+import Curry.Base.Position
+import Curry.Base.Pretty
+import Curry.Base.SpanInfo
+import Curry.Syntax
+import Curry.Syntax.Utils  (typeVariables)
+import Curry.Syntax.Pretty (pPrint)
+
+import Base.CurryTypes (ppTypeScheme, fromPred, toPredSet)
+import Base.Messages   (Message, spanInfoMessage, internalError)
+import Base.NestEnv    ( NestEnv, emptyEnv, localNestEnv, nestEnv, unnestEnv
+                       , qualBindNestEnv, qualInLocalNestEnv, qualLookupNestEnv
+                       , qualModifyNestEnv)
+
+import Base.Types
+import Base.Utils (findMultiples)
+import Env.ModuleAlias
+import Env.Class (ClassEnv, classMethods, hasDefaultImpl)
+import Env.TypeConstructor ( TCEnv, TypeInfo (..), lookupTypeInfo
+                           , qualLookupTypeInfo, getOrigName )
+import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)
+
+import CompilerOpts
+
+-- Find potentially incorrect code in a Curry program and generate warnings
+-- for the following issues:
+--   - multiply imported modules, multiply imported/hidden values
+--   - unreferenced variables
+--   - shadowing variables
+--   - idle case alternatives
+--   - overlapping case alternatives
+--   - non-adjacent function rules
+--   - wrong case mode
+--   - redundant context
+warnCheck :: WarnOpts -> CaseMode -> AliasEnv -> ValueEnv -> TCEnv -> ClassEnv
+          -> Module a -> [Message]
+warnCheck wOpts cOpts aEnv valEnv tcEnv clsEnv mdl
+  = runOn (initWcState mid aEnv valEnv tcEnv clsEnv (wnWarnFlags wOpts) cOpts) $ do
+      checkImports   is
+      checkDeclGroup ds
+      checkExports   es
+      checkMissingTypeSignatures ds
+      checkModuleAlias is
+      checkCaseMode  ds
+      checkRedContext ds
+  where Module _ _ _ mid es is ds = fmap (const ()) mdl
+
+type ScopeEnv = NestEnv IdInfo
+
+-- Current state of generating warnings
+data WcState = WcState
+  { moduleId    :: ModuleIdent
+  , scope       :: ScopeEnv
+  , aliasEnv    :: AliasEnv
+  , valueEnv    :: ValueEnv
+  , tyConsEnv   :: TCEnv
+  , classEnv    :: ClassEnv
+  , warnFlags   :: [WarnFlag]
+  , caseMode    :: CaseMode
+  , warnings    :: [Message]
+  }
+
+-- The monadic representation of the state allows the usage of monadic
+-- syntax (do expression) for dealing easier and safer with its
+-- contents.
+type WCM = State WcState
+
+initWcState :: ModuleIdent -> AliasEnv -> ValueEnv -> TCEnv -> ClassEnv
+            -> [WarnFlag] -> CaseMode -> WcState
+initWcState mid ae ve te ce wf cm = WcState mid emptyEnv ae ve te ce wf cm []
+
+getModuleIdent :: WCM ModuleIdent
+getModuleIdent = gets moduleId
+
+modifyScope :: (ScopeEnv -> ScopeEnv) -> WCM ()
+modifyScope f = modify $ \s -> s { scope = f $ scope s }
+
+warnFor :: WarnFlag -> WCM () -> WCM ()
+warnFor f act = do
+  warn <- gets $ \s -> f `elem` warnFlags s
+  when warn act
+
+report :: Message -> WCM ()
+report w = modify $ \ s -> s { warnings = w : warnings s }
+
+unAlias :: QualIdent -> WCM QualIdent
+unAlias q = do
+  aEnv <- gets aliasEnv
+  case qidModule q of
+    Nothing -> return q
+    Just m  -> case Map.lookup m aEnv of
+      Nothing -> return q
+      Just m' -> return $ qualifyWith m' (unqualify q)
+
+ok :: WCM ()
+ok = return ()
+
+-- |Run a 'WCM' action and return the list of messages
+runOn :: WcState -> WCM a -> [Message]
+runOn s f = sort $ warnings $ execState f s
+
+-- ---------------------------------------------------------------------------
+-- checkExports
+-- ---------------------------------------------------------------------------
+
+checkExports :: Maybe ExportSpec -> WCM () -- TODO checks
+checkExports Nothing                      = ok
+checkExports (Just (Exporting _ exports)) = do
+  mapM_ visitExport exports
+  reportUnusedGlobalVars
+    where
+      visitExport (Export _ qid) = visitQId qid
+      visitExport _              = ok
+
+-- ---------------------------------------------------------------------------
+-- checkImports
+-- ---------------------------------------------------------------------------
+
+-- Check import declarations for multiply imported modules and multiply
+-- imported/hidden values.
+-- The function uses a map of the already imported or hidden entities to
+-- collect the entities throughout multiple import statements.
+checkImports :: [ImportDecl] -> WCM ()
+checkImports = warnFor WarnMultipleImports . foldM_ checkImport Map.empty
+  where
+  checkImport env (ImportDecl pos mid _ _ spec) = case Map.lookup mid env of
+    Nothing   -> setImportSpec env mid $ fromImpSpec spec
+    Just ishs -> checkImportSpec env pos mid ishs spec
+
+  checkImportSpec env _ mid (_, _)    Nothing = do
+    report $ warnMultiplyImportedModule mid
+    return env
+
+  checkImportSpec env _ mid (is, hs) (Just (Importing _ is'))
+    | null is && any (`notElem` hs) is' = do
+        report $ warnMultiplyImportedModule mid
+        setImportSpec env mid (is', hs)
+    | null iis  = setImportSpec env mid (is' ++ is, hs)
+    | otherwise = do
+        mapM_ (report . (warnMultiplyImportedSymbol mid) . impName) iis
+        setImportSpec env mid (unionBy cmpImport is' is, hs)
+    where iis = intersectBy cmpImport is' is
+
+  checkImportSpec env _ mid (is, hs) (Just (Hiding _ hs'))
+    | null ihs  = setImportSpec env mid (is, hs' ++ hs)
+    | otherwise = do
+        mapM_ (report . (warnMultiplyHiddenSymbol mid) . impName) ihs
+        setImportSpec env mid (is, unionBy cmpImport hs' hs)
+    where ihs = intersectBy cmpImport hs' hs
+
+  fromImpSpec Nothing                 = ([], [])
+  fromImpSpec (Just (Importing _ is)) = (is, [])
+  fromImpSpec (Just (Hiding    _ hs)) = ([], hs)
+
+  setImportSpec env mid ishs = return $ Map.insert mid ishs env
+
+  cmpImport (ImportTypeWith _ id1 cs1) (ImportTypeWith _ id2 cs2)
+    = id1 == id2 && null (intersect cs1 cs2)
+  cmpImport i1 i2 = (impName i1) == (impName i2)
+
+  impName (Import           _ v) = v
+  impName (ImportTypeAll    _ t) = t
+  impName (ImportTypeWith _ t _) = t
+
+warnMultiplyImportedModule :: ModuleIdent -> Message
+warnMultiplyImportedModule mid = spanInfoMessage mid $ hsep $ map text
+  ["Module", moduleName mid, "is imported more than once"]
+
+warnMultiplyImportedSymbol :: ModuleIdent -> Ident -> Message
+warnMultiplyImportedSymbol mid ident = spanInfoMessage ident $ hsep $ map text
+  [ "Symbol", escName ident, "from module", moduleName mid
+  , "is imported more than once" ]
+
+warnMultiplyHiddenSymbol :: ModuleIdent -> Ident -> Message
+warnMultiplyHiddenSymbol mid ident = spanInfoMessage ident $ hsep $ map text
+  [ "Symbol", escName ident, "from module", moduleName mid
+  , "is hidden more than once" ]
+
+-- ---------------------------------------------------------------------------
+-- checkDeclGroup
+-- ---------------------------------------------------------------------------
+
+checkDeclGroup :: [Decl ()] -> WCM ()
+checkDeclGroup ds = do
+  mapM_ insertDecl   ds
+  mapM_ checkDecl    ds
+  checkRuleAdjacency ds
+
+checkLocalDeclGroup :: [Decl ()] -> WCM ()
+checkLocalDeclGroup ds = do
+  mapM_ checkLocalDecl ds
+  checkDeclGroup       ds
+
+-- ---------------------------------------------------------------------------
+-- Find function rules which are disjoined
+-- ---------------------------------------------------------------------------
+
+checkRuleAdjacency :: [Decl a] -> WCM ()
+checkRuleAdjacency decls = warnFor WarnDisjoinedRules
+                         $ foldM_ check (mkIdent "", Map.empty) decls
+  where
+  check (prevId, env) (FunctionDecl p _ f _) = do
+    cons <- isConsId f
+    if cons || prevId == f
+      then return (f, env)
+      else case Map.lookup f env of
+        Nothing -> return (f, Map.insert f p env)
+        Just p' -> do
+          report $ warnDisjoinedFunctionRules f (spanInfo2Pos p')
+          return (f, env)
+  check (_    , env) _                     = return (mkIdent "", env)
+
+warnDisjoinedFunctionRules :: Ident -> Position -> Message
+warnDisjoinedFunctionRules ident pos = spanInfoMessage ident $ hsep (map text
+  [ "Rules for function", escName ident, "are disjoined" ])
+  <+> parens (text "first occurrence at" <+> text (showLine pos))
+
+checkDecl :: Decl () -> WCM ()
+checkDecl (DataDecl          _ _ vs cs _) = inNestedScope $ do
+  mapM_ insertTypeVar   vs
+  mapM_ checkConstrDecl cs
+  reportUnusedTypeVars  vs
+checkDecl (NewtypeDecl       _ _ vs nc _) = inNestedScope $ do
+  mapM_ insertTypeVar   vs
+  checkNewConstrDecl nc
+  reportUnusedTypeVars vs
+checkDecl (TypeDecl            _ _ vs ty) = inNestedScope $ do
+  mapM_ insertTypeVar  vs
+  checkTypeExpr ty
+  reportUnusedTypeVars vs
+checkDecl (FunctionDecl        p _ f eqs) = checkFunctionDecl p f eqs
+checkDecl (PatternDecl           _ p rhs) = checkPattern p >> checkRhs rhs
+checkDecl (DefaultDecl             _ tys) = mapM_ checkTypeExpr tys
+checkDecl (ClassDecl        _ _ _ _ _ ds) = mapM_ checkDecl ds
+checkDecl (InstanceDecl p _ cx cls ty ds) = do
+  checkOrphanInstance p cx cls ty
+  checkMissingMethodImplementations p cls ds
+  mapM_ checkDecl ds
+checkDecl _                             = ok
+
+--TODO: shadowing und context etc.
+checkConstrDecl :: ConstrDecl -> WCM ()
+checkConstrDecl (ConstrDecl     _ c tys) = inNestedScope $ do
+  visitId c
+  mapM_ checkTypeExpr tys
+checkConstrDecl (ConOpDecl _ ty1 op ty2) = inNestedScope $ do
+  visitId op
+  mapM_ checkTypeExpr [ty1, ty2]
+checkConstrDecl (RecordDecl      _ c fs) = inNestedScope $ do
+  visitId c
+  mapM_ checkTypeExpr tys
+  where
+    tys = [ty | FieldDecl _ _ ty <- fs]
+
+checkNewConstrDecl :: NewConstrDecl -> WCM ()
+checkNewConstrDecl (NewConstrDecl _ c      ty) = do
+  visitId c
+  checkTypeExpr ty
+checkNewConstrDecl (NewRecordDecl _ c (_, ty)) = do
+  visitId c
+  checkTypeExpr ty
+
+checkTypeExpr :: TypeExpr -> WCM ()
+checkTypeExpr (ConstructorType     _ qid) = visitQTypeId qid
+checkTypeExpr (ApplyType       _ ty1 ty2) = mapM_ checkTypeExpr [ty1, ty2]
+checkTypeExpr (VariableType          _ v) = visitTypeId v
+checkTypeExpr (TupleType           _ tys) = mapM_ checkTypeExpr tys
+checkTypeExpr (ListType             _ ty) = checkTypeExpr ty
+checkTypeExpr (ArrowType       _ ty1 ty2) = mapM_ checkTypeExpr [ty1, ty2]
+checkTypeExpr (ParenType            _ ty) = checkTypeExpr ty
+checkTypeExpr (ForallType        _ vs ty) = do
+  mapM_ insertTypeVar vs
+  checkTypeExpr ty
+
+-- Checks locally declared identifiers (i.e. functions and logic variables)
+-- for shadowing
+checkLocalDecl :: Decl a -> WCM ()
+checkLocalDecl (FunctionDecl _ _ f _) = checkShadowing f
+checkLocalDecl (FreeDecl        _ vs) = mapM_ (checkShadowing . varIdent) vs
+checkLocalDecl (PatternDecl    _ p _) = checkPattern p
+checkLocalDecl _                      = ok
+
+checkFunctionDecl :: SpanInfo -> Ident -> [Equation ()] -> WCM ()
+checkFunctionDecl _ _ []  = ok
+checkFunctionDecl p f eqs = inNestedScope $ do
+  mapM_ checkEquation eqs
+  checkFunctionPatternMatch p f eqs
+
+checkFunctionPatternMatch :: SpanInfo -> Ident -> [Equation ()] -> WCM ()
+checkFunctionPatternMatch spi f eqs = do
+  let pats = map (\(Equation _ lhs _) -> snd (flatLhs lhs)) eqs
+  let guards = map eq2Guards eqs
+  (nonExhaustive, overlapped, nondet) <- checkPatternMatching pats guards
+  unless (null nonExhaustive) $ warnFor WarnIncompletePatterns $ report $
+    warnMissingPattern spi ("an equation for " ++ escName f) nonExhaustive
+  when (nondet || not (null overlapped)) $ warnFor WarnOverlapping $ report $
+    warnNondetOverlapping spi ("Function " ++ escName f)
+  where eq2Guards :: Equation () -> [CondExpr ()]
+        eq2Guards (Equation _ _ (GuardedRhs _ _ conds _)) = conds
+        eq2Guards _ = []
+
+-- Check an equation for warnings.
+-- This is done in a seperate scope as the left-hand-side may introduce
+-- new variables.
+checkEquation :: Equation () -> WCM ()
+checkEquation (Equation _ lhs rhs) = inNestedScope $ do
+  checkLhs lhs
+  checkRhs rhs
+  reportUnusedVars
+
+checkLhs :: Lhs a -> WCM ()
+checkLhs (FunLhs    _ _ ts) = do
+  mapM_ checkPattern ts
+  mapM_ (insertPattern False) ts
+checkLhs (OpLhs spi t1 op t2) = checkLhs (FunLhs spi op [t1, t2])
+checkLhs (ApLhs   _ lhs ts) = do
+  checkLhs lhs
+  mapM_ checkPattern ts
+  mapM_ (insertPattern False) ts
+
+checkPattern :: Pattern a -> WCM ()
+checkPattern (VariablePattern          _ _ v) = checkShadowing v
+checkPattern (ConstructorPattern    _ _ _ ps) = mapM_ checkPattern ps
+checkPattern (InfixPattern     spi a p1 f p2) =
+  checkPattern (ConstructorPattern spi a f [p1, p2])
+checkPattern (ParenPattern               _ p) = checkPattern p
+checkPattern (RecordPattern         _ _ _ fs) = mapM_ (checkField checkPattern) fs
+checkPattern (TuplePattern              _ ps) = mapM_ checkPattern ps
+checkPattern (ListPattern             _ _ ps) = mapM_ checkPattern ps
+checkPattern (AsPattern                _ v p) = checkShadowing v >> checkPattern p
+checkPattern (LazyPattern                _ p) = checkPattern p
+checkPattern (FunctionPattern       _ _ _ ps) = mapM_ checkPattern ps
+checkPattern (InfixFuncPattern spi a p1 f p2) =
+  checkPattern (FunctionPattern spi a f [p1, p2])
+checkPattern _                            = ok
+
+-- Check the right-hand-side of an equation.
+-- Because local declarations may introduce new variables, we need
+-- another scope nesting.
+checkRhs :: Rhs () -> WCM ()
+checkRhs (SimpleRhs _ _ e ds) = inNestedScope $ do
+  checkLocalDeclGroup ds
+  checkExpr e
+  reportUnusedVars
+checkRhs (GuardedRhs _ _ ce ds) = inNestedScope $ do
+  checkLocalDeclGroup ds
+  mapM_ checkCondExpr ce
+  reportUnusedVars
+
+checkCondExpr :: CondExpr () -> WCM ()
+checkCondExpr (CondExpr _ c e) = checkExpr c >> checkExpr e
+
+checkExpr :: Expression () -> WCM ()
+checkExpr (Variable            _ _ v) = visitQId v
+checkExpr (Paren                 _ e) = checkExpr e
+checkExpr (Typed               _ e _) = checkExpr e
+checkExpr (Record           _ _ _ fs) = mapM_ (checkField checkExpr) fs
+checkExpr (RecordUpdate       _ e fs) = do
+  checkExpr e
+  mapM_ (checkField checkExpr) fs
+checkExpr (Tuple                _ es) = mapM_ checkExpr es
+checkExpr (List               _ _ es) = mapM_ checkExpr es
+checkExpr (ListCompr         _ e sts) = checkStatements sts e
+checkExpr (EnumFrom              _ e) = checkExpr e
+checkExpr (EnumFromThen      _ e1 e2) = mapM_ checkExpr [e1, e2]
+checkExpr (EnumFromTo        _ e1 e2) = mapM_ checkExpr [e1, e2]
+checkExpr (EnumFromThenTo _ e1 e2 e3) = mapM_ checkExpr [e1, e2, e3]
+checkExpr (UnaryMinus            _ e) = checkExpr e
+checkExpr (Apply             _ e1 e2) = mapM_ checkExpr [e1, e2]
+checkExpr (InfixApply     _ e1 op e2) = do
+  visitQId (opName op)
+  mapM_ checkExpr [e1, e2]
+checkExpr (LeftSection         _ e _) = checkExpr e
+checkExpr (RightSection        _ _ e) = checkExpr e
+checkExpr (Lambda             _ ps e) = inNestedScope $ do
+  mapM_ checkPattern ps
+  mapM_ (insertPattern False) ps
+  checkExpr e
+  reportUnusedVars
+checkExpr (Let              _ _ ds e) = inNestedScope $ do
+  checkLocalDeclGroup ds
+  checkExpr e
+  reportUnusedVars
+checkExpr (Do              _ _ sts e) = checkStatements sts e
+checkExpr (IfThenElse     _ e1 e2 e3) = mapM_ checkExpr [e1, e2, e3]
+checkExpr (Case      spi _ ct e alts) = do
+  checkExpr e
+  mapM_ checkAlt alts
+  checkCaseAlts spi ct alts
+checkExpr _                       = ok
+
+checkStatements :: [Statement ()] -> Expression () -> WCM ()
+checkStatements []     e = checkExpr e
+checkStatements (s:ss) e = inNestedScope $ do
+  checkStatement s >> checkStatements ss e
+  reportUnusedVars
+
+checkStatement :: Statement () -> WCM ()
+checkStatement (StmtExpr    _ e) = checkExpr e
+checkStatement (StmtDecl _ _ ds) = checkLocalDeclGroup ds
+checkStatement (StmtBind _  p e) = do
+  checkPattern p >> insertPattern False p
+  checkExpr e
+
+checkAlt :: Alt () -> WCM ()
+checkAlt (Alt _ p rhs) = inNestedScope $ do
+  checkPattern p >> insertPattern False p
+  checkRhs rhs
+  reportUnusedVars
+
+checkField :: (a -> WCM ()) -> Field a -> WCM ()
+checkField check (Field _ _ x) = check x
+
+-- -----------------------------------------------------------------------------
+-- Check for orphan instances
+-- -----------------------------------------------------------------------------
+
+checkOrphanInstance :: SpanInfo -> Context -> QualIdent -> TypeExpr -> WCM ()
+checkOrphanInstance p cx cls ty = warnFor WarnOrphanInstances $ do
+  m <- getModuleIdent
+  tcEnv <- gets tyConsEnv
+  let ocls = getOrigName m cls tcEnv
+      otc  = getOrigName m tc  tcEnv
+  unless (isLocalIdent m ocls || isLocalIdent m otc) $ report $
+    warnOrphanInstance p $ pPrint $
+    InstanceDecl p WhitespaceLayout cx cls ty []
+  where tc = typeConstr ty
+
+warnOrphanInstance :: SpanInfo -> Doc -> Message
+warnOrphanInstance spi doc = spanInfoMessage spi $ text "Orphan instance:" <+> doc
+
+-- -----------------------------------------------------------------------------
+-- Check for missing method implementations
+-- -----------------------------------------------------------------------------
+
+checkMissingMethodImplementations :: SpanInfo -> QualIdent -> [Decl a] -> WCM ()
+checkMissingMethodImplementations p cls ds = warnFor WarnMissingMethods $ do
+  m <- getModuleIdent
+  tcEnv <- gets tyConsEnv
+  clsEnv <- gets classEnv
+  let ocls = getOrigName m cls tcEnv
+      ms   = classMethods ocls clsEnv
+  mapM_ (report . warnMissingMethodImplementation p) $
+    filter ((null fs ||) . not . flip (hasDefaultImpl ocls) clsEnv) $ ms \\ fs
+  where fs = map unRenameIdent $ concatMap impls ds
+
+warnMissingMethodImplementation :: SpanInfo -> Ident -> Message
+warnMissingMethodImplementation spi f = spanInfoMessage spi $ hsep $ map text
+  ["No explicit implementation for method", escName f]
+
+-- -----------------------------------------------------------------------------
+-- Check for missing type signatures
+-- -----------------------------------------------------------------------------
+
+-- |Check if every top-level function has an accompanying type signature.
+-- For external function declarations, this check is already performed
+-- during syntax checking.
+checkMissingTypeSignatures :: [Decl a] -> WCM ()
+checkMissingTypeSignatures ds = warnFor WarnMissingSignatures $ do
+  let typedFs   = [f | TypeSig       _ fs _ <- ds, f <- fs]
+      untypedFs = [f | FunctionDecl _ _ f _ <- ds, f `notElem` typedFs]
+  unless (null untypedFs) $ do
+    mid   <- getModuleIdent
+    tyScs <- mapM getTyScheme untypedFs
+    mapM_ report $ zipWith (warnMissingTypeSignature mid) untypedFs tyScs
+
+getTyScheme :: Ident -> WCM TypeScheme
+getTyScheme q = do
+  m     <- getModuleIdent
+  tyEnv <- gets valueEnv
+  return $ case qualLookupValue (qualifyWith m q) tyEnv of
+    [Value  _ _ _ tys] -> tys
+    _ -> internalError $ "Checks.WarnCheck.getTyScheme: " ++ show q
+
+warnMissingTypeSignature :: ModuleIdent -> Ident -> TypeScheme -> Message
+warnMissingTypeSignature mid i tys = spanInfoMessage i $ fsep
+  [ text "Top-level binding with no type signature:"
+  , nest 2 $ text (showIdent i) <+> text "::" <+> ppTypeScheme mid tys
+  ]
+
+-- -----------------------------------------------------------------------------
+-- Check for overlapping module alias names
+-- -----------------------------------------------------------------------------
+
+-- check if module aliases in import declarations overlap with the module name
+-- or another module alias
+
+checkModuleAlias :: [ImportDecl] -> WCM ()
+checkModuleAlias is = do
+  mid <- getModuleIdent
+  let alias      = catMaybes [a | ImportDecl _ _ _ a _ <- is]
+      modClash   = [a | a <- alias, a == mid]
+      aliasClash = findMultiples alias
+  unless (null   modClash) $ mapM_ (report . warnModuleNameClash) modClash
+  unless (null aliasClash) $ mapM_ (report . warnAliasNameClash ) aliasClash
+
+warnModuleNameClash :: ModuleIdent -> Message
+warnModuleNameClash mid = spanInfoMessage mid $ hsep $ map text
+  ["The module alias", escModuleName mid
+  , "overlaps with the current module name"]
+
+warnAliasNameClash :: [ModuleIdent] -> Message
+warnAliasNameClash []         = internalError
+  "WarnCheck.warnAliasNameClash: empty list"
+warnAliasNameClash mids = spanInfoMessage (head mids) $ text
+  "Overlapping module aliases" $+$ nest 2 (vcat (map myppAlias mids))
+  where myppAlias mid =
+          ppLine (getPosition mid) <> text ":" <+> text (escModuleName mid)
+
+-- -----------------------------------------------------------------------------
+-- Check for overlapping/unreachable and non-exhaustive case alternatives
+-- -----------------------------------------------------------------------------
+
+checkCaseAlts :: SpanInfo -> CaseType -> [Alt ()] -> WCM ()
+checkCaseAlts _ _ []      = ok
+checkCaseAlts spi ct alts = do
+  let spis = map (\(Alt s _ _) -> s) alts
+  let pats = map (\(Alt _ pat _) -> [pat]) alts
+  let guards = map alt2Guards alts
+  (nonExhaustive, overlapped, nondet) <- checkPatternMatching pats guards
+  case ct of
+    Flex -> do
+      unless (null nonExhaustive) $ warnFor WarnIncompletePatterns $ report $
+        warnMissingPattern spi "an fcase alternative" nonExhaustive
+      when (nondet || not (null overlapped)) $ warnFor WarnOverlapping $ report
+        $ warnNondetOverlapping spi "An fcase expression"
+    Rigid -> do
+      unless (null nonExhaustive) $ warnFor WarnIncompletePatterns $ report $
+        warnMissingPattern spi "a case alternative" nonExhaustive
+      unless (null overlapped) $ void $ mapM (warnFor WarnOverlapping . report) $
+        map (\(i, pat) -> warnUnreachablePattern (spis !! i) pat) overlapped
+  where alt2Guards :: Alt () -> [CondExpr ()]
+        alt2Guards (Alt _ _ (GuardedRhs _ _ conds _)) = conds
+        alt2Guards _ = []
+
+-- -----------------------------------------------------------------------------
+-- Check for non-exhaustive and overlapping patterns.
+-- For an example, consider the following function definition:
+-- @
+-- f [True]    = 0
+-- f (False:_) = 1
+-- @
+-- In this declaration, the following patterns are not matched:
+-- @
+-- [] _
+-- (True:_:_)
+-- @
+-- This is identified and reported by the following code,, both for pattern
+-- matching in function declarations and (f)case expressions.
+-- -----------------------------------------------------------------------------
+
+checkPatternMatching :: [[Pattern ()]] -> [[CondExpr ()]]
+                     -> WCM ([ExhaustivePats], [OverlappingPats], Bool)
+checkPatternMatching pats guards = do
+  -- 1. We simplify the patterns by removing syntactic sugar temporarily
+  --    for a simpler implementation.
+  simplePats <- mapM (mapM simplifyPat) pats
+  -- 2. We compute missing and used pattern matching alternatives
+  (missing, used, nondet) <- processEqs (zip3 [0..] simplePats guards)
+  -- 3. If any, we report the missing patterns, whereby we re-add the syntactic
+  --    sugar removed in step (1) for a more precise output.
+  nonExhaustive <- mapM tidyExhaustivePats missing
+  let overlap = [(i, eqn) | (i, eqn) <- zip [0..] pats, i `IntSet.notMember` used]
+  return (nonExhaustive, overlap, nondet)
+
+-- |Simplify a 'Pattern' until it only consists of
+--   * Variables
+--   * Integer, Float or Char literals
+--   * Constructors
+-- All other patterns like as-patterns, list patterns and alike are desugared.
+simplifyPat :: Pattern () -> WCM (Pattern ())
+simplifyPat p@(LiteralPattern        _ _ l) = return $ case l of
+  String s -> simplifyListPattern $ map (LiteralPattern NoSpanInfo () . Char) s
+  _        -> p
+simplifyPat (NegativePattern       spi a l) =
+  return $ LiteralPattern spi a (negateLit l)
+  where
+  negateLit (Int   n) = Int   (-n)
+  negateLit (Float d) = Float (-d)
+  negateLit x         = x
+simplifyPat v@(VariablePattern       _ _ _) = return v
+simplifyPat (ConstructorPattern spi a c ps) =
+  ConstructorPattern spi a c `liftM` mapM simplifyPat ps
+simplifyPat (InfixPattern    spi a p1 c p2) =
+  ConstructorPattern spi a c `liftM` mapM simplifyPat [p1, p2]
+simplifyPat (ParenPattern              _ p) = simplifyPat p
+simplifyPat (RecordPattern        _ _ c fs) = do
+  (_, ls) <- getAllLabels c
+  let ps = map (getPattern (map field2Tuple fs)) ls
+  simplifyPat (ConstructorPattern NoSpanInfo () c ps)
+  where
+    getPattern fs' l' =
+      fromMaybe wildPat (lookup l' [(unqualify l, p) | (l, p) <- fs'])
+simplifyPat (TuplePattern            _ ps) =
+  ConstructorPattern NoSpanInfo () (qTupleId (length ps))
+    `liftM` mapM simplifyPat ps
+simplifyPat (ListPattern           _ _ ps) =
+  simplifyListPattern `liftM` mapM simplifyPat ps
+simplifyPat (AsPattern             _ _ p) = simplifyPat p
+simplifyPat (LazyPattern             _ _) = return wildPat
+simplifyPat (FunctionPattern     _ _ _ _) = return wildPat
+simplifyPat (InfixFuncPattern  _ _ _ _ _) = return wildPat
+
+getAllLabels :: QualIdent -> WCM (QualIdent, [Ident])
+getAllLabels c = do
+  tyEnv <- gets valueEnv
+  case qualLookupValue c tyEnv of
+    [DataConstructor qc _ ls _] -> return (qc, ls)
+    _                           -> internalError $
+          "Checks.WarnCheck.getAllLabels: " ++ show c
+
+-- |Create a simplified list pattern by applying @:@ and @[]@.
+simplifyListPattern :: [Pattern ()] -> Pattern ()
+simplifyListPattern =
+  foldr (\p1 p2 -> ConstructorPattern NoSpanInfo () qConsId [p1, p2])
+        (ConstructorPattern NoSpanInfo () qNilId [])
+
+-- |'ExhaustivePats' describes those pattern missing for an exhaustive
+-- pattern matching, where a value can be thought of as a missing equation.
+-- The first component contains the unmatched patterns, while the second
+-- pattern contains an identifier and the literals matched for this identifier.
+--
+-- This is necessary when checking literal patterns because of the sheer
+-- number of possible patterns. Missing literals are therefore converted
+-- into the form @ ... x ... with x `notElem` [l1, ..., ln]@.
+type EqnPats = [Pattern ()]
+type EqnGuards = [CondExpr ()]
+type EqnNo   = Int
+type EqnInfo = (EqnNo, EqnPats, EqnGuards)
+
+type ExhaustivePats = (EqnPats, [(Ident, [Literal])])
+type OverlappingPats = (EqnNo, EqnPats)
+type EqnSet  = IntSet.IntSet
+
+-- |Compute the missing pattern by inspecting the first patterns and
+-- categorize them as literal, constructor or variable patterns.
+processEqs :: [EqnInfo] -> WCM ([ExhaustivePats], EqnSet, Bool)
+processEqs []              = return ([], IntSet.empty, False)
+processEqs eqs@((n, ps, gs):eqs')
+  | null ps                = if guardsExhaustive then return ([], IntSet.singleton n, length eqs > 1)
+                                                 else do -- Current expression is guarded, thus potentially
+                                                         -- non-exhaustive. Therefore process remaining expressions.
+                                                         (missing', used', _) <- processEqs eqs'
+                                                         return (missing', IntSet.insert n used', length eqs > 1)
+  | any isLitPat firstPats = processLits eqs
+  | any isConPat firstPats = processCons eqs
+  | all isVarPat firstPats = processVars eqs
+  | otherwise              = internalError "Checks.WarnCheck.processEqs"
+  where firstPats = map firstPat eqs
+        guardsExhaustive = null gs || any guardAlwaysTrue gs
+        guardAlwaysTrue :: CondExpr () -> Bool
+        guardAlwaysTrue (CondExpr _ e _) = case e of
+          Constructor _ _ q -> qidAlwaysTrue q
+          Variable    _ _ q -> qidAlwaysTrue q
+          _ -> False
+        qidAlwaysTrue :: QualIdent -> Bool
+        qidAlwaysTrue q = elem (idName $ qidIdent q) ["True", "success", "otherwise"]
+        
+
+-- |Literal patterns are checked by extracting the matched literals
+--  and constructing a pattern for any missing case.
+processLits :: [EqnInfo] -> WCM ([ExhaustivePats], EqnSet, Bool)
+processLits []       = error "WarnCheck.processLits"
+processLits qs@(q:_) = do
+  -- Check any patterns starting with the literals used
+  (missing1, used1, nd1) <- processUsedLits usedLits qs
+  if null defaults
+    then return $ (defaultPat : missing1, used1, nd1)
+    else do
+      -- Missing patterns for the default alternatives
+      (missing2, used2, nd2) <- processEqs defaults
+      return ( [ (wildPat : ps, cs) | (ps, cs) <- missing2 ] ++ missing1
+             , IntSet.union used1 used2, nd1 || nd2 )
+  where
+  -- The literals occurring in the patterns
+  usedLits   = nub $ concatMap (getLit . firstPat) qs
+  -- default alternatives (variable pattern)
+  defaults   = [ shiftPat q' | q' <- qs, isVarPat (firstPat q') ]
+  -- Pattern for all non-matched literals
+  defaultPat = ( VariablePattern NoSpanInfo () newVar :
+                   replicate (length (snd3 q) - 1) wildPat
+               , [(newVar, usedLits)]
+               )
+  newVar     = mkIdent "x"
+
+-- |Construct exhaustive patterns starting with the used literals
+processUsedLits :: [Literal] -> [EqnInfo]
+                -> WCM ([ExhaustivePats], EqnSet, Bool)
+processUsedLits lits qs = do
+  (eps, idxs, nds) <- unzip3 `liftM` mapM process lits
+  return (concat eps, IntSet.unions idxs, or nds)
+  where
+  process lit = do
+    let qs' = [shiftPat q | q <- qs, isVarLit lit (firstPat q)]
+        ovlp = length qs' > 1
+    (missing, used, nd) <- processEqs qs'
+    return ( map (\(xs, ys) -> (LiteralPattern NoSpanInfo () lit : xs, ys))
+                 missing
+           , used
+           , nd && ovlp
+           )
+
+-- |Constructor patterns are checked by extracting the matched constructors
+--  and constructing a pattern for any missing case.
+processCons :: [EqnInfo] -> WCM ([ExhaustivePats], EqnSet, Bool)
+processCons []       = error "WarnCheck.processCons"
+processCons qs@(q:_) = do
+  -- Compute any missing patterns starting with the used constructors
+  (missing1, used1, nd) <- processUsedCons used_cons qs
+  -- Determine unused constructors
+  unused   <- getUnusedCons (map fst used_cons)
+  if null unused
+    then return (missing1, used1, nd)
+    else if null defaults
+      then return $ (map defaultPat unused ++ missing1, used1, nd)
+      else do
+        -- Missing patterns for the default alternatives
+        (missing2, used2, nd2) <- processEqs defaults
+        return ( [ (mkPattern c : ps, cs) | c <- unused, (ps, cs) <- missing2 ]
+                  ++ missing1
+               , IntSet.union used1 used2, nd || nd2)
+  where
+  -- used constructors (occurring in a pattern)
+  used_cons    = nub $ concatMap (getCon . firstPat) qs
+  -- default alternatives (variable pattern)
+  defaults     = [ shiftPat q' | q' <- qs, isVarPat (firstPat q') ]
+  -- Pattern for a non-matched constructors
+  defaultPat c = (mkPattern c : replicate (length (snd3 q) - 1) wildPat, [])
+  mkPattern  c = ConstructorPattern NoSpanInfo ()
+                  (qualifyLike (fst $ head used_cons) (constrIdent c))
+                  (replicate (length $ constrTypes c) wildPat)
+
+-- |Construct exhaustive patterns starting with the used constructors
+processUsedCons :: [(QualIdent, Int)] -> [EqnInfo]
+                -> WCM ([ExhaustivePats], EqnSet, Bool)
+processUsedCons cons qs = do
+  (eps, idxs, nds) <- unzip3 `liftM` mapM process cons
+  return (concat eps, IntSet.unions idxs, or nds)
+  where
+  process (c, a) = do
+    let qs' = [ removeFirstCon c a q | q <- qs , isVarCon c (firstPat q)]
+        ovlp = length qs' > 1
+    (missing, used, nd) <- processEqs qs'
+    return (map (\(xs, ys) -> (makeCon c a xs, ys)) missing, used, nd && ovlp)
+
+  makeCon c a ps = let (args, rest) = splitAt a ps
+                   in ConstructorPattern NoSpanInfo () c args : rest
+  
+  removeFirstCon c a (n, p:ps, gs)
+    | isVarPat p = (n, replicate a wildPat ++ ps, gs)
+    | isCon c  p = (n, patArgs p           ++ ps, gs)
+  removeFirstCon _ _ _ = internalError "Checks.WarnCheck.removeFirstCon"
+
+-- |Variable patterns are exhaustive, so they are checked by simply
+-- checking the following patterns.
+processVars :: [EqnInfo] -> WCM ([ExhaustivePats], EqnSet, Bool)
+processVars []               = error "WarnCheck.processVars"
+processVars eqs@((n, _, _) : _) = do
+  let ovlp = length eqs > 1
+  (missing, used, nd) <- processEqs (map shiftPat eqs)
+  return ( map (\(xs, ys) -> (wildPat : xs, ys)) missing
+         , IntSet.insert n used, nd && ovlp)
+
+-- |Return the constructors of a type not contained in the list of constructors.
+getUnusedCons :: [QualIdent] -> WCM [DataConstr]
+getUnusedCons []       = internalError "Checks.WarnCheck.getUnusedCons"
+getUnusedCons qs@(q:_) = do
+  allCons <- getConTy q >>= getTyCons . rootOfType . arrowBase
+  return [c | c <- allCons, (constrIdent c) `notElem` map unqualify qs]
+
+-- |Retrieve the type of a given constructor.
+getConTy :: QualIdent -> WCM Type
+getConTy q = do
+  tyEnv <- gets valueEnv
+  tcEnv <- gets tyConsEnv
+  case qualLookupValue q tyEnv of
+    [DataConstructor  _ _ _ (ForAll _ (PredType _ ty))] -> return ty
+    [NewtypeConstructor _ _ (ForAll _ (PredType _ ty))] -> return ty
+    _ -> case qualLookupTypeInfo q tcEnv of
+      [AliasType _ _ _ ty] -> return ty
+      _ -> internalError $ "Checks.WarnCheck.getConTy: " ++ show q
+
+-- |Retrieve all constructors of a given type.
+getTyCons :: QualIdent -> WCM [DataConstr]
+getTyCons tc = do
+  tc'   <- unAlias tc
+  tcEnv <- gets tyConsEnv
+  let getTyCons' :: [TypeInfo] -> Either String [DataConstr]
+      getTyCons' ti = case ti of
+        [DataType     _ _ cs] -> Right cs
+        [RenamingType _ _ nc] -> Right $ [nc]
+        _                     -> Left $ "Checks.WarnCheck.getTyCons: " ++ show tc ++ ' ' : show ti ++ '\n' : show tcEnv
+      csResult = getTyCons' (qualLookupTypeInfo tc tcEnv)
+             <|> getTyCons' (qualLookupTypeInfo tc' tcEnv)
+             <|> getTyCons' (lookupTypeInfo (unqualify tc) tcEnv) -- Fall back on unqualified lookup if qualified doesn't work
+  case csResult of
+    Right cs -> return cs
+    Left err -> internalError err
+
+-- |Resugar the exhaustive patterns previously desugared at 'simplifyPat'.
+tidyExhaustivePats :: ExhaustivePats -> WCM ExhaustivePats
+tidyExhaustivePats (xs, ys) = mapM tidyPat xs >>= \xs' -> return (xs', ys)
+
+-- |Resugar a pattern previously desugared at 'simplifyPat', i.e.
+--   * Convert a tuple constructor pattern into a tuple pattern
+--   * Convert a list constructor pattern representing a finite list
+--     into a list pattern
+tidyPat :: Pattern () -> WCM (Pattern ())
+tidyPat p@(LiteralPattern        _ _ _) = return p
+tidyPat p@(VariablePattern       _ _ _) = return p
+tidyPat p@(ConstructorPattern _ _ c ps)
+  | isQTupleId c                      =
+    TuplePattern NoSpanInfo `liftM` mapM tidyPat ps
+  | c == qConsId && isFiniteList p    =
+    ListPattern NoSpanInfo () `liftM` mapM tidyPat (unwrapFinite p)
+  | c == qConsId                      = unwrapInfinite p
+  | otherwise                         =
+    ConstructorPattern NoSpanInfo () c `liftM` mapM tidyPat ps
+  where
+  isFiniteList (ConstructorPattern _ _ d []     ) = d == qNilId
+  isFiniteList (ConstructorPattern _ _ d [_, e2])
+                                   | d == qConsId = isFiniteList e2
+  isFiniteList _                                  = False
+
+  unwrapFinite (ConstructorPattern _ _ _ []     ) = []
+  unwrapFinite (ConstructorPattern _ _ _ [p1,p2]) = p1 : unwrapFinite p2
+  unwrapFinite pat
+    = internalError $ "WarnCheck.tidyPat.unwrapFinite: " ++ show pat
+
+  unwrapInfinite (ConstructorPattern _ a d [p1,p2]) =
+    liftM2 (flip (InfixPattern NoSpanInfo a) d) (tidyPat p1) (unwrapInfinite p2)
+  unwrapInfinite p0                                 = return p0
+
+tidyPat p = internalError $ "Checks.WarnCheck.tidyPat: " ++ show p
+
+-- |Get the first pattern of a list.
+firstPat :: EqnInfo -> Pattern ()
+firstPat (_, [],    _) = internalError "Checks.WarnCheck.firstPat: empty list"
+firstPat (_, (p:_), _) = p
+
+-- |Drop the first pattern of a list.
+shiftPat :: EqnInfo -> EqnInfo
+shiftPat (_, [],     _ ) = internalError "Checks.WarnCheck.shiftPat: empty list"
+shiftPat (n, (_:ps), gs) = (n, ps, gs)
+
+-- |Wildcard pattern.
+wildPat :: Pattern ()
+wildPat = VariablePattern NoSpanInfo () anonId
+
+-- |Retrieve any literal out of a pattern.
+getLit :: Pattern a -> [Literal]
+getLit (LiteralPattern _ _ l) = [l]
+getLit _                      = []
+
+-- |Retrieve the constructor name and its arity for a pattern.
+getCon :: Pattern a -> [(QualIdent, Int)]
+getCon (ConstructorPattern _ _ c ps) = [(c, length ps)]
+getCon _                             = []
+
+-- |Is a pattern a variable or literal pattern?
+isVarLit :: Literal -> Pattern a -> Bool
+isVarLit l p = isVarPat p || isLit l p
+
+-- |Is a pattern a variable or a constructor pattern with the given constructor?
+isVarCon :: QualIdent -> Pattern a -> Bool
+isVarCon c p = isVarPat p || isCon c p
+
+-- |Is a pattern a pattern matching for the given constructor?
+isCon :: QualIdent -> Pattern a -> Bool
+isCon c (ConstructorPattern _ _ d _) = c == d
+isCon _ _                            = False
+
+-- |Is a pattern a pattern matching for the given literal?
+isLit :: Literal -> Pattern a -> Bool
+isLit l (LiteralPattern _ _ m) = l == m
+isLit _ _                      = False
+
+-- |Is a pattern a literal pattern?
+isLitPat :: Pattern a -> Bool
+isLitPat (LiteralPattern  _ _ _) = True
+isLitPat _                       = False
+
+-- |Is a pattern a variable pattern?
+isVarPat :: Pattern a -> Bool
+isVarPat (VariablePattern _ _ _) = True
+isVarPat _                       = False
+
+-- |Is a pattern a constructor pattern?
+isConPat :: Pattern a -> Bool
+isConPat (ConstructorPattern _ _ _ _) = True
+isConPat _                            = False
+
+-- |Retrieve the arguments of a pattern.
+patArgs :: Pattern a -> [Pattern a]
+patArgs (ConstructorPattern _ _ _ ps) = ps
+patArgs _                             = []
+
+-- |Warning message for non-exhaustive patterns.
+-- To shorten the output only the first 'maxPattern' are printed,
+-- additional pattern are abbreviated by dots.
+warnMissingPattern :: SpanInfo -> String -> [ExhaustivePats] -> Message
+warnMissingPattern spi loc pats = spanInfoMessage spi
+  $   text "Pattern matches are non-exhaustive"
+  $+$ text "In" <+> text loc <> char ':'
+  $+$ nest 2 (text "Patterns not matched:" $+$ nest 2 (vcat (ppExPats pats)))
+  where
+  ppExPats ps
+    | length ps > maxPattern = ppPats ++ [text "..."]
+    | otherwise              = ppPats
+    where ppPats = map ppExPat (take maxPattern ps)
+  ppExPat (ps, cs)
+    | null cs   = ppPats
+    | otherwise = ppPats <+> text "with" <+> hsep (map ppCons cs)
+    where ppPats = hsep (map (pPrintPrec 2) ps)
+  ppCons (i, lits) = pPrint i <+> text "`notElem`"
+            <+> pPrintPrec 0 (List NoSpanInfo () (map (Literal NoSpanInfo ()) lits))
+
+-- |Warning message for unreachable patterns.
+-- To shorten the output only the first 'maxPattern' are printed,
+-- additional pattern are abbreviated by dots.
+warnUnreachablePattern :: SpanInfo  -> [Pattern a] -> Message
+warnUnreachablePattern spi pats = spanInfoMessage spi
+  $   text "Pattern matches are potentially unreachable"
+  $+$ text "In a case alternative:"
+  $+$ nest 2 (ppPat pats <+> text "->" <+> text "...")
+  where
+  ppPat ps = hsep (map (pPrintPrec 2) ps)
+
+-- |Maximum number of missing patterns to be shown.
+maxPattern :: Int
+maxPattern = 4
+
+warnNondetOverlapping :: SpanInfo -> String -> Message
+warnNondetOverlapping spi loc = spanInfoMessage spi $
+  text loc <+> text "is potentially non-deterministic due to overlapping rules"
+
+-- -----------------------------------------------------------------------------
+
+checkShadowing :: Ident -> WCM ()
+checkShadowing x = warnFor WarnNameShadowing $
+  shadowsVar x >>= maybe ok (report . warnShadowing x)
+
+reportUnusedVars :: WCM ()
+reportUnusedVars = reportAllUnusedVars WarnUnusedBindings
+
+reportUnusedGlobalVars :: WCM ()
+reportUnusedGlobalVars = reportAllUnusedVars WarnUnusedGlobalBindings
+
+reportAllUnusedVars :: WarnFlag -> WCM ()
+reportAllUnusedVars wFlag = warnFor wFlag $ do
+  unused <- returnUnrefVars
+  unless (null unused) $ mapM_ report $ map warnUnrefVar unused
+
+reportUnusedTypeVars :: [Ident] -> WCM ()
+reportUnusedTypeVars vs = warnFor WarnUnusedBindings $ do
+  unused <- filterM isUnrefTypeVar vs
+  unless (null unused) $ mapM_ report $ map warnUnrefTypeVar unused
+
+-- ---------------------------------------------------------------------------
+-- For detecting unreferenced variables, the following functions update the
+-- current check state by adding identifiers occuring in declaration left hand
+-- sides.
+
+insertDecl :: Decl a -> WCM ()
+insertDecl (DataDecl      _ d _ cs _) = do
+  insertTypeConsId d
+  mapM_ insertConstrDecl cs
+insertDecl (ExternalDataDecl   _ d _) = insertTypeConsId d
+insertDecl (NewtypeDecl   _ d _ nc _) = do
+  insertTypeConsId d
+  insertNewConstrDecl nc
+insertDecl (TypeDecl        _ t _ ty) = do
+  insertTypeConsId t
+  insertTypeExpr ty
+insertDecl (FunctionDecl     _ _ f _) = do
+  cons <- isConsId f
+  unless cons $ insertVar f
+insertDecl (ExternalDecl        _ vs) = mapM_ (insertVar . varIdent) vs
+insertDecl (PatternDecl        _ p _) = insertPattern False p
+insertDecl (FreeDecl            _ vs) = mapM_ (insertVar . varIdent) vs
+insertDecl (ClassDecl _ _ _ cls _ ds) = do
+  insertTypeConsId cls
+  mapM_ insertVar $ concatMap methods ds
+insertDecl _                          = ok
+
+insertTypeExpr :: TypeExpr -> WCM ()
+insertTypeExpr (VariableType       _ _) = ok
+insertTypeExpr (ConstructorType    _ _) = ok
+insertTypeExpr (ApplyType    _ ty1 ty2) = mapM_ insertTypeExpr [ty1,ty2]
+insertTypeExpr (TupleType        _ tys) = mapM_ insertTypeExpr tys
+insertTypeExpr (ListType          _ ty) = insertTypeExpr ty
+insertTypeExpr (ArrowType    _ ty1 ty2) = mapM_ insertTypeExpr [ty1,ty2]
+insertTypeExpr (ParenType         _ ty) = insertTypeExpr ty
+insertTypeExpr (ForallType      _ _ ty) = insertTypeExpr ty
+
+insertConstrDecl :: ConstrDecl -> WCM ()
+insertConstrDecl (ConstrDecl _    c _) = insertConsId c
+insertConstrDecl (ConOpDecl  _ _ op _) = insertConsId op
+insertConstrDecl (RecordDecl _    c _) = insertConsId c
+
+insertNewConstrDecl :: NewConstrDecl -> WCM ()
+insertNewConstrDecl (NewConstrDecl _ c _) = insertConsId c
+insertNewConstrDecl (NewRecordDecl _ c _) = insertConsId c
+
+-- 'fp' indicates whether 'checkPattern' deals with the arguments
+-- of a function pattern or not.
+-- Since function patterns are not recognized before syntax check, it is
+-- necessary to determine whether a constructor pattern represents a
+-- constructor or a function.
+insertPattern :: Bool -> Pattern a -> WCM ()
+insertPattern fp (VariablePattern       _ _ v) = do
+  cons <- isConsId v
+  unless cons $ do
+    var <- isVarId v
+    if and [fp, var, not (isAnonId v)] then visitId v else insertVar v
+insertPattern fp (ConstructorPattern _ _ c ps) = do
+  cons <- isQualConsId c
+  mapM_ (insertPattern (not cons || fp)) ps
+insertPattern fp (InfixPattern    spi a p1 c p2)
+  = insertPattern fp (ConstructorPattern spi a c [p1, p2])
+insertPattern fp (ParenPattern          _ p) = insertPattern fp p
+insertPattern fp (RecordPattern    _ _ _ fs) = mapM_ (insertFieldPattern fp) fs
+insertPattern fp (TuplePattern         _ ps) = mapM_ (insertPattern fp) ps
+insertPattern fp (ListPattern        _ _ ps) = mapM_ (insertPattern fp) ps
+insertPattern fp (AsPattern           _ v p) = insertVar v >> insertPattern fp p
+insertPattern fp (LazyPattern           _ p) = insertPattern fp p
+insertPattern _  (FunctionPattern  _ _ f ps) = do
+  visitQId f
+  mapM_ (insertPattern True) ps
+insertPattern _  (InfixFuncPattern spi a p1 f p2)
+  = insertPattern True (FunctionPattern spi a f [p1, p2])
+insertPattern _ _ = ok
+
+insertFieldPattern :: Bool -> Field (Pattern a) -> WCM ()
+insertFieldPattern fp (Field _ _ p) = insertPattern fp p
+
+-- ---------------------------------------------------------------------------
+
+-- Data type for distinguishing identifiers as either (type) constructors or
+-- (type) variables (including functions).
+data IdInfo
+  = ConsInfo           -- ^ Constructor
+  | VarInfo Ident Bool -- ^ Variable with original definition (for position)
+                       --   and used flag
+  deriving Show
+
+isVariable :: IdInfo -> Bool
+isVariable (VarInfo _ _) = True
+isVariable _             = False
+
+getVariable :: IdInfo -> Maybe Ident
+getVariable (VarInfo v _) = Just v
+getVariable _             = Nothing
+
+isConstructor :: IdInfo -> Bool
+isConstructor ConsInfo = True
+isConstructor _        = False
+
+variableVisited :: IdInfo -> Bool
+variableVisited (VarInfo _ v) = v
+variableVisited _             = True
+
+visitVariable :: IdInfo -> IdInfo
+visitVariable (VarInfo v _) = VarInfo v True
+visitVariable  info         = info
+
+insertScope :: QualIdent -> IdInfo -> WCM ()
+insertScope qid info = modifyScope $ qualBindNestEnv qid info
+
+insertVar :: Ident -> WCM ()
+insertVar v = unless (isAnonId v) $ do
+  known <- isKnownVar v
+  if known then visitId v else insertScope (commonId v) (VarInfo v False)
+
+insertTypeVar :: Ident -> WCM ()
+insertTypeVar v = unless (isAnonId v)
+                $ insertScope (typeId v) (VarInfo v False)
+
+insertConsId :: Ident -> WCM ()
+insertConsId c = insertScope (commonId c) ConsInfo
+
+insertTypeConsId :: Ident -> WCM ()
+insertTypeConsId c = insertScope (typeId c) ConsInfo
+
+isVarId :: Ident -> WCM Bool
+isVarId v = gets (isVar $ commonId v)
+
+isConsId :: Ident -> WCM Bool
+isConsId c = gets (isCons $ qualify c)
+
+isQualConsId :: QualIdent -> WCM Bool
+isQualConsId qid = gets (isCons qid)
+
+shadows :: QualIdent -> WcState -> Maybe Ident
+shadows qid s = do
+  guard $ not (qualInLocalNestEnv qid sc)
+  info      <- listToMaybe $ qualLookupNestEnv qid sc
+  getVariable info
+  where sc = scope s
+
+shadowsVar :: Ident -> WCM (Maybe Ident)
+shadowsVar v = gets (shadows $ commonId v)
+
+visitId :: Ident -> WCM ()
+visitId v = modifyScope (qualModifyNestEnv visitVariable (commonId v))
+
+visitQId :: QualIdent -> WCM ()
+visitQId v = do
+  mid <- getModuleIdent
+  maybe ok visitId (localIdent mid v)
+
+visitTypeId :: Ident -> WCM ()
+visitTypeId v = modifyScope (qualModifyNestEnv visitVariable (typeId v))
+
+visitQTypeId :: QualIdent -> WCM ()
+visitQTypeId v = do
+  mid <- getModuleIdent
+  maybe ok visitTypeId (localIdent mid v)
+
+isKnownVar :: Ident -> WCM Bool
+isKnownVar v = gets $ \s -> isKnown s (commonId v)
+
+isUnrefTypeVar :: Ident -> WCM Bool
+isUnrefTypeVar v = gets (\s -> isUnref s (typeId v))
+
+returnUnrefVars :: WCM [Ident]
+returnUnrefVars = gets (\s ->
+  let ids    = map fst (localNestEnv (scope s))
+      unrefs = filter (isUnref s . qualify) ids
+  in  unrefs )
+
+inNestedScope :: WCM a -> WCM ()
+inNestedScope m = beginScope >> m >> endScope
+
+beginScope :: WCM ()
+beginScope = modifyScope nestEnv
+
+endScope :: WCM ()
+endScope = modifyScope unnestEnv
+
+------------------------------------------------------------------------------
+
+isKnown :: WcState -> QualIdent -> Bool
+isKnown s qid = qualInLocalNestEnv qid (scope s)
+
+isUnref :: WcState -> QualIdent -> Bool
+isUnref s qid = let sc = scope s
+                in  any (not . variableVisited) (qualLookupNestEnv qid sc)
+                    && qualInLocalNestEnv qid sc
+
+isVar :: QualIdent -> WcState -> Bool
+isVar qid s = maybe (isAnonId (unqualify qid))
+                    isVariable
+                    (listToMaybe (qualLookupNestEnv qid (scope s)))
+
+isCons :: QualIdent -> WcState -> Bool
+isCons qid s = maybe (isImportedCons s qid)
+                      isConstructor
+                      (listToMaybe (qualLookupNestEnv qid (scope s)))
+ where isImportedCons s' qid' = case qualLookupValue qid' (valueEnv s') of
+          (DataConstructor  _ _ _ _) : _ -> True
+          (NewtypeConstructor _ _ _) : _ -> True
+          _                              -> False
+
+-- Since type identifiers and normal identifiers (e.g. functions, variables
+-- or constructors) don't share the same namespace, it is necessary
+-- to distinguish them in the scope environment of the check state.
+-- For this reason type identifiers are annotated with 1 and normal
+-- identifiers are annotated with 0.
+commonId :: Ident -> QualIdent
+commonId = qualify . unRenameIdent
+
+typeId :: Ident -> QualIdent
+typeId = qualify . flip renameIdent 1
+
+
+-- --------------------------------------------------------------------------
+-- Check Case Mode
+-- --------------------------------------------------------------------------
+
+
+-- The following functions traverse the AST and search for (defining)
+-- identifiers and check if their names have the appropriate case mode.
+checkCaseMode :: [Decl a] -> WCM ()
+checkCaseMode = warnFor WarnIrregularCaseMode . mapM_ checkCaseModeDecl
+
+checkCaseModeDecl :: Decl a -> WCM ()
+checkCaseModeDecl (DataDecl _ tc vs cs _) = do
+  checkCaseModeID isDataDeclName tc
+  mapM_ (checkCaseModeID isVarName) vs
+  mapM_ checkCaseModeConstr cs
+checkCaseModeDecl (NewtypeDecl _ tc vs nc _) = do
+  checkCaseModeID isDataDeclName tc
+  mapM_ (checkCaseModeID isVarName) vs
+  checkCaseModeNewConstr nc
+checkCaseModeDecl (TypeDecl _ tc vs ty) = do
+  checkCaseModeID isDataDeclName tc
+  mapM_ (checkCaseModeID isVarName) vs
+  checkCaseModeTypeExpr ty
+checkCaseModeDecl (TypeSig _ fs qty) = do
+  mapM_ (checkCaseModeID isFuncName) fs
+  checkCaseModeQualTypeExpr qty
+checkCaseModeDecl (FunctionDecl _ _ f eqs) = do
+  checkCaseModeID isFuncName f
+  mapM_ checkCaseModeEquation eqs
+checkCaseModeDecl (ExternalDecl _ vs) =
+  mapM_ (checkCaseModeID isFuncName . varIdent) vs
+checkCaseModeDecl (PatternDecl _ t rhs) = do
+  checkCaseModePattern t
+  checkCaseModeRhs rhs
+checkCaseModeDecl (FreeDecl  _ vs) =
+  mapM_ (checkCaseModeID isVarName . varIdent) vs
+checkCaseModeDecl (DefaultDecl _ tys) = mapM_ checkTypeExpr tys
+checkCaseModeDecl (ClassDecl _ _ cx cls tv ds) = do
+  checkCaseModeContext cx
+  checkCaseModeID isClassDeclName cls
+  checkCaseModeID isVarName tv
+  mapM_ checkCaseModeDecl ds
+checkCaseModeDecl (InstanceDecl _ _ cx _ inst ds) = do
+  checkCaseModeContext cx
+  checkCaseModeTypeExpr inst
+  mapM_ checkCaseModeDecl ds
+checkCaseModeDecl _ = ok
+
+checkCaseModeConstr :: ConstrDecl -> WCM ()
+checkCaseModeConstr (ConstrDecl _ c tys) = do
+  checkCaseModeID isConstrName c
+  mapM_ checkCaseModeTypeExpr tys
+checkCaseModeConstr (ConOpDecl  _ ty1 c ty2) = do
+  checkCaseModeTypeExpr ty1
+  checkCaseModeID isConstrName c
+  checkCaseModeTypeExpr ty2
+checkCaseModeConstr (RecordDecl _ c fs) = do
+  checkCaseModeID isConstrName c
+  mapM_ checkCaseModeFieldDecl fs
+
+checkCaseModeFieldDecl :: FieldDecl -> WCM ()
+checkCaseModeFieldDecl (FieldDecl _ fs ty) = do
+  mapM_ (checkCaseModeID isFuncName) fs
+  checkCaseModeTypeExpr ty
+
+checkCaseModeNewConstr :: NewConstrDecl -> WCM ()
+checkCaseModeNewConstr (NewConstrDecl _ nc ty) = do
+  checkCaseModeID isConstrName nc
+  checkCaseModeTypeExpr ty
+checkCaseModeNewConstr (NewRecordDecl _ nc (f, ty)) = do
+  checkCaseModeID isConstrName nc
+  checkCaseModeID isFuncName f
+  checkCaseModeTypeExpr ty
+
+checkCaseModeContext :: Context -> WCM ()
+checkCaseModeContext = mapM_ checkCaseModeConstraint
+
+checkCaseModeConstraint :: Constraint -> WCM ()
+checkCaseModeConstraint (Constraint _ _ ty) = checkCaseModeTypeExpr ty
+
+checkCaseModeTypeExpr :: TypeExpr -> WCM ()
+checkCaseModeTypeExpr (ApplyType _ ty1 ty2) = do
+  checkCaseModeTypeExpr ty1
+  checkCaseModeTypeExpr ty2
+checkCaseModeTypeExpr (VariableType _ tv) = checkCaseModeID isVarName tv
+checkCaseModeTypeExpr (TupleType _ tys) = mapM_ checkCaseModeTypeExpr tys
+checkCaseModeTypeExpr (ListType _ ty) = checkCaseModeTypeExpr ty
+checkCaseModeTypeExpr (ArrowType _ ty1 ty2) = do
+  checkCaseModeTypeExpr ty1
+  checkCaseModeTypeExpr ty2
+checkCaseModeTypeExpr (ParenType _ ty) = checkCaseModeTypeExpr ty
+checkCaseModeTypeExpr (ForallType _ tvs ty) = do
+  mapM_ (checkCaseModeID isVarName) tvs
+  checkCaseModeTypeExpr ty
+checkCaseModeTypeExpr _ = ok
+
+checkCaseModeQualTypeExpr :: QualTypeExpr -> WCM ()
+checkCaseModeQualTypeExpr (QualTypeExpr _ cx ty) = do
+  checkCaseModeContext cx
+  checkCaseModeTypeExpr ty
+
+checkCaseModeEquation :: Equation a -> WCM ()
+checkCaseModeEquation (Equation _ lhs rhs) = do
+  checkCaseModeLhs lhs
+  checkCaseModeRhs rhs
+
+checkCaseModeLhs :: Lhs a -> WCM ()
+checkCaseModeLhs (FunLhs _ f ts) = do
+  checkCaseModeID isFuncName f
+  mapM_ checkCaseModePattern ts
+checkCaseModeLhs (OpLhs _ t1 f t2) = do
+  checkCaseModePattern t1
+  checkCaseModeID isFuncName f
+  checkCaseModePattern t2
+checkCaseModeLhs (ApLhs _ lhs ts) = do
+  checkCaseModeLhs lhs
+  mapM_ checkCaseModePattern ts
+
+checkCaseModeRhs :: Rhs a -> WCM ()
+checkCaseModeRhs (SimpleRhs _ _ e ds) = do
+  checkCaseModeExpr e
+  mapM_ checkCaseModeDecl ds
+checkCaseModeRhs (GuardedRhs _ _ es ds) = do
+  mapM_ checkCaseModeCondExpr es
+  mapM_ checkCaseModeDecl ds
+
+checkCaseModeCondExpr :: CondExpr a -> WCM ()
+checkCaseModeCondExpr (CondExpr _ g e) = do
+  checkCaseModeExpr g
+  checkCaseModeExpr e
+
+checkCaseModePattern :: Pattern a -> WCM ()
+checkCaseModePattern (VariablePattern _ _ v) = checkCaseModeID isVarName v
+checkCaseModePattern (ConstructorPattern _ _ _ ts) =
+  mapM_ checkCaseModePattern ts
+checkCaseModePattern (InfixPattern _ _ t1 _ t2) = do
+  checkCaseModePattern t1
+  checkCaseModePattern t2
+checkCaseModePattern (ParenPattern _ t) = checkCaseModePattern t
+checkCaseModePattern (RecordPattern _ _ _ fs) =
+  mapM_ checkCaseModeFieldPattern fs
+checkCaseModePattern (TuplePattern _ ts) = mapM_ checkCaseModePattern ts
+checkCaseModePattern (ListPattern _ _ ts) = mapM_ checkCaseModePattern ts
+checkCaseModePattern (AsPattern _ v t) = do
+  checkCaseModeID isVarName v
+  checkCaseModePattern t
+checkCaseModePattern (LazyPattern _ t) = checkCaseModePattern t
+checkCaseModePattern (FunctionPattern _ _ _ ts) = mapM_ checkCaseModePattern ts
+checkCaseModePattern (InfixFuncPattern _ _ t1 _ t2) = do
+  checkCaseModePattern t1
+  checkCaseModePattern t2
+checkCaseModePattern _ = ok
+
+checkCaseModeExpr :: Expression a -> WCM ()
+checkCaseModeExpr (Paren _ e) = checkCaseModeExpr e
+checkCaseModeExpr (Typed _ e qty) = do
+  checkCaseModeExpr e
+  checkCaseModeQualTypeExpr qty
+checkCaseModeExpr (Record _ _ _ fs) = mapM_ checkCaseModeFieldExpr fs
+checkCaseModeExpr (RecordUpdate _ e fs) = do
+  checkCaseModeExpr e
+  mapM_ checkCaseModeFieldExpr fs
+checkCaseModeExpr (Tuple _ es) = mapM_ checkCaseModeExpr es
+checkCaseModeExpr (List _ _ es) = mapM_ checkCaseModeExpr es
+checkCaseModeExpr (ListCompr _ e stms)  = do
+  checkCaseModeExpr e
+  mapM_ checkCaseModeStatement stms
+checkCaseModeExpr (EnumFrom _ e) = checkCaseModeExpr e
+checkCaseModeExpr (EnumFromThen _ e1 e2) = do
+  checkCaseModeExpr e1
+  checkCaseModeExpr e2
+checkCaseModeExpr (EnumFromTo _ e1 e2) = do
+  checkCaseModeExpr e1
+  checkCaseModeExpr e2
+checkCaseModeExpr (EnumFromThenTo _ e1 e2 e3) = do
+  checkCaseModeExpr e1
+  checkCaseModeExpr e2
+  checkCaseModeExpr e3
+checkCaseModeExpr (UnaryMinus _ e) = checkCaseModeExpr e
+checkCaseModeExpr (Apply _ e1 e2) = do
+  checkCaseModeExpr e1
+  checkCaseModeExpr e2
+checkCaseModeExpr (InfixApply _ e1 _ e2) = do
+  checkCaseModeExpr e1
+  checkCaseModeExpr e2
+checkCaseModeExpr (LeftSection _ e _) = checkCaseModeExpr e
+checkCaseModeExpr (RightSection _ _ e) = checkCaseModeExpr e
+checkCaseModeExpr (Lambda _ ts e) = do
+  mapM_ checkCaseModePattern ts
+  checkCaseModeExpr e
+checkCaseModeExpr (Let _ _ ds e) = do
+  mapM_ checkCaseModeDecl ds
+  checkCaseModeExpr e
+checkCaseModeExpr (Do _ _ stms e) = do
+  mapM_ checkCaseModeStatement stms
+  checkCaseModeExpr e
+checkCaseModeExpr (IfThenElse _ e1 e2 e3) = do
+  checkCaseModeExpr e1
+  checkCaseModeExpr e2
+  checkCaseModeExpr e3
+checkCaseModeExpr (Case _ _ _ e as) = do
+  mapM_ checkCaseModeAlt as
+  checkCaseModeExpr e
+checkCaseModeExpr _ = ok
+
+checkCaseModeStatement :: Statement a -> WCM ()
+checkCaseModeStatement (StmtExpr _    e) = checkCaseModeExpr e
+checkCaseModeStatement (StmtDecl _ _ ds) = mapM_ checkCaseModeDecl ds
+checkCaseModeStatement (StmtBind _  t e) = do
+  checkCaseModePattern t
+  checkCaseModeExpr e
+
+checkCaseModeAlt :: Alt a -> WCM ()
+checkCaseModeAlt (Alt _ t rhs) = checkCaseModePattern t >> checkCaseModeRhs rhs
+
+checkCaseModeFieldPattern :: Field (Pattern a) -> WCM ()
+checkCaseModeFieldPattern (Field _ _ t) = checkCaseModePattern t
+
+checkCaseModeFieldExpr :: Field (Expression a) -> WCM ()
+checkCaseModeFieldExpr (Field _ _ e) = checkCaseModeExpr e
+
+checkCaseModeID :: (CaseMode -> String -> Bool) -> Ident -> WCM ()
+checkCaseModeID f i@(Ident _ name _) = do
+  c <- gets caseMode
+  unless (f c name) (report $ warnCaseMode i c)
+
+isVarName :: CaseMode -> String -> Bool
+isVarName CaseModeProlog  (x:_) | isAlpha x = isUpper x
+isVarName CaseModeGoedel  (x:_) | isAlpha x = isLower x
+isVarName CaseModeHaskell (x:_) | isAlpha x = isLower x
+isVarName _               _     = True
+
+isFuncName :: CaseMode -> String -> Bool
+isFuncName CaseModeHaskell (x:_) | isAlpha x = isLower x
+isFuncName CaseModeGoedel  (x:_) | isAlpha x = isUpper x
+isFuncName CaseModeProlog  (x:_) | isAlpha x = isLower x
+isFuncName _               _     = True
+
+isConstrName :: CaseMode -> String -> Bool
+isConstrName = isDataDeclName
+
+isClassDeclName :: CaseMode -> String -> Bool
+isClassDeclName = isDataDeclName
+
+isDataDeclName :: CaseMode -> String -> Bool
+isDataDeclName CaseModeProlog  (x:_) | isAlpha x = isLower x
+isDataDeclName CaseModeGoedel  (x:_) | isAlpha x = isUpper x
+isDataDeclName CaseModeHaskell (x:_) | isAlpha x = isUpper x
+isDataDeclName _               _     = True
+
+-- ---------------------------------------------------------------------------
+-- Warn for redundant context
+-- ---------------------------------------------------------------------------
+
+--traverse the AST for QualTypeExpr/Context and check for redundancy
+checkRedContext :: [Decl a] -> WCM ()
+checkRedContext = warnFor WarnRedundantContext . mapM_ checkRedContextDecl
+
+getRedPredSet :: ModuleIdent -> ClassEnv -> TCEnv -> PredSet -> PredSet
+getRedPredSet m cenv tcEnv ps =
+  Set.map (pm Map.!) $ Set.difference qps $ minPredSet cenv qps --or fromJust $ Map.lookup
+  where (qps, pm) = Set.foldr qualifyAndAddPred (Set.empty, Map.empty) ps
+        qualifyAndAddPred p@(Pred qid ty) (ps', pm') =
+          let qp = Pred (getOrigName m qid tcEnv) ty
+          in (Set.insert qp ps', Map.insert qp p pm')
+
+getPredFromContext :: Context -> ([Ident], PredSet)
+getPredFromContext cx =
+  let vs = concatMap (\(Constraint _ _ ty) -> typeVariables ty) cx
+  in (vs, toPredSet vs cx)
+
+checkRedContext' :: (Pred -> Message) -> PredSet -> WCM ()
+checkRedContext' f ps = do
+  m     <- gets moduleId
+  cenv  <- gets classEnv
+  tcEnv <- gets tyConsEnv
+  mapM_ (report . f) (getRedPredSet m cenv tcEnv ps)
+
+checkRedContextDecl :: Decl a -> WCM ()
+checkRedContextDecl (TypeSig _ ids (QualTypeExpr _ cx _)) =
+  checkRedContext' (warnRedContext (warnRedFuncString ids) vs) ps
+  where (vs, ps) = getPredFromContext cx
+checkRedContextDecl (FunctionDecl _ _ _ eqs) = mapM_ checkRedContextEq eqs
+checkRedContextDecl (PatternDecl _ _ rhs) = checkRedContextRhs rhs
+checkRedContextDecl (ClassDecl _ _ cx i _ ds) = do
+  checkRedContext'
+    (warnRedContext (text ("class declaration " ++ escName i)) vs)
+    ps
+  mapM_ checkRedContextDecl ds
+  where (vs, ps) = getPredFromContext cx
+checkRedContextDecl (InstanceDecl _ _ cx qid _ ds) = do
+  checkRedContext'
+    (warnRedContext (text ("instance declaration " ++ escQualName qid)) vs)
+    ps
+  mapM_ checkRedContextDecl ds
+  where (vs, ps) = getPredFromContext cx
+checkRedContextDecl _ = return ()
+
+checkRedContextEq :: Equation a -> WCM ()
+checkRedContextEq (Equation _ _ rhs) = checkRedContextRhs rhs
+
+checkRedContextRhs :: Rhs a -> WCM ()
+checkRedContextRhs (SimpleRhs  _ _ e  ds) = do
+  checkRedContextExpr e
+  mapM_ checkRedContextDecl ds
+checkRedContextRhs (GuardedRhs _ _ cs ds) = do
+  mapM_ checkRedContextCond cs
+  mapM_ checkRedContextDecl ds
+
+checkRedContextCond :: CondExpr a -> WCM ()
+checkRedContextCond (CondExpr _ e1 e2) = do
+  checkRedContextExpr e1
+  checkRedContextExpr e2
+
+checkRedContextExpr :: Expression a -> WCM ()
+checkRedContextExpr (Paren _ e) = checkRedContextExpr e
+checkRedContextExpr (Typed _ e (QualTypeExpr _ cx _)) = do
+  checkRedContextExpr e
+  checkRedContext' (warnRedContext (text "type signature") vs) ps
+  where (vs, ps) = getPredFromContext cx
+checkRedContextExpr (Record _ _ _ fs) = mapM_ checkRedContextFieldExpr fs
+checkRedContextExpr (RecordUpdate _ e fs) = do
+  checkRedContextExpr e
+  mapM_ checkRedContextFieldExpr fs
+checkRedContextExpr (Tuple  _ es) = mapM_ checkRedContextExpr es
+checkRedContextExpr (List _ _ es) = mapM_ checkRedContextExpr es
+checkRedContextExpr (ListCompr _ e sts) = do
+  checkRedContextExpr e
+  mapM_ checkRedContextStmt sts
+checkRedContextExpr (EnumFrom _ e) = checkRedContextExpr e
+checkRedContextExpr (EnumFromThen _ e1 e2) = do
+  checkRedContextExpr e1
+  checkRedContextExpr e2
+checkRedContextExpr (EnumFromTo _ e1 e2) = do
+  checkRedContextExpr e1
+  checkRedContextExpr e2
+checkRedContextExpr (EnumFromThenTo _ e1 e2 e3) = do
+  checkRedContextExpr e1
+  checkRedContextExpr e2
+  checkRedContextExpr e3
+checkRedContextExpr (UnaryMinus _ e) = checkRedContextExpr e
+checkRedContextExpr (Apply _ e1 e2) = do
+  checkRedContextExpr e1
+  checkRedContextExpr e2
+checkRedContextExpr (InfixApply _ e1 _ e2) = do
+  checkRedContextExpr e1
+  checkRedContextExpr e2
+checkRedContextExpr (LeftSection  _ e _) = checkRedContextExpr e
+checkRedContextExpr (RightSection _ _ e) = checkRedContextExpr e
+checkRedContextExpr (Lambda _ _ e) = checkRedContextExpr e
+checkRedContextExpr (Let _ _ ds e) = do
+  mapM_ checkRedContextDecl ds
+  checkRedContextExpr e
+checkRedContextExpr (IfThenElse _ e1 e2 e3) = do
+  checkRedContextExpr e1
+  checkRedContextExpr e2
+  checkRedContextExpr e3
+checkRedContextExpr (Case _ _ _ e as) = do
+  checkRedContextExpr e
+  mapM_ checkRedContextAlt as
+checkRedContextExpr _ = return ()
+
+checkRedContextStmt :: Statement a -> WCM ()
+checkRedContextStmt (StmtExpr   _  e) = checkRedContextExpr e
+checkRedContextStmt (StmtDecl _ _ ds) = mapM_ checkRedContextDecl ds
+checkRedContextStmt (StmtBind _ _  e) = checkRedContextExpr e
+
+checkRedContextAlt :: Alt a -> WCM ()
+checkRedContextAlt (Alt _ _ rhs) = checkRedContextRhs rhs
+
+checkRedContextFieldExpr :: Field (Expression a) -> WCM ()
+checkRedContextFieldExpr (Field _ _ e) = checkRedContextExpr e
+
+-- ---------------------------------------------------------------------------
+-- Warnings messages
+-- ---------------------------------------------------------------------------
+
+warnRedFuncString :: [Ident] -> Doc
+warnRedFuncString is = text "type signature for function" <>
+                       text (if length is == 1 then [] else "s") <+>
+                       csep (map (text . escName) is)
+
+-- Doc description -> TypeVars -> Pred -> Warning
+warnRedContext :: Doc -> [Ident] -> Pred -> Message
+warnRedContext d vs p@(Pred qid _) = spanInfoMessage qid $
+  text "Redundant context in" <+> d <> colon <+>
+  quotes (pPrint $ fromPred vs p) -- idents use ` ' as quotes not ' '
+
+-- seperate a list by ', '
+csep :: [Doc] -> Doc
+csep []     = empty
+csep [x]    = x
+csep (x:xs) = x <> comma <+> csep xs
+
+warnCaseMode :: Ident -> CaseMode -> Message
+warnCaseMode i@(Ident _ name _ ) c = spanInfoMessage i $
+  text "Wrong case mode in symbol" <+> text (escName i) <+>
+  text "due to selected case mode" <+> text (escapeCaseMode c) <> comma <+>
+  text "try renaming to" <+> text (caseSuggestion name) <+> text "instead"
+
+caseSuggestion :: String -> String
+caseSuggestion (x:xs) | isLower x = toUpper x : xs
+                      | isUpper x = toLower x : xs
+caseSuggestion _      = internalError
+ "Checks.WarnCheck.caseSuggestion: Identifier starts with illegal Symbol"
+
+escapeCaseMode :: CaseMode -> String
+escapeCaseMode CaseModeFree    = "`free`"
+escapeCaseMode CaseModeHaskell = "`haskell`"
+escapeCaseMode CaseModeProlog  = "`prolog`"
+escapeCaseMode CaseModeGoedel  = "`goedel`"
+
+warnUnrefTypeVar :: Ident -> Message
+warnUnrefTypeVar v = spanInfoMessage v $ hsep $ map text
+  [ "Unreferenced type variable", escName v ]
+
+warnUnrefVar :: Ident -> Message
+warnUnrefVar v = spanInfoMessage v $ hsep $ map text
+  [ "Unused declaration of variable", escName v ]
+
+warnShadowing :: Ident -> Ident -> Message
+warnShadowing x v = spanInfoMessage x $
+  text "Shadowing symbol" <+> text (escName x)
+  <> comma <+> text "bound at:" <+> ppPosition (getPosition v)
diff --git a/src/CompilerEnv.hs b/src/CompilerEnv.hs
new file mode 100644
--- /dev/null
+++ b/src/CompilerEnv.hs
@@ -0,0 +1,117 @@
+{- |
+    Module      :  $Header$
+    Description :  Environment containing the module's information
+    Copyright   :  (c) 2011 - 2015 Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module defines the compilation environment for a single module,
+     containing the information needed throughout the compilation process.
+-}
+module CompilerEnv where
+
+import qualified Data.Map as Map (Map, keys, toList)
+
+import Curry.Base.Ident    (ModuleIdent, moduleName)
+import Curry.Base.Pretty
+import Curry.Base.Span   (Span)
+import Curry.Syntax
+
+import Base.TopEnv (allBindings, allLocalBindings)
+
+import Env.Class
+import Env.Instance
+import Env.Interface
+import Env.ModuleAlias (AliasEnv, initAliasEnv)
+import Env.OpPrec
+import Env.TypeConstructor
+import Env.Value
+
+type CompEnv a = (CompilerEnv, a)
+
+-- |A compiler environment contains information about the module currently
+--  compiled. The information is updated during the different stages of
+--  compilation.
+data CompilerEnv = CompilerEnv
+  { moduleIdent  :: ModuleIdent         -- ^ identifier of the module
+  , filePath     :: FilePath            -- ^ 'FilePath' of compilation target
+  , extensions   :: [KnownExtension]    -- ^ enabled language extensions
+  , tokens       :: [(Span, Token)]     -- ^ token list of module
+  , interfaceEnv :: InterfaceEnv        -- ^ declarations of imported interfaces
+  , aliasEnv     :: AliasEnv            -- ^ aliases for imported modules
+  , tyConsEnv    :: TCEnv               -- ^ type constructors and type classes
+  , classEnv     :: ClassEnv            -- ^ all type classes with their super classes
+  , instEnv      :: InstEnv             -- ^ instances
+  , valueEnv     :: ValueEnv            -- ^ functions and data constructors
+  , opPrecEnv    :: OpPrecEnv           -- ^ operator precedences
+  }
+
+-- |Initial 'CompilerEnv'
+initCompilerEnv :: ModuleIdent -> CompilerEnv
+initCompilerEnv mid = CompilerEnv
+  { moduleIdent  = mid
+  , filePath     = []
+  , extensions   = []
+  , tokens       = []
+  , interfaceEnv = initInterfaceEnv
+  , aliasEnv     = initAliasEnv
+  , tyConsEnv    = initTCEnv
+  , classEnv     = initClassEnv
+  , instEnv      = initInstEnv
+  , valueEnv     = initDCEnv
+  , opPrecEnv    = initOpPrecEnv
+  }
+
+-- |Show the 'CompilerEnv'
+showCompilerEnv :: CompilerEnv -> Bool -> Bool -> String
+showCompilerEnv env allBinds simpleEnv = show $ vcat
+  [ header "Module Identifier  " $ text  $ moduleName $ moduleIdent env
+  , header "FilePath"            $ text  $ filePath    env
+  , header "Language Extensions" $ text  $ show $ extensions  env
+  , header "Interfaces         " $ hcat  $ punctuate comma
+                                         $ map (text . moduleName)
+                                         $ Map.keys $ interfaceEnv env
+  , header "Module Aliases     " $ ppMap simpleEnv $ aliasEnv env
+  , header "Precedences        " $ ppAL simpleEnv $ bindings $ opPrecEnv env
+  , header "Type Constructors  " $ ppAL simpleEnv $ bindings $ tyConsEnv env
+  , header "Classes            " $ ppMap simpleEnv $ classEnv env
+  , header "Instances          " $ ppMap simpleEnv $ instEnv env
+  , header "Values             " $ ppAL simpleEnv $ bindings $ valueEnv  env
+  ]
+  where
+  header hdr content = hang (text hdr <+> colon) 4 content
+  bindings = if allBinds then allBindings else allLocalBindings
+
+-- |Pretty print a 'Map'
+ppMap :: (Show a, Pretty a, Show b, Pretty b) => Bool-> Map.Map a b -> Doc
+ppMap True  = ppMapPretty
+ppMap False = ppMapShow
+
+ppMapShow :: (Show a, Show b) => Map.Map a b -> Doc
+ppMapShow = ppALShow . Map.toList
+
+ppMapPretty :: (Pretty a, Pretty b) => Map.Map a b -> Doc
+ppMapPretty = ppALPretty . Map.toList
+
+-- |Pretty print an association list
+ppAL :: (Show a, Pretty a, Show b, Pretty b) => Bool -> [(a, b)] -> Doc
+ppAL True  = ppALPretty
+ppAL False = ppALShow
+
+ppALShow :: (Show a, Show b) => [(a, b)] -> Doc
+ppALShow xs = vcat
+        $ map (\(a,b) -> text (pad a keyWidth) <+> equals <+> text b) showXs
+  where showXs   = map (\(a,b) -> (show a, show b)) xs
+        keyWidth = maximum (0 : map (length .fst) showXs)
+        pad s n  = take n (s ++ repeat ' ')
+
+ppALPretty :: (Pretty a, Pretty b) => [(a, b)] -> Doc
+ppALPretty xs = vcat
+        $ map (\(a,b) -> text (pad a keyWidth) <+> equals <+> text b) showXs
+  where showXs   = map (\(a,b) -> (render (pPrint a), render (pPrint b))) xs
+        keyWidth = maximum (0 : map (length .fst) showXs)
+        pad s n  = take n (s ++ repeat ' ')
+
diff --git a/src/CompilerOpts.hs b/src/CompilerOpts.hs
new file mode 100644
--- /dev/null
+++ b/src/CompilerOpts.hs
@@ -0,0 +1,644 @@
+{- |
+    Module      :  $Header$
+    Description :  Compiler options
+    Copyright   :  (c) 2005        Martin Engelke
+                       2007        Sebastian Fischer
+                       2011 - 2016 Björn Peemöller
+                       2016 - 2017 Finn Teegen
+                       2018        Kai-Oliver Prott
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module defines data structures holding options for the
+    compilation of Curry programs, and utility functions for printing
+    help information as well as parsing the command line arguments.
+-}
+module CompilerOpts
+  ( Options (..), CppOpts (..), PrepOpts (..), WarnOpts (..), DebugOpts (..)
+  , OptimizationOpts(..), CaseMode (..), CymakeMode (..), Verbosity (..)
+  , TargetType (..), WarnFlag (..), KnownExtension (..), DumpLevel (..)
+  , dumpLevel
+  , defaultOptions, defaultPrepOpts, defaultWarnOpts, defaultDebugOpts
+  , getCompilerOpts, updateOpts, usage
+  ) where
+
+import           Data.List             (intercalate, nub)
+import           Data.Maybe            (isJust)
+import           Data.Char             (isDigit)
+import qualified Data.Map    as Map    (Map, empty, insert)
+import System.Console.GetOpt
+import System.Environment              (getArgs, getProgName)
+import System.FilePath                 ( addTrailingPathSeparator, normalise
+                                       , splitSearchPath )
+
+import Curry.Files.Filenames           (defaultOutDir)
+import Curry.Syntax.Extension
+
+-- -----------------------------------------------------------------------------
+-- Option data structures
+-- -----------------------------------------------------------------------------
+
+-- |Compiler options
+data Options = Options
+  -- general
+  { optMode          :: CymakeMode          -- ^ modus operandi
+  , optVerbosity     :: Verbosity           -- ^ verbosity level
+  -- compilation
+  , optForce         :: Bool                -- ^ force (re-)compilation of target
+  , optLibraryPaths  :: [FilePath]          -- ^ directories to search in
+                                            --   for libraries
+  , optImportPaths   :: [FilePath]          -- ^ directories to search in
+                                            --   for imports
+  , optOutDir        :: FilePath            -- ^ output directory for FlatCurry, ...
+  , optHtmlDir       :: Maybe FilePath      -- ^ output directory for HTML
+  , optUseOutDir     :: Bool                -- ^ use subdir for output?
+  , optInterface     :: Bool                -- ^ create a FlatCurry interface file?
+  , optPrepOpts      :: PrepOpts            -- ^ preprocessor options
+  , optWarnOpts      :: WarnOpts            -- ^ warning options
+  , optTargetTypes   :: [TargetType]        -- ^ what to generate
+  , optExtensions    :: [KnownExtension]    -- ^ enabled language extensions
+  , optDebugOpts     :: DebugOpts           -- ^ debug options
+  , optCaseMode      :: CaseMode            -- ^ case mode
+  , optCppOpts       :: CppOpts             -- ^ C preprocessor options
+  , optOptimizations :: OptimizationOpts -- ^ Optimization options
+  } deriving Show
+
+-- |C preprocessor options
+data CppOpts = CppOpts
+  { cppRun         :: Bool                -- ^ run C preprocessor
+  , cppDefinitions :: Map.Map String Int  -- ^ defintions for the C preprocessor
+  } deriving Show
+
+-- |Preprocessor options
+data PrepOpts = PrepOpts
+  { ppPreprocess :: Bool      -- ^ apply custom preprocessor
+  , ppCmd        :: String    -- ^ preprocessor command
+  , ppOpts       :: [String]  -- ^ preprocessor options
+  } deriving Show
+
+data CaseMode
+  = CaseModeFree
+  | CaseModeHaskell
+  | CaseModeProlog
+  | CaseModeGoedel
+  deriving (Eq, Show)
+
+-- |Warning options
+data WarnOpts = WarnOpts
+  { wnWarn         :: Bool       -- ^ show warnings? (legacy option)
+  , wnWarnFlags    :: [WarnFlag] -- ^ Warnings flags (see below)
+  , wnWarnAsError  :: Bool       -- ^ Should warnings be treated as errors?
+  } deriving Show
+
+-- |Debug options
+data DebugOpts = DebugOpts
+  { dbDumpLevels      :: [DumpLevel] -- ^ dump levels
+  , dbDumpEnv         :: Bool        -- ^ dump compilation environment
+  , dbDumpRaw         :: Bool        -- ^ dump data structure
+  , dbDumpAllBindings :: Bool        -- ^ dump all bindings instead of just the
+                                     --   local bindings
+  , dbDumpSimple      :: Bool        -- ^ print more readable environments
+  } deriving Show
+
+data OptimizationOpts = OptimizationOpts
+  { optDesugarNewtypes     :: Bool -- ^ Desugar newtypes
+  , optInlineDictionaries  :: Bool -- ^ Inline type class dictionaries
+  , optRemoveUnusedImports :: Bool -- ^ Remove unused imports in IL
+  } deriving Show
+
+-- | Default compiler options
+defaultOptions :: Options
+defaultOptions = Options
+  { optMode          = ModeMake
+  , optVerbosity     = VerbStatus
+  , optForce         = False
+  , optLibraryPaths  = []
+  , optImportPaths   = []
+  , optOutDir        = defaultOutDir
+  , optHtmlDir       = Nothing
+  , optUseOutDir     = True
+  , optInterface     = True
+  , optPrepOpts      = defaultPrepOpts
+  , optWarnOpts      = defaultWarnOpts
+  , optTargetTypes   = []
+  , optExtensions    = []
+  , optDebugOpts     = defaultDebugOpts
+  , optCaseMode      = CaseModeFree
+  , optCppOpts       = defaultCppOpts
+  , optOptimizations = defaultOptimizationOpts
+  }
+
+-- | Default C preprocessor options
+defaultCppOpts :: CppOpts
+defaultCppOpts = CppOpts
+  { cppRun         = False
+  , cppDefinitions = Map.empty
+  }
+
+-- | Default preprocessor options
+defaultPrepOpts :: PrepOpts
+defaultPrepOpts = PrepOpts
+  { ppPreprocess = False
+  , ppCmd        = ""
+  , ppOpts       = []
+  }
+
+-- | Default warning options
+defaultWarnOpts :: WarnOpts
+defaultWarnOpts = WarnOpts
+  { wnWarn        = True
+  , wnWarnFlags   = stdWarnFlags
+  , wnWarnAsError = False
+  }
+
+-- | Default dump options
+defaultDebugOpts :: DebugOpts
+defaultDebugOpts = DebugOpts
+  { dbDumpLevels      = []
+  , dbDumpEnv         = False
+  , dbDumpRaw         = False
+  , dbDumpAllBindings = False
+  , dbDumpSimple      = False
+  }
+
+defaultOptimizationOpts :: OptimizationOpts
+defaultOptimizationOpts = OptimizationOpts
+  { optDesugarNewtypes     = False
+  , optInlineDictionaries  = True
+  , optRemoveUnusedImports = True
+  }
+
+-- |Modus operandi of the program
+data CymakeMode
+  = ModeHelp           -- ^ Show help information and exit
+  | ModeVersion        -- ^ Show version and exit
+  | ModeNumericVersion -- ^ Show numeric version, suitable for later processing
+  | ModeMake           -- ^ Compile with dependencies
+  deriving (Eq, Show)
+
+-- |Verbosity level
+data Verbosity
+  = VerbQuiet  -- ^ be quiet
+  | VerbStatus -- ^ show status of compilation
+  deriving (Eq, Ord, Show)
+
+-- |Description and flag of verbosities
+verbosities :: [(Verbosity, String, String)]
+verbosities = [ ( VerbQuiet , "0", "quiet" )
+              , ( VerbStatus, "1", "status")
+              ]
+
+-- |Type of the target file
+data TargetType
+  = Tokens               -- ^ Source code tokens
+  | Comments             -- ^ Source code comments
+  | Parsed               -- ^ Parsed source code
+  | FlatCurry            -- ^ FlatCurry
+  | AnnotatedFlatCurry   -- ^ Annotated FlatCurry
+  | TypedFlatCurry       -- ^ Typed FlatCurry
+  | AbstractCurry        -- ^ AbstractCurry
+  | UntypedAbstractCurry -- ^ Untyped AbstractCurry
+  | Html                 -- ^ HTML documentation
+  | AST                  -- ^ Abstract-Syntax-Tree after checks
+  | ShortAST             -- ^ Abstract-Syntax-Tree with shortened decls
+    deriving (Eq, Show)
+
+-- |Warnings flags
+data WarnFlag
+  = WarnMultipleImports      -- ^ Warn for multiple imports
+  | WarnDisjoinedRules       -- ^ Warn for disjoined function rules
+  | WarnUnusedGlobalBindings -- ^ Warn for unused global bindings
+  | WarnUnusedBindings       -- ^ Warn for unused local bindings
+  | WarnNameShadowing        -- ^ Warn for name shadowing
+  | WarnOverlapping          -- ^ Warn for overlapping rules/alternatives
+  | WarnIncompletePatterns   -- ^ Warn for incomplete pattern matching
+  | WarnMissingSignatures    -- ^ Warn for missing type signatures
+  | WarnMissingMethods       -- ^ Warn for missing method implementations
+  | WarnOrphanInstances      -- ^ Warn for orphan instances
+  | WarnIrregularCaseMode    -- ^ Warn for irregular case mode
+  | WarnRedundantContext     -- ^ Warn for redundant context in type signatures
+    deriving (Eq, Bounded, Enum, Show)
+
+-- |Warning flags enabled by default
+stdWarnFlags :: [WarnFlag]
+stdWarnFlags =
+  [ WarnMultipleImports   , WarnDisjoinedRules   --, WarnUnusedGlobalBindings
+  , WarnUnusedBindings    , WarnNameShadowing    , WarnOverlapping
+  , WarnIncompletePatterns, WarnMissingSignatures, WarnMissingMethods
+  , WarnIrregularCaseMode , WarnRedundantContext
+  ]
+
+-- |Description and flag of warnings flags
+warnFlags :: [(WarnFlag, String, String)]
+warnFlags =
+  [ ( WarnMultipleImports     , "multiple-imports"
+    , "multiple imports"               )
+  , ( WarnDisjoinedRules      , "disjoined-rules"
+    , "disjoined function rules"       )
+  , ( WarnUnusedGlobalBindings, "unused-global-bindings"
+    , "unused bindings"                )
+  , ( WarnUnusedBindings      , "unused-bindings"
+    , "unused bindings"                )
+  , ( WarnNameShadowing       , "name-shadowing"
+    , "name shadowing"                 )
+  , ( WarnOverlapping         , "overlapping"
+    , "overlapping function rules"     )
+  , ( WarnIncompletePatterns  , "incomplete-patterns"
+    , "incomplete pattern matching"    )
+  , ( WarnMissingSignatures   , "missing-signatures"
+    , "missing type signatures"        )
+  , ( WarnMissingMethods      , "missing-methods"
+    , "missing method implementations" )
+  , ( WarnOrphanInstances     , "orphan-instances"
+    , "orphan instances"               )
+  , ( WarnIrregularCaseMode   , "irregular-case-mode"
+    , "irregular case mode")
+  , ( WarnRedundantContext    , "redundant-context"
+    , "redundant context")
+  ]
+
+-- |Dump level
+data DumpLevel
+  = DumpCondCompiled      -- ^ dump source code after conditional compiling
+  | DumpParsed            -- ^ dump source code after parsing
+  | DumpExtensionChecked  -- ^ dump source code after extension checking
+  | DumpTypeSyntaxChecked -- ^ dump source code after type syntax checking
+  | DumpKindChecked       -- ^ dump source code after kind checking
+  | DumpSyntaxChecked     -- ^ dump source code after syntax checking
+  | DumpPrecChecked       -- ^ dump source code after precedence checking
+  | DumpDeriveChecked     -- ^ dump source code after derive checking
+  | DumpInstanceChecked   -- ^ dump source code after instance checking
+  | DumpTypeChecked       -- ^ dump source code after type checking
+  | DumpExportChecked     -- ^ dump source code after export checking
+  | DumpQualified         -- ^ dump source code after qualification
+  | DumpDerived           -- ^ dump source code after deriving
+  | DumpDesugared         -- ^ dump source code after desugaring
+  | DumpDictionaries      -- ^ dump source code after dictionary transformation
+  | DumpNewtypes          -- ^ dump source code after removing newtype constructors
+  | DumpSimplified        -- ^ dump source code after simplification
+  | DumpLifted            -- ^ dump source code after lambda-lifting
+  | DumpTranslated        -- ^ dump IL code after translation
+  | DumpCaseCompleted     -- ^ dump IL code after case completion
+  | DumpTypedFlatCurry    -- ^ dump typed FlatCurry code
+  | DumpFlatCurry         -- ^ dump FlatCurry code
+    deriving (Eq, Bounded, Enum, Show)
+
+-- |Description and flag of dump levels
+dumpLevel :: [(DumpLevel, String, String)]
+dumpLevel = [ (DumpCondCompiled     , "dump-cond" , "conditional compiling"           )
+            , (DumpParsed           , "dump-parse", "parsing"                         )
+            , (DumpExtensionChecked , "dump-exc"  , "extension checking"              )
+            , (DumpTypeSyntaxChecked, "dump-tsc"  , "type syntax checking"            )
+            , (DumpKindChecked      , "dump-kc"   , "kind checking"                   )
+            , (DumpSyntaxChecked    , "dump-sc"   , "syntax checking"                 )
+            , (DumpPrecChecked      , "dump-pc"   , "precedence checking"             )
+            , (DumpDeriveChecked    , "dump-dc"   , "derive checking"                 )
+            , (DumpInstanceChecked  , "dump-inc"  , "instance checking"               )
+            , (DumpTypeChecked      , "dump-tc"   , "type checking"                   )
+            , (DumpExportChecked    , "dump-ec"   , "export checking"                 )
+            , (DumpQualified        , "dump-qual" , "qualification"                   )
+            , (DumpDerived          , "dump-deriv", "deriving"                        )
+            , (DumpDesugared        , "dump-ds"   , "desugaring"                      )
+            , (DumpDictionaries     , "dump-dict" , "dictionary insertion"            )
+            , (DumpNewtypes         , "dump-new"  , "removing newtype constructors"   )
+            , (DumpLifted           , "dump-lift" , "lifting"                         )
+            , (DumpSimplified       , "dump-simpl", "simplification"                  )
+            , (DumpTranslated       , "dump-trans", "pattern matching compilation"    )
+            , (DumpCaseCompleted    , "dump-cc"   , "case completion"                 )
+            , (DumpTypedFlatCurry   , "dump-tflat", "translation into typed FlatCurry")
+            , (DumpFlatCurry        , "dump-flat" , "translation into FlatCurry"      )
+            ]
+
+-- |Description and flag of language extensions
+extensions :: [(KnownExtension, String, String)]
+extensions =
+  [ ( AnonFreeVars             , "AnonFreeVars"
+    , "enable anonymous free variables"              )
+  , ( CPP                      , "CPP"
+    , "run C preprocessor"                           )
+  , ( FunctionalPatterns       , "FunctionalPatterns"
+    , "enable functional patterns"                   )
+  , ( NegativeLiterals         , "NegativeLiterals"
+    , "desugar negated literals as negative literal" )
+  , ( NoImplicitPrelude        , "NoImplicitPrelude"
+    , "do not implicitly import the Prelude"         )
+  ]
+
+-- -----------------------------------------------------------------------------
+-- Parsing of the command line options.
+--
+-- Because some flags require additional arguments, the structure is slightly
+-- more complicated to enable malformed arguments to be reported.
+-- -----------------------------------------------------------------------------
+
+-- |Instead of just returning the resulting 'Options' structure, we also
+-- collect errors from arguments passed to specific options.
+type OptErr = (Options, [String])
+
+-- |An 'OptErrTable' consists of a list of entries of the following form:
+--   * a flag to be recognized on the command line
+--   * an explanation text for the usage information
+--   * a modification funtion adjusting the options structure
+-- The type is parametric about the option's type to adjust.
+type OptErrTable opt = [(String, String, opt -> opt)]
+
+onOpts :: (Options -> Options) -> OptErr -> OptErr
+onOpts f (opts, errs) = (f opts, errs)
+
+onCppOpts :: (CppOpts -> CppOpts) -> OptErr -> OptErr
+onCppOpts f (opts, errs) = (opts { optCppOpts = f (optCppOpts opts) }, errs)
+
+onPrepOpts :: (PrepOpts -> PrepOpts) -> OptErr -> OptErr
+onPrepOpts f (opts, errs) = (opts { optPrepOpts = f (optPrepOpts opts) }, errs)
+
+onWarnOpts :: (WarnOpts -> WarnOpts) -> OptErr -> OptErr
+onWarnOpts f (opts, errs) = (opts { optWarnOpts = f (optWarnOpts opts) }, errs)
+
+onDebugOpts :: (DebugOpts -> DebugOpts) -> OptErr -> OptErr
+onDebugOpts f (opts, errs)
+  = (opts { optDebugOpts = f (optDebugOpts opts) }, errs)
+
+onOptimOpts :: (OptimizationOpts -> OptimizationOpts) -> OptErr -> OptErr
+onOptimOpts f (opts, errs)
+    = (opts { optOptimizations = f (optOptimizations opts) }, errs)
+
+withArg :: ((a -> b) -> OptErr -> OptErr)
+        -> (String -> a -> b) -> String -> OptErr -> OptErr
+withArg lift f arg = lift (f arg)
+
+addErr :: String -> OptErr -> OptErr
+addErr err (opts, errs) = (opts, errs ++ [err])
+
+mkOptDescr :: ((opt -> opt) -> OptErr -> OptErr)
+           -> String -> [String] -> String -> String -> OptErrTable opt
+           -> OptDescr (OptErr -> OptErr)
+mkOptDescr lift flags longFlags arg what tbl = Option flags longFlags
+  (ReqArg (parseOptErr lift what tbl) arg)
+  ("set " ++ what ++ " `" ++ arg ++ "', where `" ++ arg ++ "' is one of\n"
+    ++ renderOptErrTable tbl)
+
+parseOptErr :: ((opt -> opt) -> OptErr -> OptErr)
+            -> String -> OptErrTable opt -> String -> OptErr -> OptErr
+parseOptErr lift what table opt = case lookup3 opt table of
+  Just f  -> lift f
+  Nothing -> addErr $ "unrecognized " ++ what ++ '`' : opt ++ "'\n"
+  where
+  lookup3 _ []                  = Nothing
+  lookup3 k ((k', _, v2) : kvs)
+    | k == k'                   = Just v2
+    | otherwise                 = lookup3 k kvs
+
+renderOptErrTable :: OptErrTable opt -> String
+renderOptErrTable ds
+  = intercalate "\n" $ map (\(k, d, _) -> "  " ++ rpad maxLen k ++ ": " ++ d) ds
+  where
+  maxLen = maximum $ map (\(k, _, _) -> length k) ds
+  rpad n x = x ++ replicate (n - length x) ' '
+
+-- | All available compiler options
+options :: [OptDescr (OptErr -> OptErr)]
+options =
+  -- modus operandi
+  [ Option "h?" ["help"]
+      (NoArg (onOpts $ \ opts -> opts { optMode = ModeHelp }))
+      "display this help and exit"
+  , Option "V"  ["version"]
+      (NoArg (onOpts $ \ opts -> opts { optMode = ModeVersion }))
+      "show the version number and exit"
+  , Option ""   ["numeric-version"]
+      (NoArg (onOpts $ \ opts -> opts { optMode = ModeNumericVersion }))
+      "show the numeric version number and exit"
+  -- verbosity
+  , mkOptDescr onOpts "v" ["verbosity"] "n" "verbosity level" verbDescriptions
+  , Option "q"  ["no-verb"]
+      (NoArg (onOpts $ \ opts -> opts { optVerbosity = VerbQuiet } ))
+      "set verbosity level to quiet"
+  -- compilation
+  , Option "f"  ["force"]
+      (NoArg (onOpts $ \ opts -> opts { optForce = True }))
+      "force compilation of target file"
+  , Option "P"  ["lib-dir"]
+      (ReqArg (withArg onOpts $ \ arg opts -> opts { optLibraryPaths =
+        nub $ optLibraryPaths opts ++ splitSearchPath arg}) "dir[:dir]")
+      "search for libraries in dir[:dir]"
+  , Option "i"  ["import-dir"]
+      (ReqArg (withArg onOpts $ \ arg opts -> opts { optImportPaths =
+        nub $ optImportPaths opts ++
+              map (normalise . addTrailingPathSeparator) (splitSearchPath arg)
+              }) "dir[:dir]")
+      "search for imports in dir[:dir]"
+  , Option "o"  ["outdir"]
+      (ReqArg (withArg onOpts $ \ arg opts -> opts { optOutDir = arg }) "dir")
+      "write compilation artifacts (FlatCurry, ...) into directory `dir'"
+  , Option []   ["htmldir"]
+      (ReqArg (withArg onOpts $ \ arg opts -> opts { optHtmlDir =
+        Just arg }) "dir")
+      "write HTML documentation into directory `dir'"
+  , Option ""   ["no-outdir", "no-subdir"]
+      (NoArg (onOpts $ \ opts -> opts { optUseOutDir = False }))
+      ("disable writing to `" ++ defaultOutDir ++ "' subdirectory")
+  , Option ""   ["no-intf"]
+      (NoArg (onOpts $ \ opts -> opts { optInterface = False }))
+      "do not create an interface file"
+    -- legacy warning flags
+  , Option ""   ["no-warn"]
+      (NoArg (onWarnOpts $ \ opts -> opts { wnWarn = False }))
+      "do not print warnings"
+  , Option ""   ["no-overlap-warn"]
+      (NoArg (onWarnOpts $ \ opts -> opts {wnWarnFlags =
+        addFlag WarnOverlapping (wnWarnFlags opts) }))
+      "do not print warnings for overlapping rules"
+  -- target types
+  , targetOption Tokens                 "tokens"
+      "generate token stream"
+  , targetOption Comments               "comments"
+      "generate comments stream"
+  , targetOption Parsed                 "parse-only"
+      "generate source representation"
+  , targetOption FlatCurry              "flat"
+      "generate FlatCurry code"
+  , targetOption TypedFlatCurry         "typed-flat"
+      "generate typed FlatCurry code"
+  , targetOption AnnotatedFlatCurry     "type-annotated-flat"
+      "generate type-annotated FlatCurry code"
+  , targetOption AbstractCurry          "acy"
+      "generate typed AbstractCurry"
+  , targetOption UntypedAbstractCurry   "uacy"
+      "generate untyped AbstractCurry"
+  , targetOption Html                   "html"
+      "generate html documentation"
+  , targetOption AST                    "ast"
+      "generate abstract syntax tree"
+  , targetOption ShortAST               "short-ast"
+      "generate shortened abstract syntax tree for documentation"
+  , Option "F"  []
+      (NoArg (onPrepOpts $ \ opts -> opts { ppPreprocess = True }))
+      "use custom preprocessor"
+  , Option ""   ["pgmF"]
+      (ReqArg (withArg onPrepOpts $ \ arg opts -> opts { ppCmd = arg})
+        "cmd")
+      "execute preprocessor command <cmd>"
+  , Option ""   ["optF"]
+      (ReqArg (withArg onPrepOpts $ \ arg opts ->
+        opts { ppOpts = ppOpts opts ++ [arg]}) "option")
+      "execute preprocessor with option <option>"
+  -- extensions
+  , Option "e"  ["extended"]
+      (NoArg (onOpts $ \ opts -> opts { optExtensions =
+        nub $ kielExtensions ++ optExtensions opts }))
+      "enable extended Curry functionalities"
+  , mkOptDescr onOpts      "c" ["case-mode"] "mode" "case mode"           caseModeDescriptions
+  , mkOptDescr onOpts      "X" []            "ext"  "language extension"  extDescriptions
+  , mkOptDescr onWarnOpts  "W" []            "opt"  "warning option"      warnDescriptions
+  , mkOptDescr onDebugOpts "d" []            "opt"  "debug option"        debugDescriptions
+  , mkOptDescr onOptimOpts "O" []            "opt"  "optimization option" optimizeDescriptions
+  , Option ""   ["cpp"]
+      (NoArg (onCppOpts $ \ opts -> opts { cppRun = True }))
+      "run C preprocessor"
+  , Option "D"  []
+      (ReqArg (withArg ($) parseCppDefinition) "s=v")
+      "define symbol `s` with value `v` for the C preprocessor"
+  ]
+
+parseCppDefinition :: String -> OptErr -> OptErr
+parseCppDefinition arg optErr
+  | not (null s) && not (null v) && all isDigit v
+  = onCppOpts (addCppDefinition s v) optErr
+  | otherwise
+  = addErr (cppDefinitionErr arg) optErr
+  where (s, v) = drop 1 <$> break ('=' ==) arg
+
+addCppDefinition :: String -> String -> CppOpts -> CppOpts
+addCppDefinition s v opts =
+  opts { cppDefinitions = Map.insert s (read v) (cppDefinitions opts) }
+
+cppDefinitionErr :: String -> String
+cppDefinitionErr = (++) "Invalid format for option '-D': "
+
+targetOption :: TargetType -> String -> String -> OptDescr (OptErr -> OptErr)
+targetOption ty flag
+  = Option "" [flag] (NoArg (onOpts $ \ opts -> opts { optTargetTypes =
+      nub $ ty : optTargetTypes opts }))
+
+verbDescriptions :: OptErrTable Options
+verbDescriptions = map toDescr verbosities
+  where
+  toDescr (flag, name, desc)
+    = (name, desc, \ opts -> opts { optVerbosity = flag })
+
+extDescriptions :: OptErrTable Options
+extDescriptions = map toDescr extensions
+  where
+  toDescr (flag, name, desc)
+    = (name, desc,
+        \opts -> let cppOpts = optCppOpts opts
+                 in opts { optCppOpts    =
+                             cppOpts { cppRun = cppRun cppOpts || flag == CPP }
+                         , optExtensions = addFlag flag (optExtensions opts)
+                         })
+
+
+caseModeDescriptions :: OptErrTable Options
+caseModeDescriptions
+  = [ ( "free"   , "use free case mode"
+        , \ opts -> opts { optCaseMode = CaseModeFree    } )
+    , ( "haskell", "use haskell style case mode"
+        , \ opts -> opts { optCaseMode = CaseModeHaskell } )
+    , ( "prolog" , "use prolog style case mode"
+        , \ opts -> opts { optCaseMode = CaseModeProlog  } )
+    , ( "goedel"  , "use goedel case mode"
+        , \ opts -> opts { optCaseMode = CaseModeGoedel  } )
+    ]
+
+warnDescriptions :: OptErrTable WarnOpts
+warnDescriptions
+  = [ ( "all"  , "turn on all warnings"
+        , \ opts -> opts { wnWarnFlags = [minBound .. maxBound] } )
+    , ("none" , "turn off all warnings"
+        , \ opts -> opts { wnWarnFlags = []                     } )
+    , ("error", "treat warnings as errors"
+        , \ opts -> opts { wnWarnAsError = True                 } )
+    ] ++ map turnOn warnFlags ++ map turnOff warnFlags
+  where
+  turnOn (flag, name, desc)
+    = (name, "warn for " ++ desc
+      , \ opts -> opts { wnWarnFlags = addFlag flag (wnWarnFlags opts)})
+  turnOff (flag, name, desc)
+    = ("no-" ++ name, "do not warn for " ++ desc
+      , \ opts -> opts { wnWarnFlags = removeFlag flag (wnWarnFlags opts)})
+
+debugDescriptions :: OptErrTable DebugOpts
+debugDescriptions =
+  [ ( "dump-all"          , "dump everything"
+    , \ opts -> opts { dbDumpLevels = [minBound .. maxBound]    })
+  , ( "dump-none"         , "dump nothing"
+    , \ opts -> opts { dbDumpLevels = []                        })
+  , ( "dump-env"          , "additionally dump compiler environment"
+    , \ opts -> opts { dbDumpEnv = True                         })
+  , ( "dump-raw"          , "dump as raw AST (instead of pretty printing)"
+    , \ opts -> opts { dbDumpRaw = True                         })
+  , ( "dump-all-bindings" , "when dumping bindings, dump all instead of just local ones"
+    , \ opts -> opts { dbDumpAllBindings = True                 })
+  , ( "dump-simple" , "print a simplified, more readable environment"
+    , \ opts -> opts { dbDumpSimple = True                      })
+
+  ] ++ map toDescr dumpLevel
+  where
+  toDescr (flag, name, desc)
+    = (name , "dump code after " ++ desc
+        , \ opts -> opts { dbDumpLevels = addFlag flag (dbDumpLevels opts)})
+
+optimizeDescriptions :: OptErrTable OptimizationOpts
+optimizeDescriptions =
+  [ ( "desugar-newtypes"        , "desugars newtypes in FlatCurry"
+    , \ opts -> opts { optDesugarNewtypes     = True    })
+  , ( "inline-dictionaries"     , "inlines type class dictionaries"
+    , \ opts -> opts { optInlineDictionaries  = True    })
+  , ( "remove-unused-imports"   , "removes unused imports"
+    , \ opts -> opts { optRemoveUnusedImports = True    })
+  , ( "no-desugar-newtypes"     , "prevents desugaring of newtypes in FlatCurry"
+    , \ opts -> opts { optDesugarNewtypes     = False   })
+  , ( "no-inline-dictionaries"  , "prevents inlining of type class dictionaries"
+    , \ opts -> opts { optInlineDictionaries  = False   })
+  , ( "no-remove-unused-imports", "prevents removing of unused imports"
+    , \ opts -> opts { optRemoveUnusedImports = False   })
+  ]
+
+addFlag :: Eq a => a -> [a] -> [a]
+addFlag o opts = nub $ o : opts
+
+removeFlag :: Eq a => a -> [a] -> [a]
+removeFlag o = filter (/= o)
+
+-- |Update the 'Options' record by the parsed and processed arguments
+updateOpts :: Options -> [String] -> (Options, [String], [String])
+updateOpts opts args = (opts', files, errs ++ errs2 ++ checkOpts opts files)
+  where
+  (opts', errs2) = foldl (flip ($)) (opts, []) optErrs
+  (optErrs, files, errs) = getOpt Permute options args
+
+-- |Parse the command line arguments
+parseOpts :: [String] -> (Options, [String], [String])
+parseOpts = updateOpts defaultOptions
+
+-- |Check options and files and return a list of error messages
+checkOpts :: Options -> [String] -> [String]
+checkOpts opts _
+  = [ "The option '--htmldir' is only valid for HTML generation mode"
+    | isJust (optHtmlDir opts) && Html `notElem` optTargetTypes opts ]
+
+-- |Print the usage information of the command line tool.
+usage :: String -> String
+usage prog = usageInfo header options
+  where header = "usage: " ++ prog ++ " [OPTION] ... MODULES ..."
+
+-- |Retrieve the compiler 'Options'
+getCompilerOpts :: IO (String, Options, [String], [String])
+getCompilerOpts = do
+  args <- getArgs
+  prog <- getProgName
+  let (opts, files, errs) = parseOpts args
+  return (prog, opts, files, errs)
diff --git a/src/CondCompile.hs b/src/CondCompile.hs
new file mode 100644
--- /dev/null
+++ b/src/CondCompile.hs
@@ -0,0 +1,26 @@
+{- |
+    Module      :  $Header$
+    Description :  Conditional compilation
+    Copyright   :  (c)        2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    TODO
+-}
+
+module CondCompile (condCompile) where
+
+import Curry.Base.Monad
+import Curry.CondCompile.Transform (condTransform)
+
+import CompilerOpts (CppOpts (..))
+
+condCompile :: CppOpts -> FilePath -> String -> CYIO String
+condCompile opts fn p
+  | not (cppRun opts) = return p
+  | otherwise         = either (failMessages . (: []))
+                               ok
+                               (condTransform (cppDefinitions opts) fn p)
diff --git a/src/Curry/AbstractCurry.hs b/src/Curry/AbstractCurry.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/AbstractCurry.hs
@@ -0,0 +1,30 @@
+{- |
+    Module      :  $Header$
+    Description :  Library to support meta-programming in Curry
+    Copyright   :  Michael Hanus  , 2004
+                   Martin Engelke , 2005
+                   Björn Peemöller, 2013
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This library contains a definition for representing Curry programs
+    in Haskell by the type 'CurryProg' and I/O actions to read Curry programs
+    and transform them into this abstract representation as well as
+    write them to a file.
+
+    Note that this defines a slightly new format for AbstractCurry
+    in comparison to the first proposal of 2003.
+
+    /Assumption:/ An AbstractCurry program @Prog@ is stored in a file with
+    the file extension @acy@, i.e. in a file @Prog.acy@.
+-}
+module Curry.AbstractCurry
+  ( module Curry.AbstractCurry.Type
+  , module Curry.AbstractCurry.Files
+  ) where
+
+import Curry.AbstractCurry.Type
+import Curry.AbstractCurry.Files
diff --git a/src/Curry/AbstractCurry/Files.hs b/src/Curry/AbstractCurry/Files.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/AbstractCurry/Files.hs
@@ -0,0 +1,61 @@
+{- |
+    Module      :  $Header$
+    Description :  Library to support meta-programming in Curry
+    Copyright   :  (c) Michael Hanus  , 2004
+                       Martin Engelke , 2005
+                       Björn Peemöller, 2014
+                       Finn Teegen    , 2016
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This library contains I/O actions to read Curry programs
+    and transform them into this abstract representation as well as
+    write them to a file.
+-}
+module Curry.AbstractCurry.Files
+  ( readCurry, writeCurry, showCurry
+  ) where
+
+import qualified Control.Exception        as C (catch)
+import           Data.List                     (intercalate)
+
+import           Curry.Files.PathUtils         ( writeModule, readModule
+                                               , addVersion, checkVersion)
+
+import           Curry.AbstractCurry.Type
+
+-- ---------------------------------------------------------------------------
+-- Reading and writing AbstractCurry terms
+-- ---------------------------------------------------------------------------
+
+-- |Read an AbstractCurry file and return the corresponding AbstractCurry
+--  program term of type 'CurryProg'
+readCurry :: FilePath -> IO (Maybe CurryProg)
+readCurry fn = do
+  mbSrc <- readModule fn
+  return $ case mbSrc of
+    Nothing  -> Nothing
+    Just src -> case checkVersion version src of
+      Left  _  -> Nothing
+      Right ac -> Just (read ac)
+
+-- |Write an AbstractCurry program term into a file.
+writeCurry :: FilePath -> CurryProg -> IO ()
+writeCurry fn p = C.catch (writeModule fn $ addVersion version $ showCurry p)
+                  ioError
+
+-- |Show an AbstractCurry program in a nicer way
+showCurry :: CurryProg -> String
+showCurry (CurryProg mname imps dflt clss insts types funcs ops)
+  =  "CurryProg " ++ show mname ++ "\n"
+  ++ show imps ++ "\n"
+  ++ showsPrec 11 dflt "\n"
+  ++ wrapList clss
+  ++ wrapList insts
+  ++ wrapList types
+  ++ wrapList funcs
+  ++ wrapList ops
+  where wrapList xs = " [" ++ intercalate ",\n  " (map show xs) ++ "]\n"
diff --git a/src/Curry/AbstractCurry/Type.hs b/src/Curry/AbstractCurry/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/AbstractCurry/Type.hs
@@ -0,0 +1,329 @@
+{- |
+    Module      :  $Header$
+    Description :  Library to support meta-programming in Curry
+    Copyright   :  Michael Hanus  , 2004
+                   Martin Engelke , 2005
+                   Björn Peemöller, 2015
+                   Finn Teegen    , 2016
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This library contains a definition for representing Curry programs
+    in Haskell by the type 'CurryProg' and I/O actions to read Curry programs
+    and transform them into this abstract representation as well as
+    write them to a file.
+
+    Note that this defines a slightly new format for AbstractCurry
+    in comparison to the first proposal of 2003.
+-}
+module Curry.AbstractCurry.Type
+  ( CurryProg (..), MName, QName, CVisibility (..), CTVarIName
+  , CDefaultDecl (..), CClassDecl (..), CInstanceDecl (..)
+  , CTypeDecl (..), CConsDecl (..), CFieldDecl (..)
+  , CConstraint, CContext (..), CTypeExpr (..), CQualTypeExpr (..)
+  , COpDecl (..), CFixity (..), Arity, CFuncDecl (..), CRhs (..), CRule (..)
+  , CLocalDecl (..), CVarIName, CExpr (..), CCaseType (..), CStatement (..)
+  , CPattern (..), CLiteral (..), CField, version
+  ) where
+
+-- ---------------------------------------------------------------------------
+-- Abstract syntax
+-- ---------------------------------------------------------------------------
+
+-- |Current version of AbstractCurry
+version :: String
+version = "AbstractCurry 3.0"
+
+-- |A module name.
+type MName = String
+
+-- |A qualified name.
+-- In AbstractCurry all names are qualified to avoid name clashes.
+-- The first component is the module name and the second component the
+-- unqualified name as it occurs in the source program.
+type QName = (MName, String)
+
+-- |Data type to specify the visibility of various entities.
+data CVisibility
+  = Public    -- ^ exported entity
+  | Private   -- ^ private entity
+    deriving (Eq, Read, Show)
+
+-- |A Curry module in the intermediate form. A value of this type has the form
+-- @
+-- CurryProg modname imports dfltdecl clsdecls instdecls typedecls funcdecls opdecls
+-- @
+-- where
+-- [@modname@]   Name of this module
+-- [@imports@]   List of modules names that are imported
+-- [@dfltdecl@]  Optional default declaration
+-- [@clsdecls@]  Class declarations
+-- [@instdecls@] Instance declarations
+-- [@typedecls@] Type declarations
+-- [@funcdecls@] Function declarations
+-- [@opdecls@]   Operator precedence declarations
+data CurryProg = CurryProg MName [MName] (Maybe CDefaultDecl) [CClassDecl]
+                           [CInstanceDecl] [CTypeDecl] [CFuncDecl] [COpDecl]
+    deriving (Eq, Read, Show)
+
+-- |Default declaration.
+data CDefaultDecl = CDefaultDecl [CTypeExpr]
+    deriving (Eq, Read, Show)
+
+-- |Definitions of type classes.
+-- A type class definition of the form
+-- @
+-- class cx => c a where { ...;f :: t;... }
+-- @
+-- is represented by the Curry term
+-- @
+-- (CClass c v cx tv [...(CFunc f ar v t [...,CRule r,...])...])
+-- @
+-- where @tv@ is the index of the type variable @a@ and @v@ is the
+-- visibility of the type class resp. method.
+-- /Note:/ The type variable indices are unique inside each class
+--         declaration and are usually numbered from 0.
+--         The methods' types share the type class' type variable index
+--         as the class variable has to occur in a method's type signature.
+--         The list of rules for a method's declaration may be empty if
+--         no default implementation is provided. The arity @ar@ is
+--         determined by a given default implementation or 0.
+--         Regardless of whether typed or untyped abstract curry is generated,
+--         the methods' declarations are always typed.
+data CClassDecl = CClass QName CVisibility CContext CTVarIName [CFuncDecl]
+    deriving (Eq, Read, Show)
+
+-- |Definitions of instances.
+-- An instance definition of the form
+-- @
+-- instance cx => c ty where { ...;fundecl;... }
+-- @
+-- is represented by the Curry term
+-- @
+-- (CInstance c cx ty [...fundecl...])
+-- @
+-- /Note:/ The type variable indices are unique inside each instance
+--         declaration and are usually numbered from 0.
+--         The methods' types use the instance's type variable indices
+--         (if typed abstract curry is generated).
+data CInstanceDecl = CInstance QName CContext CTypeExpr [CFuncDecl]
+    deriving (Eq, Read, Show)
+
+-- |Definitions of algebraic data types and type synonyms.
+-- A data type definition of the form
+-- @
+-- data t x1...xn = ...| forall y1...ym . cx => c t1....tkc |...
+--   deriving (d1,...,dp)
+-- @
+-- is represented by the Curry term
+-- @
+-- (CType t v [i1,...,in] [...(CCons [l1,...,lm] cx c kc v [t1,...,tkc])...]
+--        [d1,...,dp])
+-- @
+-- where each @ij@ is the index of the type variable @xj@, each @lj@ is the
+-- index of the existentially quantified type variable @yj@ and @v@ is the
+-- visibility of the type resp. constructor.
+-- /Note:/ The type variable indices are unique inside each type declaration
+--         and are usually numbered from 0.
+-- Thus, a data type declaration consists of the name of the data type,
+-- a list of type parameters and a list of constructor declarations.
+data CTypeDecl
+    -- |algebraic data type
+  = CType    QName CVisibility [CTVarIName] [CConsDecl] [QName]
+    -- |type synonym
+  | CTypeSyn QName CVisibility [CTVarIName] CTypeExpr
+    -- |renaming type, may have only exactly one type expression
+    -- in the constructor declaration and no existentially type variables and
+    -- no context
+  | CNewType QName CVisibility [CTVarIName] CConsDecl [QName]
+    deriving (Eq, Read, Show)
+
+-- |The type for representing type variables.
+-- They are represented by @(i,n)@ where @i@ is a type variable index
+-- which is unique inside a function and @n@ is a name (if possible,
+-- the name written in the source program).
+type CTVarIName = (Int, String)
+
+-- |A constructor declaration consists of the name of the constructor
+-- and a list of the argument types of the constructor.
+-- The arity equals the number of types.
+data CConsDecl
+  = CCons   QName CVisibility [CTypeExpr]
+  | CRecord QName CVisibility [CFieldDecl]
+    deriving (Eq, Read, Show)
+
+-- |A record field declaration consists of the name of the
+-- the label, the visibility and its corresponding type.
+data CFieldDecl = CField QName CVisibility CTypeExpr
+  deriving (Eq, Read, Show)
+
+-- |The type for representing a class constraint.
+type CConstraint = (QName, CTypeExpr)
+
+-- |The type for representing a context.
+data CContext = CContext [CConstraint]
+  deriving (Eq, Read, Show)
+
+-- |Type expression.
+-- A type expression is either a type variable, a function type,
+-- a type constructor or a type application.
+data CTypeExpr
+    -- |Type variable
+  = CTVar CTVarIName
+    -- |Function type @t1 -> t2@
+  | CFuncType CTypeExpr CTypeExpr
+    -- |Type constructor
+  | CTCons QName
+    -- |Type application
+  | CTApply CTypeExpr CTypeExpr
+    deriving (Eq, Read, Show)
+
+-- |Qualified type expression.
+data CQualTypeExpr = CQualType CContext CTypeExpr
+    deriving (Eq, Read, Show)
+
+-- |Labeled record fields
+type CField a = (QName, a)
+
+-- |Operator precedence declaration.
+-- An operator precedence declaration @fix p n@ in Curry corresponds to the
+-- AbstractCurry term @(COp n fix p)@.
+data COpDecl = COp QName CFixity Int
+    deriving (Eq, Read, Show)
+
+-- |Fixity declarations of infix operators
+data CFixity
+  = CInfixOp  -- ^ non-associative infix operator
+  | CInfixlOp -- ^ left-associative infix operator
+  | CInfixrOp -- ^ right-associative infix operator
+    deriving (Eq, Read, Show)
+
+-- |Function arity
+type Arity = Int
+
+-- |Data type for representing function declarations.
+-- A function declaration in FlatCurry is a term of the form
+-- @
+-- (CFunc name arity visibility type (CRules eval [CRule rule1,...,rulek]))
+-- @
+-- and represents the function @name@ with definition
+-- @
+-- name :: type
+-- rule1
+-- ...
+-- rulek
+-- @
+-- /Note:/ The variable indices are unique inside each rule.
+-- External functions are represented as
+-- @
+-- (CFunc name arity type (CExternal s))
+-- @
+-- where s is the external name associated to this function.
+-- Thus, a function declaration consists of the name, arity, type, and
+-- a list of rules.
+-- If the list of rules is empty, the function is considered
+-- to be externally defined.
+data CFuncDecl = CFunc QName Arity CVisibility CQualTypeExpr [CRule]
+    deriving (Eq, Read, Show)
+
+-- |The general form of a function rule. It consists of a list of patterns
+-- (left-hand side), a list of guards (@success@ if not present in the
+-- source text) with their corresponding right-hand sides, and
+-- a list of local declarations.
+data CRule = CRule [CPattern] CRhs
+    deriving (Eq, Read, Show)
+
+-- |Right-hand-side of a 'CRule' or an @case@ expression
+data CRhs
+  = CSimpleRhs  CExpr            [CLocalDecl] -- @expr where decls@
+  | CGuardedRhs [(CExpr, CExpr)] [CLocalDecl] -- @| cond = expr where decls@
+    deriving (Eq, Read, Show)
+
+-- | Local (let/where) declarations
+data CLocalDecl
+  = CLocalFunc CFuncDecl     -- ^ local function declaration
+  | CLocalPat  CPattern CRhs -- ^ local pattern declaration
+  | CLocalVars [CVarIName]   -- ^ local free variable declarations
+    deriving (Eq, Read, Show)
+
+-- |Variable names.
+-- Object variables occurring in expressions are represented by @(Var i)@
+-- where @i@ is a variable index.
+type CVarIName = (Int, String)
+
+-- |Pattern expressions.
+data CPattern
+    -- |pattern variable (unique index / name)
+  = CPVar CVarIName
+    -- |literal (Integer/Float/Char constant)
+  | CPLit CLiteral
+    -- |application @(m.c e1 ... en)@ of n-ary constructor @m.c@
+    --  (@CPComb (m,c) [e1,...,en]@)
+  | CPComb QName [CPattern]
+    -- |as-pattern (extended Curry)
+  | CPAs CVarIName CPattern
+    -- |functional pattern (extended Curry)
+  | CPFuncComb QName [CPattern]
+    -- |lazy pattern (extended Curry)
+  | CPLazy CPattern
+    -- |record pattern (extended curry)
+  | CPRecord QName [CField CPattern]
+    deriving (Eq, Read, Show)
+
+-- | Curry expressions.
+data CExpr
+    -- |variable (unique index / name)
+  = CVar       CVarIName
+    -- |literal (Integer/Float/Char/String constant)
+  | CLit       CLiteral
+    -- |a defined symbol with module and name, i.e., a function or a constructor
+  | CSymbol    QName
+    -- |application (e1 e2)
+  | CApply     CExpr CExpr
+    -- |lambda abstraction
+  | CLambda    [CPattern] CExpr
+    -- |local let declarations
+  | CLetDecl   [CLocalDecl] CExpr
+    -- |do block
+  | CDoExpr    [CStatement]
+    -- |list comprehension
+  | CListComp  CExpr [CStatement]
+    -- |case expression
+  | CCase      CCaseType CExpr [(CPattern, CRhs)]
+    -- |typed expression
+  | CTyped     CExpr CQualTypeExpr
+    -- |record construction (extended Curry)
+  | CRecConstr QName [CField CExpr]
+    -- |record update (extended Curry)
+  | CRecUpdate CExpr [CField CExpr]
+    deriving (Eq, Read, Show)
+
+-- |Literals occurring in an expression or a pattern,
+-- either an integer, a float, a character, or a string constant.
+-- /Note:/ The constructor definition of 'CIntc' differs from the original
+-- PAKCS definition. It uses Haskell type 'Integer' instead of 'Int'
+-- to provide an unlimited range of integer numbers. Furthermore,
+-- float values are represented with Haskell type 'Double' instead of
+-- 'Float' to gain double precision.
+data CLiteral
+  = CIntc    Integer -- ^ Int literal
+  | CFloatc  Double  -- ^ Float literal
+  | CCharc   Char    -- ^ Char literal
+  | CStringc String  -- ^ String literal
+    deriving (Eq, Read, Show)
+
+-- |Statements in do expressions and list comprehensions.
+data CStatement
+  = CSExpr CExpr          -- ^ an expression (I/O action or boolean)
+  | CSPat  CPattern CExpr -- ^ a pattern definition
+  | CSLet  [CLocalDecl]   -- ^ a local let declaration
+    deriving (Eq, Read, Show)
+
+-- |Type of case expressions
+data CCaseType
+  = CRigid -- ^ rigid case expression
+  | CFlex  -- ^ flexible case expression
+    deriving (Eq, Read, Show)
diff --git a/src/Curry/Base/Ident.hs b/src/Curry/Base/Ident.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Base/Ident.hs
@@ -0,0 +1,1036 @@
+{- |
+    Module      :  $Header$
+    Description :  Identifiers
+    Copyright   :  (c) 1999 - 2004, Wolfgang Lux
+                       2011 - 2013, Björn Peemöller
+                       2016       , Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module provides the implementation of identifiers and some
+    utility functions for identifiers.
+
+    Identifiers comprise the name of the denoted entity and an /id/,
+    which can be used for renaming identifiers, e.g., in order to resolve
+    name conflicts between identifiers from different scopes. An
+    identifier with an /id/ @0@ is considered as not being renamed
+    and, hence, its /id/ will not be shown.
+
+    Qualified identifiers may optionally be prefixed by a module name.
+-}
+{-# LANGUAGE CPP #-}
+module Curry.Base.Ident
+  ( -- * Module identifiers
+    ModuleIdent (..), mkMIdent, moduleName, escModuleName
+  , fromModuleName, isValidModuleName, addPositionModuleIdent, mIdentLength
+
+    -- * Local identifiers
+  , Ident (..), mkIdent, showIdent, escName, identSupply
+  , globalScope, hasGlobalScope, isRenamed, renameIdent, unRenameIdent
+  , updIdentName, addPositionIdent, isInfixOp, identLength
+
+    -- * Qualified identifiers
+  , QualIdent (..), qualName, escQualName, isQInfixOp, qualify
+  , qualifyWith, qualQualify, qualifyLike, isQualified, unqualify, qualUnqualify
+  , localIdent, isLocalIdent, updQualIdent, qIdentLength
+
+    -- * Predefined simple identifiers
+    -- ** Identifiers for modules
+  , emptyMIdent, mainMIdent, preludeMIdent
+    -- ** Identifiers for types
+  , arrowId, unitId, boolId, charId, intId, floatId, listId, ioId, successId
+    -- ** Identifiers for type classes
+  , eqId, ordId, enumId, boundedId, readId, showId
+  , numId, fractionalId
+  , monadId, monadFailId
+  , dataId
+    -- ** Identifiers for constructors
+  , trueId, falseId, nilId, consId, tupleId, isTupleId, tupleArity
+    -- ** Identifiers for values
+  , mainId, minusId, fminusId, applyId, errorId, failedId, idId
+  , succId, predId, toEnumId, fromEnumId, enumFromId, enumFromThenId
+  , enumFromToId, enumFromThenToId
+  , maxBoundId, minBoundId
+  , lexId, readsPrecId, readParenId
+  , showsPrecId, showParenId, showStringId
+  , andOpId, eqOpId, leqOpId, ltOpId, orOpId, appendOpId, dotOpId
+  , aValueId, dataEqId
+  , anonId, isAnonId
+
+    -- * Predefined qualified identifiers
+    -- ** Identifiers for types
+  , qArrowId, qUnitId, qBoolId, qCharId, qIntId, qFloatId, qListId, qIOId
+  , qSuccessId, isPrimTypeId
+    -- ** Identifiers for type classes
+  , qEqId, qOrdId, qEnumId, qBoundedId, qReadId, qShowId
+  , qNumId, qFractionalId
+  , qMonadId, qMonadFailId
+  , qDataId
+    -- ** Identifiers for constructors
+  , qTrueId, qFalseId, qNilId, qConsId, qTupleId, isQTupleId, qTupleArity
+    -- ** Identifiers for values
+  , qApplyId, qErrorId, qFailedId, qIdId
+  , qFromEnumId, qEnumFromId, qEnumFromThenId, qEnumFromToId, qEnumFromThenToId
+  , qMaxBoundId, qMinBoundId
+  , qLexId, qReadsPrecId, qReadParenId
+  , qShowsPrecId, qShowParenId, qShowStringId
+  , qAndOpId, qEqOpId, qLeqOpId, qLtOpId, qOrOpId, qAppendOpId, qDotOpId
+  , qAValueId, qDataEqId
+
+    -- * Extended functionality
+    -- ** Functional patterns
+  , fpSelectorId, isFpSelectorId, isQualFpSelectorId
+    -- ** Records
+  , recSelectorId, qualRecSelectorId, recUpdateId, qualRecUpdateId
+  , recordExt, recordExtId, isRecordExtId, fromRecordExtId
+  , labelExt, labelExtId, isLabelExtId, fromLabelExtId
+  , renameLabel, mkLabelIdent
+  ) where
+
+import Prelude hiding ((<>))
+import Data.Char           (isAlpha, isAlphaNum)
+import Data.Function       (on)
+import Data.List           (intercalate, isInfixOf, isPrefixOf)
+import Data.Maybe          (isJust, fromMaybe)
+import Data.Binary
+import Control.Monad
+
+import Curry.Base.Position
+import Curry.Base.Span hiding (file)
+import Curry.Base.SpanInfo
+import Curry.Base.Pretty
+
+-- ---------------------------------------------------------------------------
+-- Module identifier
+-- ---------------------------------------------------------------------------
+
+-- | Module identifier
+data ModuleIdent = ModuleIdent
+  { midSpanInfo   :: SpanInfo -- ^ source code 'SpanInfo'
+  , midQualifiers :: [String] -- ^ hierarchical idenfiers
+  } deriving (Read, Show)
+
+instance Eq ModuleIdent where
+  (==) = (==) `on` midQualifiers
+
+instance Ord ModuleIdent where
+  compare = compare `on` midQualifiers
+
+instance HasSpanInfo ModuleIdent where
+  getSpanInfo = midSpanInfo
+  setSpanInfo spi a = a { midSpanInfo = spi }
+  updateEndPos i =
+    setEndPosition (incr (getPosition i) (mIdentLength i - 1)) i
+
+instance HasPosition ModuleIdent where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance Pretty ModuleIdent where
+  pPrint = hcat . punctuate dot . map text . midQualifiers
+
+instance Binary ModuleIdent where
+  put (ModuleIdent sp qs) = put sp >> put qs
+  get = liftM2 ModuleIdent get get
+
+mIdentLength :: ModuleIdent -> Int
+mIdentLength a = length (concat (midQualifiers a))
+               + length (midQualifiers a)
+
+-- |Construct a 'ModuleIdent' from a list of 'String's forming the
+--  the hierarchical module name.
+mkMIdent :: [String] -> ModuleIdent
+mkMIdent = ModuleIdent NoSpanInfo
+
+-- |Retrieve the hierarchical name of a module
+moduleName :: ModuleIdent -> String
+moduleName = intercalate "." . midQualifiers
+
+-- |Show the name of an 'ModuleIdent' escaped by ticks
+escModuleName :: ModuleIdent -> String
+escModuleName m = '`' : moduleName m ++ "'"
+
+-- |Add a source code 'Position' to a 'ModuleIdent'
+addPositionModuleIdent :: Position -> ModuleIdent -> ModuleIdent
+addPositionModuleIdent = setPosition
+
+-- |Check whether a 'String' is a valid module name.
+--
+-- Valid module names must satisfy the following conditions:
+--
+--  * The name must not be empty
+--  * The name must consist of one or more single identifiers,
+--    seperated by dots
+--  * Each single identifier must be non-empty, start with a letter and
+--    consist of letter, digits, single quotes or underscores only
+isValidModuleName :: String -> Bool
+isValidModuleName [] = False -- Module names may not be empty
+isValidModuleName qs = all isModuleIdentifier $ splitIdentifiers qs
+  where
+  -- components of a module identifier may not be null
+  isModuleIdentifier []     = False
+  -- components of a module identifier must start with a letter and consist
+  -- of letter, digits, underscores or single quotes
+  isModuleIdentifier (c:cs) = isAlpha c && all isIdent cs
+  isIdent c                 = isAlphaNum c || c `elem` "'_"
+
+-- |Resemble the hierarchical module name from a 'String' by splitting
+-- the 'String' at inner dots.
+--
+-- /Note:/ This function does not check the 'String' to be a valid module
+-- identifier, use isValidModuleName for this purpose.
+fromModuleName :: String -> ModuleIdent
+fromModuleName = mkMIdent . splitIdentifiers
+
+-- Auxiliary function to split a hierarchical module identifier at the dots
+splitIdentifiers :: String -> [String]
+splitIdentifiers s = let (pref, rest) = break (== '.') s in
+  pref : case rest of
+    []     -> []
+    (_:s') -> splitIdentifiers s'
+
+-- ---------------------------------------------------------------------------
+-- Simple identifier
+-- ---------------------------------------------------------------------------
+
+-- |Simple identifier
+data Ident = Ident
+  { idSpanInfo :: SpanInfo -- ^ Source code 'SpanInfo'
+  , idName     :: String   -- ^ Name of the identifier
+  , idUnique   :: Integer  -- ^ Unique number of the identifier
+  } deriving (Read, Show)
+
+instance Eq Ident where
+  Ident _ m i == Ident _ n j = (m, i) == (n, j)
+
+instance Ord Ident where
+  Ident _ m i `compare` Ident _ n j = (m, i) `compare` (n, j)
+
+instance HasSpanInfo Ident where
+  getSpanInfo = idSpanInfo
+  setSpanInfo spi a = a { idSpanInfo = spi }
+  updateEndPos i@(Ident (SpanInfo _ [_,ss]) _ _) =
+    setEndPosition (end ss) i
+  updateEndPos i =
+    setEndPosition (incr (getPosition i) (identLength i - 1)) i
+
+instance HasPosition Ident where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance Pretty Ident where
+  pPrint (Ident _ x n) | n == globalScope = text x
+                       | otherwise        = text x <> dot <> integer n
+
+instance Binary Ident where
+  put (Ident sp qs i) = put sp >> put qs >> put i
+  get = liftM3 Ident get get get
+
+identLength :: Ident -> Int
+identLength a = length (idName a)
+
+-- |Global scope for renaming
+globalScope :: Integer
+globalScope = 0
+
+-- |Construct an 'Ident' from a 'String'
+mkIdent :: String -> Ident
+mkIdent x = Ident NoSpanInfo x globalScope
+
+-- |Infinite list of different 'Ident's
+identSupply :: [Ident]
+identSupply = [ mkNewIdent c i | i <- [0 ..] :: [Integer], c <- ['a'..'z'] ]
+  where mkNewIdent c 0 = mkIdent [c]
+        mkNewIdent c n = mkIdent $ c : show n
+
+-- |Show function for an 'Ident'
+showIdent :: Ident -> String
+showIdent (Ident _ x n) | n == globalScope = x
+                        | otherwise        = x ++ '.' : show n
+
+-- |Show the name of an 'Ident' escaped by ticks
+escName :: Ident -> String
+escName i = '`' : idName i ++ "'"
+
+-- |Has the identifier global scope?
+hasGlobalScope :: Ident -> Bool
+hasGlobalScope = (== globalScope) . idUnique
+
+-- |Is the 'Ident' renamed?
+isRenamed :: Ident -> Bool
+isRenamed = (/= globalScope) . idUnique
+
+-- |Rename an 'Ident' by changing its unique number
+renameIdent :: Ident -> Integer -> Ident
+renameIdent ident n = ident { idUnique = n }
+
+-- |Revert the renaming of an 'Ident' by resetting its unique number
+unRenameIdent :: Ident -> Ident
+unRenameIdent ident = renameIdent ident globalScope
+
+-- |Change the name of an 'Ident' using a renaming function
+updIdentName :: (String -> String) -> Ident -> Ident
+updIdentName f (Ident p n i) = Ident p (f n) i
+
+-- |Add a 'Position' to an 'Ident'
+addPositionIdent :: Position -> Ident -> Ident
+addPositionIdent = setPosition
+
+-- |Check whether an 'Ident' identifies an infix operation
+isInfixOp :: Ident -> Bool
+isInfixOp (Ident _ ('<' : c : cs) _) =
+  last (c : cs) /= '>' || not (isAlphaNum c) && c `notElem` "_(["
+isInfixOp (Ident _ (c : _) _)    = not (isAlphaNum c) && c `notElem` "_(["
+isInfixOp Ident{}                = False -- error "Zero-length identifier"
+
+-- ---------------------------------------------------------------------------
+-- Qualified identifier
+-- ---------------------------------------------------------------------------
+
+-- |Qualified identifier
+data QualIdent = QualIdent
+  { qidSpanInfo :: SpanInfo          -- ^ Source code 'SpanInfo'
+  , qidModule   :: Maybe ModuleIdent -- ^ optional module identifier
+  , qidIdent    :: Ident             -- ^ identifier itself
+  } deriving (Read, Show)
+
+instance Eq QualIdent where
+  QualIdent _ m i == QualIdent _ n j = (m, i) == (n, j)
+
+instance Ord QualIdent where
+  QualIdent _ m i `compare` QualIdent _ n j = (m, i) `compare` (n, j)
+
+instance HasSpanInfo QualIdent where
+  getSpanInfo = qidSpanInfo
+  setSpanInfo spi a = a { qidSpanInfo = spi }
+  updateEndPos i@(QualIdent (SpanInfo _ [_,ss]) _ _) =
+    setEndPosition (end ss) i
+  updateEndPos i =
+    setEndPosition (incr (getPosition i) (qIdentLength i - 1)) i
+
+instance HasPosition QualIdent where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance Pretty QualIdent where
+  pPrint = text . qualName
+
+instance Binary QualIdent where
+  put (QualIdent sp mid idt) = put sp >> put mid >> put idt
+  get = liftM3 QualIdent get get get
+
+qIdentLength :: QualIdent -> Int
+qIdentLength (QualIdent _ (Just m) i) = identLength i + mIdentLength m
+qIdentLength (QualIdent _ Nothing  i) = identLength i
+
+-- |show function for qualified identifiers)=
+qualName :: QualIdent -> String
+qualName (QualIdent _ Nothing  x) = idName x
+qualName (QualIdent _ (Just m) x) = moduleName m ++ "." ++ idName x
+
+-- |Show the name of an 'QualIdent' escaped by ticks
+escQualName :: QualIdent -> String
+escQualName qn = '`' : qualName qn ++ "'"
+
+-- |Check whether an 'QualIdent' identifies an infix operation
+isQInfixOp :: QualIdent -> Bool
+isQInfixOp = isInfixOp . qidIdent
+
+-- ---------------------------------------------------------------------------
+-- The functions \texttt{qualify} and \texttt{qualifyWith} convert an
+-- unqualified identifier into a qualified identifier (without and with a
+-- given module prefix, respectively).
+-- ---------------------------------------------------------------------------
+
+-- | Convert an 'Ident' to a 'QualIdent'
+qualify :: Ident -> QualIdent
+qualify i = QualIdent (fromSrcSpan (getSrcSpan i)) Nothing i
+
+-- | Convert an 'Ident' to a 'QualIdent' with a given 'ModuleIdent'
+qualifyWith :: ModuleIdent -> Ident -> QualIdent
+qualifyWith mid i = updateEndPos $
+  QualIdent (fromSrcSpan (getSrcSpan mid)) (Just mid) i
+
+-- | Convert an 'QualIdent' to a new 'QualIdent' with a given 'ModuleIdent'.
+--   If the original 'QualIdent' already contains an 'ModuleIdent' it
+--   remains unchanged.
+qualQualify :: ModuleIdent -> QualIdent -> QualIdent
+qualQualify m (QualIdent _ Nothing x) = qualifyWith m x
+qualQualify _ x = x
+
+-- |Qualify an 'Ident' with the 'ModuleIdent' of the given 'QualIdent',
+-- if present.
+qualifyLike :: QualIdent -> Ident -> QualIdent
+qualifyLike (QualIdent _ Nothing  _) x = qualify x
+qualifyLike (QualIdent _ (Just m) _) x = qualifyWith m x
+
+-- | Check whether a 'QualIdent' contains a 'ModuleIdent'
+isQualified :: QualIdent -> Bool
+isQualified = isJust . qidModule
+
+-- | Remove the qualification of an 'QualIdent'
+unqualify :: QualIdent -> Ident
+unqualify = qidIdent
+
+-- | Remove the qualification with a specific 'ModuleIdent'. If the
+--   original 'QualIdent' has no 'ModuleIdent' or a different one, it
+--   remains unchanged.
+qualUnqualify :: ModuleIdent -> QualIdent -> QualIdent
+qualUnqualify _ qid@(QualIdent _   Nothing   _) = qid
+qualUnqualify m     (QualIdent spi (Just m') x) = QualIdent spi m'' x
+  where m'' | m == m'   = Nothing
+            | otherwise = Just m'
+
+-- | Extract the 'Ident' of an 'QualIdent' if it is local to the
+--   'ModuleIdent', i.e. if the 'Ident' is either unqualified or qualified
+--   with the given 'ModuleIdent'.
+localIdent :: ModuleIdent -> QualIdent -> Maybe Ident
+localIdent _ (QualIdent _ Nothing   x) = Just x
+localIdent m (QualIdent _ (Just m') x)
+  | m == m'   = Just x
+  | otherwise = Nothing
+
+-- |Check whether the given 'QualIdent' is local to the given 'ModuleIdent'.
+isLocalIdent :: ModuleIdent -> QualIdent -> Bool
+isLocalIdent mid qid = isJust (localIdent mid qid)
+
+-- | Update a 'QualIdent' by applying functions to its components
+updQualIdent :: (ModuleIdent -> ModuleIdent) -> (Ident -> Ident)
+             -> QualIdent -> QualIdent
+updQualIdent f g (QualIdent spi m x) = QualIdent spi (fmap f m) (g x)
+
+-- ---------------------------------------------------------------------------
+-- A few identifiers are predefined here.
+-- ---------------------------------------------------------------------------
+-- | 'ModuleIdent' for the empty module
+emptyMIdent :: ModuleIdent
+emptyMIdent = ModuleIdent NoSpanInfo []
+
+-- | 'ModuleIdent' for the main module
+mainMIdent :: ModuleIdent
+mainMIdent = ModuleIdent NoSpanInfo ["main"]
+
+-- | 'ModuleIdent' for the Prelude
+preludeMIdent :: ModuleIdent
+preludeMIdent = ModuleIdent NoSpanInfo ["Prelude"]
+
+-- ---------------------------------------------------------------------------
+-- Identifiers for types
+-- ---------------------------------------------------------------------------
+
+-- | 'Ident' for the type '(->)'
+arrowId :: Ident
+arrowId = mkIdent "(->)"
+
+-- | 'Ident' for the type/value unit ('()')
+unitId :: Ident
+unitId = mkIdent "()"
+
+-- | 'Ident' for the type 'Bool'
+boolId :: Ident
+boolId = mkIdent "Bool"
+
+-- | 'Ident' for the type 'Char'
+charId :: Ident
+charId = mkIdent "Char"
+
+-- | 'Ident' for the type 'Int'
+intId :: Ident
+intId = mkIdent "Int"
+
+-- | 'Ident' for the type 'Float'
+floatId :: Ident
+floatId = mkIdent "Float"
+
+-- | 'Ident' for the type '[]'
+listId :: Ident
+listId = mkIdent "[]"
+
+-- | 'Ident' for the type 'IO'
+ioId :: Ident
+ioId = mkIdent "IO"
+
+-- | 'Ident' for the type 'Success'
+successId :: Ident
+successId = mkIdent "Success"
+
+-- | Construct an 'Ident' for an n-ary tuple where n > 1
+tupleId :: Int -> Ident
+tupleId n
+  | n > 1     = mkIdent $ '(' : replicate (n - 1) ',' ++ ")"
+  | otherwise = error $ "Curry.Base.Ident.tupleId: wrong arity " ++ show n
+
+-- | Check whether an 'Ident' is an identifier for an tuple type
+isTupleId :: Ident -> Bool
+isTupleId (Ident _ x _) = n > 1 && x == idName (tupleId n)
+  where n = length x - 1
+
+-- | Compute the arity of a tuple identifier
+tupleArity :: Ident -> Int
+tupleArity i@(Ident _ x _)
+  | n > 1 && x == idName (tupleId n) = n
+  | otherwise                        = error $
+      "Curry.Base.Ident.tupleArity: no tuple identifier: " ++ showIdent i
+  where n = length x - 1
+
+-- ---------------------------------------------------------------------------
+-- Identifiers for type classes
+-- ---------------------------------------------------------------------------
+
+-- | 'Ident' for the 'Eq' class
+eqId :: Ident
+eqId = mkIdent "Eq"
+
+-- | 'Ident' for the 'Ord' class
+ordId :: Ident
+ordId = mkIdent "Ord"
+
+-- | 'Ident' for the 'Enum' class
+enumId :: Ident
+enumId = mkIdent "Enum"
+
+-- | 'Ident' for the 'Bounded' class
+boundedId :: Ident
+boundedId = mkIdent "Bounded"
+
+-- | 'Ident' for the 'Read' class
+readId :: Ident
+readId = mkIdent "Read"
+
+-- | 'Ident' for the 'Show' class
+showId :: Ident
+showId = mkIdent "Show"
+
+-- | 'Ident' for the 'Num' class
+numId :: Ident
+numId = mkIdent "Num"
+
+-- | 'Ident' for the 'Fractional' class
+fractionalId :: Ident
+fractionalId = mkIdent "Fractional"
+
+-- | 'Ident' for the 'Monad' class
+monadId :: Ident
+monadId = mkIdent "Monad"
+
+-- | 'Ident' for the 'MonadFail' class
+monadFailId :: Ident
+monadFailId = mkIdent "MonadFail"
+
+-- | 'Ident' for the 'Data' class
+dataId :: Ident
+dataId = mkIdent "Data"
+
+-- ---------------------------------------------------------------------------
+-- Identifiers for constructors
+-- ---------------------------------------------------------------------------
+
+-- | 'Ident' for the value 'True'
+trueId :: Ident
+trueId = mkIdent "True"
+
+-- | 'Ident' for the value 'False'
+falseId :: Ident
+falseId = mkIdent "False"
+
+-- | 'Ident' for the value '[]'
+nilId :: Ident
+nilId = mkIdent "[]"
+
+-- | 'Ident' for the function ':'
+consId :: Ident
+consId = mkIdent ":"
+
+-- ---------------------------------------------------------------------------
+-- Identifiers for values
+-- ---------------------------------------------------------------------------
+
+-- | 'Ident' for the main function
+mainId :: Ident
+mainId = mkIdent "main"
+
+-- | 'Ident' for the minus function
+minusId :: Ident
+minusId = mkIdent "-"
+
+-- | 'Ident' for the minus function for Floats
+fminusId :: Ident
+fminusId = mkIdent "-."
+
+-- | 'Ident' for the apply function
+applyId :: Ident
+applyId = mkIdent "apply"
+
+-- | 'Ident' for the error function
+errorId :: Ident
+errorId = mkIdent "error"
+
+-- | 'Ident' for the failed function
+failedId :: Ident
+failedId = mkIdent "failed"
+
+-- | 'Ident' for the id function
+idId :: Ident
+idId = mkIdent "id"
+
+-- | 'Ident' for the maxBound function
+maxBoundId :: Ident
+maxBoundId = mkIdent "maxBound"
+
+-- | 'Ident' for the minBound function
+minBoundId :: Ident
+minBoundId = mkIdent "minBound"
+
+-- | 'Ident' for the pred function
+predId :: Ident
+predId = mkIdent "pred"
+
+-- | 'Ident' for the succ function
+succId :: Ident
+succId = mkIdent "succ"
+
+-- | 'Ident' for the toEnum function
+toEnumId :: Ident
+toEnumId = mkIdent "toEnum"
+
+-- | 'Ident' for the fromEnum function
+fromEnumId :: Ident
+fromEnumId = mkIdent "fromEnum"
+
+-- | 'Ident' for the enumFrom function
+enumFromId :: Ident
+enumFromId = mkIdent "enumFrom"
+
+-- | 'Ident' for the enumFromThen function
+enumFromThenId :: Ident
+enumFromThenId = mkIdent "enumFromThen"
+
+-- | 'Ident' for the enumFromTo function
+enumFromToId :: Ident
+enumFromToId = mkIdent "enumFromTo"
+
+-- | 'Ident' for the enumFromThenTo function
+enumFromThenToId :: Ident
+enumFromThenToId = mkIdent "enumFromThenTo"
+
+-- | 'Ident' for the lex function
+lexId :: Ident
+lexId = mkIdent "lex"
+
+-- | 'Ident' for the readsPrec function
+readsPrecId :: Ident
+readsPrecId = mkIdent "readsPrec"
+
+-- | 'Ident' for the readParen function
+readParenId :: Ident
+readParenId = mkIdent "readParen"
+
+-- | 'Ident' for the showsPrec function
+showsPrecId :: Ident
+showsPrecId = mkIdent "showsPrec"
+
+-- | 'Ident' for the showParen function
+showParenId :: Ident
+showParenId = mkIdent "showParen"
+
+-- | 'Ident' for the showString function
+showStringId :: Ident
+showStringId = mkIdent "showString"
+
+-- | 'Ident' for the '&&' operator
+andOpId :: Ident
+andOpId = mkIdent "&&"
+
+-- | 'Ident' for the '==' operator
+eqOpId :: Ident
+eqOpId = mkIdent "=="
+
+-- | 'Ident' for the '<=' operator
+leqOpId :: Ident
+leqOpId = mkIdent "<="
+
+-- | 'Ident' for the '<' operator
+ltOpId :: Ident
+ltOpId = mkIdent "<"
+
+-- | 'Ident' for the '||' operator
+orOpId :: Ident
+orOpId = mkIdent "||"
+
+-- | 'Ident' for the '++' operator
+appendOpId :: Ident
+appendOpId = mkIdent "++"
+
+-- | 'Ident' for the '.' operator
+dotOpId :: Ident
+dotOpId = mkIdent "."
+
+aValueId :: Ident
+aValueId = mkIdent "aValue"
+
+dataEqId :: Ident
+dataEqId = mkIdent "==="
+
+-- | 'Ident' for anonymous variable
+anonId :: Ident
+anonId = mkIdent "_"
+
+-- |Check whether an 'Ident' represents an anonymous identifier ('anonId')
+isAnonId :: Ident -> Bool
+isAnonId = (== anonId) . unRenameIdent
+
+-- ---------------------------------------------------------------------------
+-- Qualified Identifiers for types
+-- ---------------------------------------------------------------------------
+
+-- | Construct a 'QualIdent' for an 'Ident' using the module prelude
+qPreludeIdent :: Ident -> QualIdent
+qPreludeIdent = qualifyWith preludeMIdent
+
+-- | 'QualIdent' for the type '(->)'
+qArrowId :: QualIdent
+qArrowId = qualify arrowId
+
+-- | 'QualIdent' for the type/value unit ('()')
+qUnitId :: QualIdent
+qUnitId = qualify unitId
+
+-- | 'QualIdent' for the type '[]'
+qListId :: QualIdent
+qListId = qualify listId
+
+-- | 'QualIdent' for the type 'Bool'
+qBoolId :: QualIdent
+qBoolId = qPreludeIdent boolId
+
+-- | 'QualIdent' for the type 'Char'
+qCharId :: QualIdent
+qCharId = qPreludeIdent charId
+
+-- | 'QualIdent' for the type 'Int'
+qIntId :: QualIdent
+qIntId = qPreludeIdent intId
+
+-- | 'QualIdent' for the type 'Float'
+qFloatId :: QualIdent
+qFloatId = qPreludeIdent floatId
+
+-- | 'QualIdent' for the type 'IO'
+qIOId :: QualIdent
+qIOId = qPreludeIdent ioId
+
+-- | 'QualIdent' for the type 'Success'
+qSuccessId :: QualIdent
+qSuccessId = qPreludeIdent successId
+
+-- | Check whether an 'QualIdent' is an primary type constructor
+isPrimTypeId :: QualIdent -> Bool
+isPrimTypeId tc = tc `elem` [qArrowId, qUnitId, qListId] || isQTupleId tc
+
+-- ---------------------------------------------------------------------------
+-- Qualified Identifiers for type classes
+-- ---------------------------------------------------------------------------
+
+-- | 'QualIdent' for the 'Eq' class
+qEqId :: QualIdent
+qEqId = qPreludeIdent eqId
+
+-- | 'QualIdent' for the 'Ord' class
+qOrdId :: QualIdent
+qOrdId = qPreludeIdent ordId
+
+-- | 'QualIdent' for the 'Enum' class
+qEnumId :: QualIdent
+qEnumId = qPreludeIdent enumId
+
+-- | 'QualIdent' for the 'Bounded' class
+qBoundedId :: QualIdent
+qBoundedId = qPreludeIdent boundedId
+
+-- | 'QualIdent' for the 'Read' class
+qReadId :: QualIdent
+qReadId = qPreludeIdent readId
+
+-- | 'QualIdent' for the 'Show' class
+qShowId :: QualIdent
+qShowId = qPreludeIdent showId
+
+-- | 'QualIdent' for the 'Num' class
+qNumId :: QualIdent
+qNumId = qPreludeIdent numId
+
+-- | 'QualIdent' for the 'Fractional' class
+qFractionalId :: QualIdent
+qFractionalId = qPreludeIdent fractionalId
+
+-- | 'QualIdent' for the 'Monad' class
+qMonadId :: QualIdent
+qMonadId = qPreludeIdent monadId
+
+-- | 'QualIdent' for the 'MonadFail' class
+qMonadFailId :: QualIdent
+qMonadFailId = qPreludeIdent monadFailId
+
+-- | 'QualIdent' for the 'Data' class
+qDataId :: QualIdent
+qDataId = qPreludeIdent dataId
+
+-- ---------------------------------------------------------------------------
+-- Qualified Identifiers for constructors
+-- ---------------------------------------------------------------------------
+
+-- | 'QualIdent' for the constructor 'True'
+qTrueId :: QualIdent
+qTrueId = qPreludeIdent trueId
+
+-- | 'QualIdent' for the constructor 'False'
+qFalseId :: QualIdent
+qFalseId = qPreludeIdent falseId
+
+-- | 'QualIdent' for the constructor '[]'
+qNilId :: QualIdent
+qNilId = qualify nilId
+
+-- | 'QualIdent' for the constructor ':'
+qConsId :: QualIdent
+qConsId = qualify consId
+
+-- | 'QualIdent' for the type of n-ary tuples
+qTupleId :: Int -> QualIdent
+qTupleId = qualify . tupleId
+
+-- | Check whether an 'QualIdent' is an identifier for an tuple type
+isQTupleId :: QualIdent -> Bool
+isQTupleId = isTupleId . unqualify
+
+-- | Compute the arity of an qualified tuple identifier
+qTupleArity :: QualIdent -> Int
+qTupleArity = tupleArity . unqualify
+
+-- ---------------------------------------------------------------------------
+-- Qualified Identifiers for values
+-- ---------------------------------------------------------------------------
+
+-- | 'QualIdent' for the apply function
+qApplyId :: QualIdent
+qApplyId = qPreludeIdent applyId
+
+-- | 'QualIdent' for the error function
+qErrorId :: QualIdent
+qErrorId = qPreludeIdent errorId
+
+-- | 'QualIdent' for the failed function
+qFailedId :: QualIdent
+qFailedId = qPreludeIdent failedId
+
+-- | 'QualIdent' for the id function
+qIdId :: QualIdent
+qIdId = qPreludeIdent idId
+
+-- | 'QualIdent' for the maxBound function
+qMaxBoundId :: QualIdent
+qMaxBoundId = qPreludeIdent maxBoundId
+
+-- | 'QualIdent' for the minBound function
+qMinBoundId :: QualIdent
+qMinBoundId = qPreludeIdent minBoundId
+
+-- | 'QualIdent' for the fromEnum function
+qFromEnumId :: QualIdent
+qFromEnumId = qPreludeIdent fromEnumId
+
+-- | 'QualIdent' for the enumFrom function
+qEnumFromId :: QualIdent
+qEnumFromId = qPreludeIdent enumFromId
+
+-- | 'QualIdent' for the enumFromThen function
+qEnumFromThenId :: QualIdent
+qEnumFromThenId = qPreludeIdent enumFromThenId
+
+-- | 'QualIdent' for the enumFromTo function
+qEnumFromToId :: QualIdent
+qEnumFromToId = qPreludeIdent enumFromToId
+
+-- | 'QualIdent' for the enumFromThenTo function
+qEnumFromThenToId :: QualIdent
+qEnumFromThenToId = qPreludeIdent enumFromThenToId
+
+-- | 'QualIdent' for the lex function
+qLexId :: QualIdent
+qLexId = qPreludeIdent lexId
+
+-- | 'QualIdent' for the readsPrec function
+qReadsPrecId :: QualIdent
+qReadsPrecId = qPreludeIdent readsPrecId
+
+-- | 'QualIdent' for the readParen function
+qReadParenId :: QualIdent
+qReadParenId = qPreludeIdent readParenId
+
+-- | 'QualIdent' for the showsPrec function
+qShowsPrecId :: QualIdent
+qShowsPrecId = qPreludeIdent showsPrecId
+
+-- | 'QualIdent' for the showParen function
+qShowParenId :: QualIdent
+qShowParenId = qPreludeIdent showParenId
+
+-- | 'QualIdent' for the showString function
+qShowStringId :: QualIdent
+qShowStringId = qPreludeIdent showStringId
+
+-- | 'QualIdent' for the '&&' operator
+qAndOpId :: QualIdent
+qAndOpId = qPreludeIdent andOpId
+
+-- | 'QualIdent' for the '==' operator
+qEqOpId :: QualIdent
+qEqOpId = qPreludeIdent eqOpId
+
+-- | 'QualIdent' for the '<=' operator
+qLeqOpId :: QualIdent
+qLeqOpId = qPreludeIdent leqOpId
+
+-- | 'QualIdent' for the '<' operator
+qLtOpId :: QualIdent
+qLtOpId = qPreludeIdent ltOpId
+
+-- | 'QualIdent' for the '||' operator
+qOrOpId :: QualIdent
+qOrOpId = qPreludeIdent orOpId
+
+-- | 'QualIdent' for the '.' operator
+qDotOpId :: QualIdent
+qDotOpId = qPreludeIdent dotOpId
+
+qAValueId :: QualIdent
+qAValueId = qPreludeIdent aValueId
+
+qDataEqId :: QualIdent
+qDataEqId = qPreludeIdent dataEqId
+
+-- | 'QualIdent' for the '++' operator
+qAppendOpId :: QualIdent
+qAppendOpId = qPreludeIdent appendOpId
+
+-- ---------------------------------------------------------------------------
+-- Micellaneous functions for generating and testing extended identifiers
+-- ---------------------------------------------------------------------------
+
+-- Functional patterns
+
+-- | Annotation for function pattern identifiers
+fpSelExt :: String
+fpSelExt = "_#selFP"
+
+-- | Construct an 'Ident' for a functional pattern
+fpSelectorId :: Int -> Ident
+fpSelectorId n = mkIdent $ fpSelExt ++ show n
+
+-- | Check whether an 'Ident' is an identifier for a functional pattern
+isFpSelectorId :: Ident -> Bool
+isFpSelectorId = (fpSelExt `isInfixOf`) . idName
+
+-- | Check whether an 'QualIdent' is an identifier for a function pattern
+isQualFpSelectorId :: QualIdent -> Bool
+isQualFpSelectorId = isFpSelectorId . unqualify
+
+-- Record selection
+
+-- | Annotation for record selection identifiers
+recSelExt :: String
+recSelExt = "_#selR@"
+
+-- | Construct an 'Ident' for a record selection pattern
+recSelectorId :: QualIdent -- ^ identifier of the record
+              -> Ident     -- ^ identifier of the label
+              -> Ident
+recSelectorId = mkRecordId recSelExt
+
+-- | Construct a 'QualIdent' for a record selection pattern
+qualRecSelectorId :: ModuleIdent -- ^ default module
+                  -> QualIdent   -- ^ record identifier
+                  -> Ident       -- ^ label identifier
+                  -> QualIdent
+qualRecSelectorId m r l = qualRecordId m r $ recSelectorId r l
+
+-- Record update
+
+-- | Annotation for record update identifiers
+recUpdExt :: String
+recUpdExt = "_#updR@"
+
+-- | Construct an 'Ident' for a record update pattern
+recUpdateId :: QualIdent -- ^ record identifier
+            -> Ident     -- ^ label identifier
+            -> Ident
+recUpdateId = mkRecordId recUpdExt
+
+-- | Construct a 'QualIdent' for a record update pattern
+qualRecUpdateId :: ModuleIdent -- ^ default module
+                -> QualIdent   -- ^ record identifier
+                -> Ident       -- ^ label identifier
+                -> QualIdent
+qualRecUpdateId m r l = qualRecordId m r $ recUpdateId r l
+
+-- Auxiliary function to construct a selector/update identifier
+mkRecordId :: String -> QualIdent -> Ident -> Ident
+mkRecordId ann r l = mkIdent $ concat
+  [ann, idName (unqualify r), ".", idName l]
+
+-- Auxiliary function to qualify a selector/update identifier
+qualRecordId :: ModuleIdent -> QualIdent -> Ident -> QualIdent
+qualRecordId m r = qualifyWith (fromMaybe m $ qidModule r)
+
+-- Record tyes
+
+-- | Annotation for record identifiers
+recordExt :: String
+recordExt = "_#Rec:"
+
+-- | Construct an 'Ident' for a record
+recordExtId :: Ident -> Ident
+recordExtId r = mkIdent $ recordExt ++ idName r
+
+-- | Check whether an 'Ident' is an identifier for a record
+isRecordExtId :: Ident -> Bool
+isRecordExtId = (recordExt `isPrefixOf`) . idName
+
+-- | Retrieve the 'Ident' from a record identifier
+fromRecordExtId :: Ident -> Ident
+fromRecordExtId r
+  | p == recordExt = mkIdent r'
+  | otherwise      = r
+ where (p, r') = splitAt (length recordExt) (idName r)
+
+-- Record labels
+
+-- | Annotation for record label identifiers
+labelExt :: String
+labelExt = "_#Lab:"
+
+-- | Construct an 'Ident' for a record label
+labelExtId :: Ident -> Ident
+labelExtId l = mkIdent $ labelExt ++ idName l
+
+-- | Check whether an 'Ident' is an identifier for a record label
+isLabelExtId :: Ident -> Bool
+isLabelExtId = (labelExt `isPrefixOf`) . idName
+
+-- | Retrieve the 'Ident' from a record label identifier
+fromLabelExtId :: Ident -> Ident
+fromLabelExtId l
+  | p == labelExt = mkIdent l'
+  | otherwise     = l
+ where (p, l') = splitAt (length labelExt) (idName l)
+
+-- | Construct an 'Ident' for a record label
+mkLabelIdent :: String -> Ident
+mkLabelIdent c = renameIdent (mkIdent c) (-1)
+
+-- | Rename an 'Ident' for a record label
+renameLabel :: Ident -> Ident
+renameLabel l = renameIdent l (-1)
diff --git a/src/Curry/Base/LLParseComb.hs b/src/Curry/Base/LLParseComb.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Base/LLParseComb.hs
@@ -0,0 +1,380 @@
+{- |
+    Module      :  $Header$
+    Description :  Parser combinators
+    Copyright   :  (c) 1999-2004, Wolfgang Lux
+                       2016     , Jan Tikovsky
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    The parsing combinators implemented in this module are based on the
+    LL(1) parsing combinators developed by Swierstra and Duponcheel.
+    They have been adapted to using continuation passing style in order to
+    work with the lexing combinators described in the previous section.
+    In addition, the facilities for error correction are omitted
+    in this implementation.
+
+    The two functions 'applyParser' and 'prefixParser' use the specified
+    parser for parsing a string. When 'applyParser' is used, an error is
+    reported if the parser does not consume the whole string,
+    whereas 'prefixParser' discards the rest of the input string in this case.
+-}
+{-# LANGUAGE CPP #-}
+
+module Curry.Base.LLParseComb
+  ( -- * Data types
+    Parser
+
+    -- * Parser application
+  , fullParser, prefixParser
+
+    -- * Basic parsers
+  , position, spanPosition, succeed, failure, symbol
+
+    -- *  parser combinators
+  , (<?>), (<|>), (<|?>), (<*>), (<\>), (<\\>)
+  , (<$>), (<$->), (<*->), (<-*>), (<**>), (<??>), (<.>)
+  , opt, choice, flag, optional, option, many, many1, sepBy, sepBy1
+  , sepBySp, sepBy1Sp
+  , chainr, chainr1, chainl, chainl1, between, ops
+
+    -- * Layout combinators
+  , layoutOn, layoutOff, layoutEnd
+  ) where
+
+#if __GLASGOW_HASKELL__ < 710
+import Control.Applicative (Applicative, (<*>), (<$>), pure)
+#endif
+import Control.Monad
+import qualified Data.Map as Map
+import Data.Maybe
+import qualified Data.Set as Set
+
+import Curry.Base.LexComb
+import Curry.Base.Position
+import Curry.Base.Span (span2Pos, Span, startCol, setDistance)
+
+infixl 5 <\>, <\\>
+infixl 4 <$->, <*->, <-*>, <**>, <??>, <.>
+infixl 3 <|>, <|?>
+infixl 2 <?>, `opt`
+
+-- ---------------------------------------------------------------------------
+-- Parser types
+-- ---------------------------------------------------------------------------
+
+-- |Parsing function
+type ParseFun a s b  = (b -> SuccessP s a) -> FailP a -> SuccessP s a
+
+-- |CPS-Parser type
+data Parser a s b = Parser
+  -- Parsing function for empty word
+  (Maybe (ParseFun a s b))
+  -- Lookup table (continuations for 'Symbol's recognized by the parser)
+  (Map.Map s (Lexer s a -> ParseFun a s b))
+
+instance Symbol s => Functor (Parser a s) where
+  fmap f p = succeed f <*> p
+
+instance Symbol s => Applicative (Parser a s) where
+  pure = succeed
+
+  -- |Apply the result function of the first parser to the result of the
+  --  second parser.
+  Parser Nothing   ps1 <*> p2                  = Parser Nothing
+    (fmap (`seqPP` p2) ps1)
+  Parser (Just p1) ps1 <*> ~p2@(Parser e2 ps2) = Parser (fmap (seqEE p1) e2)
+    (Map.union (fmap (`seqPP` p2) ps1) (fmap (seqEP p1) ps2))
+
+instance Show s => Show (Parser a s b) where
+  showsPrec p (Parser e ps) = showParen (p >= 10) $
+    showString "Parser " . shows (isJust e) .
+    showChar ' ' . shows (Map.keysSet ps)
+
+-- ---------------------------------------------------------------------------
+-- Parser application
+-- ---------------------------------------------------------------------------
+
+-- |Apply a parser and lexer to a 'String', whereas the 'FilePath' is used
+-- to identify the origin of the 'String' in case of parsing errors.
+fullParser :: Symbol s => Parser a s a -> Lexer s a -> FilePath -> String
+           -> CYM a
+fullParser p lexer = parse (lexer (choose p lexer successP failP) failP)
+  where successP x pos s
+          | isEOF s   = returnP x
+          | otherwise = failP pos (unexpected s)
+
+-- |Apply a parser and lexer to parse the beginning of a 'String'.
+-- The 'FilePath' is used to identify the origin of the 'String' in case of
+-- parsing errors.
+prefixParser :: Symbol s => Parser a s a -> Lexer s a -> FilePath -> String
+             -> CYM a
+prefixParser p lexer = parse (lexer (choose p lexer discardP failP) failP)
+  where discardP x _ _ = returnP x
+
+-- |Choose the appropriate parsing function w.r.t. to the next 'Symbol'.
+choose :: Symbol s => Parser a s b -> Lexer s a -> ParseFun a s b
+choose (Parser e ps) lexer success failp pos s = case Map.lookup s ps of
+  Just p  -> p lexer success failp pos s
+  Nothing -> case e of
+    Just p  -> p success failp pos s
+    Nothing -> failp pos (unexpected s)
+
+-- |Fail on an unexpected 'Symbol'
+unexpected :: Symbol s => s -> String
+unexpected s
+  | isEOF s   = "Unexpected end-of-file"
+  | otherwise = "Unexpected token " ++ show s
+
+-- ---------------------------------------------------------------------------
+-- Basic parsers
+-- ---------------------------------------------------------------------------
+
+-- |Return the current position without consuming the input
+position :: Parser a s Position
+position = Parser (Just p) Map.empty
+  where p success _ sp = success (span2Pos sp) sp
+
+spanPosition :: Symbol s => Parser a s Span
+spanPosition = Parser (Just p) Map.empty
+  where p success _ sp s = success (setDistance sp (dist (startCol sp) s)) sp s
+
+-- |Always succeeding parser
+succeed :: b -> Parser a s b
+succeed x = Parser (Just p) Map.empty
+  where p success _ = success x
+
+-- |Always failing parser with a given message
+failure :: String -> Parser a s b
+failure msg = Parser (Just p) Map.empty
+  where p _ failp pos _ = failp pos msg
+
+-- |Create a parser accepting the given 'Symbol'
+symbol :: s -> Parser a s s
+symbol s = Parser Nothing (Map.singleton s p)
+  where p lexer success failp _ s' = lexer (success s') failp
+
+-- ---------------------------------------------------------------------------
+-- Parser combinators
+-- ---------------------------------------------------------------------------
+
+-- |Behave like the given parser, but use the given 'String' as the error
+-- message if the parser fails
+(<?>) :: Symbol s => Parser a s b -> String -> Parser a s b
+p <?> msg = p <|> failure msg
+
+-- |Deterministic choice between two parsers.
+-- The appropriate parser is chosen based on the next 'Symbol'
+(<|>) :: Symbol s => Parser a s b -> Parser a s b -> Parser a s b
+Parser e1 ps1 <|> Parser e2 ps2
+  | isJust e1 && isJust e2 = failure "Ambiguous parser for empty word"
+  | not (Set.null common)  = failure $ "Ambiguous parser for " ++ show common
+  | otherwise              = Parser (e1 `mplus` e2) (Map.union ps1 ps2)
+  where common = Map.keysSet ps1 `Set.intersection` Map.keysSet ps2
+
+-- |Non-deterministic choice between two parsers.
+--
+-- The other parsing combinators require that the grammar being parsed
+-- is LL(1). In some cases it may be difficult or even
+-- impossible to transform a grammar into LL(1) form. As a remedy, we
+-- include a non-deterministic version of the choice combinator in
+-- addition to the deterministic combinator adapted from the paper. For
+-- every symbol from the intersection of the parser's first sets, the
+-- combinator '(<|?>)' applies both parsing functions to the input
+-- stream and uses that one which processes the longer prefix of the
+-- input stream irrespective of whether it succeeds or fails. If both
+-- functions recognize the same prefix, we choose the one that succeeds
+-- and report an ambiguous parse error if both succeed.
+(<|?>) :: Symbol s => Parser a s b -> Parser a s b -> Parser a s b
+Parser e1 ps1 <|?> Parser e2 ps2
+  | isJust e1 && isJust e2 = failure "Ambiguous parser for empty word"
+  | otherwise              = Parser (e1 `mplus` e2) (Map.union ps1' ps2)
+  where
+  ps1' = Map.fromList [ (s, maybe p (try p) (Map.lookup s ps2))
+                      | (s, p) <- Map.toList ps1
+                      ]
+  try p1 p2 lexer success failp pos s =
+    closeP1 p2s `thenP` \p2s' ->
+    closeP1 p2f `thenP` \p2f' ->
+    parse' p1 (retry p2s') (retry p2f')
+    where p2s r1 = parse' p2       (select True   r1) (select False r1)
+          p2f r1 = parse' p2 (flip (select False) r1) (select False r1)
+          parse' p psucc pfail =
+            p lexer (successK psucc) (failK pfail) pos s
+          successK k x pos' s' = k (pos', success x pos' s')
+          failK k pos' msg = k (pos', failp pos' msg)
+          retry k (pos',p) = closeP0 p `thenP` curry k pos'
+  select suc (pos1, p1) (pos2, p2) = case pos1 `compare` pos2 of
+    GT -> p1
+    EQ | suc       -> failP pos1 $ "Ambiguous parse before " ++ showPosition (span2Pos pos1)
+       | otherwise -> p1
+    LT -> p2
+
+seqEE :: ParseFun a s (b -> c) -> ParseFun a s b -> ParseFun a s c
+seqEE p1 p2 success failp = p1 (\f -> p2 (success . f) failp) failp
+
+seqEP :: ParseFun a s (b -> c) -> (Lexer s a -> ParseFun a s b)
+      -> Lexer s a -> ParseFun a s c
+seqEP p1 p2 lexer success failp = p1 (\f -> p2 lexer (success . f) failp) failp
+
+seqPP :: Symbol s => (Lexer s a -> ParseFun a s (b -> c)) -> Parser a s b
+      -> Lexer s a -> ParseFun a s c
+seqPP p1 p2 lexer success failp =
+  p1 lexer (\f -> choose p2 lexer (success . f) failp) failp
+
+-- ---------------------------------------------------------------------------
+-- The combinators \verb|<\\>| and \verb|<\>| can be used to restrict
+-- the first set of a parser. This is useful for combining two parsers
+-- with an overlapping first set with the deterministic combinator <|>.
+-- ---------------------------------------------------------------------------
+
+-- |Restrict the first parser by the first 'Symbol's of the second
+(<\>) :: Symbol s => Parser a s b -> Parser a s c -> Parser a s b
+p <\> Parser _ ps = p <\\> Map.keys ps
+
+-- |Restrict a parser by a list of first 'Symbol's
+(<\\>) :: Symbol s => Parser a s b -> [s] -> Parser a s b
+Parser e ps <\\> xs = Parser e (foldr Map.delete ps xs)
+
+-- ---------------------------------------------------------------------------
+-- Other combinators
+-- Note that some of these combinators have not been published in the
+-- paper, but were taken from the implementation found on the web.
+-- ---------------------------------------------------------------------------
+
+-- |Replace the result of the parser with the first argument
+(<$->) :: Symbol s => a -> Parser b s c -> Parser b s a
+f <$-> p = f <$ p
+
+-- |Apply two parsers in sequence, but return only the result of the first
+-- parser
+(<*->) :: Symbol s => Parser a s b -> Parser a s c -> Parser a s b
+p <*-> q = const <$> p <*> q
+
+-- |Apply two parsers in sequence, but return only the result of the second
+-- parser
+(<-*>) :: Symbol s => Parser a s b -> Parser a s c -> Parser a s c
+p <-*> q = id <$ p <*> q
+
+-- |Apply the parsers in sequence and apply the result function of the second
+-- parse to the result of the first
+(<**>) :: Symbol s => Parser a s b -> Parser a s (b -> c) -> Parser a s c
+p <**> q = flip ($) <$> p <*> q
+
+-- |Same as (<**>), but only applies the function if the second parser
+-- succeeded.
+(<??>) :: Symbol s => Parser a s b -> Parser a s (b -> b) -> Parser a s b
+p <??> q = p <**> (q `opt` id)
+
+-- |Flipped function composition on parsers
+(<.>) :: Symbol s => Parser a s (b -> c) -> Parser a s (c -> d)
+      -> Parser a s (b -> d)
+p1 <.> p2 = p1 <**> ((.) <$> p2)
+
+-- |Try the first parser, but return the second argument if it didn't succeed
+opt :: Symbol s => Parser a s b -> b -> Parser a s b
+p `opt` x = p <|> succeed x
+
+-- |Choose the first succeeding parser from a non-empty list of parsers
+choice :: Symbol s => [Parser a s b] -> Parser a s b
+choice = foldr1 (<|>)
+
+-- |Try to apply a given parser and return a boolean value if the parser
+-- succeeded.
+flag :: Symbol s => Parser a s b -> Parser a s Bool
+flag p = True <$-> p `opt` False
+
+-- |Try to apply a parser but forget if it succeeded
+optional :: Symbol s => Parser a s b -> Parser a s ()
+optional p = void p `opt` ()
+
+-- |Try to apply a parser and return its result in a 'Maybe' type
+option :: Symbol s => Parser a s b -> Parser a s (Maybe b)
+option p = Just <$> p `opt` Nothing
+
+-- |Repeatedly apply a parser for 0 or more occurences
+many :: Symbol s => Parser a s b -> Parser a s [b]
+many p = many1 p `opt` []
+
+-- |Repeatedly apply a parser for 1 or more occurences
+many1 :: Symbol s => Parser a s b -> Parser a s [b]
+many1 p = (:) <$> p <*> many p
+
+-- |Parse a list with is separated by a seperator
+sepBy :: Symbol s => Parser a s b -> Parser a s c -> Parser a s [b]
+p `sepBy` q = p `sepBy1` q `opt` []
+
+-- |Parse a non-empty list with is separated by a seperator
+sepBy1 :: Symbol s => Parser a s b -> Parser a s c -> Parser a s [b]
+p `sepBy1` q = (:) <$> p <*> many (q <-*> p)
+
+-- |Parse a list with is separated by a seperator
+sepBySp :: Symbol s => Parser a s b -> Parser a s c -> Parser a s ([b], [Span])
+p `sepBySp` q = p `sepBy1Sp` q `opt` ([], [])
+
+sepBy1Sp :: Symbol s => Parser a s b -> Parser a s c -> Parser a s ([b], [Span])
+p `sepBy1Sp` q = comb <$> p <*> many ((,) <$> spanPosition <*-> q <*> p)
+  where comb x xs = let (ss, ys) = unzip xs
+                    in (x:ys,ss)
+
+-- |@chainr p op x@ parses zero or more occurrences of @p@, separated by @op@.
+-- Returns a value produced by a *right* associative application of all
+-- functions returned by op. If there are no occurrences of @p@, @x@ is
+-- returned.
+chainr :: Symbol s
+       => Parser a s b -> Parser a s (b -> b -> b) -> b -> Parser a s b
+chainr p op x = chainr1 p op `opt` x
+
+-- |Like 'chainr', but parses one or more occurrences of p.
+chainr1 :: Symbol s => Parser a s b -> Parser a s (b -> b -> b) -> Parser a s b
+chainr1 p op = r where r = p <**> (flip <$> op <*> r `opt` id)
+
+-- |@chainr p op x@ parses zero or more occurrences of @p@, separated by @op@.
+-- Returns a value produced by a *left* associative application of all
+-- functions returned by op. If there are no occurrences of @p@, @x@ is
+-- returned.
+chainl :: Symbol s
+       => Parser a s b -> Parser a s (b -> b -> b) -> b -> Parser a s b
+chainl p op x = chainl1 p op `opt` x
+
+-- |Like 'chainl', but parses one or more occurrences of p.
+chainl1 :: Symbol s => Parser a s b -> Parser a s (b -> b -> b) -> Parser a s b
+chainl1 p op = foldF <$> p <*> many (flip <$> op <*> p)
+  where foldF x []     = x
+        foldF x (f:fs) = foldF (f x) fs
+
+-- |Parse an expression between an opening and a closing part.
+between :: Symbol s => Parser a s b -> Parser a s c -> Parser a s b
+        -> Parser a s c
+between open p close = open <-*> p <*-> close
+
+-- |Parse one of the given operators
+ops :: Symbol s => [(s, b)] -> Parser a s b
+ops []              = failure "Curry.Base.LLParseComb.ops: empty list"
+ops [(s, x)]        = x <$-> symbol s
+ops ((s, x) : rest) = x <$-> symbol s <|> ops rest
+
+-- ---------------------------------------------------------------------------
+-- Layout combinators
+-- Note that the layout functions grab the next token (and its position).
+-- After modifying the layout context, the continuation is called with
+-- the same token and an undefined result.
+-- ---------------------------------------------------------------------------
+
+-- |Disable layout-awareness for the following
+layoutOff :: Symbol s => Parser a s b
+layoutOff = Parser (Just off) Map.empty
+  where off success _ pos = pushContext (-1) . success undefined pos
+
+-- |Add a new scope for layout
+layoutOn :: Symbol s => Parser a s b
+layoutOn = Parser (Just on) Map.empty
+  where on success _ pos = pushContext (column (span2Pos pos)) . success undefined pos
+
+-- |End the current layout scope (or re-enable layout-awareness if it is
+-- currently disabled
+layoutEnd :: Symbol s => Parser a s b
+layoutEnd = Parser (Just end) Map.empty
+  where end success _ pos = popContext . success undefined pos
diff --git a/src/Curry/Base/LexComb.hs b/src/Curry/Base/LexComb.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Base/LexComb.hs
@@ -0,0 +1,179 @@
+{- |
+    Module      :  $Header$
+    Description :  Lexer combinators
+    Copyright   :  (c) 1999 - 2004, Wolfgang Lux
+                       2012 - 2013, Björn Peemöller
+                       2016       , Jan Tikovsky
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module provides the basic types and combinators to implement the
+    lexers. The combinators use continuation passing code in a monadic style.
+
+    The first argument of the continuation function is the current span,
+    and the second is the string to be parsed. The third argument is a flag
+    which signals the lexer that it is lexing the beginning of a line and
+    therefore has to check for layout tokens. The fourth argument is a stack
+    of indentations that is used to handle nested layout groups.
+-}
+module Curry.Base.LexComb
+  ( -- * Types
+    Symbol (..), Indent, Context, P, CYM, SuccessP, FailP, Lexer
+
+    -- * Monadic functions
+  , parse, applyLexer, returnP, thenP, thenP_, failP, warnP
+  , liftP, closeP0, closeP1
+
+    -- * Combinators for layout handling
+  , pushContext, popContext
+
+    -- * Conversion of numbers
+  , convertSignedIntegral, convertSignedFloating
+  , convertIntegral, convertFloating
+  ) where
+
+import Data.Char        (digitToInt)
+
+import Curry.Base.Monad (CYM, failMessageAt, warnMessageAt)
+import Curry.Base.Span  ( Distance, Span (..), startCol, fstSpan
+                        , setDistance)
+
+
+infixl 1 `thenP`, `thenP_`
+
+-- |Type class for symbols
+class (Ord s, Show s) => Symbol s where
+  -- |Does the 'Symbol' represent the end of the input?
+  isEOF :: s -> Bool
+  -- |Compute the distance of a 'Symbol'
+  dist :: Int -> s -> Distance
+
+-- |Type for indentations, necessary for the layout rule
+type Indent = Int
+
+-- |Type of context for representing layout grouping
+type Context = [Indent]
+
+-- |Basic lexer function
+type P a = Span     -- ^ Current source code span
+        -> String   -- ^ 'String' to be parsed
+        -> Bool     -- ^ Flag whether the beginning of a line should be
+                    --   parsed, which requires layout checking
+        -> Context  -- ^ context as a stack of 'Indent's
+        -> CYM a
+
+-- |Apply a lexer on a 'String' to lex the content. The second parameter
+-- requires a 'FilePath' to use in the 'Span'
+parse :: P a -> FilePath -> String -> CYM a
+parse p fn s = p (fstSpan fn) s True []
+
+-- ---------------------------------------------------------------------------
+-- CPS lexer
+-- ---------------------------------------------------------------------------
+
+-- |success continuation
+type SuccessP s a = Span -> s -> P a
+
+-- |failure continuation
+type FailP a      = Span -> String -> P a
+
+-- |A CPS lexer
+type Lexer s a    = SuccessP s a -> FailP a -> P a
+
+-- |Apply a lexer
+applyLexer :: Symbol s => Lexer s [(Span, s)] -> P [(Span, s)]
+applyLexer lexer = lexer successP failP
+  where successP sp t | isEOF t   = returnP [(sp', t)]
+                      | otherwise = ((sp', t) :) `liftP` lexer successP failP
+          where sp' = setDistance sp (dist (startCol sp) t)
+
+-- ---------------------------------------------------------------------------
+-- Monadic functions for the lexer.
+-- ---------------------------------------------------------------------------
+
+-- |Lift a value into the lexer type
+returnP :: a -> P a
+returnP x _ _ _ _ = return x
+
+-- |Apply the first lexer and then apply the second one, based on the result
+-- of the first lexer.
+thenP :: P a -> (a -> P b) -> P b
+thenP lexer k sp s bol ctxt
+  = lexer sp s bol ctxt >>= \x -> k x sp s bol ctxt
+
+-- |Apply the first lexer and then apply the second one, ignoring the first
+-- result.
+thenP_ :: P a -> P b -> P b
+p1 `thenP_` p2 = p1 `thenP` const p2
+
+-- |Fail to lex on a 'Span', given an error message
+failP :: Span -> String -> P a
+failP sp msg _ _ _ _ = failMessageAt sp msg
+
+-- |Warn on a 'Span', given a warning message
+warnP :: Span -> String -> P a -> P a
+warnP warnSpan msg lexer sp s bol ctxt
+  = warnMessageAt warnSpan msg >> lexer sp s bol ctxt
+
+-- |Apply a pure function to the lexers result
+liftP :: (a -> b) -> P a -> P b
+liftP f p = p `thenP` returnP . f
+
+-- |Lift a lexer into the 'P' monad, returning the lexer when evaluated.
+closeP0 :: P a -> P (P a)
+closeP0 lexer sp s bol ctxt = return (\_ _ _ _ -> lexer sp s bol ctxt)
+
+-- |Lift a lexer-generating function into the 'P' monad, returning the
+--  function when evaluated.
+closeP1 :: (a -> P b) -> P (a -> P b)
+closeP1 f sp s bol ctxt = return (\x _ _ _ _ -> f x sp s bol ctxt)
+
+-- ---------------------------------------------------------------------------
+-- Combinators for handling layout.
+-- ---------------------------------------------------------------------------
+
+-- |Push an 'Indent' to the context, increasing the levels of indentation
+pushContext :: Indent -> P a -> P a
+pushContext col cont sp s bol ctxt = cont sp s bol (col : ctxt)
+
+-- |Pop an 'Indent' from the context, decreasing the levels of indentation
+popContext :: P a -> P a
+popContext cont sp s bol (_ : ctxt) = cont sp s bol ctxt
+popContext _    sp _ _   []         = failMessageAt sp $
+  "Parse error: popping layout from empty context stack. " ++
+  "Perhaps you have inserted too many '}'?"
+
+-- ---------------------------------------------------------------------------
+-- Conversions from 'String's into numbers.
+-- ---------------------------------------------------------------------------
+
+-- |Convert a String into a signed intergral using a given base
+convertSignedIntegral :: Num a => a -> String -> a
+convertSignedIntegral b ('+':s) =   convertIntegral b s
+convertSignedIntegral b ('-':s) = - convertIntegral b s
+convertSignedIntegral b s       =   convertIntegral b s
+
+-- |Convert a String into an unsigned intergral using a given base
+convertIntegral :: Num a => a -> String -> a
+convertIntegral b = foldl op 0
+  where m `op` n = b * m + fromIntegral (digitToInt n)
+
+-- |Convert a mantissa, a fraction part and an exponent into a signed
+-- floating value
+convertSignedFloating :: Fractional a => String -> String -> Int -> a
+convertSignedFloating ('+':m) f e =   convertFloating m f e
+convertSignedFloating ('-':m) f e = - convertFloating m f e
+convertSignedFloating m       f e =   convertFloating m f e
+
+-- |Convert a mantissa, a fraction part and an exponent into an unsigned
+-- floating value
+convertFloating :: Fractional a => String -> String -> Int -> a
+convertFloating m f e
+  | e' == 0   = m'
+  | e' >  0   = m' * 10 ^ e'
+  | otherwise = m' / 10 ^ (- e')
+  where m' = convertIntegral 10 (m ++ f)
+        e' = e - length f
diff --git a/src/Curry/Base/Message.hs b/src/Curry/Base/Message.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Base/Message.hs
@@ -0,0 +1,114 @@
+{- |
+    Module      :  $Header$
+    Description :  Monads for message handling
+    Copyright   :  2009        Holger Siegel
+                   2012 - 2015 Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    The type message represents a compiler message with an optional source
+    code position.
+-}
+{-# LANGUAGE CPP #-}
+module Curry.Base.Message
+  ( Message (..), message, posMessage, spanMessage, spanInfoMessage
+  , showWarning, showError
+  , ppMessage, ppWarning, ppError, ppMessages, ppMessagesWithPreviews
+  ) where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+import Curry.Base.Position
+import Curry.Base.Pretty
+import Curry.Base.Span
+import Curry.Base.SpanInfo
+
+-- ---------------------------------------------------------------------------
+-- Message
+-- ---------------------------------------------------------------------------
+
+-- |Compiler message
+data Message = Message
+  { msgSpanInfo :: SpanInfo -- ^ span in the source code
+  , msgTxt      :: Doc      -- ^ the message itself
+  }
+
+instance Eq Message where
+  Message s1 t1 == Message s2 t2 = (s1, show t1) == (s2, show t2)
+
+instance Ord Message where
+  Message s1 t1 `compare` Message s2 t2 = compare (s1, show t1) (s2, show t2)
+
+instance Show Message where
+  showsPrec _ = shows . ppMessage
+
+instance HasPosition Message where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasSpanInfo Message where
+  getSpanInfo       = msgSpanInfo
+  setSpanInfo spi m = m { msgSpanInfo = spi }
+
+instance Pretty Message where
+  pPrint = ppMessage
+
+-- |Construct a 'Message' without a 'SpanInfo'
+message :: Doc -> Message
+message = Message NoSpanInfo
+
+-- |Construct a message from a position.
+posMessage :: HasPosition p => p -> Doc -> Message
+posMessage p = spanMessage $ pos2Span $ getPosition p
+
+-- |Construct a message from a span and a text
+spanMessage :: Span -> Doc -> Message
+spanMessage s = spanInfoMessage $ fromSrcSpan s
+
+-- |Construct a message from an entity with a 'SpanInfo' and a text
+spanInfoMessage :: HasSpanInfo s => s -> Doc -> Message
+spanInfoMessage s msg = Message (getSpanInfo s) msg
+
+-- |Show a 'Message' as a warning
+showWarning :: Message -> String
+showWarning = show . ppWarning
+
+-- |Show a 'Message' as an error
+showError :: Message -> String
+showError = show . ppError
+
+-- |Pretty print a 'Message'
+ppMessage :: Message -> Doc
+ppMessage = ppAs ""
+
+-- |Pretty print a 'Message' as a warning
+ppWarning :: Message -> Doc
+ppWarning = ppAs "Warning"
+
+-- |Pretty print a 'Message' as an error
+ppError :: Message -> Doc
+ppError = ppAs "Error"
+
+-- |Pretty print a 'Message' with a given key
+ppAs :: String -> Message -> Doc
+ppAs key (Message mbSpanInfo txt) = (hsep $ filter (not . isEmpty) [spanPP, keyPP]) $$ nest 4 txt
+  where
+  spanPP = ppCompactSpan $ getSrcSpan $ mbSpanInfo
+  keyPP = if null key then empty else text key <> colon
+
+-- |Pretty print a list of 'Message's by vertical concatenation
+ppMessages :: (Message -> Doc) -> [Message] -> Doc
+ppMessages ppFun = foldr (\m ms -> text "" $+$ m $+$ ms) empty . map ppFun
+
+-- |Pretty print a list of 'Message's with previews by vertical concatenation
+ppMessagesWithPreviews :: (Message -> Doc) -> [Message] -> IO Doc
+ppMessagesWithPreviews ppFun = (fmap $ foldr (\m ms -> text "" $+$ m $+$ ms) empty) . mapM ppFunWithPreview
+  where ppFunWithPreview m = do preview <- case m of
+                                  Message (SpanInfo sp _) _ -> ppSpanPreview sp
+                                  _                         -> return empty
+                                return $ ppFun m $+$ preview
diff --git a/src/Curry/Base/Monad.hs b/src/Curry/Base/Monad.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Base/Monad.hs
@@ -0,0 +1,95 @@
+{- |
+    Module      :  $Header$
+    Description :  Monads for message handling
+    Copyright   :  2014 - 2016 Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+
+    The monads defined in this module provide a common way to stop execution
+    when some errors occur. They are used to integrate different compiler passes
+    smoothly.
+-}
+
+module Curry.Base.Monad
+  ( CYIO, CYM, CYT, failMessages, failMessageAt, warnMessages, warnMessageAt
+  , ok, runCYIO, runCYM, runCYIOIgnWarn, runCYMIgnWarn, liftCYM, silent
+  ) where
+
+import Control.Monad.Identity
+import Control.Monad.Trans.Except (ExceptT, mapExceptT, runExceptT, throwE)
+import Control.Monad.Writer
+
+import Curry.Base.Message  (Message, spanMessage)
+import Curry.Base.Span (Span)
+import Curry.Base.Pretty   (text)
+
+-- |Curry compiler monad transformer
+type CYT m a = WriterT [Message] (ExceptT [Message] m) a
+
+-- |Curry compiler monad based on the `IO` monad
+type CYIO a = CYT IO a
+
+-- |Pure Curry compiler monad
+type CYM a = CYT Identity a
+
+-- |Run an `IO`-based Curry compiler action in the `IO` monad,
+-- yielding either a list of errors or a result in case of success
+-- consisting of the actual result and a (possibly empty) list of warnings
+runCYIO :: CYIO a -> IO (Either [Message] (a, [Message]))
+runCYIO = runExceptT . runWriterT
+
+-- |Run an pure Curry compiler action,
+-- yielding either a list of errors or a result in case of success
+-- consisting of the actual result and a (possibly empty) list of warnings
+runCYM :: CYM a -> Either [Message] (a, [Message])
+runCYM = runIdentity . runExceptT . runWriterT
+
+-- |Run an `IO`-based Curry compiler action in the `IO` monad,
+-- yielding either a list of errors or a result in case of success.
+runCYIOIgnWarn :: CYIO a -> IO (Either [Message] a)
+runCYIOIgnWarn = runExceptT . (liftM fst) . runWriterT
+
+-- |Run an pure Curry compiler action,
+-- yielding either a list of errors or a result in case of success.
+runCYMIgnWarn :: CYM a -> Either [Message] a
+runCYMIgnWarn = runIdentity . runExceptT . (liftM fst) . runWriterT
+
+-- |Failing action with a message describing the cause of failure.
+failMessage :: Monad m => Message -> CYT m a
+failMessage msg = failMessages [msg]
+
+-- |Failing action with a list of messages describing the cause(s) of failure.
+failMessages :: Monad m => [Message] -> CYT m a
+failMessages = lift . throwE
+
+-- |Failing action with a source code span and a `String` indicating
+-- the cause of failure.
+failMessageAt :: Monad m => Span -> String -> CYT m a
+failMessageAt sp s = failMessage $ spanMessage sp $ text s
+
+-- |Warning with a message describing the cause of the warning.
+warnMessage :: Monad m => Message -> CYT m ()
+warnMessage msg = warnMessages [msg]
+
+-- |Warning with a list of messages describing the cause(s) of the warnings.
+warnMessages :: Monad m => [Message] -> CYT m ()
+warnMessages msgs = tell msgs
+
+-- |Execute a monadic action, but ignore any warnings it issues
+silent :: Monad m => CYT m a -> CYT m a
+silent act = censor (const []) act
+
+-- |Warning with a source code position and a `String` indicating
+-- the cause of the warning.
+warnMessageAt :: Monad m => Span -> String -> CYT m ()
+warnMessageAt sp s = warnMessage $ spanMessage sp $ text s
+
+-- |Lift a value into the `CYT m` monad, same as `return`.
+ok :: Monad m => a -> CYT m a
+ok = return
+
+-- |Lift a pure action into an action based on another monad.
+liftCYM :: Monad m => CYM a -> CYT m a
+liftCYM = mapWriterT (mapExceptT (return . runIdentity))
diff --git a/src/Curry/Base/Position.hs b/src/Curry/Base/Position.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Base/Position.hs
@@ -0,0 +1,128 @@
+{- |
+    Module      :  $Header$
+    Description :  Positions in a source file
+    Copyright   :  (c) Wolfgang Lux
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module implements a data type for positions in a source file and
+    respective functions to operate on them. A source file position consists
+    of a filename, a line number, and a column number. A tab stop is assumed
+    at every eighth column.
+-}
+module Curry.Base.Position
+  ( -- * Source code position
+    HasPosition (..), Position (..), (@>)
+  , showPosition, ppPosition, ppCompactLine, ppLine, showLine
+  , first, next, incr, tab, tabWidth, nl
+  ) where
+
+import Prelude hiding ((<>))
+import Data.Binary
+import Control.Monad
+import System.FilePath
+
+import Curry.Base.Pretty
+
+-- |Type class for entities which have a source code 'Position'
+class HasPosition a where
+  -- |Get the 'Position'
+  getPosition :: a -> Position
+  getPosition _ = NoPos
+
+  -- |Set the 'Position'
+  setPosition :: Position -> a -> a
+  setPosition _ = id
+
+-- | @x \@> y@ returns @x@ with the position obtained from @y@
+(@>) :: (HasPosition a, HasPosition b) => a -> b -> a
+x @> y = setPosition (getPosition y) x
+
+-- |Source code positions
+data Position
+  -- |Normal source code position
+  = Position
+    { file   :: FilePath -- ^ 'FilePath' of the source file
+    , line   :: Int      -- ^ line number, beginning at 1
+    , column :: Int      -- ^ column number, beginning at 1
+    }
+  -- |no position
+  | NoPos
+    deriving (Eq, Ord, Read, Show)
+
+instance HasPosition Position where
+  getPosition = id
+  setPosition = const
+
+instance Pretty Position where
+  pPrint = ppPosition
+
+instance Binary Position where
+  put (Position _ l c) = putWord8 0 >> put l >> put c
+  put NoPos            = putWord8 1
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 (Position "") get get
+      1 -> return NoPos
+      _ -> fail "Not a valid encoding for a Position"
+
+-- |Show a 'Position' as a 'String'
+showPosition :: Position -> String
+showPosition = show . ppPosition
+
+-- |Pretty print a 'Position'
+ppPosition :: Position -> Doc
+ppPosition p@(Position f _ _)
+  | null f    = lineCol
+  | otherwise = text (normalise f) <> comma <+> lineCol
+  where lineCol = ppLine p
+ppPosition _  = empty
+
+-- |Pretty print a compact representation of a 'Position''s line/column
+ppCompactLine :: Position -> Doc
+ppCompactLine (Position _ l c) = text (show l)
+                                 <> if c == 0 then empty else (colon <> text (show c))
+ppCompactLine _ = empty
+
+-- |Pretty print the line and column of a 'Position'
+ppLine :: Position -> Doc
+ppLine (Position _ l c) = text "line" <+> text (show l)
+                          <> if c == 0 then empty else text ('.' : show c)
+ppLine _                = empty
+
+-- |Show the line and column of a 'Position'
+showLine :: Position -> String
+showLine = show . ppLine
+
+-- | Absolute first position of a file
+first :: FilePath -> Position
+first fn = Position fn 1 1
+
+-- |Next position to the right
+next :: Position -> Position
+next = flip incr 1
+
+-- |Increment a position by a number of columns
+incr :: Position -> Int -> Position
+incr p@Position { column = c } n = p { column = c + n }
+incr p _ = p
+
+-- |Number of spaces for a tabulator
+tabWidth :: Int
+tabWidth = 8
+
+-- |First position after the next tabulator
+tab :: Position -> Position
+tab p@Position { column = c }
+  = p { column = c + tabWidth - (c - 1) `mod` tabWidth }
+tab p = p
+
+-- |First position of the next line
+nl :: Position -> Position
+nl p@Position { line = l } = p { line = l + 1, column = 1 }
+nl p = p
diff --git a/src/Curry/Base/Pretty.hs b/src/Curry/Base/Pretty.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Base/Pretty.hs
@@ -0,0 +1,209 @@
+{- |
+    Module      :  $Header$
+    Description :  Pretty printing
+    Copyright   :  (c) 2013 - 2014 Björn Peemöller
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  stable
+    Portability :  portable
+
+    This module re-exports the well known pretty printing combinators
+    from Hughes and Peyton-Jones. In addition, it re-exports the type class
+    'Pretty' for pretty printing arbitrary types.
+-}
+{-# LANGUAGE CPP #-}
+module Curry.Base.Pretty
+  ( module Curry.Base.Pretty
+  , module Text.PrettyPrint
+  ) where
+
+import Prelude hiding ((<>))
+
+import Text.PrettyPrint
+
+-- | Pretty printing class.
+-- The precedence level is used in a similar way as in the 'Show' class.
+-- Minimal complete definition is either 'pPrintPrec' or 'pPrint'.
+class Pretty a where
+  -- | Pretty-print something in isolation.
+  pPrint :: a -> Doc
+  pPrint = pPrintPrec 0
+
+  -- | Pretty-print something in a precedence context.
+  pPrintPrec :: Int -> a -> Doc
+  pPrintPrec _ = pPrint
+
+  -- |Pretty-print a list.
+  pPrintList :: [a] -> Doc
+  pPrintList = brackets . fsep . punctuate comma . map (pPrintPrec 0)
+
+#if __GLASGOW_HASKELL__ >= 707
+  {-# MINIMAL pPrintPrec | pPrint #-}
+#endif
+
+-- | Pretty print a value to a 'String'.
+prettyShow :: Pretty a => a -> String
+prettyShow = render . pPrint
+
+-- | Parenthesize an value if the boolean is true.
+parenIf :: Bool -> Doc -> Doc
+parenIf False = id
+parenIf True  = parens
+
+-- | Pretty print a value if the boolean is true
+ppIf :: Bool -> Doc -> Doc
+ppIf True  = id
+ppIf False = const empty
+
+-- | Pretty print a 'Maybe' value for the 'Just' constructor only
+maybePP :: (a -> Doc) -> Maybe a -> Doc
+maybePP = maybe empty
+
+-- | A blank line.
+blankLine :: Doc
+blankLine = text ""
+
+-- |Above with a blank line in between. If one of the documents is empty,
+-- then the other document is returned.
+($++$) :: Doc -> Doc -> Doc
+d1 $++$ d2 | isEmpty d1 = d2
+           | isEmpty d2 = d1
+           | otherwise  = d1 $+$ blankLine $+$ d2
+
+-- |Above with overlapping, but with a space in between. If one of the
+-- documents is empty, then the other document is returned.
+($-$) :: Doc -> Doc -> Doc
+d1 $-$ d2 | isEmpty d1 = d2
+          | isEmpty d2 = d1
+          | otherwise  = d1 $$ space $$ d2
+
+-- | Seperate a list of 'Doc's by a 'blankLine'.
+sepByBlankLine :: [Doc] -> Doc
+sepByBlankLine = foldr ($++$) empty
+
+-- |A '.' character.
+dot :: Doc
+dot = char '.'
+
+-- |Precedence of function application
+appPrec :: Int
+appPrec = 10
+
+-- |A left arrow @<-@.
+larrow :: Doc
+larrow = text "<-"
+
+-- |A right arrow @->@.
+rarrow :: Doc
+rarrow = text "->"
+
+-- |A double arrow @=>@.
+darrow :: Doc
+darrow = text "=>"
+
+-- |A back quote @`@.
+backQuote :: Doc
+backQuote = char '`'
+
+-- |A backslash @\@.
+backsl :: Doc
+backsl = char '\\'
+
+-- |A vertical bar @|@.
+vbar :: Doc
+vbar = char '|'
+
+-- |Set a document in backquotes.
+bquotes :: Doc -> Doc
+bquotes doc = backQuote <> doc <> backQuote
+
+-- |Set a document in backquotes if the condition is @True@.
+bquotesIf :: Bool -> Doc -> Doc
+bquotesIf b doc = if b then bquotes doc else doc
+
+-- |Seperate a list of documents by commas
+list :: [Doc] -> Doc
+list = fsep . punctuate comma . filter (not . isEmpty)
+
+-- | Instance for 'Int'
+instance Pretty Int      where pPrint = int
+
+-- | Instance for 'Integer'
+instance Pretty Integer  where pPrint = integer
+
+-- | Instance for 'Float'
+instance Pretty Float    where pPrint = float
+
+-- | Instance for 'Double'
+instance Pretty Double   where pPrint = double
+
+-- | Instance for '()'
+instance Pretty ()       where pPrint _ = text "()"
+
+-- | Instance for 'Bool'
+instance Pretty Bool     where pPrint = text . show
+
+-- | Instance for 'Ordering'
+instance Pretty Ordering where pPrint = text . show
+
+-- | Instance for 'Char'
+instance Pretty Char where
+  pPrint     = char
+  pPrintList = text . show
+
+-- | Instance for 'Maybe'
+instance (Pretty a) => Pretty (Maybe a) where
+  pPrintPrec _ Nothing  = text "Nothing"
+  pPrintPrec p (Just x) = parenIf (p > appPrec)
+                        $ text "Just" <+> pPrintPrec (appPrec + 1) x
+
+-- | Instance for 'Either'
+instance (Pretty a, Pretty b) => Pretty (Either a b) where
+  pPrintPrec p (Left  x) = parenIf (p > appPrec)
+                         $ text "Left" <+> pPrintPrec (appPrec + 1) x
+  pPrintPrec p (Right x) = parenIf (p > appPrec)
+                         $ text "Right" <+> pPrintPrec (appPrec + 1) x
+
+-- | Instance for '[]'
+instance (Pretty a) => Pretty [a] where
+  pPrintPrec _ = pPrintList
+
+-- | Instance for '(,)'
+instance (Pretty a, Pretty b) => Pretty (a, b) where
+  pPrintPrec _ (a, b) = parens $ fsep $ punctuate comma [pPrint a, pPrint b]
+
+-- | Instance for '(,,)'
+instance (Pretty a, Pretty b, Pretty c) => Pretty (a, b, c) where
+  pPrintPrec _ (a, b, c) = parens $ fsep $ punctuate comma
+    [pPrint a, pPrint b, pPrint c]
+
+-- | Instance for '(,,,)'
+instance (Pretty a, Pretty b, Pretty c, Pretty d) => Pretty (a, b, c, d) where
+  pPrintPrec _ (a, b, c, d) = parens $ fsep $ punctuate comma
+    [pPrint a, pPrint b, pPrint c, pPrint d]
+
+-- | Instance for '(,,,,)'
+instance (Pretty a, Pretty b, Pretty c, Pretty d, Pretty e)
+  => Pretty (a, b, c, d, e) where
+  pPrintPrec _ (a, b, c, d, e) = parens $ fsep $ punctuate comma
+    [pPrint a, pPrint b, pPrint c, pPrint d, pPrint e]
+
+-- | Instance for '(,,,,,)'
+instance (Pretty a, Pretty b, Pretty c, Pretty d, Pretty e, Pretty f)
+  => Pretty (a, b, c, d, e, f) where
+  pPrintPrec _ (a, b, c, d, e, f) = parens $ fsep $ punctuate comma
+    [pPrint a, pPrint b, pPrint c, pPrint d, pPrint e, pPrint f]
+
+-- | Instance for '(,,,,,,)'
+instance (Pretty a, Pretty b, Pretty c, Pretty d, Pretty e, Pretty f, Pretty g)
+  => Pretty (a, b, c, d, e, f, g) where
+  pPrintPrec _ (a, b, c, d, e, f, g) = parens $ fsep $ punctuate comma
+    [pPrint a, pPrint b, pPrint c, pPrint d, pPrint e, pPrint f, pPrint g]
+
+-- | Instance for '(,,,,,,,)'
+instance (Pretty a, Pretty b, Pretty c, Pretty d, Pretty e, Pretty f, Pretty g, Pretty h)
+  => Pretty (a, b, c, d, e, f, g, h) where
+  pPrintPrec _ (a, b, c, d, e, f, g, h) = parens $ fsep $ punctuate comma
+    [pPrint a, pPrint b, pPrint c, pPrint d, pPrint e, pPrint f, pPrint g, pPrint h]
diff --git a/src/Curry/Base/Span.hs b/src/Curry/Base/Span.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Base/Span.hs
@@ -0,0 +1,180 @@
+{- |
+    Module      :  $Header$
+    Description :  Spans in a source file
+    Copyright   :  (c) 2016 Jan Tikovsky
+                       2016 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  jrt@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module implements a data type for span information in a source file and
+    respective functions to operate on them. A source file span consists
+    of a filename, a start position and an end position.
+
+    In addition, the type 'SrcRef' identifies the path to an expression in
+    the abstract syntax tree by argument positions, which is used for
+    debugging purposes.
+-}
+module Curry.Base.Span where
+
+import Prelude hiding ((<>))
+
+import Data.Binary
+import Data.List (transpose)
+import Control.Monad
+import System.FilePath
+
+import Curry.Base.Position hiding (file)
+import Curry.Base.Pretty
+
+data Span
+  -- |Normal source code span
+  = Span
+    { file     :: FilePath -- ^ 'FilePath' of the source file
+    , start    :: Position -- ^ start position
+    , end      :: Position -- ^ end position
+    }
+  -- |no span
+  | NoSpan
+    deriving (Eq, Ord, Read, Show)
+
+instance Pretty Span where
+  pPrint = ppSpan
+
+instance HasPosition Span where
+  setPosition p NoSpan       = Span "" p NoPos
+  setPosition p (Span f _ e) = Span f p e
+
+  getPosition NoSpan       = NoPos
+  getPosition (Span _ p _) = p
+
+instance Binary Span where
+  put (Span _ s e) = putWord8 0 >> put s >> put e
+  put NoSpan       = putWord8 1
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 (Span "") get get
+      1 -> return NoSpan
+      _ -> fail "Not a valid encoding for a Span"
+
+-- |Show a 'Span' as a 'String'
+showSpan :: Span -> String
+showSpan = show . ppSpan
+
+-- |Pretty print a 'Span'
+ppSpan :: Span -> Doc
+ppSpan s@(Span f _ _)
+  | null f    = startEnd
+  | otherwise = text (normalise f) <> comma <+> startEnd
+  where startEnd = ppPositions s
+ppSpan _ = empty
+
+-- |Pretty print a span with it's file path and position compactly.
+ppCompactSpan :: Span -> Doc
+ppCompactSpan s@(Span f _ _)
+  | null f    = ppCompactPositions s
+  | otherwise = text (normalise f) <> colon <> ppCompactPositions s
+ppCompactSpan _ = empty
+
+-- |Pretty print a source preview of a span
+ppSpanPreview :: Span -> IO Doc
+ppSpanPreview (Span f (Position _ sl sc) (Position _ el ec))
+  | null f    = return empty
+  | otherwise = do
+      fileContents <- readFile f
+
+      let lns = lines fileContents
+          lnContent | sl <= 0 || sl > length lns = ""
+                    | otherwise = lns !! (sl - 1)
+          lnNum = text <$> lPadStr lnNumWidth <$> (vPad ++ [show sl] ++ vPad)
+          ec' = if isMultiline then length lnContent else ec
+          gutter = text <$> replicate (1 + 2 * vPadCount) "|"
+          highlight = replicate (sc - 1) ' ' ++ replicate (1 + ec' - sc) '^' ++ if isMultiline then "..." else ""
+          previews = text <$> (vPad ++ [lnContent, highlight] ++ replicate (vPadCount - 1) "")
+      
+      return $ vcat $ map hsep $ transpose [lnNum, gutter, previews]
+  where vPadCount = 1 -- Number of padding lines at the top and bottom
+        isMultiline = el - sl > 0
+        numWidth = length . show
+        lnNumWidth = 1 + numWidth el
+        vPad = replicate vPadCount ""
+        lPadStr n s = replicate (n - length s) ' ' ++ s
+ppSpanPreview _ = return empty
+
+-- |Pretty print the positions compactly.
+ppCompactPositions :: Span -> Doc
+ppCompactPositions (Span _ s e) | s == e    = ppCompactLine s
+                                | otherwise = ppCompactLine s <> text "-" <> ppCompactLine e
+ppCompactPositions _            = empty
+
+-- |Pretty print the start and end position of a 'Span'
+ppPositions :: Span -> Doc
+ppPositions (Span _ s e) =  text "startPos:" <+> ppLine s <> comma
+                        <+> text "endPos:"   <+> ppLine e
+ppPositions _            = empty
+
+fstSpan :: FilePath -> Span
+fstSpan fn = Span fn (first fn) (first fn)
+
+-- |Compute the column of the start position of a 'Span'
+startCol :: Span -> Int
+startCol (Span _ p _) = column p
+startCol _            = 0
+
+nextSpan :: Span -> Span
+nextSpan sp = incrSpan sp 1
+
+incrSpan :: Span -> Int -> Span
+incrSpan (Span fn s e) n = Span fn (incr s n) (incr e n)
+incrSpan sp            _ = sp
+
+-- TODO: Rename to tab and nl as soon as positions are completely replaced by spans
+
+-- |Convert a position to a single character span.
+pos2Span :: Position -> Span
+pos2Span p@(Position f _ _) = Span f p p
+pos2Span _                  = NoSpan
+
+-- |Convert a span to a (start) position
+-- TODO: This function should be removed as soon as positions are completely replaced by spans
+-- in the frontend
+span2Pos :: Span -> Position
+span2Pos (Span _ p _) = p
+span2Pos NoSpan       = NoPos
+
+combineSpans :: Span -> Span -> Span
+combineSpans sp1 sp2 = Span f s e
+  where s = start sp1
+        e = end sp2
+        f = file sp1
+
+-- |First position after the next tabulator
+tabSpan :: Span -> Span
+tabSpan (Span fn s e) = Span fn (tab s) (tab e)
+tabSpan sp            = sp
+
+-- |First position of the next line
+nlSpan :: Span -> Span
+nlSpan (Span fn s e) = Span fn (nl s) (nl e)
+nlSpan sp            = sp
+
+addSpan :: Span -> (a, [Span]) -> (a, [Span])
+addSpan sp (a, ss) = (a, sp:ss)
+
+-- |Distance of a span, i.e. the line and column distance between start
+-- and end position
+type Distance = (Int, Int)
+
+-- |Set the distance of a span, i.e. update its end position
+setDistance :: Span -> Distance -> Span
+setDistance (Span fn p _) d = Span fn p (p `moveBy` d)
+setDistance s             _ = s
+
+-- |Move position by given distance
+moveBy :: Position -> Distance -> Position
+moveBy (Position fn l c) (ld, cd) = Position fn (l + ld) (c + cd)
+moveBy p                 _        = p
diff --git a/src/Curry/Base/SpanInfo.hs b/src/Curry/Base/SpanInfo.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Base/SpanInfo.hs
@@ -0,0 +1,139 @@
+{- |
+    Module      :  $Header$
+    Description :  SpansInfo for entities
+    Copyright   :  (c) 2017 Kai-Oliver Prott
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module implements a data type for span information for entities from a
+    source file and function to operate on them. A span info consists of the
+    span of the entity and a list of sub-spans whith additional information
+    about location of keywords, e.g.
+-}
+module Curry.Base.SpanInfo
+  ( SpanInfo(..), spanInfo, LayoutInfo(..), HasSpanInfo(..)
+  , fromSrcSpan, fromSrcSpanBoth, getSrcSpan, setSrcSpan, spanInfoLike
+  , fromSrcInfoPoints, getSrcInfoPoints, setSrcInfoPoints
+  , getStartPosition, getSrcSpanEnd, setStartPosition, setEndPosition
+  , spanInfo2Pos
+  ) where
+
+import Data.Binary
+import Control.Monad
+
+import Curry.Base.Position
+import Curry.Base.Span
+
+data SpanInfo = SpanInfo
+    { srcSpan        :: Span
+    , srcInfoPoints  :: [Span]
+    }
+    | NoSpanInfo
+  deriving (Eq, Ord, Read, Show)
+
+spanInfo :: Span -> [Span] -> SpanInfo
+spanInfo sp sps = SpanInfo sp sps
+
+data LayoutInfo = ExplicitLayout [Span]
+                | WhitespaceLayout
+  deriving (Eq, Read, Show)
+
+class HasPosition a => HasSpanInfo a where
+
+  getSpanInfo :: a -> SpanInfo
+
+  setSpanInfo :: SpanInfo -> a -> a
+
+  updateEndPos :: a -> a
+  updateEndPos = id
+
+  getLayoutInfo :: a -> LayoutInfo
+  getLayoutInfo = const WhitespaceLayout
+
+instance HasSpanInfo SpanInfo where
+  getSpanInfo = id
+  setSpanInfo = const
+
+instance HasPosition SpanInfo where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance Binary SpanInfo where
+  put (SpanInfo sp ss) = putWord8 0 >> put sp >> put ss
+  put NoSpanInfo       = putWord8 1
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 SpanInfo get get
+      1 -> return NoSpanInfo
+      _ -> fail "Not a valid encoding for a SpanInfo"
+
+instance Binary LayoutInfo where
+  put (ExplicitLayout ss) = putWord8 0 >> put ss
+  put WhitespaceLayout = putWord8 1
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> fmap ExplicitLayout get
+      1 -> return WhitespaceLayout
+      _ -> fail "Not a valid encoding for a LayoutInfo"
+
+fromSrcSpan :: Span -> SpanInfo
+fromSrcSpan sp = SpanInfo sp []
+
+fromSrcSpanBoth :: Span -> SpanInfo
+fromSrcSpanBoth sp = SpanInfo sp [sp]
+
+getSrcSpan :: HasSpanInfo a => a -> Span
+getSrcSpan a = case getSpanInfo a of
+  NoSpanInfo   -> NoSpan
+  SpanInfo s _ -> s
+
+setSrcSpan :: HasSpanInfo a => Span -> a -> a
+setSrcSpan s a = case getSpanInfo a of
+  NoSpanInfo     -> setSpanInfo (SpanInfo s [] ) a
+  SpanInfo _ inf -> setSpanInfo (SpanInfo s inf) a
+
+fromSrcInfoPoints :: [Span] -> SpanInfo
+fromSrcInfoPoints = SpanInfo NoSpan
+
+getSrcInfoPoints :: HasSpanInfo a => a -> [Span]
+getSrcInfoPoints a = case getSpanInfo a of
+  NoSpanInfo    -> []
+  SpanInfo _ xs -> xs
+
+setSrcInfoPoints :: HasSpanInfo a => [Span] -> a -> a
+setSrcInfoPoints inf a = case getSpanInfo a of
+  NoSpanInfo    -> setSpanInfo (SpanInfo NoSpan inf) a
+  SpanInfo s _  -> setSpanInfo (SpanInfo s      inf) a
+
+getStartPosition :: HasSpanInfo a => a -> Position
+getStartPosition a =  case getSrcSpan a of
+  NoSpan     -> NoPos
+  Span _ s _ -> s
+
+getSrcSpanEnd :: HasSpanInfo a => a -> Position
+getSrcSpanEnd a = case getSpanInfo a of
+  NoSpanInfo   -> NoPos
+  SpanInfo s _ -> end s
+
+setStartPosition :: HasSpanInfo a => Position -> a -> a
+setStartPosition p a = case getSrcSpan a of
+  NoSpan     -> setSrcSpan (Span "" p NoPos) a
+  Span f _ e -> setSrcSpan (Span f  p     e) a
+
+setEndPosition :: HasSpanInfo a => Position -> a -> a
+setEndPosition e a = case getSrcSpan a of
+  NoSpan     -> setSrcSpan (Span "" NoPos e) a
+  Span f p _ -> setSrcSpan (Span f  p     e) a
+
+spanInfo2Pos :: HasSpanInfo a => a -> Position
+spanInfo2Pos = getStartPosition
+
+spanInfoLike :: (HasSpanInfo a, HasSpanInfo b) => a -> b -> a
+spanInfoLike a b = setSpanInfo (getSpanInfo b) a
diff --git a/src/Curry/CondCompile/Parser.hs b/src/Curry/CondCompile/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/CondCompile/Parser.hs
@@ -0,0 +1,90 @@
+{- |
+    Module      :  $Header$
+    Description :  Parser for conditional compiling
+    Copyright   :  (c) 2017        Kai-Oliver Prott
+                       2017        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    TODO
+-}
+{-# LANGUAGE CPP #-}
+module Curry.CondCompile.Parser where
+
+#if __GLASGOW_HASKELL__ < 710
+import Control.Applicative ((<$>), (<*>), (*>), (<*))
+#endif
+
+import Text.Parsec
+
+import Curry.CondCompile.Type
+
+type Parser a = Parsec String () a
+
+program :: Parser Program
+program = statement `sepBy` eol <* eof
+
+statement :: Parser Stmt
+statement =  ifElse "if" condition If
+         <|> ifElse "ifdef" identifier IfDef
+         <|> ifElse "ifndef" identifier IfNDef
+         <|> define
+         <|> undef
+         <|> line
+
+ifElse :: String -> Parser a -> (a -> [Stmt] -> [Elif] -> Else -> Stmt)
+       -> Parser Stmt
+ifElse k p c = c <$> (try (many sp *> keyword k *> many1 sp) *> p <* many sp <* eol)
+                 <*> many (statement <* eol)
+                 <*> many (Elif <$> ((,) <$> (try (many sp *> keyword "elif" *> many1 sp) *> condition <* many sp <* eol)
+                                         <*> many (statement <* eol)))
+                 <*> (Else <$> optionMaybe
+                                 (try (many sp *> keyword "else" *> many sp) *> eol *> many (statement <* eol)))
+                 <*  try (many sp <* keyword "endif" <* many sp)
+
+define :: Parser Stmt
+define = Define <$> (try (many sp *> keyword "define" *> many1 sp) *> identifier <* many1 sp)
+                <*> value <* many sp
+
+undef :: Parser Stmt
+undef = Undef <$> (try (many sp *> keyword "undef" *> many1 sp) *> identifier <* many sp)
+
+line :: Parser Stmt
+line = do
+  sps <- many sp
+  try $  ((char '#' <?> "") *> fail "unknown directive")
+     <|> ((Line . (sps ++)) <$> manyTill anyChar (try (lookAhead (eol <|> eof))))
+
+keyword :: String -> Parser String
+keyword = string . ('#' :)
+
+condition :: Parser Cond
+condition =  (Defined  <$> (try (string  "defined(") *> many sp *> identifier <* many sp <* char ')'))
+         <|> (NDefined <$> (try (string "!defined(") *> many sp *> identifier <* many sp <* char ')'))
+         <|> (Comp <$> (identifier <* many sp) <*> operator <*> (many sp *> value) <?> "condition")
+
+identifier :: Parser String
+identifier = (:) <$> firstChar <*> many (firstChar <|> digit) <?> "identifier"
+  where firstChar = letter <|> char '_'
+
+operator :: Parser Op
+operator = choice [ Leq <$ try (string "<=")
+                  , Lt  <$ try (string "<")
+                  , Geq <$ try (string ">=")
+                  , Gt  <$ try (string ">")
+                  , Neq <$ try (string "!=")
+                  , Eq  <$ string "=="
+                  ] <?> "operator"
+
+value :: Parser Int
+value = fmap read (many1 digit)
+
+eol :: Parser ()
+eol = endOfLine *> return ()
+
+sp :: Parser Char
+sp = try $  lookAhead (eol *> unexpected "end of line" <?> "")
+        <|> space
diff --git a/src/Curry/CondCompile/Transform.hs b/src/Curry/CondCompile/Transform.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/CondCompile/Transform.hs
@@ -0,0 +1,116 @@
+{- |
+    Module      :  $Header$
+    Description :  Conditional compiling transformation
+    Copyright   :  (c) 2017        Kai-Oliver Prott
+                       2017        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    TODO
+-}
+module Curry.CondCompile.Transform (condTransform) where
+
+import           Control.Monad.State
+import           Control.Monad.Extra        (concatMapM)
+import qualified Data.Map            as Map
+import           Data.Maybe                 (fromMaybe)
+import           Text.Parsec                             hiding (State)
+import           Text.Parsec.Error          ()
+
+import Curry.Base.Message
+import Curry.Base.Position
+import Curry.Base.Pretty
+
+import Curry.CondCompile.Parser
+import Curry.CondCompile.Type
+
+type CCState = Map.Map String Int
+
+type CCM = State CCState
+
+condTransform :: CCState -> FilePath -> String -> Either Message String
+condTransform s fn p = either (Left . convertError)
+                              (Right . transformWith s)
+                              (parse program fn p)
+
+transformWith :: CCState -> Program -> String
+transformWith s p = show $ pPrint $ evalState (transform p) s
+
+convertError :: ParseError -> Message
+convertError err = posMessage pos $
+  foldr ($+$) empty $ map text $ tail $ lines $ show err
+  where pos = Position (sourceName src) (sourceLine src) (sourceColumn src)
+        src = errorPos err
+
+class CCTransform a where
+  transform :: a -> CCM [Stmt]
+
+instance CCTransform Stmt where
+  transform (Line              s) = return [Line s]
+  transform (If     c stmts is e) = do
+    s <- get
+    if checkCond c s
+      then do stmts' <- transform stmts
+              return (blank : stmts' ++ fill is ++ fill e ++ [blank])
+      else case is of
+             []                        -> do
+               stmts' <- transform e
+               return (blank : fill stmts ++ stmts' ++ [blank])
+             (Elif (c', stmts') : is') -> do
+               stmts'' <- transform (If c' stmts' is' e)
+               return (blank : fill stmts ++ stmts'')
+  transform (IfDef  v stmts is e) = transform (If (Defined  v) stmts is e)
+  transform (IfNDef v stmts is e) = transform (If (NDefined v) stmts is e)
+  transform (Define          v i) = modify (Map.insert v i) >> return [blank]
+  transform (Undef           v  ) = modify (Map.delete v) >> return [blank]
+
+instance CCTransform a => CCTransform [a] where
+  transform = concatMapM transform
+
+instance CCTransform Else where
+  transform (Else (Just p)) = (blank :) <$> transform p
+  transform (Else Nothing ) = return []
+
+checkCond :: Cond -> CCState -> Bool
+checkCond (Comp v op i) = flip (compareOp op) i . fromMaybe 0 . Map.lookup v
+checkCond (Defined   v) = Map.member v
+checkCond (NDefined  v) = Map.notMember v
+
+compareOp :: Ord a => Op -> a -> a -> Bool
+compareOp Eq  = (==)
+compareOp Neq = (/=)
+compareOp Lt  = (<)
+compareOp Leq = (<=)
+compareOp Gt  = (>)
+compareOp Geq = (>=)
+
+class FillLength a where
+  fillLength :: a -> Int
+
+instance FillLength Stmt where
+  fillLength (Line   _           ) = 1
+  fillLength (Define _ _         ) = 1
+  fillLength (Undef  _           ) = 1
+  fillLength (If     _ stmts is e) =
+    3 + fillLength stmts + fillLength e + fillLength is
+  fillLength (IfDef  v stmts is e) = fillLength (If (Defined  v) stmts is e)
+  fillLength (IfNDef v stmts is e) = fillLength (If (NDefined v) stmts is e)
+
+instance FillLength a => FillLength [a] where
+  fillLength = foldr ((+) . fillLength) 0
+
+instance FillLength Else where
+  fillLength (Else (Just stmts)) = 1 + fillLength stmts
+  fillLength (Else Nothing     ) = 0
+
+instance FillLength Elif where
+  fillLength (Elif (_, stmts)) = 1 + fillLength stmts
+
+fill :: FillLength a => a -> [Stmt]
+fill p = replicate (fillLength p) blank
+
+blank :: Stmt
+blank = Line ""
diff --git a/src/Curry/CondCompile/Type.hs b/src/Curry/CondCompile/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/CondCompile/Type.hs
@@ -0,0 +1,88 @@
+{- |
+    Module      :  $Header$
+    Description :  Abstract syntax for conditional compiling
+    Copyright   :  (c) 2017        Kai-Oliver Prott
+                       2017        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    TODO
+-}
+{-# LANGUAGE CPP #-}
+module Curry.CondCompile.Type
+  ( Program, Stmt (..), Else (..), Elif (..), Cond (..), Op (..)
+  ) where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+import Curry.Base.Pretty
+
+type Program = [Stmt]
+
+data Stmt = If Cond [Stmt] [Elif] Else
+          | IfDef String [Stmt] [Elif] Else
+          | IfNDef String [Stmt] [Elif] Else
+          | Define String Int
+          | Undef String
+          | Line String
+  deriving Show
+
+newtype Else = Else (Maybe [Stmt])
+  deriving Show
+
+newtype Elif = Elif (Cond, [Stmt])
+  deriving Show
+
+data Cond = Comp String Op Int
+          | Defined String
+          | NDefined String
+  deriving Show
+
+data Op = Eq
+        | Neq
+        | Lt
+        | Leq
+        | Gt
+        | Geq
+  deriving Show
+
+instance Pretty Stmt where
+  pPrint (If     c stmts is e) = prettyIf "#if"     (pPrint c) stmts is e
+  pPrint (IfDef  v stmts is e) = prettyIf "#ifdef"  (text v)   stmts is e
+  pPrint (IfNDef v stmts is e) = prettyIf "#ifndef" (text v)   stmts is e
+  pPrint (Define v i         ) = text "#define" <+> text v <+> int i
+  pPrint (Undef  v           ) = text "#undef"  <+> text v
+  pPrint (Line   s           ) = text s
+
+  pPrintList = foldr (($+$) . pPrint) empty
+
+instance Pretty Elif where
+  pPrint (Elif (c, stmts)) = text "#elif" <+> pPrint c $+$ pPrint stmts
+
+  pPrintList = foldr (($+$) . pPrint) empty
+
+instance Pretty Else where
+  pPrint (Else (Just stmts)) = text "#else" $+$ pPrint stmts
+  pPrint (Else Nothing)      = empty
+
+prettyIf :: String -> Doc -> [Stmt] -> [Elif] -> Else -> Doc
+prettyIf k doc stmts is e = foldr ($+$) empty
+  [text k <+> doc, pPrint stmts, pPrint is, pPrint e, text "#endif"]
+
+instance Pretty Cond where
+  pPrint (Comp v op i) = text v <+> pPrint op <+> int i
+  pPrint (Defined  v ) = text "defined("  <> text v <> char ')'
+  pPrint (NDefined v ) = text "!defined(" <> text v <> char ')'
+
+instance Pretty Op where
+  pPrint Eq  = text "=="
+  pPrint Neq = text "/="
+  pPrint Lt  = text "<"
+  pPrint Leq = text "<="
+  pPrint Gt  = text ">"
+  pPrint Geq = text ">="
diff --git a/src/Curry/Files/CymakePath.hs b/src/Curry/Files/CymakePath.hs
deleted file mode 100644
--- a/src/Curry/Files/CymakePath.hs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Curry.Files.CymakePath (getCymake,cymakeVersion) where
-
-import Data.Version
-import System.FilePath
-import Paths_curry_frontend
-
--- | Retrieve the version number of cymake
-cymakeVersion :: String
-cymakeVersion = showVersion version
-
--- | Retrieve the location of the cymake executable
-getCymake :: IO String
-getCymake     = do
-  cymakeDir <- getBinDir
-  return (cymakeDir </> "cymake")
diff --git a/src/Curry/Files/Filenames.hs b/src/Curry/Files/Filenames.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Files/Filenames.hs
@@ -0,0 +1,256 @@
+{- |
+    Module      :  $Header$
+    Description :  File names for several intermediate file formats.
+    Copyright   :  (c) 2009        Holger Siegel
+                       2013 - 2014 Björn Peemöller
+                       2018        Kai-Oliver Prott
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    The functions in this module were collected from several compiler modules
+    in order to provide a unique accessing point for this functionality.
+-}
+module Curry.Files.Filenames
+  ( -- * Re-exports from 'System.FilePath'
+    FilePath, takeBaseName, dropExtension, takeExtension, takeFileName
+
+    -- * Conversion between 'ModuleIdent' and 'FilePath'
+  , moduleNameToFile, fileNameToModule, splitModuleFileName, isCurryFilePath
+
+    -- * Curry sub-directory
+  , defaultOutDir, hasOutDir, addOutDir, addOutDirModule
+  , ensureOutDir
+
+    -- * File name extensions
+    -- ** Curry files
+  , curryExt, lcurryExt, icurryExt
+
+    -- ** FlatCurry files
+  , annotatedFlatExt, typedFlatExt, flatExt, flatIntExt
+
+    -- ** AbstractCurry files
+  , acyExt, uacyExt
+
+    -- ** Source and object files
+  , sourceRepExt, sourceExts, moduleExts
+
+    -- * Functions for computing file names
+  , interfName, typedFlatName, annotatedFlatName, flatName, flatIntName
+  , acyName, uacyName, sourceRepName, tokensName, commentsName
+  , astName, shortASTName, htmlName
+  ) where
+
+import System.FilePath
+
+import Curry.Base.Ident
+
+-- -----------------------------------------------------------------------------
+-- Conversion between ModuleIdent and FilePath
+-- -----------------------------------------------------------------------------
+
+-- |Create a 'FilePath' from a 'ModuleIdent' using the hierarchical module
+-- system
+moduleNameToFile :: ModuleIdent -> FilePath
+moduleNameToFile = foldr1 (</>) . midQualifiers
+
+-- |Extract the 'ModuleIdent' from a 'FilePath'
+fileNameToModule :: FilePath -> ModuleIdent
+fileNameToModule = mkMIdent . splitDirectories . dropExtension . dropDrive
+
+-- |Split a 'FilePath' into a prefix directory part and those part that
+-- corresponds to the 'ModuleIdent'. This is especially useful for
+-- hierarchically module names.
+splitModuleFileName :: ModuleIdent -> FilePath -> (FilePath, FilePath)
+splitModuleFileName m fn = case midQualifiers m of
+  [_] -> splitFileName fn
+  ms  -> let (base, ext) = splitExtension fn
+             dirs        = splitDirectories base
+             (pre, suf)  = splitAt (length dirs - length ms) dirs
+             path        = if null pre then ""
+                                       else addTrailingPathSeparator (joinPath pre)
+         in  (path, joinPath suf <.> ext)
+
+-- |Checks whether a 'String' represents a 'FilePath' to a Curry module
+isCurryFilePath :: String -> Bool
+isCurryFilePath str =  isValid str
+                    && takeExtension str `elem` ("" : moduleExts)
+
+-- -----------------------------------------------------------------------------
+-- Curry sub-directory
+-- -----------------------------------------------------------------------------
+
+-- |The standard hidden subdirectory for curry files
+defaultOutDir :: String
+defaultOutDir = ".curry"
+
+-- |Does the given 'FilePath' contain the 'outDir'
+-- as its last directory component?
+hasOutDir :: String -> FilePath -> Bool
+hasOutDir outDir f = not (null dirs) && last dirs == outDir
+  where dirs = splitDirectories $ takeDirectory f
+
+-- |Add the 'outDir' to the given 'FilePath' if the flag is 'True' and
+-- the path does not already contain it, otherwise leave the path untouched.
+addOutDir :: Bool -> String -> FilePath -> FilePath
+addOutDir b outDir fn = if b then ensureOutDir outDir fn else fn
+
+-- |Add the 'outDir' to the given 'FilePath' if the flag is 'True' and
+-- the path does not already contain it, otherwise leave the path untouched.
+addOutDirModule :: Bool -> String -> ModuleIdent -> FilePath -> FilePath
+addOutDirModule b outDir m fn
+  | b         = let (pre, file) = splitModuleFileName m fn
+                in  ensureOutDir outDir pre </> file
+  | otherwise = fn
+
+-- | Ensure that the 'outDir' is the last component of the
+-- directory structure of the given 'FilePath'. If the 'FilePath' already
+-- contains the sub-directory, it remains unchanged.
+ensureOutDir :: String   -- ^ the 'outDir'
+             -> FilePath -- ^ original 'FilePath'
+             -> FilePath -- ^ new 'FilePath'
+ensureOutDir outDir fn = normalise $ addSub (splitDirectories d) </> f
+  where
+  (d, f) = splitFileName fn
+  addSub dirs | null dirs           = outDir
+              | last dirs == outDir = joinPath dirs
+              | otherwise           = joinPath dirs </> outDir
+
+-- -----------------------------------------------------------------------------
+-- File name extensions
+-- -----------------------------------------------------------------------------
+
+-- |Filename extension for non-literate curry files
+curryExt :: String
+curryExt = ".curry"
+
+-- |Filename extension for literate curry files
+lcurryExt :: String
+lcurryExt = ".lcurry"
+
+-- |Filename extension for curry interface files
+icurryExt :: String
+icurryExt = ".icurry"
+
+-- |Filename extension for curry source files.
+--
+-- /Note:/ The order of the extensions defines the order in which source files
+-- should be searched for, i.e. given a module name @M@, the search order
+-- should be the following:
+--
+-- 1. @M.curry@
+-- 2. @M.lcurry@
+--
+sourceExts :: [String]
+sourceExts = [curryExt, lcurryExt]
+
+-- |Filename extension for curry module files
+-- TODO: Is the order correct?
+moduleExts :: [String]
+moduleExts = sourceExts ++ [icurryExt]
+
+-- |Filename extension for typed flat-curry files
+typedFlatExt :: String
+typedFlatExt = ".tfcy"
+
+-- |Filename extension for type-annotated flat-curry files
+annotatedFlatExt :: String
+annotatedFlatExt = ".tafcy"
+
+-- |Filename extension for flat-curry files
+flatExt :: String
+flatExt = ".fcy"
+
+-- |Filename extension for extended-flat-curry interface files
+flatIntExt :: String
+flatIntExt = ".fint"
+
+-- |Filename extension for abstract-curry files
+acyExt :: String
+acyExt = ".acy"
+
+-- |Filename extension for untyped-abstract-curry files
+uacyExt :: String
+uacyExt = ".uacy"
+
+-- |Filename extension for curry source representation files
+sourceRepExt :: String
+sourceRepExt = ".cy"
+
+-- |Filename extension for token files
+tokensExt :: String
+tokensExt = ".tokens"
+
+-- |Filename extension for comment token files
+commentsExt :: String
+commentsExt = ".cycom"
+
+-- |Filename extension for AST files
+astExt :: String
+astExt = ".ast"
+
+-- |Filename extension for shortened AST files
+shortASTExt :: String
+shortASTExt = ".sast"
+
+-- ---------------------------------------------------------------------------
+-- Computation of file names for a given source file
+-- ---------------------------------------------------------------------------
+
+-- |Compute the filename of the interface file for a source file
+interfName :: FilePath -> FilePath
+interfName = replaceExtensionWith icurryExt
+
+-- |Compute the filename of the typed flat curry file for a source file
+typedFlatName :: FilePath -> FilePath
+typedFlatName = replaceExtensionWith typedFlatExt
+
+-- |Compute the filename of the typed flat curry file for a source file
+annotatedFlatName :: FilePath -> FilePath
+annotatedFlatName = replaceExtensionWith annotatedFlatExt
+
+-- |Compute the filename of the flat curry file for a source file
+flatName :: FilePath -> FilePath
+flatName = replaceExtensionWith flatExt
+
+-- |Compute the filename of the flat curry interface file for a source file
+flatIntName :: FilePath -> FilePath
+flatIntName = replaceExtensionWith flatIntExt
+
+-- |Compute the filename of the abstract curry file for a source file
+acyName :: FilePath -> FilePath
+acyName = replaceExtensionWith acyExt
+
+-- |Compute the filename of the untyped abstract curry file for a source file
+uacyName :: FilePath -> FilePath
+uacyName = replaceExtensionWith uacyExt
+
+-- |Compute the filename of the source representation file for a source file
+sourceRepName :: FilePath -> FilePath
+sourceRepName = replaceExtensionWith sourceRepExt
+
+-- |Compute the filename of the tokens file for a source file
+tokensName :: FilePath -> FilePath
+tokensName = replaceExtensionWith tokensExt
+
+-- |Compute the filename of the comment tokens file for a source file
+commentsName :: FilePath -> FilePath
+commentsName = replaceExtensionWith commentsExt
+
+-- |Compute the filename of the ast file for a source file
+astName :: FilePath -> FilePath
+astName = replaceExtensionWith astExt
+
+-- |Compute the filename of the ast file for a source file
+shortASTName :: FilePath -> FilePath
+shortASTName = replaceExtensionWith shortASTExt
+
+-- |Compute the filename of the HTML file for a source file
+htmlName :: ModuleIdent -> String
+htmlName m = moduleName m ++ "_curry.html"
+
+-- |Replace a filename extension with a new extension
+replaceExtensionWith :: String -> FilePath -> FilePath
+replaceExtensionWith = flip replaceExtension
diff --git a/src/Curry/Files/PathUtils.hs b/src/Curry/Files/PathUtils.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Files/PathUtils.hs
@@ -0,0 +1,206 @@
+{- |
+    Module      :  $Header$
+    Description :  Utility functions for reading and writing files
+    Copyright   :  (c) 1999 - 2003, Wolfgang Lux
+                       2011 - 2014, Björn Peemöller (bjp@informatik.uni-kiel.de)
+                       2017       , Finn Teegen (fte@informatik.uni-kiel.de)
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+-}
+
+{-# LANGUAGE CPP #-}
+
+module Curry.Files.PathUtils
+  ( -- * Retrieving curry files
+    lookupCurryFile
+  , lookupCurryModule
+  , lookupCurryInterface
+  , lookupFile
+
+    -- * Reading and writing modules from files
+  , getModuleModTime
+  , writeModule
+  , readModule
+  , writeBinaryModule
+  , addVersion
+  , checkVersion
+  ) where
+
+import qualified Control.Exception    as C (IOException, handle)
+import           Control.Monad             (liftM)
+import           Data.List                 (isPrefixOf, isSuffixOf)
+import qualified Data.ByteString.Lazy as B (ByteString, writeFile)
+import           System.FilePath
+import           System.Directory
+import           System.IO
+
+#if MIN_VERSION_directory(1,2,0)
+import Data.Time                        (UTCTime)
+#else
+import System.Time                      (ClockTime)
+#endif
+
+import Curry.Base.Ident
+import Curry.Files.Filenames
+
+-- ---------------------------------------------------------------------------
+-- Searching for files
+-- ---------------------------------------------------------------------------
+
+-- |Search in the given list of paths for the given 'FilePath' and eventually
+-- return the file name of the found file.
+--
+-- - If the file name already contains a directory, then the paths to search
+--   in are ignored.
+-- - If the file name has no extension, then a source file extension is
+--   assumed.
+lookupCurryFile :: [FilePath] -> FilePath -> IO (Maybe FilePath)
+lookupCurryFile paths fn = lookupFile paths exts fn
+  where
+  exts  | null fnExt = sourceExts
+        | otherwise  = [fnExt]
+  fnExt              = takeExtension fn
+
+-- |Search for a given curry module in the given source file and
+-- library paths. Note that the current directory is always searched first.
+-- Returns the path of the found file.
+lookupCurryModule :: [FilePath]          -- ^ list of paths to source files
+                  -> [FilePath]          -- ^ list of paths to library files
+                  -> ModuleIdent         -- ^ module identifier
+                  -> IO (Maybe FilePath)
+lookupCurryModule paths libPaths m =
+  lookupFile (paths ++ libPaths) moduleExts (moduleNameToFile m)
+
+-- |Search for an interface file in the import search path using the
+-- interface extension 'icurryExt'. Note that the current directory is
+-- always searched first.
+lookupCurryInterface :: [FilePath]          -- ^ list of paths to search in
+                     -> ModuleIdent         -- ^ module identifier
+                     -> IO (Maybe FilePath) -- ^ the file path if found
+lookupCurryInterface paths m = lookupFile paths [icurryExt] (moduleNameToFile m)
+
+-- |Search in the given directories for the file with the specified file
+-- extensions and eventually return the 'FilePath' of the file.
+lookupFile :: [FilePath]          -- ^ Directories to search in
+           -> [String]            -- ^ Accepted file extensions
+           -> FilePath            -- ^ Initial file name
+           -> IO (Maybe FilePath) -- ^ 'FilePath' of the file if found
+lookupFile paths exts file = lookup' files
+  where
+  files     = [ normalise (p </> f) | p <- paths, f <- baseNames ]
+  baseNames = map (replaceExtension file) exts
+
+  lookup' []       = return Nothing
+  lookup' (f : fs) = do
+    exists <- doesFileExist f
+    if exists then return (Just f) else lookup' fs
+
+-- ---------------------------------------------------------------------------
+-- Reading and writing files
+-- ---------------------------------------------------------------------------
+
+-- | Write the content to a file in the given directory.
+writeModule :: FilePath -- ^ original path
+            -> String   -- ^ file content
+            -> IO ()
+writeModule fn contents = do
+  createDirectoryIfMissing True $ takeDirectory fn
+  tryWriteFile fn contents
+
+-- | Write the content in binary to a file in the given directory.
+writeBinaryModule :: FilePath -- ^ original path
+                  -> B.ByteString   -- ^ file content
+                  -> IO ()
+writeBinaryModule fn contents = do
+  createDirectoryIfMissing True $ takeDirectory fn
+  tryWriteBinaryFile (fn ++ "-bin") contents
+
+-- | Read the specified module and returns either 'Just String' if
+-- reading was successful or 'Nothing' otherwise.
+readModule :: FilePath -> IO (Maybe String)
+readModule = tryOnExistingFile readFileUTF8
+ where
+  readFileUTF8 :: FilePath -> IO String
+  readFileUTF8 fn = do
+    hdl <- openFile fn ReadMode
+    hSetEncoding hdl utf8
+    hGetContents hdl
+
+-- | Get the modification time of a file, if existent
+#if MIN_VERSION_directory(1,2,0)
+getModuleModTime :: FilePath -> IO (Maybe UTCTime)
+#else
+getModuleModTime :: FilePath -> IO (Maybe ClockTime)
+#endif
+getModuleModTime = tryOnExistingFile getModificationTime
+
+-- |Add the given version string to the file content
+addVersion :: String -> String -> String
+addVersion v content = "{- " ++ v ++ " -}\n" ++ content
+
+-- |Check a source file for the given version string
+checkVersion :: String -> String -> Either String String
+checkVersion expected src = case lines src of
+  [] -> Left "empty file"
+  (l:ls) -> case getVersion l of
+    Just v | v == expected -> Right (unlines ls)
+           | otherwise     -> Left $ "Expected version `" ++ expected
+                                     ++ "', but found version `" ++ v ++ "'"
+    _                      -> Left $ "No version found"
+
+  where
+    getVersion s | "{- " `isPrefixOf` s && " -}" `isSuffixOf` s
+                 = Just (reverse $ drop 3 $ reverse $ drop 3 s)
+                 | otherwise
+                 = Nothing
+
+-- ---------------------------------------------------------------------------
+-- Helper functions
+-- ---------------------------------------------------------------------------
+
+tryOnExistingFile :: (FilePath -> IO a) -> FilePath -> IO (Maybe a)
+tryOnExistingFile action fn = C.handle ignoreIOException $ do
+  exists <- doesFileExist fn
+  if exists then Just `liftM` action fn
+            else return Nothing
+
+ignoreIOException :: C.IOException -> IO (Maybe a)
+ignoreIOException _ = return Nothing
+
+-- | Try to write a file. If it already exists and is not writable,
+-- a warning is issued. This solves some file dependency problems
+-- in global installations.
+tryWriteFile :: FilePath -- ^ original path
+             -> String   -- ^ file content
+             -> IO ()
+tryWriteFile fn contents = do
+  exists <- doesFileExist fn
+  if exists then C.handle issueWarning (writeFileUTF8 fn contents)
+            else writeFileUTF8 fn contents
+ where
+  issueWarning :: C.IOException -> IO ()
+  issueWarning _ = do
+    putStrLn $ "*** Warning: cannot update file `" ++ fn ++ "' (update ignored)"
+    return ()
+  writeFileUTF8 :: FilePath -> String -> IO ()
+  writeFileUTF8 fn' str =
+    withFile fn' WriteMode (\hdl -> hSetEncoding hdl utf8 >> hPutStr hdl str)
+
+-- | Try to write a file. If it already exists and is not writable,
+-- a warning is issued. This solves some file dependency problems
+-- in global installations.
+tryWriteBinaryFile :: FilePath -- ^ original path
+                   -> B.ByteString   -- ^ file content
+                   -> IO ()
+tryWriteBinaryFile fn contents = do
+  exists <- doesFileExist fn
+  if exists then C.handle issueWarning (B.writeFile fn contents)
+            else B.writeFile fn contents
+ where
+  issueWarning :: C.IOException -> IO ()
+  issueWarning _ = do
+    putStrLn $ "*** Warning: cannot update file `" ++ fn ++ "' (update ignored)"
+    return ()
diff --git a/src/Curry/Files/Unlit.hs b/src/Curry/Files/Unlit.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Files/Unlit.hs
@@ -0,0 +1,124 @@
+{-# LANGUAGE ViewPatterns #-}
+{- |
+    Module      :  $Header$
+    Description :  Handling of literate Curry files
+    Copyright   :  (c) 2009         Holger Siegel
+                       2012  - 2014 Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    Since version 0.7 of the language report, Curry accepts literate
+    source programs. In a literate source, all program lines must begin
+    with a greater sign in the first column. All other lines are assumed
+    to be documentation. In order to avoid some common errors with
+    literate programs, Curry requires at least one program line to be
+    present in the file. In addition, every block of program code must be
+    preceded by a blank line and followed by a blank line.
+
+    It is also possible to use "\begin{code}" and "\end{code}"
+    to mark code segments. Both styles can be used in mixed fashion.
+-}
+
+module Curry.Files.Unlit (isLiterate, unlit) where
+
+import Control.Monad         (when, unless, zipWithM)
+import Data.Char             (isSpace)
+import Data.List             (stripPrefix)
+
+import Curry.Base.Monad      (CYM, failMessageAt)
+import Curry.Base.Span       (pos2Span)
+import Curry.Base.Position   (Position (..), first)
+import Curry.Files.Filenames (lcurryExt, takeExtension)
+
+-- |Check whether a 'FilePath' represents a literate Curry module
+isLiterate :: FilePath -> Bool
+isLiterate = (== lcurryExt) . takeExtension
+
+-- |Data type representing different kind of lines in a literate source
+data Line
+  = ProgramStart !Int        -- ^ \begin{code}
+  | ProgramEnd   !Int        -- ^ \end{code}
+  | Program      !Int String -- ^ program line with a line number and content
+  | Comment      !Int String -- ^ comment line
+  | Blank        !Int        -- ^ blank line
+
+-- |Process a curry program into error messages (if any) and the
+-- corresponding non-literate program.
+unlit :: FilePath -> String -> CYM String
+unlit fn cy
+  | isLiterate fn = do
+      let cyl = lines cy
+      ls <- progLines fn =<<
+            normalize fn (length cyl) False (zipWith classify [1 .. ] cyl)
+      when (all null ls) $ failMessageAt (pos2Span $ first fn) "No code in literate script"
+      return (unlines ls)
+  | otherwise     = return cy
+
+-- |Classification of a single program line
+classify :: Int -> String -> Line
+classify l s@('>' : _) = Program l s
+classify l s@(stripPrefix "\\begin{code}" -> Just cs)
+  | all isSpace cs = ProgramStart l
+  | otherwise      = Comment l s
+classify l s@(stripPrefix "\\end{code}" -> Just cs)
+  | all isSpace cs = ProgramEnd l
+  | otherwise      = Comment l s
+classify l s
+  | all isSpace s = Blank l
+  | otherwise     = Comment l s
+
+-- |Check that ProgramStart and ProgramEnd match and desugar them.
+normalize :: FilePath -> Int -> Bool -> [Line] -> CYM [Line]
+normalize _  _ False [] = return []
+normalize fn n True  [] = reportMissingEnd fn n
+normalize fn n b (ProgramStart l : rest) = do
+  when b $ reportSpurious fn l "\\begin{code}"
+  norm <- normalize fn n True rest
+  return (Blank l : norm)
+normalize fn n b (ProgramEnd   l : rest) = do
+  unless b $ reportSpurious fn l "\\end{code}"
+  norm <- normalize fn n False rest
+  return (Blank l : norm)
+normalize fn n b (Comment l s : rest) = do
+  let cons = if b then Program l s else Comment l s
+  norm <- normalize fn n b rest
+  return (cons : norm)
+normalize fn n b (Program l s : rest) = do
+  let cons = if b then Program l s else Program l (drop 1 s)
+  norm <- normalize fn n b rest
+  return (cons : norm)
+normalize fn n b (Blank   l   : rest) = do
+  let cons = if b then Program l "" else Blank l
+  norm <- normalize fn n b rest
+  return (cons : norm)
+
+-- |Check that each program line is not adjacent to a comment line.
+progLines :: FilePath -> [Line] -> CYM [String]
+progLines fn cs = zipWithM checkAdjacency (Blank 0 : cs) cs where
+  checkAdjacency (Program p _) (Comment _ _) = reportBlank fn p "followed"
+  checkAdjacency (Comment _ _) (Program p _) = reportBlank fn p "preceded"
+  checkAdjacency _             (Program _ s) = return s
+  checkAdjacency _             _             = return ""
+
+-- |Compute an appropiate error message
+reportBlank :: FilePath -> Int -> String -> CYM a
+reportBlank f l cause = failMessageAt (pos2Span $ Position f l 1) msg
+  where msg = concat [ "When reading literate source: "
+                     , "Program line is " ++ cause ++ " by comment line."
+                     ]
+
+reportMissingEnd :: FilePath -> Int -> CYM a
+reportMissingEnd f l = failMessageAt (pos2Span $ Position f (l+1) 1) msg
+  where msg = concat [ "When reading literate source: "
+                     , "Missing '\\end{code}' at the end of file."
+                     ]
+
+
+reportSpurious :: FilePath -> Int -> String -> CYM a
+reportSpurious f l cause = failMessageAt (pos2Span $ Position f l 1) msg
+  where msg = concat [ "When reading literate source: "
+                     , "Spurious '" ++ cause ++ "'."
+                     ]
diff --git a/src/Curry/FlatCurry.hs b/src/Curry/FlatCurry.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/FlatCurry.hs
@@ -0,0 +1,19 @@
+{- |
+    Module      :  $Header$
+    Description :  Interface for reading and manipulating FlatCurry source code
+    Copyright   :  (c) 2014 Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+-}
+module Curry.FlatCurry
+  ( module Curry.FlatCurry.Type
+  , module Curry.FlatCurry.Pretty
+  , module Curry.FlatCurry.Files
+  ) where
+
+import Curry.FlatCurry.Files
+import Curry.FlatCurry.Pretty
+import Curry.FlatCurry.Type
diff --git a/src/Curry/FlatCurry/Annotated/Goodies.hs b/src/Curry/FlatCurry/Annotated/Goodies.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/FlatCurry/Annotated/Goodies.hs
@@ -0,0 +1,685 @@
+{- |
+    Module      : $Header$
+    Description : Utility functions for working with annotated FlatCurry.
+    Copyright   : (c) 2016 - 2017 Finn Teegen
+    License     : BSD-3-clause
+
+    Maintainer  : fte@informatik.uni-kiel.de
+    Stability   : experimental
+    Portability : portable
+
+    This library provides selector functions, test and update operations
+    as well as some useful auxiliary functions for AnnotatedFlatCurry data terms.
+    Most of the provided functions are based on general transformation
+    functions that replace constructors with user-defined
+    functions. For recursive datatypes the transformations are defined
+    inductively over the term structure. This is quite usual for
+    transformations on AnnotatedFlatCurry terms,
+    so the provided functions can be used to implement specific transformations
+    without having to explicitly state the recursion. Essentially, the tedious
+    part of such transformations - descend in fairly complex term structures -
+    is abstracted away, which hopefully makes the code more clear and brief.
+-}
+
+module Curry.FlatCurry.Annotated.Goodies
+  ( module Curry.FlatCurry.Annotated.Goodies
+  , module Curry.FlatCurry.Goodies
+  ) where
+
+import Curry.FlatCurry.Goodies ( Update
+                               , trType, typeName, typeVisibility, typeParams
+                               , typeConsDecls, typeSyn, isTypeSyn
+                               , isDataTypeDecl, isExternalType, isPublicType
+                               , updType, updTypeName, updTypeVisibility
+                               , updTypeParams, updTypeConsDecls, updTypeSynonym
+                               , updQNamesInType
+                               , trCons, consName, consArity, consVisibility
+                               , isPublicCons, consArgs, updCons, updConsName
+                               , updConsArity, updConsVisibility, updConsArgs
+                               , updQNamesInConsDecl
+                               , trNewCons, newConsName, newConsVisibility
+                               , isPublicNewCons, newConsArg
+                               , updNewCons, updNewConsName
+                               , updNewConsVisibility, updNewConsArg
+                               , updQNamesInNewConsDecl
+                               , tVarIndex, domain, range, tConsName, tConsArgs
+                               , trTypeExpr, isTVar, isTCons, isFuncType
+                               , updTVars, updTCons, updFuncTypes, argTypes
+                               , typeArity, resultType, allVarsInTypeExpr
+                               , allTypeCons, rnmAllVarsInTypeExpr
+                               , updQNamesInTypeExpr
+                               , trOp, opName, opFixity, opPrecedence, updOp
+                               , updOpName, updOpFixity, updOpPrecedence
+                               , trCombType, isCombTypeFuncCall
+                               , isCombTypeFuncPartCall, isCombTypeConsCall
+                               , isCombTypeConsPartCall
+                               , isPublic
+                               )
+
+import Curry.FlatCurry.Annotated.Type
+
+-- AProg ----------------------------------------------------------------------
+
+-- |transform program
+trAProg :: (String -> [String] -> [TypeDecl] -> [AFuncDecl a] -> [OpDecl] -> b)
+        -> AProg a -> b
+trAProg prog (AProg name imps types funcs ops) = prog name imps types funcs ops
+
+-- Selectors
+
+-- |get name from program
+aProgName :: AProg a -> String
+aProgName = trAProg (\name _ _ _ _ -> name)
+
+-- |get imports from program
+aProgImports :: AProg a -> [String]
+aProgImports = trAProg (\_ imps _ _ _ -> imps)
+
+-- |get type declarations from program
+aProgTypes :: AProg a -> [TypeDecl]
+aProgTypes = trAProg (\_ _ types _ _ -> types)
+
+-- |get functions from program
+aProgAFuncs :: AProg a -> [AFuncDecl a]
+aProgAFuncs = trAProg (\_ _ _ funcs _ -> funcs)
+
+-- |get infix operators from program
+aProgOps :: AProg a -> [OpDecl]
+aProgOps = trAProg (\_ _ _ _ ops -> ops)
+
+-- Update Operations
+
+-- |update program
+updAProg :: (String -> String) ->
+            ([String] -> [String]) ->
+            ([TypeDecl] -> [TypeDecl]) ->
+            ([AFuncDecl a] -> [AFuncDecl a]) ->
+            ([OpDecl] -> [OpDecl]) -> AProg a -> AProg a
+updAProg fn fi ft ff fo = trAProg prog
+ where
+  prog name imps types funcs ops
+    = AProg (fn name) (fi imps) (ft types) (ff funcs) (fo ops)
+
+-- |update name of program
+updAProgName :: Update (AProg a) String
+updAProgName f = updAProg f id id id id
+
+-- |update imports of program
+updAProgImports :: Update (AProg a) [String]
+updAProgImports f = updAProg id f id id id
+
+-- |update type declarations of program
+updAProgTypes :: Update (AProg a) [TypeDecl]
+updAProgTypes f = updAProg id id f id id
+
+-- |update functions of program
+updAProgAFuncs :: Update (AProg a) [AFuncDecl a]
+updAProgAFuncs f = updAProg id id id f id
+
+-- |update infix operators of program
+updAProgOps :: Update (AProg a) [OpDecl]
+updAProgOps = updAProg id id id id
+
+-- Auxiliary Functions
+
+-- |get all program variables (also from patterns)
+allVarsInAProg :: AProg a -> [(VarIndex, a)]
+allVarsInAProg = concatMap allVarsInAFunc . aProgAFuncs
+
+-- |lift transformation on expressions to program
+updAProgAExps :: Update (AProg a) (AExpr a)
+updAProgAExps = updAProgAFuncs . map . updAFuncBody
+
+-- |rename programs variables
+rnmAllVarsInAProg :: Update (AProg a) VarIndex
+rnmAllVarsInAProg = updAProgAFuncs . map . rnmAllVarsInAFunc
+
+-- |update all qualified names in program
+updQNamesInAProg :: Update (AProg a) QName
+updQNamesInAProg f = updAProg id id
+  (map (updQNamesInType f)) (map (updQNamesInAFunc f)) (map (updOpName f))
+
+-- |rename program (update name of and all qualified names in program)
+rnmAProg :: String -> AProg a -> AProg a
+rnmAProg name p = updAProgName (const name) (updQNamesInAProg rnm p)
+ where
+  rnm (m, n) | m == aProgName p = (name, n)
+             | otherwise = (m, n)
+
+-- AFuncDecl ------------------------------------------------------------------
+
+-- |transform function
+trAFunc :: (QName -> Int -> Visibility -> TypeExpr -> ARule a -> b) -> AFuncDecl a -> b
+trAFunc func (AFunc name arity vis t rule) = func name arity vis t rule
+
+-- Selectors
+
+-- |get name of function
+aFuncName :: AFuncDecl a -> QName
+aFuncName = trAFunc (\name _ _ _ _ -> name)
+
+-- |get arity of function
+aFuncArity :: AFuncDecl a -> Int
+aFuncArity = trAFunc (\_ arity _ _ _ -> arity)
+
+-- |get visibility of function
+aFuncVisibility :: AFuncDecl a -> Visibility
+aFuncVisibility = trAFunc (\_ _ vis _ _ -> vis)
+
+-- |get type of function
+aFuncType :: AFuncDecl a -> TypeExpr
+aFuncType = trAFunc (\_ _ _ t _ -> t)
+
+-- |get rule of function
+aFuncARule :: AFuncDecl a -> ARule a
+aFuncARule = trAFunc (\_ _ _ _ rule -> rule)
+
+-- Update Operations
+
+-- |update function
+updAFunc :: (QName -> QName) ->
+            (Int -> Int) ->
+            (Visibility -> Visibility) ->
+            (TypeExpr -> TypeExpr) ->
+            (ARule a -> ARule a) -> AFuncDecl a -> AFuncDecl a
+updAFunc fn fa fv ft fr = trAFunc func
+ where
+  func name arity vis t rule
+    = AFunc (fn name) (fa arity) (fv vis) (ft t) (fr rule)
+
+-- |update name of function
+updAFuncName :: Update (AFuncDecl a) QName
+updAFuncName f = updAFunc f id id id id
+
+-- |update arity of function
+updAFuncArity :: Update (AFuncDecl a) Int
+updAFuncArity f = updAFunc id f id id id
+
+-- |update visibility of function
+updAFuncVisibility :: Update (AFuncDecl a) Visibility
+updAFuncVisibility f = updAFunc id id f id id
+
+-- |update type of function
+updFuncType :: Update (AFuncDecl a) TypeExpr
+updFuncType f = updAFunc id id id f id
+
+-- |update rule of function
+updAFuncARule :: Update (AFuncDecl a) (ARule a)
+updAFuncARule = updAFunc id id id id
+
+-- Auxiliary Functions
+
+-- |is function public?
+isPublicAFunc :: AFuncDecl a -> Bool
+isPublicAFunc = isPublic . aFuncVisibility
+
+-- |is function externally defined?
+isExternal :: AFuncDecl a -> Bool
+isExternal = isARuleExternal . aFuncARule
+
+-- |get variable names in a function declaration
+allVarsInAFunc :: AFuncDecl a -> [(VarIndex, a)]
+allVarsInAFunc = allVarsInARule . aFuncARule
+
+-- |get arguments of function, if not externally defined
+aFuncArgs :: AFuncDecl a -> [(VarIndex, a)]
+aFuncArgs = aRuleArgs . aFuncARule
+
+-- |get body of function, if not externally defined
+aFuncBody :: AFuncDecl a -> AExpr a
+aFuncBody = aRuleBody . aFuncARule
+
+-- |get the right-hand-sides of a 'FuncDecl'
+aFuncRHS :: AFuncDecl a -> [AExpr a]
+aFuncRHS f | not (isExternal f) = orCase (aFuncBody f)
+           | otherwise = []
+ where
+  orCase e
+    | isAOr e = concatMap orCase (orExps e)
+    | isACase e = concatMap orCase (map aBranchAExpr (caseBranches e))
+    | otherwise = [e]
+
+-- |rename all variables in function
+rnmAllVarsInAFunc :: Update (AFuncDecl a) VarIndex
+rnmAllVarsInAFunc = updAFunc id id id id . rnmAllVarsInARule
+
+-- |update all qualified names in function
+updQNamesInAFunc :: Update (AFuncDecl a) QName
+updQNamesInAFunc f = updAFunc f id id (updQNamesInTypeExpr f) (updQNamesInARule f)
+
+-- |update arguments of function, if not externally defined
+updAFuncArgs :: Update (AFuncDecl a) [(VarIndex, a)]
+updAFuncArgs = updAFuncARule . updARuleArgs
+
+-- |update body of function, if not externally defined
+updAFuncBody :: Update (AFuncDecl a) (AExpr a)
+updAFuncBody = updAFuncARule . updARuleBody
+
+-- ARule ----------------------------------------------------------------------
+
+-- |transform rule
+trARule :: (a -> [(VarIndex, a)] -> AExpr a -> b) -> (a -> String -> b) -> ARule a -> b
+trARule rule _ (ARule a args e) = rule a args e
+trARule _ ext (AExternal a s) = ext a s
+
+-- Selectors
+
+-- |get rules annotation
+aRuleAnnot :: ARule a -> a
+aRuleAnnot = trARule (\a _ _ -> a) (\a _ -> a)
+
+-- |get rules arguments if it's not external
+aRuleArgs :: ARule a -> [(VarIndex, a)]
+aRuleArgs = trARule (\_ args _ -> args) undefined
+
+-- |get rules body if it's not external
+aRuleBody :: ARule a -> AExpr a
+aRuleBody = trARule (\_ _ e -> e) undefined
+
+-- |get rules external declaration
+aRuleExtDecl :: ARule a -> String
+aRuleExtDecl = trARule undefined (\_ s -> s)
+
+-- Test Operations
+
+-- |is rule external?
+isARuleExternal :: ARule a -> Bool
+isARuleExternal = trARule (\_ _ _ -> False) (\_ _ -> True)
+
+-- Update Operations
+
+-- |update rule
+updARule :: (a -> b) ->
+            ([(VarIndex, a)] -> [(VarIndex, b)]) ->
+            (AExpr a -> AExpr b) ->
+            (String -> String) -> ARule a -> ARule b
+updARule fannot fa fe fs = trARule rule ext
+ where
+  rule a args e = ARule (fannot a) (fa args) (fe e)
+  ext a s = AExternal (fannot a) (fs s)
+
+-- |update rules annotation
+updARuleAnnot :: Update (ARule a) a
+updARuleAnnot f = updARule f id id id
+
+-- |update rules arguments
+updARuleArgs :: Update (ARule a) [(VarIndex, a)]
+updARuleArgs f = updARule id f id id
+
+-- |update rules body
+updARuleBody :: Update (ARule a) (AExpr a)
+updARuleBody f = updARule id id f id
+
+-- |update rules external declaration
+updARuleExtDecl :: Update (ARule a) String
+updARuleExtDecl f = updARule id id id f
+
+-- Auxiliary Functions
+
+-- |get variable names in a functions rule
+allVarsInARule :: ARule a -> [(VarIndex, a)]
+allVarsInARule = trARule (\_ args body -> args ++ allVars body) (\_ _ -> [])
+
+-- |rename all variables in rule
+rnmAllVarsInARule :: Update (ARule a) VarIndex
+rnmAllVarsInARule f = updARule id (map (\(a, b) -> (f a, b))) (rnmAllVars f) id
+
+-- |update all qualified names in rule
+updQNamesInARule :: Update (ARule a) QName
+updQNamesInARule = updARuleBody . updQNames
+
+-- AExpr ----------------------------------------------------------------------
+
+-- Selectors
+
+-- |get annoation of an expression
+annot :: AExpr a -> a
+annot (AVar   a _    ) = a
+annot (ALit   a _    ) = a
+annot (AComb  a _ _ _) = a
+annot (ALet   a _ _  ) = a
+annot (AFree  a _ _  ) = a
+annot (AOr    a _ _  ) = a
+annot (ACase  a _ _ _) = a
+annot (ATyped a _ _  ) = a
+
+-- |get internal number of variable
+varNr :: AExpr a -> VarIndex
+varNr (AVar _ n) = n
+varNr _          = error "Curry.FlatCurry.Annotated.Goodies.varNr: no variable"
+
+-- |get literal if expression is literal expression
+literal :: AExpr a -> Literal
+literal (ALit _ l) = l
+literal _          = error "Curry.FlatCurry.Annotated.Goodies.literal: no literal"
+
+-- |get combination type of a combined expression
+combType :: AExpr a -> CombType
+combType (AComb _ ct _ _) = ct
+combType _                = error $ "Curry.FlatCurry.Annotated.Goodies.combType: " ++
+                                    "no combined expression"
+
+-- |get name of a combined expression
+combName :: AExpr a -> (QName, a)
+combName (AComb _ _ name _) = name
+combName _                  = error $ "Curry.FlatCurry.Annotated.Goodies.combName: " ++
+                                      "no combined expression"
+
+-- |get arguments of a combined expression
+combArgs :: AExpr a -> [AExpr a]
+combArgs (AComb _ _ _ args) = args
+combArgs _                  = error $ "Curry.FlatCurry.Annotated.Goodies.combArgs: " ++
+                                      "no combined expression"
+
+-- |get number of missing arguments if expression is combined
+missingCombArgs :: AExpr a -> Int
+missingCombArgs = missingArgs . combType
+  where
+  missingArgs :: CombType -> Int
+  missingArgs = trCombType 0 id 0 id
+
+-- |get indices of varoables in let declaration
+letBinds :: AExpr a -> [((VarIndex, a), AExpr a)]
+letBinds (ALet _ vs _) = vs
+letBinds _             = error $ "Curry.FlatCurry.Annotated.Goodies.letBinds: " ++
+                                 "no let expression"
+
+-- |get body of let declaration
+letBody :: AExpr a -> AExpr a
+letBody (ALet _ _ e) = e
+letBody _            = error $ "Curry.FlatCurry.Annotated.Goodies.letBody: " ++
+                               "no let expression"
+
+-- |get variable indices from declaration of free variables
+freeVars :: AExpr a -> [(VarIndex, a)]
+freeVars (AFree _ vs _) = vs
+freeVars _              = error $ "Curry.FlatCurry.Annotated.Goodies.freeVars: " ++
+                                  "no declaration of free variables"
+
+-- |get expression from declaration of free variables
+freeExpr :: AExpr a -> AExpr a
+freeExpr (AFree _ _ e) = e
+freeExpr _             = error $ "Curry.FlatCurry.Annotated.Goodies.freeExpr: " ++
+                                 "no declaration of free variables"
+
+-- |get expressions from or-expression
+orExps :: AExpr a -> [AExpr a]
+orExps (AOr _ e1 e2) = [e1, e2]
+orExps _             = error $ "Curry.FlatCurry.Annotated.Goodies.orExps: " ++
+                               "no or expression"
+
+-- |get case-type of case expression
+caseType :: AExpr a -> CaseType
+caseType (ACase _ ct _ _) = ct
+caseType _                = error $ "Curry.FlatCurry.Annotated.Goodies.caseType: " ++
+                                    "no case expression"
+
+-- |get scrutinee of case expression
+caseExpr :: AExpr a -> AExpr a
+caseExpr (ACase _ _ e _) = e
+caseExpr _               = error $ "Curry.FlatCurry.Annotated.Goodies.caseExpr: " ++
+                                   "no case expression"
+
+
+-- |get branch expressions from case expression
+caseBranches :: AExpr a -> [ABranchExpr a]
+caseBranches (ACase _ _ _ bs) = bs
+caseBranches _                = error
+  "Curry.FlatCurry.Annotated.Goodies.caseBranches: no case expression"
+
+-- Test Operations
+
+-- |is expression a variable?
+isAVar :: AExpr a -> Bool
+isAVar e = case e of
+  AVar _ _ -> True
+  _ -> False
+
+-- |is expression a literal expression?
+isALit :: AExpr a -> Bool
+isALit e = case e of
+  ALit _ _ -> True
+  _ -> False
+
+-- |is expression combined?
+isAComb :: AExpr a -> Bool
+isAComb e = case e of
+  AComb _ _ _ _ -> True
+  _ -> False
+
+-- |is expression a let expression?
+isALet :: AExpr a -> Bool
+isALet e = case e of
+  ALet _ _ _ -> True
+  _ -> False
+
+-- |is expression a declaration of free variables?
+isAFree :: AExpr a -> Bool
+isAFree e = case e of
+  AFree _ _ _ -> True
+  _ -> False
+
+-- |is expression an or-expression?
+isAOr :: AExpr a -> Bool
+isAOr e = case e of
+  AOr _ _ _ -> True
+  _ -> False
+
+-- |is expression a case expression?
+isACase :: AExpr a -> Bool
+isACase e = case e of
+  ACase _ _ _ _ -> True
+  _ -> False
+
+-- |transform expression
+trAExpr  :: (a -> VarIndex -> b)
+         -> (a -> Literal -> b)
+         -> (a -> CombType -> (QName, a) -> [b] -> b)
+         -> (a -> [((VarIndex, a), b)] -> b -> b)
+         -> (a -> [(VarIndex, a)] -> b -> b)
+         -> (a -> b -> b -> b)
+         -> (a -> CaseType -> b -> [c] -> b)
+         -> (APattern a -> b -> c)
+         -> (a -> b -> TypeExpr -> b)
+         -> AExpr a
+         -> b
+trAExpr var lit comb lt fr oR cas branch typed expr = case expr of
+  AVar a n             -> var a n
+  ALit a l             -> lit a l
+  AComb a ct name args -> comb a ct name (map f args)
+  ALet a bs e          -> lt a (map (\(v, x) -> (v, f x)) bs) (f e)
+  AFree a vs e         -> fr a vs (f e)
+  AOr a e1 e2          -> oR a (f e1) (f e2)
+  ACase a ct e bs      -> cas a ct (f e) (map (\ (ABranch p e') -> branch p (f e')) bs)
+  ATyped a e ty        -> typed a (f e) ty
+  where
+  f = trAExpr var lit comb lt fr oR cas branch typed
+
+-- |update all variables in given expression
+updVars :: (a -> VarIndex -> AExpr a) -> AExpr a -> AExpr a
+updVars var = trAExpr var ALit AComb ALet AFree AOr ACase ABranch ATyped
+
+-- |update all literals in given expression
+updLiterals :: (a -> Literal -> AExpr a) -> AExpr a -> AExpr a
+updLiterals lit = trAExpr AVar lit AComb ALet AFree AOr ACase ABranch ATyped
+
+-- |update all combined expressions in given expression
+updCombs :: (a -> CombType -> (QName, a) -> [AExpr a] -> AExpr a) -> AExpr a -> AExpr a
+updCombs comb = trAExpr AVar ALit comb ALet AFree AOr ACase ABranch ATyped
+
+-- |update all let expressions in given expression
+updLets :: (a -> [((VarIndex, a), AExpr a)] -> AExpr a -> AExpr a) -> AExpr a -> AExpr a
+updLets lt = trAExpr AVar ALit AComb lt AFree AOr ACase ABranch ATyped
+
+-- |update all free declarations in given expression
+updFrees :: (a -> [(VarIndex, a)] -> AExpr a -> AExpr a) -> AExpr a -> AExpr a
+updFrees fr = trAExpr AVar ALit AComb ALet fr AOr ACase ABranch ATyped
+
+-- |update all or expressions in given expression
+updOrs :: (a -> AExpr a -> AExpr a -> AExpr a) -> AExpr a -> AExpr a
+updOrs oR = trAExpr AVar ALit AComb ALet AFree oR ACase ABranch ATyped
+
+-- |update all case expressions in given expression
+updCases :: (a -> CaseType -> AExpr a -> [ABranchExpr a] -> AExpr a) -> AExpr a -> AExpr a
+updCases cas = trAExpr AVar ALit AComb ALet AFree AOr cas ABranch ATyped
+
+-- |update all case branches in given expression
+updBranches :: (APattern a -> AExpr a -> ABranchExpr a) -> AExpr a -> AExpr a
+updBranches branch = trAExpr AVar ALit AComb ALet AFree AOr ACase branch ATyped
+
+-- |update all typed expressions in given expression
+updTypeds :: (a -> AExpr a -> TypeExpr -> AExpr a) -> AExpr a -> AExpr a
+updTypeds = trAExpr AVar ALit AComb ALet AFree AOr ACase ABranch
+
+-- Auxiliary Functions
+
+-- |is expression a call of a function where all arguments are provided?
+isFuncCall :: AExpr a -> Bool
+isFuncCall e = isAComb e && isCombTypeFuncCall (combType e)
+
+-- |is expression a partial function call?
+isFuncPartCall :: AExpr a -> Bool
+isFuncPartCall e = isAComb e && isCombTypeFuncPartCall (combType e)
+
+-- |is expression a call of a constructor?
+isConsCall :: AExpr a -> Bool
+isConsCall e = isAComb e && isCombTypeConsCall (combType e)
+
+-- |is expression a partial constructor call?
+isConsPartCall :: AExpr a -> Bool
+isConsPartCall e = isAComb e && isCombTypeConsPartCall (combType e)
+
+-- |is expression fully evaluated?
+isGround :: AExpr a -> Bool
+isGround e
+  = case e of
+      AComb _ ConsCall _ args -> all isGround args
+      _ -> isALit e
+
+-- |get all variables (also pattern variables) in expression
+allVars :: AExpr a -> [(VarIndex, a)]
+allVars e = trAExpr var lit comb lt fr (const (.)) cas branch typ e []
+ where
+  var a v = (:) (v, a)
+  lit = const (const id)
+  comb _ _ _ = foldr (.) id
+  lt _ bs e' = e' . foldr (.) id (map (\(n,ns) -> (n:) . ns) bs)
+  fr _ vs e' = (vs++) . e'
+  cas _ _ e' bs = e' . foldr (.) id bs
+  branch pat e' = ((args pat)++) . e'
+  typ _ = const
+  args pat | isConsPattern pat = aPatArgs pat
+           | otherwise = []
+
+-- |rename all variables (also in patterns) in expression
+rnmAllVars :: Update (AExpr a) VarIndex
+rnmAllVars f = trAExpr var ALit AComb lt fr AOr ACase branch ATyped
+ where
+   var a = AVar a . f
+   lt a = ALet a . map (\((n, b), e) -> ((f n, b), e))
+   fr a = AFree a . map (\(b, c) -> (f b, c))
+   branch = ABranch . updAPatArgs (map (\(a, b) -> (f a, b)))
+
+-- |update all qualified names in expression
+updQNames :: Update (AExpr a) QName
+updQNames f = trAExpr AVar ALit comb ALet AFree AOr ACase branch ATyped
+ where
+  comb a ct (name, a') args = AComb a ct (f name, a') args
+  branch = ABranch . updAPatCons (\(q, a) -> (f q, a))
+
+-- ABranchExpr ----------------------------------------------------------------
+
+-- |transform branch expression
+trABranch :: (APattern a -> AExpr a -> b) -> ABranchExpr a -> b
+trABranch branch (ABranch pat e) = branch pat e
+
+-- Selectors
+
+-- |get pattern from branch expression
+aBranchAPattern :: ABranchExpr a -> APattern a
+aBranchAPattern = trABranch (\pat _ -> pat)
+
+-- |get expression from branch expression
+aBranchAExpr :: ABranchExpr a -> AExpr a
+aBranchAExpr = trABranch (\_ e -> e)
+
+-- Update Operations
+
+-- |update branch expression
+updABranch :: (APattern a -> APattern a) -> (AExpr a -> AExpr a) -> ABranchExpr a -> ABranchExpr a
+updABranch fp fe = trABranch branch
+ where
+  branch pat e = ABranch (fp pat) (fe e)
+
+-- |update pattern of branch expression
+updABranchAPattern :: Update (ABranchExpr a) (APattern a)
+updABranchAPattern f = updABranch f id
+
+-- |update expression of branch expression
+updABranchAExpr :: Update (ABranchExpr a) (AExpr a)
+updABranchAExpr = updABranch id
+
+-- APattern -------------------------------------------------------------------
+
+-- |transform pattern
+trAPattern :: (a -> (QName, a) -> [(VarIndex, a)] -> b) -> (a -> Literal -> b) -> APattern a -> b
+trAPattern pat _ (APattern a name args) = pat a name args
+trAPattern _ lpat (ALPattern a l) = lpat a l
+
+-- Selectors
+
+-- |get annotation from pattern
+aPatAnnot :: APattern a -> a
+aPatAnnot = trAPattern (\a _ _ -> a) (\a _ -> a)
+
+-- |get name from constructor pattern
+aPatCons :: APattern a -> (QName, a)
+aPatCons = trAPattern (\_ name _ -> name) undefined
+
+-- |get arguments from constructor pattern
+aPatArgs :: APattern a -> [(VarIndex, a)]
+aPatArgs = trAPattern (\_ _ args -> args) undefined
+
+-- |get literal from literal pattern
+aPatLiteral :: APattern a -> Literal
+aPatLiteral = trAPattern undefined (const id)
+
+-- Test Operations
+
+-- |is pattern a constructor pattern?
+isConsPattern :: APattern a -> Bool
+isConsPattern = trAPattern (\_ _ _ -> True) (\_ _ -> False)
+
+-- Update Operations
+
+-- |update pattern
+updAPattern :: (a -> a) ->
+               ((QName, a) -> (QName, a)) ->
+               ([(VarIndex, a)] -> [(VarIndex, a)]) ->
+               (Literal -> Literal) -> APattern a -> APattern a
+updAPattern fannot fn fa fl = trAPattern pat lpat
+ where
+  pat a name args = APattern (fannot a) (fn name) (fa args)
+  lpat a l = ALPattern (fannot a) (fl l)
+
+-- |update annotation of pattern
+updAPatAnnot :: (a -> a) -> APattern a -> APattern a
+updAPatAnnot f = updAPattern f id id id
+
+-- |update constructors name of pattern
+updAPatCons :: ((QName, a) -> (QName, a)) -> APattern a -> APattern a
+updAPatCons f = updAPattern id f id id
+
+-- |update arguments of constructor pattern
+updAPatArgs :: ([(VarIndex, a)] -> [(VarIndex, a)]) -> APattern a -> APattern a
+updAPatArgs f = updAPattern id id f id
+
+-- |update literal of pattern
+updAPatLiteral :: (Literal -> Literal) -> APattern a -> APattern a
+updAPatLiteral f = updAPattern id id id f
+
+-- Auxiliary Functions
+
+-- |build expression from pattern
+aPatExpr :: APattern a -> AExpr a
+aPatExpr = trAPattern (\a name -> AComb a ConsCall name . map (uncurry (flip AVar))) ALit
diff --git a/src/Curry/FlatCurry/Annotated/Type.hs b/src/Curry/FlatCurry/Annotated/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/FlatCurry/Annotated/Type.hs
@@ -0,0 +1,132 @@
+{- |
+    Module      : $Header$
+    Description : Representation of annotated FlatCurry.
+    Copyright   : (c) 2016 - 2017 Finn Teegen
+    License     : BSD-3-clause
+
+    Maintainer  : fte@informatik.uni-kiel.de
+    Stability   : experimental
+    Portability : portable
+
+    TODO
+-}
+
+module Curry.FlatCurry.Annotated.Type
+  ( module Curry.FlatCurry.Annotated.Type
+  , module Curry.FlatCurry.Typeable
+  , module Curry.FlatCurry.Type
+  ) where
+
+import Data.Binary
+import Control.Monad
+
+import Curry.FlatCurry.Typeable
+import Curry.FlatCurry.Type ( QName, VarIndex, Visibility (..), TVarIndex
+                            , TypeDecl (..), Kind (..), OpDecl (..), Fixity (..)
+                            , TypeExpr (..), ConsDecl (..), NewConsDecl (..)
+                            , Literal (..), CombType (..), CaseType (..)
+                            )
+
+data AProg a = AProg String [String] [TypeDecl] [AFuncDecl a] [OpDecl]
+  deriving (Eq, Read, Show)
+
+data AFuncDecl a = AFunc QName Int Visibility TypeExpr (ARule a)
+  deriving (Eq, Read, Show)
+
+data ARule a
+  = ARule     a [(VarIndex, a)] (AExpr a)
+  | AExternal a String
+  deriving (Eq, Read, Show)
+
+data AExpr a
+  = AVar   a VarIndex
+  | ALit   a Literal
+  | AComb  a CombType (QName, a) [AExpr a]
+  | ALet   a [((VarIndex, a), AExpr a)] (AExpr a)
+  | AFree  a [(VarIndex, a)] (AExpr a)
+  | AOr    a (AExpr a) (AExpr a)
+  | ACase  a CaseType (AExpr a) [ABranchExpr a]
+  | ATyped a (AExpr a) TypeExpr
+  deriving (Eq, Read, Show)
+
+data ABranchExpr a = ABranch (APattern a) (AExpr a)
+  deriving (Eq, Read, Show)
+
+data APattern a
+  = APattern  a (QName, a) [(VarIndex, a)]
+  | ALPattern a Literal
+  deriving (Eq, Read, Show)
+
+instance Typeable a => Typeable (AExpr a) where
+  typeOf (AVar a _) = typeOf a
+  typeOf (ALit a _) = typeOf a
+  typeOf (AComb a _ _ _) = typeOf a
+  typeOf (ALet a _ _) = typeOf a
+  typeOf (AFree a _ _) = typeOf a
+  typeOf (AOr a _ _) = typeOf a
+  typeOf (ACase a _ _ _) = typeOf a
+  typeOf (ATyped a _ _) = typeOf a
+
+instance Typeable a => Typeable (APattern a) where
+  typeOf (APattern a _ _) = typeOf a
+  typeOf (ALPattern a _) = typeOf a
+
+instance Binary a => Binary (AProg a) where
+  put (AProg mid im tys fus ops) =
+    put mid >> put im >> put tys >> put fus >> put ops
+  get = AProg <$> get <*> get <*> get <*> get <*> get
+
+instance Binary a => Binary (AFuncDecl a) where
+  put (AFunc qid arity vis ty r) =
+    put qid >> put arity >> put vis >> put ty >> put r
+  get = AFunc <$> get <*> get <*> get <*> get <*> get
+
+instance Binary a => Binary (ARule a) where
+  put (ARule     a alts e) = putWord8 0 >> put a  >> put alts >> put e
+  put (AExternal ty n    ) = putWord8 1 >> put ty >> put n
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM3 ARule get get get
+      1 -> liftM2 AExternal get get
+      _ -> fail "Invalid encoding for TRule"
+
+instance Binary a => Binary (AExpr a) where
+  put (AVar a v) = putWord8 0 >> put a >> put v
+  put (ALit a l) = putWord8 1 >> put a >> put l
+  put (AComb a cty qid es) =
+    putWord8 2 >> put a >> put cty >> put qid >> put es
+  put (ALet  a bs e ) = putWord8 3 >> put a >> put bs >> put e
+  put (AFree a vs e ) = putWord8 4 >> put a >> put vs >> put e
+  put (AOr   a e1 e2) = putWord8 5 >> put a >> put e1 >> put e2
+  put (ACase a cty ty as) = putWord8 6 >> put a >> put cty >> put ty >> put as
+  put (ATyped a e ty) = putWord8 7 >> put a >> put e >> put ty
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 AVar get get
+      1 -> liftM2 ALit get get
+      2 -> liftM4 AComb get get get get
+      3 -> liftM3 ALet get get get
+      4 -> liftM3 AFree get get get
+      5 -> liftM3 AOr get get get
+      6 -> liftM4 ACase get get get get
+      7 -> liftM3 ATyped get get get
+      _ -> fail "Invalid encoding for TExpr"
+
+instance Binary a => Binary (ABranchExpr a) where
+  put (ABranch p e) = put p >> put e
+  get = liftM2 ABranch get get
+
+instance Binary a => Binary (APattern a) where
+  put (APattern  a qid vs) = putWord8 0 >> put a >> put qid >> put vs
+  put (ALPattern a l     ) = putWord8 1 >> put a >> put l
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM3 APattern get get get
+      1 -> liftM2 ALPattern get get
+      _ -> fail "Invalid encoding for TPattern"
diff --git a/src/Curry/FlatCurry/Files.hs b/src/Curry/FlatCurry/Files.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/FlatCurry/Files.hs
@@ -0,0 +1,68 @@
+{- |
+    Module      : $Header$
+    Description : Functions for reading and writing FlatCurry files
+    Copyright   : (c) 2014        Björn Peemöller
+                      2017        Finn Teegen
+    License     : BSD-3-clause
+
+    Maintainer  : bjp@informatik.uni-kiel.de
+    Stability   : experimental
+    Portability : portable
+
+    This module contains functions for reading and writing FlatCurry files.
+-}
+
+module Curry.FlatCurry.Files
+  ( readTypedFlatCurry, readFlatCurry, readFlatInterface
+  , writeFlatCurry, writeBinaryFlatCurry
+  ) where
+
+import Data.Binary           (Binary, encode)
+import Data.Char             (isSpace)
+
+import Curry.Files.Filenames (typedFlatName, flatName, flatIntName)
+import Curry.Files.PathUtils (writeModule, writeBinaryModule, readModule)
+
+import Curry.FlatCurry.Type  (Prog)
+import Curry.FlatCurry.Annotated.Type (AProg, TypeExpr)
+
+
+-- ---------------------------------------------------------------------------
+-- Functions for reading and writing FlatCurry terms
+-- ---------------------------------------------------------------------------
+
+-- |Reads an typed FlatCurry file (extension ".tfcy") and eventually
+-- returns the corresponding FlatCurry program term (type 'AProg').
+readTypedFlatCurry :: FilePath -> IO (Maybe (AProg TypeExpr))
+readTypedFlatCurry = readFlat . typedFlatName
+
+-- |Reads a FlatCurry file (extension ".fcy") and eventually returns the
+-- corresponding FlatCurry program term (type 'Prog').
+readFlatCurry :: FilePath -> IO (Maybe Prog)
+readFlatCurry = readFlat . flatName
+
+-- |Reads a FlatInterface file (extension @.fint@) and returns the
+-- corresponding term (type 'Prog') as a value of type 'Maybe'.
+readFlatInterface :: FilePath -> IO (Maybe Prog)
+readFlatInterface = readFlat . flatIntName
+
+-- |Reads a Flat file and returns the corresponding term (type 'Prog' or
+-- 'AProg') as a value of type 'Maybe'.
+-- Due to compatibility with PAKCS it is allowed to have a commentary
+-- at the beginning of the file enclosed in {- ... -}.
+readFlat :: Read a => FilePath -> IO (Maybe a)
+readFlat = fmap (fmap (read . skipComment)) . readModule where
+  skipComment s = case dropWhile isSpace s of
+      '{' : '-' : s' -> dropComment s'
+      s'             -> s'
+  dropComment ('-' : '}' : xs) = xs
+  dropComment (_ : xs)         = dropComment xs
+  dropComment []               = []
+
+-- |Writes a FlatCurry program term into a file.
+writeFlatCurry :: Show a => FilePath -> a -> IO ()
+writeFlatCurry fn = writeModule fn . show
+
+-- |Writes a FlatCurry program term into a normal and a binary file.
+writeBinaryFlatCurry :: Binary a => FilePath -> a -> IO ()
+writeBinaryFlatCurry fn = writeBinaryModule fn . encode
diff --git a/src/Curry/FlatCurry/Goodies.hs b/src/Curry/FlatCurry/Goodies.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/FlatCurry/Goodies.hs
@@ -0,0 +1,1037 @@
+{- |
+    Module      : $Header$
+    Description : Utility functions for working with FlatCurry.
+    Copyright   : (c) Sebastian Fischer 2006
+                      Björn Peemöller 2011
+    License     : BSD-3-clause
+
+    Maintainer  : bjp@informatik.uni-kiel.de
+    Stability   : experimental
+    Portability : portable
+
+    This library provides selector functions, test and update operations
+    as well as some useful auxiliary functions for FlatCurry data terms.
+    Most of the provided functions are based on general transformation
+    functions that replace constructors with user-defined functions. For
+    recursive datatypes the transformations are defined inductively over the
+    term structure. This is quite usual for transformations on FlatCurry
+    terms, so the provided functions can be used to implement specific
+    transformations without having to explicitly state the recursion.
+    Essentially, the tedious part of such transformations - descend in fairly
+    complex term structures - is abstracted away, which hopefully makes the
+    code more clear and brief.
+-}
+
+module Curry.FlatCurry.Goodies where
+
+import Curry.FlatCurry.Type
+
+-- |Update of a type's component
+type Update a b = (b -> b) -> a -> a
+
+-- Prog ----------------------------------------------------------------------
+
+-- |transform program
+trProg :: (String -> [String] -> [TypeDecl] -> [FuncDecl] -> [OpDecl] -> a)
+          -> Prog -> a
+trProg prog (Prog name imps types funcs ops) = prog name imps types funcs ops
+
+-- Selectors
+
+-- |get name from program
+progName :: Prog -> String
+progName = trProg (\name _ _ _ _ -> name)
+
+-- |get imports from program
+progImports :: Prog -> [String]
+progImports = trProg (\_ imps _ _ _ -> imps)
+
+-- |get type declarations from program
+progTypes :: Prog -> [TypeDecl]
+progTypes = trProg (\_ _ types _ _ -> types)
+
+-- |get functions from program
+progFuncs :: Prog -> [FuncDecl]
+progFuncs = trProg (\_ _ _ funcs _ -> funcs)
+
+-- |get infix operators from program
+progOps :: Prog -> [OpDecl]
+progOps = trProg (\_ _ _ _ ops -> ops)
+
+-- Update Operations
+
+-- |update program
+updProg :: (String -> String)         ->
+           ([String] -> [String])     ->
+           ([TypeDecl] -> [TypeDecl]) ->
+           ([FuncDecl] -> [FuncDecl]) ->
+           ([OpDecl] -> [OpDecl])     -> Prog -> Prog
+updProg fn fi ft ff fo = trProg prog
+ where
+  prog name imps types funcs ops
+    = Prog (fn name) (fi imps) (ft types) (ff funcs) (fo ops)
+
+-- |update name of program
+updProgName :: Update Prog String
+updProgName f = updProg f id id id id
+
+-- |update imports of program
+updProgImports :: Update Prog [String]
+updProgImports f = updProg id f id id id
+
+-- |update type declarations of program
+updProgTypes :: Update Prog [TypeDecl]
+updProgTypes f = updProg id id f id id
+
+-- |update functions of program
+updProgFuncs :: Update Prog [FuncDecl]
+updProgFuncs f = updProg id id id f id
+
+-- |update infix operators of program
+updProgOps :: Update Prog [OpDecl]
+updProgOps = updProg id id id id
+
+-- Auxiliary Functions
+
+-- |get all program variables (also from patterns)
+allVarsInProg :: Prog -> [VarIndex]
+allVarsInProg = concatMap allVarsInFunc . progFuncs
+
+-- |lift transformation on expressions to program
+updProgExps :: Update Prog Expr
+updProgExps = updProgFuncs . map . updFuncBody
+
+-- |rename programs variables
+rnmAllVarsInProg :: Update Prog VarIndex
+rnmAllVarsInProg = updProgFuncs . map . rnmAllVarsInFunc
+
+-- |update all qualified names in program
+updQNamesInProg :: Update Prog QName
+updQNamesInProg f = updProg id id
+  (map (updQNamesInType f)) (map (updQNamesInFunc f)) (map (updOpName f))
+
+-- |rename program (update name of and all qualified names in program)
+rnmProg :: String -> Prog -> Prog
+rnmProg name p = updProgName (const name) (updQNamesInProg rnm p)
+ where
+  rnm (m,n) | m==progName p = (name,n)
+            | otherwise = (m,n)
+
+-- TypeDecl ------------------------------------------------------------------
+
+-- Selectors
+
+-- |transform type declaration
+trType :: (QName -> Visibility -> [TVarWithKind] -> [ConsDecl]  -> a) ->
+          (QName -> Visibility -> [TVarWithKind] -> TypeExpr    -> a) ->
+          (QName -> Visibility -> [TVarWithKind] -> NewConsDecl -> a) -> TypeDecl -> a
+trType typ _ _ (Type name vis params cs) = typ name vis params cs
+trType _ typesyn _ (TypeSyn name vis params syn) = typesyn name vis params syn
+trType _ _ newtyp (TypeNew name vis params nc) = newtyp name vis params nc
+
+-- |get name of type declaration
+typeName :: TypeDecl -> QName
+typeName = trType (\name _ _ _ -> name) (\name _ _ _ -> name) (\name _ _ _ -> name)
+
+-- |get visibility of type declaration
+typeVisibility :: TypeDecl -> Visibility
+typeVisibility = trType (\_ vis _ _ -> vis) (\_ vis _ _ -> vis) (\_ vis _ _ -> vis)
+
+-- |get type parameters of type declaration
+typeParams :: TypeDecl -> [TVarWithKind]
+typeParams = trType (\_ _ params _ -> params) (\_ _ params _ -> params) (\_ _ params _ -> params)
+
+-- |get constructor declarations from type declaration
+typeConsDecls :: TypeDecl -> [ConsDecl]
+typeConsDecls = trType (\_ _ _ cs -> cs)
+                       (error "Curry.FlatCurry.Goodies: type synonym")
+                       (error "Curry.FlatCurry.Goodies: newtype")
+
+-- |get synonym of type declaration
+typeSyn :: TypeDecl -> TypeExpr
+typeSyn = trType undefined (\_ _ _ syn -> syn) undefined
+
+-- |is type declaration a type synonym?
+isTypeSyn :: TypeDecl -> Bool
+isTypeSyn = trType (\_ _ _ _ -> False) (\_ _ _ _ -> True) (\_ _ _ _ -> False)
+
+-- | is type declaration declaring a regular type?
+isDataTypeDecl :: TypeDecl -> Bool
+isDataTypeDecl = trType (\_ _ _ cs -> not (null cs)) (\_ _ _ _ -> False) (\_ _ _ _ -> False)
+
+-- | is type declaration declaring an external type?
+isExternalType :: TypeDecl -> Bool
+isExternalType = trType (\_ _ _ cs -> null cs) (\_ _ _ _ -> False) (\_ _ _ _ -> False)
+
+-- |is type declaration a newtype?
+isNewtype :: TypeDecl -> Bool
+isNewtype = trType (\_ _ _ _ -> False) (\_ _ _ _ -> False) (\_ _ _ _ -> False)
+
+-- |Is the 'TypeDecl' public?
+isPublicType :: TypeDecl -> Bool
+isPublicType = (== Public) . typeVisibility
+
+-- Update Operations
+
+-- |update type declaration
+updType :: (QName -> QName) ->
+           (Visibility -> Visibility) ->
+           ([TVarWithKind] -> [TVarWithKind]) ->
+           ([ConsDecl] -> [ConsDecl]) ->
+           (NewConsDecl -> NewConsDecl) ->
+           (TypeExpr -> TypeExpr)     -> TypeDecl -> TypeDecl
+updType fn fv fp fc fnc fs = trType typ typesyn newtyp
+ where
+  typ name vis params cs = Type (fn name) (fv vis) (fp params) (fc cs)
+  newtyp name vis params nc = TypeNew (fn name) (fv vis) (fp params) (fnc nc)
+  typesyn name vis params syn = TypeSyn (fn name) (fv vis) (fp params) (fs syn)
+
+-- |update name of type declaration
+updTypeName :: Update TypeDecl QName
+updTypeName f = updType f id id id id id
+
+-- |update visibility of type declaration
+updTypeVisibility :: Update TypeDecl Visibility
+updTypeVisibility f = updType id f id id id id
+
+-- |update type parameters of type declaration
+updTypeParams :: Update TypeDecl [TVarWithKind]
+updTypeParams f = updType id id f id id id
+
+-- |update constructor declarations of type declaration
+updTypeConsDecls :: Update TypeDecl [ConsDecl]
+updTypeConsDecls f = updType id id id f id id
+
+-- |update constructor declarations of newtype declaration
+updTypeNewConsDecls :: Update TypeDecl NewConsDecl
+updTypeNewConsDecls f = updType id id id id f id
+
+-- |update synonym of type declaration
+updTypeSynonym :: Update TypeDecl TypeExpr
+updTypeSynonym = updType id id id id id
+
+-- Auxiliary Functions
+
+-- |update all qualified names in type declaration
+updQNamesInType :: Update TypeDecl QName
+updQNamesInType f
+  = updType f id id (map (updQNamesInConsDecl f)) (updQNamesInNewConsDecl f)
+            (updQNamesInTypeExpr f)
+
+-- ConsDecl ------------------------------------------------------------------
+
+-- Selectors
+
+-- |transform constructor declaration
+trCons :: (QName -> Int -> Visibility -> [TypeExpr] -> a) -> ConsDecl -> a
+trCons cons (Cons name arity vis args) = cons name arity vis args
+
+-- |get name of constructor declaration
+consName :: ConsDecl -> QName
+consName = trCons (\name _ _ _ -> name)
+
+-- |get arity of constructor declaration
+consArity :: ConsDecl -> Int
+consArity = trCons (\_ arity _ _ -> arity)
+
+-- |get visibility of constructor declaration
+consVisibility :: ConsDecl -> Visibility
+consVisibility = trCons (\_ _ vis _ -> vis)
+
+-- |Is the constructor declaration public?
+isPublicCons :: ConsDecl -> Bool
+isPublicCons = isPublic . consVisibility
+
+-- |get arguments of constructor declaration
+consArgs :: ConsDecl -> [TypeExpr]
+consArgs = trCons (\_ _ _ args -> args)
+
+-- Update Operations
+
+-- |update constructor declaration
+updCons :: (QName -> QName) ->
+           (Int -> Int) ->
+           (Visibility -> Visibility) ->
+           ([TypeExpr] -> [TypeExpr]) -> ConsDecl -> ConsDecl
+updCons fn fa fv fas = trCons cons
+ where
+  cons name arity vis args = Cons (fn name) (fa arity) (fv vis) (fas args)
+
+-- |update name of constructor declaration
+updConsName :: Update ConsDecl QName
+updConsName f = updCons f id id id
+
+-- |update arity of constructor declaration
+updConsArity :: Update ConsDecl Int
+updConsArity f = updCons id f id id
+
+-- |update visibility of constructor declaration
+updConsVisibility :: Update ConsDecl Visibility
+updConsVisibility f = updCons id id f id
+
+-- |update arguments of constructor declaration
+updConsArgs :: Update ConsDecl [TypeExpr]
+updConsArgs = updCons id id id
+
+-- Auxiliary Functions
+
+-- |update all qualified names in constructor declaration
+updQNamesInConsDecl :: Update ConsDecl QName
+updQNamesInConsDecl f = updCons f id id (map (updQNamesInTypeExpr f))
+
+
+-- NewConsDecl ------------------------------------------------------------------
+
+-- Selectors
+
+-- |transform newtype constructor declaration
+trNewCons :: (QName -> Visibility -> TypeExpr -> a) -> NewConsDecl -> a
+trNewCons cons (NewCons name vis arg) = cons name vis arg
+
+-- |get name of new constructor declaration
+newConsName :: NewConsDecl -> QName
+newConsName = trNewCons (\name _ _ -> name)
+
+-- |get visibility of new constructor declaration
+newConsVisibility :: NewConsDecl -> Visibility
+newConsVisibility = trNewCons (\_ vis _ -> vis)
+
+-- |Is the new constructor declaration public?
+isPublicNewCons :: ConsDecl -> Bool
+isPublicNewCons = isPublic . consVisibility
+
+-- |get argument of new constructor declaration
+newConsArg :: NewConsDecl -> TypeExpr
+newConsArg = trNewCons (\_ _ arg -> arg)
+
+-- Update Operations
+
+-- |update new constructor declaration
+updNewCons :: (QName -> QName) ->
+              (Visibility -> Visibility) ->
+              (TypeExpr -> TypeExpr) -> NewConsDecl -> NewConsDecl
+updNewCons fn fv fas = trNewCons cons
+ where
+  cons name vis args = NewCons (fn name) (fv vis) (fas args)
+
+-- |update name of new constructor declaration
+updNewConsName :: Update NewConsDecl QName
+updNewConsName f = updNewCons f id id
+
+-- |update visibility of new constructor declaration
+updNewConsVisibility :: Update NewConsDecl Visibility
+updNewConsVisibility f = updNewCons id f id
+
+-- |update argument of new constructor declaration
+updNewConsArg :: Update NewConsDecl TypeExpr
+updNewConsArg = updNewCons id id
+
+-- Auxiliary Functions
+
+-- |update all qualified names in new constructor declaration
+updQNamesInNewConsDecl :: Update NewConsDecl QName
+updQNamesInNewConsDecl f = updNewCons f id (updQNamesInTypeExpr f)
+
+-- TypeExpr ------------------------------------------------------------------
+
+-- Selectors
+
+-- |get index from type variable
+tVarIndex :: TypeExpr -> TVarIndex
+tVarIndex (TVar n) = n
+tVarIndex _        = error $ "Curry.FlatCurry.Goodies.tvarIndex: " ++
+                             "no type variable"
+
+-- |get domain from functional type
+domain :: TypeExpr -> TypeExpr
+domain (FuncType dom _) = dom
+domain _                = error $ "Curry.FlatCurry.Goodies.domain: " ++
+                                  "no function type"
+
+-- |get range from functional type
+range :: TypeExpr -> TypeExpr
+range (FuncType _ ran) = ran
+range _                = error $ "Curry.FlatCurry.Goodies.range: " ++
+                                  "no function type"
+
+-- |get name from constructed type
+tConsName :: TypeExpr -> QName
+tConsName (TCons name _) = name
+tConsName _              = error $ "Curry.FlatCurry.Goodies.tConsName: " ++
+                                   "no constructor type"
+
+-- |get arguments from constructed type
+tConsArgs :: TypeExpr -> [TypeExpr]
+tConsArgs (TCons _ args) = args
+tConsArgs _              = error $ "Curry.FlatCurry.Goodies.tConsArgs: " ++
+                                   "no constructor type"
+
+-- |transform type expression
+trTypeExpr :: (TVarIndex -> a) ->
+              (QName -> [a] -> a) ->
+              (a -> a -> a) ->
+              ([TVarWithKind] -> a -> a) -> TypeExpr -> a
+trTypeExpr tvar _ _ _ (TVar t) = tvar t
+trTypeExpr tvar tcons functype foralltype (TCons name args)
+  = tcons name (map (trTypeExpr tvar tcons functype foralltype) args)
+trTypeExpr tvar tcons functype foralltype (FuncType from to)
+  = functype (f from) (f to)
+ where
+  f = trTypeExpr tvar tcons functype foralltype
+trTypeExpr tvar tcons functype foralltype (ForallType ns t)
+  = foralltype ns (trTypeExpr tvar tcons functype foralltype t)
+
+-- Test Operations
+
+-- |is type expression a type variable?
+isTVar :: TypeExpr -> Bool
+isTVar = trTypeExpr (\_ -> True) (\_ _ -> False) (\_ _ -> False) (\_ _ -> False)
+
+-- |is type declaration a constructed type?
+isTCons :: TypeExpr -> Bool
+isTCons
+  = trTypeExpr (\_ -> False) (\_ _ -> True) (\_ _ -> False) (\_ _ -> False)
+
+-- |is type declaration a functional type?
+isFuncType :: TypeExpr -> Bool
+isFuncType
+  = trTypeExpr (\_ -> False) (\_ _ -> False) (\_ _ -> True) (\_ _ -> False)
+
+-- |is type declaration a forall type?
+isForallType :: TypeExpr -> Bool
+isForallType
+  = trTypeExpr (\_ -> False) (\_ _ -> False) (\_ _ -> False) (\_ _ -> True)
+
+-- Update Operations
+
+-- |update all type variables
+updTVars :: (TVarIndex -> TypeExpr) -> TypeExpr -> TypeExpr
+updTVars tvar = trTypeExpr tvar TCons FuncType ForallType
+
+-- |update all type constructors
+updTCons :: (QName -> [TypeExpr] -> TypeExpr) -> TypeExpr -> TypeExpr
+updTCons tcons = trTypeExpr TVar tcons FuncType ForallType
+
+-- |update all functional types
+updFuncTypes :: (TypeExpr -> TypeExpr -> TypeExpr) -> TypeExpr -> TypeExpr
+updFuncTypes functype = trTypeExpr TVar TCons functype ForallType
+
+-- |update all forall types
+updForallTypes :: ([TVarWithKind] -> TypeExpr -> TypeExpr) -> TypeExpr -> TypeExpr
+updForallTypes = trTypeExpr TVar TCons FuncType
+
+-- Auxiliary Functions
+
+-- |get argument types from functional type
+argTypes :: TypeExpr -> [TypeExpr]
+argTypes (TVar _) = []
+argTypes (TCons _ _) = []
+argTypes (FuncType dom ran) = dom : argTypes ran
+argTypes (ForallType _ _) = []
+
+-- |Compute the arity of a 'TypeExpr'
+typeArity :: TypeExpr -> Int
+typeArity = length . argTypes
+
+-- |get result type from (nested) functional type
+resultType :: TypeExpr -> TypeExpr
+resultType (TVar n) = TVar n
+resultType (TCons name args) = TCons name args
+resultType (FuncType _ ran) = resultType ran
+resultType (ForallType ns t) = ForallType ns t
+
+-- |get indexes of all type variables
+allVarsInTypeExpr :: TypeExpr -> [TVarIndex]
+allVarsInTypeExpr = trTypeExpr pure (const concat) (++) ((++) . map fst)
+
+-- |yield the list of all contained type constructors
+allTypeCons :: TypeExpr -> [QName]
+allTypeCons (TVar _) = []
+allTypeCons (TCons name args) = name : concatMap allTypeCons args
+allTypeCons (FuncType t1 t2) = allTypeCons t1 ++ allTypeCons t2
+allTypeCons (ForallType _ t) = allTypeCons t
+
+-- |rename variables in type expression
+rnmAllVarsInTypeExpr :: (TVarIndex -> TVarIndex) -> TypeExpr -> TypeExpr
+rnmAllVarsInTypeExpr f = updTVars (TVar . f)
+
+-- |update all qualified names in type expression
+updQNamesInTypeExpr :: (QName -> QName) -> TypeExpr -> TypeExpr
+updQNamesInTypeExpr f = updTCons (\name args -> TCons (f name) args)
+
+-- OpDecl --------------------------------------------------------------------
+
+-- |transform operator declaration
+trOp :: (QName -> Fixity -> Integer -> a) -> OpDecl -> a
+trOp op (Op name fix prec) = op name fix prec
+
+-- Selectors
+
+-- |get name from operator declaration
+opName :: OpDecl -> QName
+opName = trOp (\name _ _ -> name)
+
+-- |get fixity of operator declaration
+opFixity :: OpDecl -> Fixity
+opFixity = trOp (\_ fix _ -> fix)
+
+-- |get precedence of operator declaration
+opPrecedence :: OpDecl -> Integer
+opPrecedence = trOp (\_ _ prec -> prec)
+
+-- Update Operations
+
+-- |update operator declaration
+updOp :: (QName -> QName) ->
+         (Fixity -> Fixity) ->
+         (Integer -> Integer) -> OpDecl -> OpDecl
+updOp fn ff fp = trOp op
+ where op name fix prec = Op (fn name) (ff fix) (fp prec)
+
+-- |update name of operator declaration
+updOpName :: Update OpDecl QName
+updOpName f = updOp f id id
+
+-- |update fixity of operator declaration
+updOpFixity :: Update OpDecl Fixity
+updOpFixity f = updOp id f id
+
+-- |update precedence of operator declaration
+updOpPrecedence :: Update OpDecl Integer
+updOpPrecedence = updOp id id
+
+-- FuncDecl ------------------------------------------------------------------
+
+-- |transform function
+trFunc :: (QName -> Int -> Visibility -> TypeExpr -> Rule -> a) -> FuncDecl -> a
+trFunc func (Func name arity vis t rule) = func name arity vis t rule
+
+-- Selectors
+
+-- |get name of function
+funcName :: FuncDecl -> QName
+funcName = trFunc (\name _ _ _ _ -> name)
+
+-- |get arity of function
+funcArity :: FuncDecl -> Int
+funcArity = trFunc (\_ arity _ _ _ -> arity)
+
+-- |get visibility of function
+funcVisibility :: FuncDecl -> Visibility
+funcVisibility = trFunc (\_ _ vis _ _ -> vis)
+
+-- |get type of function
+funcType :: FuncDecl -> TypeExpr
+funcType = trFunc (\_ _ _ t _ -> t)
+
+-- |get rule of function
+funcRule :: FuncDecl -> Rule
+funcRule = trFunc (\_ _ _ _ rule -> rule)
+
+-- Update Operations
+
+-- |update function
+updFunc :: (QName -> QName) ->
+           (Int -> Int) ->
+           (Visibility -> Visibility) ->
+           (TypeExpr -> TypeExpr) ->
+           (Rule -> Rule)             -> FuncDecl -> FuncDecl
+updFunc fn fa fv ft fr = trFunc func
+ where
+  func name arity vis t rule
+    = Func (fn name) (fa arity) (fv vis) (ft t) (fr rule)
+
+-- |update name of function
+updFuncName :: Update FuncDecl QName
+updFuncName f = updFunc f id id id id
+
+-- |update arity of function
+updFuncArity :: Update FuncDecl Int
+updFuncArity f = updFunc id f id id id
+
+-- |update visibility of function
+updFuncVisibility :: Update FuncDecl Visibility
+updFuncVisibility f = updFunc id id f id id
+
+-- |update type of function
+updFuncType :: Update FuncDecl TypeExpr
+updFuncType f = updFunc id id id f id
+
+-- |update rule of function
+updFuncRule :: Update FuncDecl Rule
+updFuncRule = updFunc id id id id
+
+-- Auxiliary Functions
+
+-- |is function public?
+isPublicFunc :: FuncDecl -> Bool
+isPublicFunc = isPublic . funcVisibility
+
+-- |is function externally defined?
+isExternal :: FuncDecl -> Bool
+isExternal = isRuleExternal . funcRule
+
+-- |get variable names in a function declaration
+allVarsInFunc :: FuncDecl -> [VarIndex]
+allVarsInFunc = allVarsInRule . funcRule
+
+-- |get arguments of function, if not externally defined
+funcArgs :: FuncDecl -> [VarIndex]
+funcArgs = ruleArgs . funcRule
+
+-- |get body of function, if not externally defined
+funcBody :: FuncDecl -> Expr
+funcBody = ruleBody . funcRule
+
+-- |get the right-hand-sides of a 'FuncDecl'
+funcRHS :: FuncDecl -> [Expr]
+funcRHS f | not (isExternal f) = orCase (funcBody f)
+          | otherwise = []
+ where
+  orCase e
+    | isOr e = concatMap orCase (orExps e)
+    | isCase e = concatMap orCase (map branchExpr (caseBranches e))
+    | otherwise = [e]
+
+-- |rename all variables in function
+rnmAllVarsInFunc :: Update FuncDecl VarIndex
+rnmAllVarsInFunc = updFunc id id id id . rnmAllVarsInRule
+
+-- |update all qualified names in function
+updQNamesInFunc :: Update FuncDecl QName
+updQNamesInFunc f = updFunc f id id (updQNamesInTypeExpr f) (updQNamesInRule f)
+
+-- |update arguments of function, if not externally defined
+updFuncArgs :: Update FuncDecl [VarIndex]
+updFuncArgs = updFuncRule . updRuleArgs
+
+-- |update body of function, if not externally defined
+updFuncBody :: Update FuncDecl Expr
+updFuncBody = updFuncRule . updRuleBody
+
+-- Rule ----------------------------------------------------------------------
+
+-- |transform rule
+trRule :: ([VarIndex] -> Expr -> a) -> (String -> a) -> Rule -> a
+trRule rule _ (Rule args e) = rule args e
+trRule _ ext (External s) = ext s
+
+-- Selectors
+
+-- |get rules arguments if it's not external
+ruleArgs :: Rule -> [VarIndex]
+ruleArgs = trRule (\args _ -> args) undefined
+
+-- |get rules body if it's not external
+ruleBody :: Rule -> Expr
+ruleBody = trRule (\_ e -> e) undefined
+
+-- |get rules external declaration
+ruleExtDecl :: Rule -> String
+ruleExtDecl = trRule undefined id
+
+-- Test Operations
+
+-- |is rule external?
+isRuleExternal :: Rule -> Bool
+isRuleExternal = trRule (\_ _ -> False) (\_ -> True)
+
+-- Update Operations
+
+-- |update rule
+updRule :: ([VarIndex] -> [VarIndex]) ->
+           (Expr -> Expr) ->
+           (String -> String) -> Rule -> Rule
+updRule fa fe fs = trRule rule ext
+ where
+  rule args e = Rule (fa args) (fe e)
+  ext s = External (fs s)
+
+-- |update rules arguments
+updRuleArgs :: Update Rule [VarIndex]
+updRuleArgs f = updRule f id id
+
+-- |update rules body
+updRuleBody :: Update Rule Expr
+updRuleBody f = updRule id f id
+
+-- |update rules external declaration
+updRuleExtDecl :: Update Rule String
+updRuleExtDecl f = updRule id id f
+
+-- Auxiliary Functions
+
+-- |get variable names in a functions rule
+allVarsInRule :: Rule -> [VarIndex]
+allVarsInRule = trRule (\args body -> args ++ allVars body) (\_ -> [])
+
+-- |rename all variables in rule
+rnmAllVarsInRule :: Update Rule VarIndex
+rnmAllVarsInRule f = updRule (map f) (rnmAllVars f) id
+
+-- |update all qualified names in rule
+updQNamesInRule :: Update Rule QName
+updQNamesInRule = updRuleBody . updQNames
+
+-- CombType ------------------------------------------------------------------
+
+-- |transform combination type
+trCombType :: a -> (Int -> a) -> a -> (Int -> a) -> CombType -> a
+trCombType fc _ _ _ FuncCall = fc
+trCombType _ fpc _ _ (FuncPartCall n) = fpc n
+trCombType _ _ cc _ ConsCall = cc
+trCombType _ _ _ cpc (ConsPartCall n) = cpc n
+
+-- Test Operations
+
+-- |is type of combination FuncCall?
+isCombTypeFuncCall :: CombType -> Bool
+isCombTypeFuncCall = trCombType True (\_ -> False) False (\_ -> False)
+
+-- |is type of combination FuncPartCall?
+isCombTypeFuncPartCall :: CombType -> Bool
+isCombTypeFuncPartCall = trCombType False (\_ -> True) False (\_ -> False)
+
+-- |is type of combination ConsCall?
+isCombTypeConsCall :: CombType -> Bool
+isCombTypeConsCall = trCombType False (\_ -> False) True (\_ -> False)
+
+-- |is type of combination ConsPartCall?
+isCombTypeConsPartCall :: CombType -> Bool
+isCombTypeConsPartCall = trCombType False (\_ -> False) False (\_ -> True)
+
+-- Expr ----------------------------------------------------------------------
+
+-- Selectors
+
+-- |get internal number of variable
+varNr :: Expr -> VarIndex
+varNr (Var n) = n
+varNr _       = error "Curry.FlatCurry.Goodies.varNr: no variable"
+
+-- |get literal if expression is literal expression
+literal :: Expr -> Literal
+literal (Lit l) = l
+literal _       = error "Curry.FlatCurry.Goodies.literal: no literal"
+
+-- |get combination type of a combined expression
+combType :: Expr -> CombType
+combType (Comb ct _ _) = ct
+combType _             = error $ "Curry.FlatCurry.Goodies.combType: " ++
+                                 "no combined expression"
+
+-- |get name of a combined expression
+combName :: Expr -> QName
+combName (Comb _ name _) = name
+combName _               = error $ "Curry.FlatCurry.Goodies.combName: " ++
+                                 "no combined expression"
+
+-- |get arguments of a combined expression
+combArgs :: Expr -> [Expr]
+combArgs (Comb _ _ args) = args
+combArgs _               = error $ "Curry.FlatCurry.Goodies.combArgs: " ++
+                                 "no combined expression"
+
+-- |get number of missing arguments if expression is combined
+missingCombArgs :: Expr -> Int
+missingCombArgs = missingArgs . combType
+  where
+  missingArgs :: CombType -> Int
+  missingArgs = trCombType 0 id 0 id
+
+-- |get indices of varoables in let declaration
+letBinds :: Expr -> [(VarIndex,Expr)]
+letBinds (Let vs _) = vs
+letBinds _          = error $ "Curry.FlatCurry.Goodies.letBinds: " ++
+                              "no let expression"
+
+-- |get body of let declaration
+letBody :: Expr -> Expr
+letBody (Let _ e) = e
+letBody _         = error $ "Curry.FlatCurry.Goodies.letBody: " ++
+                              "no let expression"
+
+-- |get variable indices from declaration of free variables
+freeVars :: Expr -> [VarIndex]
+freeVars (Free vs _) = vs
+freeVars _           = error $ "Curry.FlatCurry.Goodies.freeVars: " ++
+                               "no declaration of free variables"
+
+-- |get expression from declaration of free variables
+freeExpr :: Expr -> Expr
+freeExpr (Free _ e) = e
+freeExpr _           = error $ "Curry.FlatCurry.Goodies.freeExpr: " ++
+                               "no declaration of free variables"
+
+-- |get expressions from or-expression
+orExps :: Expr -> [Expr]
+orExps (Or e1 e2) = [e1,e2]
+orExps _          = error $ "Curry.FlatCurry.Goodies.orExps: " ++
+                            "no or expression"
+
+-- |get case-type of case expression
+caseType :: Expr -> CaseType
+caseType (Case ct _ _) = ct
+caseType _               = error $ "Curry.FlatCurry.Goodies.caseType: " ++
+                                   "no case expression"
+
+-- |get scrutinee of case expression
+caseExpr :: Expr -> Expr
+caseExpr (Case _ e _) = e
+caseExpr _              = error $ "Curry.FlatCurry.Goodies.caseExpr: " ++
+                                  "no case expression"
+
+
+-- |get branch expressions from case expression
+caseBranches :: Expr -> [BranchExpr]
+caseBranches (Case _ _ bs) = bs
+caseBranches _             = error
+  "Curry.FlatCurry.Goodies.caseBranches: no case expression"
+
+-- Test Operations
+
+-- |is expression a variable?
+isVar :: Expr -> Bool
+isVar e = case e of
+  Var _ -> True
+  _ -> False
+
+-- |is expression a literal expression?
+isLit :: Expr -> Bool
+isLit e = case e of
+  Lit _ -> True
+  _ -> False
+
+-- |is expression combined?
+isComb :: Expr -> Bool
+isComb e = case e of
+  Comb _ _ _ -> True
+  _ -> False
+
+-- |is expression a let expression?
+isLet :: Expr -> Bool
+isLet e = case e of
+  Let _ _ -> True
+  _ -> False
+
+-- |is expression a declaration of free variables?
+isFree :: Expr -> Bool
+isFree e = case e of
+  Free _ _ -> True
+  _ -> False
+
+-- |is expression an or-expression?
+isOr :: Expr -> Bool
+isOr e = case e of
+  Or _ _ -> True
+  _ -> False
+
+-- |is expression a case expression?
+isCase :: Expr -> Bool
+isCase e = case e of
+  Case _ _ _ -> True
+  _ -> False
+
+-- |transform expression
+trExpr  :: (VarIndex -> a)
+        -> (Literal -> a)
+        -> (CombType -> QName -> [a] -> a)
+        -> ([(VarIndex, a)] -> a -> a)
+        -> ([VarIndex] -> a -> a)
+        -> (a -> a -> a)
+        -> (CaseType -> a -> [b] -> a)
+        -> (Pattern -> a -> b)
+        -> (a -> TypeExpr -> a)
+        -> Expr
+        -> a
+trExpr var lit comb lt fr oR cas branch typed expr = case expr of
+  Var n             -> var n
+  Lit l             -> lit l
+  Comb ct name args -> comb ct name (map f args)
+  Let bs e          -> lt (map (\(v, x) -> (v, f x)) bs) (f e)
+  Free vs e         -> fr vs (f e)
+  Or e1 e2          -> oR (f e1) (f e2)
+  Case ct e bs      -> cas ct (f e) (map (\ (Branch p e') -> branch p (f e')) bs)
+  Typed e ty        -> typed (f e) ty
+  where
+  f = trExpr var lit comb lt fr oR cas branch typed
+
+-- Update Operations
+
+-- |update all variables in given expression
+updVars :: (VarIndex -> Expr) -> Expr -> Expr
+updVars var = trExpr var Lit Comb Let Free Or Case Branch Typed
+
+-- |update all literals in given expression
+updLiterals :: (Literal -> Expr) -> Expr -> Expr
+updLiterals lit = trExpr Var lit Comb Let Free Or Case Branch Typed
+
+-- |update all combined expressions in given expression
+updCombs :: (CombType -> QName -> [Expr] -> Expr) -> Expr -> Expr
+updCombs comb = trExpr Var Lit comb Let Free Or Case Branch Typed
+
+-- |update all let expressions in given expression
+updLets :: ([(VarIndex,Expr)] -> Expr -> Expr) -> Expr -> Expr
+updLets lt = trExpr Var Lit Comb lt Free Or Case Branch Typed
+
+-- |update all free declarations in given expression
+updFrees :: ([VarIndex] -> Expr -> Expr) -> Expr -> Expr
+updFrees fr = trExpr Var Lit Comb Let fr Or Case Branch Typed
+
+-- |update all or expressions in given expression
+updOrs :: (Expr -> Expr -> Expr) -> Expr -> Expr
+updOrs oR = trExpr Var Lit Comb Let Free oR Case Branch Typed
+
+-- |update all case expressions in given expression
+updCases :: (CaseType -> Expr -> [BranchExpr] -> Expr) -> Expr -> Expr
+updCases cas = trExpr Var Lit Comb Let Free Or cas Branch Typed
+
+-- |update all case branches in given expression
+updBranches :: (Pattern -> Expr -> BranchExpr) -> Expr -> Expr
+updBranches branch = trExpr Var Lit Comb Let Free Or Case branch Typed
+
+-- |update all typed expressions in given expression
+updTypeds :: (Expr -> TypeExpr -> Expr) -> Expr -> Expr
+updTypeds = trExpr Var Lit Comb Let Free Or Case Branch
+
+-- Auxiliary Functions
+
+-- |is expression a call of a function where all arguments are provided?
+isFuncCall :: Expr -> Bool
+isFuncCall e = isComb e && isCombTypeFuncCall (combType e)
+
+-- |is expression a partial function call?
+isFuncPartCall :: Expr -> Bool
+isFuncPartCall e = isComb e && isCombTypeFuncPartCall (combType e)
+
+-- |is expression a call of a constructor?
+isConsCall :: Expr -> Bool
+isConsCall e = isComb e && isCombTypeConsCall (combType e)
+
+-- |is expression a partial constructor call?
+isConsPartCall :: Expr -> Bool
+isConsPartCall e = isComb e && isCombTypeConsPartCall (combType e)
+
+-- |is expression fully evaluated?
+isGround :: Expr -> Bool
+isGround e
+  = case e of
+      Comb ConsCall _ args -> all isGround args
+      _ -> isLit e
+
+-- |get all variables (also pattern variables) in expression
+allVars :: Expr -> [VarIndex]
+allVars e = trExpr (:) (const id) comb lt fr (.) cas branch const e []
+ where
+  comb _ _ = foldr (.) id
+  lt bs e' = e' . foldr (.) id (map (\ (n,ns) -> (n:) . ns) bs)
+  fr vs e' = (vs++) . e'
+  cas _ e' bs = e' . foldr (.) id bs
+  branch pat e' = ((args pat)++) . e'
+  args pat | isConsPattern pat = patArgs pat
+           | otherwise = []
+
+-- |rename all variables (also in patterns) in expression
+rnmAllVars :: Update Expr VarIndex
+rnmAllVars f = trExpr (Var . f) Lit Comb lt (Free . map f) Or Case branch Typed
+ where
+   lt = Let . map (\ (n,e) -> (f n,e))
+   branch = Branch . updPatArgs (map f)
+
+-- |update all qualified names in expression
+updQNames :: Update Expr QName
+updQNames f = trExpr Var Lit comb Let Free Or Case (Branch . updPatCons f) Typed
+ where
+  comb ct name args = Comb ct (f name) args
+
+-- BranchExpr ----------------------------------------------------------------
+
+-- |transform branch expression
+trBranch :: (Pattern -> Expr -> a) -> BranchExpr -> a
+trBranch branch (Branch pat e) = branch pat e
+
+-- Selectors
+
+-- |get pattern from branch expression
+branchPattern :: BranchExpr -> Pattern
+branchPattern = trBranch (\pat _ -> pat)
+
+-- |get expression from branch expression
+branchExpr :: BranchExpr -> Expr
+branchExpr = trBranch (\_ e -> e)
+
+-- Update Operations
+
+-- |update branch expression
+updBranch :: (Pattern -> Pattern) -> (Expr -> Expr) -> BranchExpr -> BranchExpr
+updBranch fp fe = trBranch branch
+ where
+  branch pat e = Branch (fp pat) (fe e)
+
+-- |update pattern of branch expression
+updBranchPattern :: Update BranchExpr Pattern
+updBranchPattern f = updBranch f id
+
+-- |update expression of branch expression
+updBranchExpr :: Update BranchExpr Expr
+updBranchExpr = updBranch id
+
+-- Pattern -------------------------------------------------------------------
+
+-- |transform pattern
+trPattern :: (QName -> [VarIndex] -> a) -> (Literal -> a) -> Pattern -> a
+trPattern pattern _ (Pattern name args) = pattern name args
+trPattern _ lpattern (LPattern l) = lpattern l
+
+-- Selectors
+
+-- |get name from constructor pattern
+patCons :: Pattern -> QName
+patCons = trPattern (\name _ -> name) undefined
+
+-- |get arguments from constructor pattern
+patArgs :: Pattern -> [VarIndex]
+patArgs = trPattern (\_ args -> args) undefined
+
+-- |get literal from literal pattern
+patLiteral :: Pattern -> Literal
+patLiteral = trPattern undefined id
+
+-- Test Operations
+
+-- |is pattern a constructor pattern?
+isConsPattern :: Pattern -> Bool
+isConsPattern = trPattern (\_ _ -> True) (\_ -> False)
+
+-- Update Operations
+
+-- |update pattern
+updPattern :: (QName -> QName) ->
+              ([VarIndex] -> [VarIndex]) ->
+              (Literal -> Literal) -> Pattern -> Pattern
+updPattern fn fa fl = trPattern pattern lpattern
+ where
+  pattern name args = Pattern (fn name) (fa args)
+  lpattern l = LPattern (fl l)
+
+-- |update constructors name of pattern
+updPatCons :: (QName -> QName) -> Pattern -> Pattern
+updPatCons f = updPattern f id id
+
+-- |update arguments of constructor pattern
+updPatArgs :: ([VarIndex] -> [VarIndex]) -> Pattern -> Pattern
+updPatArgs f = updPattern id f id
+
+-- |update literal of pattern
+updPatLiteral :: (Literal -> Literal) -> Pattern -> Pattern
+updPatLiteral f = updPattern id id f
+
+-- Auxiliary Functions
+
+-- |build expression from pattern
+patExpr :: Pattern -> Expr
+patExpr = trPattern (\ name -> Comb ConsCall name . map Var) Lit
+
+-- |Is this a public 'Visibility'?
+isPublic :: Visibility -> Bool
+isPublic = (== Public)
diff --git a/src/Curry/FlatCurry/InterfaceEquivalence.hs b/src/Curry/FlatCurry/InterfaceEquivalence.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/FlatCurry/InterfaceEquivalence.hs
@@ -0,0 +1,58 @@
+{- |
+    Module      :  $Header$
+    Description :  Check the equality of two FlatCurry interfaces
+    Copyright   :  (c) 2006       , Martin Engelke
+                       2011 - 2014, Björn Peemöller
+                       2014       , Jan Tikovsky
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+-}
+
+module Curry.FlatCurry.InterfaceEquivalence (eqInterface) where
+
+import Data.List (deleteFirstsBy)
+
+import Curry.FlatCurry.Type
+
+infix 4 =~=, `eqvSet`
+
+-- |Check whether the interfaces of two FlatCurry programs are equivalent.
+eqInterface :: Prog -> Prog -> Bool
+eqInterface = (=~=)
+
+-- |Type class to express the equivalence of two values
+class Equiv a where
+  (=~=) :: a -> a -> Bool
+
+instance Equiv a => Equiv [a] where
+  []     =~= []     = True
+  (x:xs) =~= (y:ys) = x =~= y && xs =~= ys
+  _      =~= _      = False
+
+instance Equiv Char where (=~=) = (==)
+
+-- |Equivalence of lists independent of the order.
+eqvSet :: Equiv a => [a] -> [a] -> Bool
+xs `eqvSet` ys = null (deleteFirstsBy (=~=) xs ys ++ deleteFirstsBy (=~=) ys xs)
+
+instance Equiv Prog where
+  Prog m1 is1 ts1 fs1 os1 =~= Prog m2 is2 ts2 fs2 os2
+    = m1 == m2 && is1 `eqvSet` is2 && ts1 `eqvSet` ts2
+               && fs1 `eqvSet` fs2 && os1 `eqvSet` os2
+
+instance Equiv TypeDecl where (=~=) = (==)
+
+instance Equiv FuncDecl where
+  Func qn1 ar1 vis1 ty1 r1 =~= Func qn2 ar2 vis2 ty2 r2
+    = qn1 == qn2 && ar1 == ar2 && vis1 == vis2 && ty1 == ty2 && r1 =~= r2
+
+-- TODO: Check why arguments of rules are not checked for equivalence
+instance Equiv Rule where
+  Rule _ _   =~= Rule _ _   = True
+  External _ =~= External _ = True
+  _          =~= _          = False
+
+instance Equiv OpDecl where (=~=) = (==)
diff --git a/src/Curry/FlatCurry/Pretty.hs b/src/Curry/FlatCurry/Pretty.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/FlatCurry/Pretty.hs
@@ -0,0 +1,217 @@
+{- |
+    Module      :  $Header$
+    Description :  A pretty printer for FlatCurry
+    Copyright   :  (c) 2015 Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module implements a pretty printer for FlatCurry modules.
+-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+module Curry.FlatCurry.Pretty (pPrint, pPrintPrec) where
+
+import Prelude hiding ((<>))
+import Data.Char      (ord)
+
+import Curry.Base.Pretty
+import Curry.FlatCurry.Type
+
+instance Pretty Prog where
+  pPrint (Prog m is ts fs os) = sepByBlankLine
+    [ ppHeader m ts fs
+    , vcat           (map ppImport is)
+    , vcat           (map pPrint   os)
+    , sepByBlankLine (map pPrint   ts)
+    , sepByBlankLine (map pPrint   fs)
+    ]
+
+ppHeader :: String -> [TypeDecl] -> [FuncDecl] -> Doc
+ppHeader m ts fs = sep
+  [text "module" <+> text m, ppExports ts fs, text "where"]
+
+-- |pretty-print the export list
+ppExports :: [TypeDecl] -> [FuncDecl] -> Doc
+ppExports ts fs = parens $ list (map ppTypeExport ts ++ ppFuncExports fs)
+
+ppTypeExport :: TypeDecl -> Doc
+ppTypeExport (Type    qn vis _ cs)
+  | vis == Private      = empty
+  | all isPublicCons cs = ppPrefixOp qn <+> text "(..)"
+  | otherwise           = ppPrefixOp qn <+> parens (list (ppConsExports cs))
+    where isPublicCons (Cons _ _ v _) = v == Public
+ppTypeExport (TypeNew qn vis _ nc)
+  | vis == Private  = empty
+  | isPublicCons nc = ppPrefixOp qn <+> text "(..)"
+  | otherwise       = ppPrefixOp qn <+> parens empty
+    where isPublicCons (NewCons _ v _) = v == Public
+ppTypeExport (TypeSyn qn vis _ _ )
+  | vis == Private = empty
+  | otherwise      = ppPrefixOp qn
+
+-- |pretty-print the export list of constructors
+ppConsExports :: [ConsDecl] -> [Doc]
+ppConsExports cs = [ ppPrefixOp qn | Cons qn _ Public _ <- cs]
+
+-- |pretty-print the export list of functions
+ppFuncExports :: [FuncDecl] -> [Doc]
+ppFuncExports fs = [ ppPrefixOp qn | Func qn _ Public _ _ <- fs]
+
+-- |pretty-print an import statement
+ppImport :: String -> Doc
+ppImport m = text "import" <+> text m
+
+instance Pretty OpDecl where
+  pPrint(Op qn fix n) = pPrint fix <+> integer n <+> ppInfixOp qn
+
+instance Pretty Fixity where
+  pPrint InfixOp  = text "infix"
+  pPrint InfixlOp = text "infixl"
+  pPrint InfixrOp = text "infixr"
+
+instance Pretty TypeDecl where
+  pPrint (Type    qn _ vs cs) = text "data" <+> ppQName qn
+    <+> hsep (ppTVarIndex <$> fst <$> vs) $+$ ppConsDecls cs
+  pPrint (TypeSyn qn _ vs ty) = text "type" <+> ppQName qn
+    <+> hsep (ppTVarIndex <$> fst <$> vs) <+> equals <+> pPrintPrec 0 ty
+  pPrint (TypeNew qn _ vs nc) = text "newtype" <+> ppQName qn
+    <+> hsep (ppTVarIndex <$> fst <$> vs) <+> equals <+> pPrint nc
+
+-- |pretty-print the constructor declarations
+ppConsDecls :: [ConsDecl] -> Doc
+ppConsDecls cs = indent $ vcat $
+  zipWith (<+>) (equals : repeat (char '|')) (map pPrint cs)
+
+instance Pretty ConsDecl where
+  pPrint (Cons qn _ _ tys) = fsep $ ppPrefixOp qn : map (pPrintPrec 2) tys
+
+instance Pretty NewConsDecl where
+  pPrint (NewCons qn _ ty) = fsep [pPrint qn, pPrintPrec 2 ty]
+
+instance Pretty TypeExpr where
+  pPrintPrec _ (TVar           i) = ppTVarIndex i
+  pPrintPrec p (FuncType ty1 ty2) = parenIf (p > 0) $ fsep
+    [pPrintPrec 1 ty1, rarrow, pPrintPrec 0 ty2]
+  pPrintPrec p (TCons     qn tys) = parenIf (p > 1 && not (null tys)) $ fsep
+    (ppPrefixOp qn : map (pPrintPrec 2) tys)
+  pPrintPrec p (ForallType vs ty)
+    | null vs   = pPrintPrec p ty
+    | otherwise = parenIf (p > 0) $ ppQuantifiedVars vs <+> pPrintPrec 0 ty
+
+-- |pretty-print explicitly quantified type variables (without kinds)
+ppQuantifiedVars :: [(TVarIndex, Kind)] -> Doc
+ppQuantifiedVars vs
+  | null vs = empty
+  | otherwise = text "forall" <+> hsep (map ppTVar vs) <> char '.'
+
+ppTVar :: (TVarIndex, Kind) -> Doc
+ppTVar (i, _) = ppTVarIndex i
+
+-- |pretty-print a type variable
+ppTVarIndex :: TVarIndex -> Doc
+ppTVarIndex i = text $ vars !! i
+  where vars = [ if n == 0 then [c] else c : show n
+               | n <- [0 :: Int ..], c <- ['a' .. 'z']
+               ]
+
+instance Pretty FuncDecl where
+  pPrint (Func qn _ _ ty r)
+    = hsep [ppPrefixOp qn, text "::", pPrintPrec 0 ty]
+      $+$ ppPrefixOp qn <+> pPrint r
+
+instance Pretty Rule where
+  pPrint (Rule  vs e) =
+    fsep (map ppVarIndex vs) <+> equals <+> indent (pPrintPrec 0 e)
+  pPrint (External _) = text "external"
+
+instance Pretty Expr where
+  pPrintPrec _ (Var        v) = ppVarIndex v
+  pPrintPrec _ (Lit        l) = pPrint l
+  pPrintPrec p (Comb _ qn es) = ppComb p qn es
+  pPrintPrec p (Free    vs e)
+    | null vs             = pPrintPrec p e
+    | otherwise           = parenIf (p > 0) $ sep
+                            [ text "let" <+> list (map ppVarIndex vs)
+                                         <+> text "free"
+                            , text "in"  <+> pPrintPrec 0 e
+                            ]
+  pPrintPrec p (Let     ds e) = parenIf (p > 0) $
+    sep [text "let" <+> ppDecls ds, text "in" <+> pPrintPrec 0 e]
+  pPrintPrec p (Or     e1 e2) = parenIf (p > 0) $
+    pPrintPrec 1 e1 <+> text "?" <+> pPrintPrec 1 e2
+  pPrintPrec p (Case ct e bs) = parenIf (p > 0) $
+    pPrint ct <+> pPrintPrec 0 e <+> text "of" $$ indent (vcat (map pPrint bs))
+  pPrintPrec p (Typed   e ty) = parenIf (p > 0) $
+    pPrintPrec 0 e <+> text "::" <+> pPrintPrec 0 ty
+
+-- |pretty-print a variable
+ppVarIndex :: VarIndex -> Doc
+ppVarIndex i = text $ 'v' : show i
+
+instance Pretty Literal where
+  pPrint (Intc   i) = integer i
+  pPrint (Floatc f) = double  f
+  pPrint (Charc  c) = text (showEscape c)
+
+-- |Escape character literal
+showEscape :: Char -> String
+showEscape c
+  | o <   10  = "'\\00" ++ show o ++ "'"
+  | o <   32  = "'\\0"  ++ show o ++ "'"
+  | o == 127  = "'\\127'"
+  | otherwise = show c
+  where o = ord c
+
+-- |Pretty print a constructor or function call
+ppComb :: Int -> QName -> [Expr] -> Doc
+ppComb _ qn []      = ppPrefixOp qn
+ppComb p qn [e1,e2]
+  | isInfixOp qn    = parenIf (p > 0)
+                    $ hsep [pPrintPrec 1 e1, pPrint qn, pPrintPrec 1 e2]
+ppComb p qn es      = parenIf (p > 0)
+                    $ hsep (ppPrefixOp qn : map (pPrintPrec 1) es)
+
+-- |pretty-print a list of declarations
+ppDecls :: [(VarIndex, Expr)] -> Doc
+ppDecls = vcat . map ppDecl
+
+-- |pretty-print a single declaration
+ppDecl :: (VarIndex, Expr) -> Doc
+ppDecl (v, e) = ppVarIndex v <+> equals <+> pPrintPrec 0 e
+
+instance Pretty CaseType where
+  pPrint Rigid = text "case"
+  pPrint Flex  = text "fcase"
+
+instance Pretty BranchExpr where
+  pPrint (Branch p e) = pPrint p <+> rarrow <+> pPrintPrec 0 e
+
+instance Pretty Pattern where
+  pPrint (Pattern c [v1,v2])
+    | isInfixOp c            = ppVarIndex v1 <+> ppInfixOp c <+> ppVarIndex v2
+  pPrint (Pattern  c     vs) = fsep (ppPrefixOp c : map ppVarIndex vs)
+  pPrint (LPattern        l) = pPrint l
+
+-- Names
+
+-- |pretty-print a prefix operator
+ppPrefixOp :: QName -> Doc
+ppPrefixOp qn = parenIf (isInfixOp qn) (ppQName qn)
+
+-- |pretty-print a name in infix manner
+ppInfixOp :: QName -> Doc
+ppInfixOp qn = if isInfixOp qn then ppQName qn else bquotes (ppQName qn)
+
+-- |pretty-print a qualified name
+ppQName :: QName -> Doc
+ppQName (m, i) = text $ m ++ '.' : i
+
+-- |Check whether an operator is an infix operator
+isInfixOp :: QName -> Bool
+isInfixOp = all (`elem` "~!@#$%^&*+-=<>:?./|\\") . snd
+
+-- Indentation
+indent :: Doc -> Doc
+indent = nest 2
diff --git a/src/Curry/FlatCurry/Type.hs b/src/Curry/FlatCurry/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/FlatCurry/Type.hs
@@ -0,0 +1,521 @@
+{- |
+    Module      : $Header$
+    Description : Representation of FlatCurry.
+    Copyright   : (c) Michael Hanus  2003
+                      Martin Engelke 2004
+                      Bernd Brassel  2005
+    License     : BSD-3-clause
+
+    Maintainer  : bjp@informatik.uni-kiel.de
+    Stability   : experimental
+    Portability : portable
+
+    This module contains a definition for representing FlatCurry programs
+    in Haskell in type 'Prog'.
+-}
+
+module Curry.FlatCurry.Type
+  ( -- * Representation of qualified names and (type) variables
+    QName, VarIndex, TVarIndex, TVarWithKind
+    -- * Data types for FlatCurry
+  , Visibility (..), Prog (..), TypeDecl (..), TypeExpr (..), Kind (..)
+  , ConsDecl (..), NewConsDecl(..), OpDecl (..), Fixity (..)
+  , FuncDecl (..), Rule (..), Expr (..), Literal (..)
+  , CombType (..), CaseType (..), BranchExpr (..), Pattern (..)
+  ) where
+
+import Data.Binary
+import Control.Monad
+
+-- ---------------------------------------------------------------------------
+-- Qualified names
+-- ---------------------------------------------------------------------------
+
+-- |Qualified names.
+--
+-- In FlatCurry all names are qualified to avoid name clashes.
+-- The first component is the module name and the second component the
+-- unqualified name as it occurs in the source program.
+type QName = (String, String)
+
+-- ---------------------------------------------------------------------------
+-- Variable representation
+-- ---------------------------------------------------------------------------
+
+-- |Representation of variables.
+type VarIndex = Int
+
+-- ---------------------------------------------------------------------------
+-- FlatCurry representation
+-- ---------------------------------------------------------------------------
+
+-- |Visibility of various entities.
+data Visibility
+  = Public    -- ^ public (exported) entity
+  | Private   -- ^ private entity
+    deriving (Eq, Read, Show)
+
+-- |A FlatCurry module.
+--
+-- A value of this data type has the form
+--
+-- @Prog modname imports typedecls functions opdecls@
+--
+-- where
+--
+-- [@modname@]   Name of this module
+-- [@imports@]   List of modules names that are imported
+-- [@typedecls@] Type declarations
+-- [@funcdecls@] Function declarations
+-- [@ opdecls@]  Operator declarations
+data Prog = Prog String [String] [TypeDecl] [FuncDecl] [OpDecl]
+    deriving (Eq, Read, Show)
+
+-- |Declaration of algebraic data type or type synonym.
+--
+-- A data type declaration of the form
+--
+-- @data t x1...xn = ...| c t1....tkc |...@
+--
+-- is represented by the FlatCurry term
+--
+-- @Type t [i1,...,in] [...(Cons c kc [t1,...,tkc])...]@
+--
+-- where each @ij@ is the index of the type variable @xj@
+--
+-- /Note:/ The type variable indices are unique inside each type declaration
+--         and are usually numbered from 0.
+--
+-- Thus, a data type declaration consists of the name of the data type,
+-- a list of type parameters and a list of constructor declarations.
+data TypeDecl
+  = Type    QName Visibility [TVarWithKind] [ConsDecl]
+  | TypeSyn QName Visibility [TVarWithKind] TypeExpr
+  | TypeNew QName Visibility [TVarWithKind] NewConsDecl
+    deriving (Eq, Read, Show)
+
+-- |Type variables are represented by @(TVar i)@ where @i@ is a
+-- type variable index.
+type TVarIndex = Int
+
+-- |Kinded type variables are represented by a tuple of type variable
+-- index and kind.
+type TVarWithKind = (TVarIndex, Kind)
+
+-- |A constructor declaration consists of the name and arity of the
+-- constructor and a list of the argument types of the constructor.
+data ConsDecl = Cons QName Int Visibility [TypeExpr]
+    deriving (Eq, Read, Show)
+
+-- |A constructor declaration for a newtype consists
+-- of the name of the constructor
+-- and the argument type of the constructor.
+data NewConsDecl = NewCons QName Visibility TypeExpr
+    deriving (Eq, Read, Show)
+
+-- |Type expressions.
+--
+-- A type expression is either a type variable, a function type,
+-- or a type constructor application.
+--
+-- /Note:/ the names of the predefined type constructors are
+-- @Int@, @Float@, @Bool@, @Char@, @IO@, @Success@,
+-- @()@ (unit type), @(,...,)@ (tuple types), @[]@ (list type)
+data TypeExpr
+  = TVar        TVarIndex               -- ^ type variable
+  | FuncType    TypeExpr TypeExpr       -- ^ function type @t1 -> t2@
+  | TCons QName [TypeExpr]              -- ^ type constructor application
+  | ForallType  [TVarWithKind] TypeExpr -- ^ forall type
+    deriving (Eq, Read, Show)
+
+-- |Kinds.
+--
+-- A kind is either * or k_1 -> k_2 where k_1 and k_2 are kinds.
+data Kind
+  = KStar            -- ^ star kind
+  | KArrow Kind Kind -- ^ arrow kind
+ deriving (Eq, Ord, Read, Show)
+    
+-- |Operator declarations.
+--
+-- An operator declaration @fix p n@ in Curry corresponds to the
+-- FlatCurry term @(Op n fix p)@.
+--
+-- /Note:/ the constructor definition of 'Op' differs from the original
+-- PAKCS definition using Haskell type 'Integer' instead of 'Int'
+-- for representing the precedence.
+data OpDecl = Op QName Fixity Integer
+    deriving (Eq, Read, Show)
+
+-- |Fixity of an operator.
+data Fixity
+  = InfixOp  -- ^ non-associative infix operator
+  | InfixlOp -- ^ left-associative infix operator
+  | InfixrOp -- ^ right-associative infix operator
+    deriving (Eq, Read, Show)
+
+-- |Data type for representing function declarations.
+--
+-- A function declaration in FlatCurry is a term of the form
+--
+-- @(Func name arity type (Rule [i_1,...,i_arity] e))@
+--
+-- and represents the function "name" with definition
+--
+-- @
+-- name :: type
+-- name x_1...x_arity = e
+-- @
+--
+-- where each @i_j@ is the index of the variable @x_j@
+--
+-- /Note:/ The variable indices are unique inside each function declaration
+--         and are usually numbered from 0.
+--
+-- External functions are represented as
+--
+-- @Func name arity type (External s)@
+--
+-- where s is the external name associated to this function.
+--
+-- Thus, a function declaration consists of the name, arity, type, and rule.
+data FuncDecl = Func QName Int Visibility TypeExpr Rule
+    deriving (Eq, Read, Show)
+
+-- |A rule is either a list of formal parameters together with an expression
+-- or an 'External' tag.
+data Rule
+  = Rule [VarIndex] Expr
+  | External String
+    deriving (Eq, Read, Show)
+
+-- |Data type for representing expressions.
+--
+-- Remarks:
+--
+-- 1.if-then-else expressions are represented as function calls:
+--
+--   @(if e1 then e2 else e3)@
+--
+--   is represented as
+--
+--   @(Comb FuncCall ("Prelude","ifThenElse") [e1,e2,e3])@
+--
+-- 2.Higher order applications are represented as calls to the (external)
+--   function @apply@. For instance, the rule
+--
+--   @app f x = f x@
+--
+--   is represented as
+--
+--   @(Rule  [0,1] (Comb FuncCall ("Prelude","apply") [Var 0, Var 1]))@
+--
+-- 3.A conditional rule is represented as a call to an external function
+--   @cond@ where the first argument is the condition (a constraint).
+--
+--   For instance, the rule
+--
+--   @equal2 x | x=:=2 = success@
+--
+--   is represented as
+--
+--   @
+--   (Rule [0]
+--       (Comb FuncCall ("Prelude","cond")
+--             [Comb FuncCall ("Prelude","=:=") [Var 0, Lit (Intc 2)],
+--             Comb FuncCall ("Prelude","success") []]))
+--   @
+--
+-- 4.Functions with evaluation annotation @choice@ are represented
+--   by a rule whose right-hand side is enclosed in a call to the
+--   external function @Prelude.commit@.
+--   Furthermore, all rules of the original definition must be
+--   represented by conditional expressions (i.e., (cond [c,e]))
+--   after pattern matching.
+--
+--   Example:
+--
+--   @
+--   m eval choice
+--   m [] y = y
+--   m x [] = x
+--   @
+--
+--   is translated into (note that the conditional branches can be also
+--   wrapped with Free declarations in general):
+--
+--   @
+--   Rule [0,1]
+--     (Comb FuncCall ("Prelude","commit")
+--       [Or (Case Rigid (Var 0)
+--             [(Pattern ("Prelude","[]") []
+--                 (Comb FuncCall ("Prelude","cond")
+--                       [Comb FuncCall ("Prelude","success") [],
+--                         Var 1]))] )
+--           (Case Rigid (Var 1)
+--             [(Pattern ("Prelude","[]") []
+--                 (Comb FuncCall ("Prelude","cond")
+--                       [Comb FuncCall ("Prelude","success") [],
+--                         Var 0]))] )])
+--   @
+--
+--   Operational meaning of @(Prelude.commit e)@:
+--   evaluate @e@ with local search spaces and commit to the first
+--   @(Comb FuncCall ("Prelude","cond") [c,ge])@ in @e@ whose constraint @c@
+--   is satisfied
+data Expr
+  -- |Variable, represented by unique index
+  = Var VarIndex
+  -- |Literal (Integer/Float/Char constant)
+  | Lit Literal
+  -- |Application @(f e1 ... en)@ of function/constructor @f@
+  --  with @n <= arity f@
+  | Comb CombType QName [Expr]
+  -- |Introduction of free local variables for an expression
+  | Free [VarIndex] Expr
+  -- |Local let-declarations
+  | Let [(VarIndex, Expr)] Expr
+  -- |Disjunction of two expressions
+  -- (resulting from overlapping left-hand sides)
+  | Or Expr Expr
+  -- |case expression
+  | Case CaseType Expr [BranchExpr]
+  -- |typed expression
+  | Typed Expr TypeExpr
+    deriving (Eq, Read, Show)
+
+-- |Data type for representing literals.
+--
+-- A literal  is either an integer, a float, or a character constant.
+--
+-- /Note:/ The constructor definition of 'Intc' differs from the original
+-- PAKCS definition. It uses Haskell type 'Integer' instead of 'Int'
+-- to provide an unlimited range of integer numbers. Furthermore,
+-- float values are represented with Haskell type 'Double' instead of
+-- 'Float'.
+data Literal
+  = Intc   Integer
+  | Floatc Double
+  | Charc  Char
+    deriving (Eq, Read, Show)
+
+-- |Data type for classifying combinations
+-- (i.e., a function/constructor applied to some arguments).
+data CombType
+  -- |a call to a function where all arguments are provided
+  = FuncCall
+  -- |a call with a constructor at the top, all arguments are provided
+  | ConsCall
+  -- |a partial call to a function (i.e., not all arguments are provided)
+  --  where the parameter is the number of missing arguments
+  | FuncPartCall Int
+  -- |a partial call to a constructor along with number of missing arguments
+  | ConsPartCall Int
+    deriving (Eq, Read, Show)
+
+-- |Classification of case expressions, either flexible or rigid.
+data CaseType
+  = Rigid
+  | Flex
+    deriving (Eq, Read, Show)
+
+-- |Branches in a case expression.
+--
+-- Branches @(m.c x1...xn) -> e@ in case expressions are represented as
+--
+-- @(Branch (Pattern (m,c) [i1,...,in]) e)@
+--
+-- where each @ij@ is the index of the pattern variable @xj@, or as
+--
+-- @(Branch (LPattern (Intc i)) e)@
+--
+-- for integers as branch patterns (similarly for other literals
+-- like float or character constants).
+data BranchExpr = Branch Pattern Expr
+    deriving (Eq, Read, Show)
+
+-- |Patterns in case expressions.
+data Pattern
+  = Pattern QName [VarIndex]
+  | LPattern Literal
+    deriving (Eq, Read, Show)
+
+instance Binary Visibility where
+  put Public  = putWord8 0
+  put Private = putWord8 1
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> return Public
+      1 -> return Private
+      _ -> fail "Invalid encoding for Visibility"
+
+instance Binary Prog where
+  put (Prog mid im tys fus ops) =
+    put mid >> put im >> put tys >> put fus >> put ops
+  get = Prog <$> get <*> get <*> get <*> get <*> get
+
+instance Binary TypeDecl where
+  put (Type    qid vis vs cs) =
+    putWord8 0 >> put qid >> put vis >> put vs >> put cs
+  put (TypeSyn qid vis vs ty) =
+    putWord8 1 >> put qid >> put vis >> put vs >> put ty
+  put (TypeNew qid vis vs c ) =
+    putWord8 2 >> put qid >> put vis >> put vs >> put c
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM4 Type get get get get
+      1 -> liftM4 TypeSyn get get get get
+      2 -> liftM4 TypeNew get get get get
+      _ -> fail "Invalid encoding for TypeDecl"
+
+instance Binary ConsDecl where
+  put (Cons qid arity vis tys) = put qid >> put arity >> put vis >> put tys
+  get = Cons <$> get <*> get <*> get <*> get
+
+instance Binary NewConsDecl where
+  put (NewCons qid vis ty) = put qid >> put vis >> put ty
+  get = NewCons <$> get <*> get <*> get
+
+instance Binary TypeExpr where
+  put (TVar tv) =
+    putWord8 0 >> put tv
+  put (FuncType ty1 ty2) =
+    putWord8 1 >> put ty1 >> put ty2
+  put (TCons qid tys) =
+    putWord8 2 >> put qid >> put tys
+  put (ForallType vs ty) =
+    putWord8 3 >> put vs >> put ty
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> fmap TVar get
+      1 -> liftM2 FuncType get get
+      2 -> liftM2 TCons get get
+      3 -> liftM2 ForallType get get
+      _ -> fail "Invalid encoding for TypeExpr"
+
+instance Binary Kind where
+  put KStar          = putWord8 0
+  put (KArrow k1 k2) = putWord8 1 >> put k1 >> put k2
+  get = do
+    x <- getWord8
+    case x of
+      0 -> return KStar
+      1 -> liftM2 KArrow get get
+      _ -> fail "Invalid encoding for Kind"
+
+instance Binary OpDecl where
+  put (Op qid fix pr) = put qid >> put fix >> put pr
+  get = liftM3 Op get get get
+
+instance Binary Fixity where
+  put InfixOp  = putWord8 0
+  put InfixlOp = putWord8 1
+  put InfixrOp = putWord8 2
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> return InfixOp
+      1 -> return InfixlOp
+      2 -> return InfixrOp
+      _ -> fail "Invalid encoding for Fixity"
+
+instance Binary FuncDecl where
+  put (Func qid arity vis ty r) =
+    put qid >> put arity >> put vis >> put ty >> put r
+  get = Func <$> get <*> get <*> get <*> get <*> get
+
+instance Binary Rule where
+  put (Rule     alts e) = putWord8 0 >> put alts >> put e
+  put (External n     ) = putWord8 1 >> put n
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 Rule get get
+      1 -> fmap External get
+      _ -> fail "Invalid encoding for TRule"
+
+instance Binary Expr where
+  put (Var v) = putWord8 0 >> put v
+  put (Lit l) = putWord8 1 >> put l
+  put (Comb cty qid es) =
+    putWord8 2 >> put cty >> put qid >> put es
+  put (Let  bs e) = putWord8 3 >> put bs >> put e
+  put (Free vs e) = putWord8 4 >> put vs >> put e
+  put (Or  e1 e2) = putWord8 5 >> put e1 >> put e2
+  put (Case cty ty as) = putWord8 6 >> put cty >> put ty >> put as
+  put (Typed e ty) = putWord8 7 >> put e >> put ty
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> fmap Var get
+      1 -> fmap Lit get
+      2 -> liftM3 Comb get get get
+      3 -> liftM2 Let get get
+      4 -> liftM2 Free get get
+      5 -> liftM2 Or get get
+      6 -> liftM3 Case get get get
+      7 -> liftM2 Typed get get
+      _ -> fail "Invalid encoding for TExpr"
+
+instance Binary BranchExpr where
+  put (Branch p e) = put p >> put e
+  get = liftM2 Branch get get
+
+instance Binary Pattern where
+  put (Pattern  qid vs) = putWord8 0 >> put qid >> put vs
+  put (LPattern l     ) = putWord8 1 >> put l
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 Pattern get get
+      1 -> fmap LPattern get
+      _ -> fail "Invalid encoding for TPattern"
+
+instance Binary Literal where
+  put (Intc   i) = putWord8 0 >> put i
+  put (Floatc f) = putWord8 1 >> put f
+  put (Charc  c) = putWord8 2 >> put c
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> fmap Intc get
+      1 -> fmap Floatc get
+      2 -> fmap Charc get
+      _ -> fail "Invalid encoding for Literal"
+
+instance Binary CombType where
+  put FuncCall = putWord8 0
+  put ConsCall = putWord8 1
+  put (FuncPartCall i) = putWord8 2 >> put i
+  put (ConsPartCall i) = putWord8 3 >> put i
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> return FuncCall
+      1 -> return ConsCall
+      2 -> fmap FuncPartCall get
+      3 -> fmap ConsPartCall get
+      _ -> fail "Invalid encoding for CombType"
+
+instance Binary CaseType where
+  put Rigid = putWord8 0
+  put Flex  = putWord8 1
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> return Rigid
+      1 -> return Flex
+      _ -> fail "Invalid encoding for CaseType"
diff --git a/src/Curry/FlatCurry/Typeable.hs b/src/Curry/FlatCurry/Typeable.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/FlatCurry/Typeable.hs
@@ -0,0 +1,22 @@
+{- |
+    Module      : $Header$
+    Description : Typeclass of Typeable entities
+    Copyright   : (c) 2018        Kai-Oliver Prott
+    License     : BSD-3-clause
+
+    Maintainer  : fte@informatik.uni-kiel.de
+    Stability   : experimental
+    Portability : portable
+
+    This module defines a Typeclass for easy access to the type of entites
+-}
+
+module Curry.FlatCurry.Typeable (Typeable(..)) where
+
+import Curry.FlatCurry.Type (TypeExpr)
+
+class Typeable a where
+  typeOf :: a -> TypeExpr
+
+instance Typeable TypeExpr where
+  typeOf = id
diff --git a/src/Curry/FlatCurry/Typed/Goodies.hs b/src/Curry/FlatCurry/Typed/Goodies.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/FlatCurry/Typed/Goodies.hs
@@ -0,0 +1,666 @@
+{- |
+    Module      : $Header$
+    Description : Utility functions for working with TypedFlatCurry.
+    Copyright   : (c) 2016 - 2017 Finn Teegen
+                      2018        Kai-Oliver Prott
+    License     : BSD-3-clause
+
+    Maintainer  : fte@informatik.uni-kiel.de
+    Stability   : experimental
+    Portability : portable
+
+    This library provides selector functions, test and update operations
+    as well as some useful auxiliary functions for TypedFlatCurry data terms.
+    Most of the provided functions are based on general transformation
+    functions that replace constructors with user-defined
+    functions. For recursive datatypes the transformations are defined
+    inductively over the term structure. This is quite usual for
+    transformations on TypedFlatCurry terms,
+    so the provided functions can be used to implement specific transformations
+    without having to explicitly state the recursion. Essentially, the tedious
+    part of such transformations - descend in fairly complex term structures -
+    is abstracted away, which hopefully makes the code more clear and brief.
+-}
+
+module Curry.FlatCurry.Typed.Goodies
+  ( module Curry.FlatCurry.Typed.Goodies
+  , module Curry.FlatCurry.Goodies
+  ) where
+
+import Curry.FlatCurry.Goodies ( Update
+                               , trType, typeName, typeVisibility, typeParams
+                               , typeConsDecls, typeSyn, isTypeSyn
+                               , isDataTypeDecl, isExternalType, isPublicType
+                               , updType, updTypeName, updTypeVisibility
+                               , updTypeParams, updTypeConsDecls, updTypeSynonym
+                               , updQNamesInType
+                               , trCons, consName, consArity, consVisibility
+                               , isPublicCons, consArgs, updCons, updConsName
+                               , updConsArity, updConsVisibility, updConsArgs
+                               , updQNamesInConsDecl
+                               , trNewCons, newConsName, newConsVisibility
+                               , isPublicNewCons, newConsArg
+                               , updNewCons, updNewConsName
+                               , updNewConsVisibility, updNewConsArg
+                               , updQNamesInNewConsDecl
+                               , tVarIndex, domain, range, tConsName, tConsArgs
+                               , trTypeExpr, isTVar, isTCons, isFuncType
+                               , updTVars, updTCons, updFuncTypes, argTypes
+                               , typeArity, resultType, allVarsInTypeExpr
+                               , allTypeCons, rnmAllVarsInTypeExpr
+                               , updQNamesInTypeExpr
+                               , trOp, opName, opFixity, opPrecedence, updOp
+                               , updOpName, updOpFixity, updOpPrecedence
+                               , trCombType, isCombTypeFuncCall
+                               , isCombTypeFuncPartCall, isCombTypeConsCall
+                               , isCombTypeConsPartCall
+                               , isPublic
+                               )
+
+import Curry.FlatCurry.Typed.Type
+
+-- TProg ----------------------------------------------------------------------
+
+-- |transform program
+trTProg :: (String -> [String] -> [TypeDecl] -> [TFuncDecl] -> [OpDecl] -> b)
+        -> TProg -> b
+trTProg prog (TProg name imps types funcs ops) = prog name imps types funcs ops
+
+-- Selectors
+
+-- |get name from program
+tProgName :: TProg -> String
+tProgName = trTProg (\name _ _ _ _ -> name)
+
+-- |get imports from program
+tProgImports :: TProg -> [String]
+tProgImports = trTProg (\_ imps _ _ _ -> imps)
+
+-- |get type declarations from program
+tProgTypes :: TProg -> [TypeDecl]
+tProgTypes = trTProg (\_ _ types _ _ -> types)
+
+-- |get functions from program
+tProgTFuncs :: TProg -> [TFuncDecl]
+tProgTFuncs = trTProg (\_ _ _ funcs _ -> funcs)
+
+-- |get infix operators from program
+tProgOps :: TProg -> [OpDecl]
+tProgOps = trTProg (\_ _ _ _ ops -> ops)
+
+-- Update Operations
+
+-- |update program
+updTProg :: (String -> String) ->
+            ([String] -> [String]) ->
+            ([TypeDecl] -> [TypeDecl]) ->
+            ([TFuncDecl] -> [TFuncDecl]) ->
+            ([OpDecl] -> [OpDecl]) -> TProg -> TProg
+updTProg fn fi ft ff fo = trTProg prog
+ where
+  prog name imps types funcs ops
+    = TProg (fn name) (fi imps) (ft types) (ff funcs) (fo ops)
+
+-- |update name of program
+updTProgName :: Update TProg String
+updTProgName f = updTProg f id id id id
+
+-- |update imports of program
+updTProgImports :: Update TProg [String]
+updTProgImports f = updTProg id f id id id
+
+-- |update type declarations of program
+updTProgTypes :: Update TProg [TypeDecl]
+updTProgTypes f = updTProg id id f id id
+
+-- |update functions of program
+updTProgTFuncs :: Update TProg [TFuncDecl]
+updTProgTFuncs f = updTProg id id id f id
+
+-- |update infix operators of program
+updTProgOps :: Update TProg [OpDecl]
+updTProgOps = updTProg id id id id
+
+-- Auxiliary Functions
+
+-- |get all program variables (also from patterns)
+allVarsInTProg :: TProg -> [(VarIndex, TypeExpr)]
+allVarsInTProg = concatMap allVarsInTFunc . tProgTFuncs
+
+-- |lift transformation on expressions to program
+updTProgTExps :: Update TProg TExpr
+updTProgTExps = updTProgTFuncs . map . updTFuncBody
+
+-- |rename programs variables
+rnmAllVarsInTProg :: Update TProg VarIndex
+rnmAllVarsInTProg = updTProgTFuncs . map . rnmAllVarsInTFunc
+
+-- |update all qualified names in program
+updQNamesInTProg :: Update TProg QName
+updQNamesInTProg f = updTProg id id
+  (map (updQNamesInType f)) (map (updQNamesInTFunc f)) (map (updOpName f))
+
+-- |rename program (update name of and all qualified names in program)
+rnmTProg :: String -> TProg -> TProg
+rnmTProg name p = updTProgName (const name) (updQNamesInTProg rnm p)
+ where
+  rnm (m, n) | m == tProgName p = (name, n)
+             | otherwise = (m, n)
+
+-- TFuncDecl ------------------------------------------------------------------
+
+-- |transform function
+trTFunc :: (QName -> Int -> Visibility -> TypeExpr -> TRule -> b) -> TFuncDecl -> b
+trTFunc func (TFunc name arity vis t rule) = func name arity vis t rule
+
+-- Selectors
+
+-- |get name of function
+tFuncName :: TFuncDecl -> QName
+tFuncName = trTFunc (\name _ _ _ _ -> name)
+
+-- |get arity of function
+tFuncArity :: TFuncDecl -> Int
+tFuncArity = trTFunc (\_ arity _ _ _ -> arity)
+
+-- |get visibility of function
+tFuncVisibility :: TFuncDecl -> Visibility
+tFuncVisibility = trTFunc (\_ _ vis _ _ -> vis)
+
+-- |get type of function
+tFuncType :: TFuncDecl -> TypeExpr
+tFuncType = trTFunc (\_ _ _ t _ -> t)
+
+-- |get rule of function
+tFuncTRule :: TFuncDecl -> TRule
+tFuncTRule = trTFunc (\_ _ _ _ rule -> rule)
+
+-- Update Operations
+
+-- |update function
+updTFunc :: (QName -> QName) ->
+            (Int -> Int) ->
+            (Visibility -> Visibility) ->
+            (TypeExpr -> TypeExpr) ->
+            (TRule -> TRule) -> TFuncDecl -> TFuncDecl
+updTFunc fn fa fv ft fr = trTFunc func
+ where
+  func name arity vis t rule
+    = TFunc (fn name) (fa arity) (fv vis) (ft t) (fr rule)
+
+-- |update name of function
+updTFuncName :: Update TFuncDecl QName
+updTFuncName f = updTFunc f id id id id
+
+-- |update arity of function
+updTFuncArity :: Update TFuncDecl Int
+updTFuncArity f = updTFunc id f id id id
+
+-- |update visibility of function
+updTFuncVisibility :: Update TFuncDecl Visibility
+updTFuncVisibility f = updTFunc id id f id id
+
+-- |update type of function
+updFuncType :: Update TFuncDecl TypeExpr
+updFuncType f = updTFunc id id id f id
+
+-- |update rule of function
+updTFuncTRule :: Update TFuncDecl TRule
+updTFuncTRule = updTFunc id id id id
+
+-- Auxiliary Functions
+
+-- |is function public?
+isPublicTFunc :: TFuncDecl -> Bool
+isPublicTFunc = isPublic . tFuncVisibility
+
+-- |is function externally defined?
+isExternal :: TFuncDecl -> Bool
+isExternal = isTRuleExternal . tFuncTRule
+
+-- |get variable names in a function declaration
+allVarsInTFunc :: TFuncDecl -> [(VarIndex, TypeExpr)]
+allVarsInTFunc = allVarsInTRule . tFuncTRule
+
+-- |get arguments of function, if not externally defined
+tFuncArgs :: TFuncDecl -> [(VarIndex, TypeExpr)]
+tFuncArgs = tRuleArgs . tFuncTRule
+
+-- |get body of function, if not externally defined
+tFuncBody :: TFuncDecl -> TExpr
+tFuncBody = tRuleBody . tFuncTRule
+
+-- |get the right-hand-sides of a 'FuncDecl'
+tFuncRHS :: TFuncDecl -> [TExpr]
+tFuncRHS f | not (isExternal f) = orCase (tFuncBody f)
+           | otherwise = []
+ where
+  orCase e
+    | isTOr e = concatMap orCase (orExps e)
+    | isTCase e = concatMap (orCase . tBranchTExpr) (caseBranches e)
+    | otherwise = [e]
+
+-- |rename all variables in function
+rnmAllVarsInTFunc :: Update TFuncDecl VarIndex
+rnmAllVarsInTFunc = updTFunc id id id id . rnmAllVarsInTRule
+
+-- |update all qualified names in function
+updQNamesInTFunc :: Update TFuncDecl QName
+updQNamesInTFunc f = updTFunc f id id (updQNamesInTypeExpr f) (updQNamesInTRule f)
+
+-- |update arguments of function, if not externally defined
+updTFuncArgs :: Update TFuncDecl [(VarIndex, TypeExpr)]
+updTFuncArgs = updTFuncTRule . updTRuleArgs
+
+-- |update body of function, if not externally defined
+updTFuncBody :: Update TFuncDecl TExpr
+updTFuncBody = updTFuncTRule . updTRuleBody
+
+-- TRule ----------------------------------------------------------------------
+
+-- |transform rule
+trTRule :: ([(VarIndex, TypeExpr)] -> TExpr -> b) -> (TypeExpr -> String -> b) -> TRule -> b
+trTRule rule _ (TRule args e) = rule args e
+trTRule _ ext (TExternal ty s) = ext ty s
+
+-- Selectors
+
+-- |get rules arguments if it's not external
+tRuleArgs :: TRule -> [(VarIndex, TypeExpr)]
+tRuleArgs = trTRule const undefined
+
+-- |get rules body if it's not external
+tRuleBody :: TRule -> TExpr
+tRuleBody = trTRule (\_ e -> e) undefined
+
+-- |get rules external declaration
+tRuleExtDecl :: TRule -> String
+tRuleExtDecl = trTRule undefined (\_ s -> s)
+
+-- Test Operations
+
+-- |is rule external?
+isTRuleExternal :: TRule -> Bool
+isTRuleExternal = trTRule (\_ _ -> False) (\_ _ -> True)
+
+-- Update Operations
+
+-- |update rule
+updTRule :: (TypeExpr -> TypeExpr) ->
+            ([(VarIndex, TypeExpr)] -> [(VarIndex, TypeExpr)]) ->
+            (TExpr -> TExpr) ->
+            (String -> String) -> TRule -> TRule
+updTRule fannot fa fe fs = trTRule rule ext
+ where
+  rule args e = TRule (fa args) (fe e)
+  ext ty s = TExternal (fannot ty) (fs s)
+
+-- |update rules TypeExpr
+updTRuleType :: Update TRule TypeExpr
+updTRuleType f = updTRule f id id id
+
+-- |update rules arguments
+updTRuleArgs :: Update TRule [(VarIndex, TypeExpr)]
+updTRuleArgs f = updTRule id f id id
+
+-- |update rules body
+updTRuleBody :: Update TRule TExpr
+updTRuleBody f = updTRule id id f id
+
+-- |update rules external declaration
+updTRuleExtDecl :: Update TRule String
+updTRuleExtDecl = updTRule id id id
+
+-- Auxiliary Functions
+
+-- |get variable names in a functions rule
+allVarsInTRule :: TRule -> [(VarIndex, TypeExpr)]
+allVarsInTRule = trTRule (\args body -> args ++ allVars body) (\_ _ -> [])
+
+-- |rename all variables in rule
+rnmAllVarsInTRule :: Update TRule VarIndex
+rnmAllVarsInTRule f = updTRule id (map (\(a, b) -> (f a, b))) (rnmAllVars f) id
+
+-- |update all qualified names in rule
+updQNamesInTRule :: Update TRule QName
+updQNamesInTRule = updTRuleBody . updQNames
+
+-- TExpr ----------------------------------------------------------------------
+
+-- Selectors
+
+-- |get internal number of variable
+varNr :: TExpr -> VarIndex
+varNr (TVarE _ n) = n
+varNr _           = error "Curry.FlatCurry.Typed.Goodies.varNr: no variable"
+
+-- |get literal if expression is literal expression
+literal :: TExpr -> Literal
+literal (TLit _ l) = l
+literal _          = error "Curry.FlatCurry.Typed.Goodies.literal: no literal"
+
+-- |get combination type of a combined expression
+combType :: TExpr -> CombType
+combType (TComb _ ct _ _) = ct
+combType _                = error $ "Curry.FlatCurry.Typed.Goodies.combType: " ++
+                                    "no combined expression"
+
+-- |get name of a combined expression
+combName :: TExpr -> QName
+combName (TComb _ _ name _) = name
+combName _                  = error $ "Curry.FlatCurry.Typed.Goodies.combName: " ++
+                                      "no combined expression"
+
+-- |get arguments of a combined expression
+combArgs :: TExpr -> [TExpr]
+combArgs (TComb _ _ _ args) = args
+combArgs _                  = error $ "Curry.FlatCurry.Typed.Goodies.combArgs: " ++
+                                      "no combined expression"
+
+-- |get number of missing arguments if expression is combined
+missingCombArgs :: TExpr -> Int
+missingCombArgs = missingArgs . combType
+  where
+  missingArgs :: CombType -> Int
+  missingArgs = trCombType 0 id 0 id
+
+-- |get indices of variables in let declaration
+letBinds :: TExpr -> [((VarIndex, TypeExpr), TExpr)]
+letBinds (TLet vs _) = vs
+letBinds _           = error $ "Curry.FlatCurry.Typed.Goodies.letBinds: " ++
+                               "no let expression"
+
+-- |get body of let declaration
+letBody :: TExpr -> TExpr
+letBody (TLet _ e) = e
+letBody _          = error $ "Curry.FlatCurry.Typed.Goodies.letBody: " ++
+                             "no let expression"
+
+-- |get variable indices from declaration of free variables
+freeVars :: TExpr -> [(VarIndex, TypeExpr)]
+freeVars (TFree vs _) = vs
+freeVars _            = error $ "Curry.FlatCurry.Typed.Goodies.freeVars: " ++
+                                "no declaration of free variables"
+
+-- |get expression from declaration of free variables
+freeExpr :: TExpr -> TExpr
+freeExpr (TFree _ e) = e
+freeExpr _           = error $ "Curry.FlatCurry.Typed.Goodies.freeExpr: " ++
+                               "no declaration of free variables"
+
+-- |get expressions from or-expression
+orExps :: TExpr -> [TExpr]
+orExps (TOr e1 e2) = [e1, e2]
+orExps _           = error $ "Curry.FlatCurry.Typed.Goodies.orExps: " ++
+                             "no or expression"
+
+-- |get case-type of case expression
+caseType :: TExpr -> CaseType
+caseType (TCase ct _ _) = ct
+caseType _              = error $ "Curry.FlatCurry.Typed.Goodies.caseType: " ++
+                                  "no case expression"
+
+-- |get scrutinee of case expression
+caseExpr :: TExpr -> TExpr
+caseExpr (TCase _ e _) = e
+caseExpr _             = error $ "Curry.FlatCurry.Typed.Goodies.caseExpr: " ++
+                                   "no case expression"
+
+
+-- |get branch expressions from case expression
+caseBranches :: TExpr -> [TBranchExpr]
+caseBranches (TCase _ _ bs) = bs
+caseBranches _              = error "Curry.FlatCurry.Typed.Goodies.caseBranches: no case expression"
+
+-- Test Operations
+
+-- |is expression a variable?
+isTVarE :: TExpr -> Bool
+isTVarE e = case e of
+  TVarE _ _ -> True
+  _ -> False
+
+-- |is expression a literal expression?
+isTLit :: TExpr -> Bool
+isTLit e = case e of
+  TLit _ _ -> True
+  _ -> False
+
+-- |is expression combined?
+isTComb :: TExpr -> Bool
+isTComb e = case e of
+  TComb _ _ _ _ -> True
+  _ -> False
+
+-- |is expression a let expression?
+isTLet :: TExpr -> Bool
+isTLet e = case e of
+  TLet _ _ -> True
+  _ -> False
+
+-- |is expression a declaration of free variables?
+isTFree :: TExpr -> Bool
+isTFree e = case e of
+  TFree _ _ -> True
+  _ -> False
+
+-- |is expression an or-expression?
+isTOr :: TExpr -> Bool
+isTOr e = case e of
+  TOr _ _ -> True
+  _ -> False
+
+-- |is expression a case expression?
+isTCase :: TExpr -> Bool
+isTCase e = case e of
+  TCase _ _ _ -> True
+  _ -> False
+
+-- |transform expression
+trTExpr  :: (TypeExpr -> VarIndex -> b)
+         -> (TypeExpr -> Literal -> b)
+         -> (TypeExpr -> CombType -> QName -> [b] -> b)
+         -> ([((VarIndex, TypeExpr), b)] -> b -> b)
+         -> ([(VarIndex, TypeExpr)] -> b -> b)
+         -> (b -> b -> b)
+         -> (CaseType -> b -> [c] -> b)
+         -> (TPattern -> b -> c)
+         -> (b -> TypeExpr -> b)
+         -> TExpr
+         -> b
+trTExpr var lit comb lt fr oR cas branch typed expr = case expr of
+  TVarE ty n            -> var ty n
+  TLit ty l             -> lit ty l
+  TComb ty ct name args -> comb ty ct name (map f args)
+  TLet bs e             -> lt (map (\(v, x) -> (v, f x)) bs) (f e)
+  TFree vs e            -> fr vs (f e)
+  TOr e1 e2             -> oR (f e1) (f e2)
+  TCase ct e bs         -> cas ct (f e) (map (\ (TBranch p e') -> branch p (f e')) bs)
+  TTyped e ty           -> typed (f e) ty
+  where
+  f = trTExpr var lit comb lt fr oR cas branch typed
+
+-- |update all variables in given expression
+updVars :: (TypeExpr -> VarIndex -> TExpr) -> TExpr -> TExpr
+updVars var = trTExpr var TLit TComb TLet TFree TOr TCase TBranch TTyped
+
+-- |update all literals in given expression
+updLiterals :: (TypeExpr -> Literal -> TExpr) -> TExpr -> TExpr
+updLiterals lit = trTExpr TVarE lit TComb TLet TFree TOr TCase TBranch TTyped
+
+-- |update all combined expressions in given expression
+updCombs :: (TypeExpr -> CombType -> QName -> [TExpr] -> TExpr) -> TExpr -> TExpr
+updCombs comb = trTExpr TVarE TLit comb TLet TFree TOr TCase TBranch TTyped
+
+-- |update all let expressions in given expression
+updLets :: ([((VarIndex, TypeExpr), TExpr)] -> TExpr -> TExpr) -> TExpr -> TExpr
+updLets lt = trTExpr TVarE TLit TComb lt TFree TOr TCase TBranch TTyped
+
+-- |update all free declarations in given expression
+updFrees :: ([(VarIndex, TypeExpr)] -> TExpr -> TExpr) -> TExpr -> TExpr
+updFrees fr = trTExpr TVarE TLit TComb TLet fr TOr TCase TBranch TTyped
+
+-- |update all or expressions in given expression
+updOrs :: (TExpr -> TExpr -> TExpr) -> TExpr -> TExpr
+updOrs oR = trTExpr TVarE TLit TComb TLet TFree oR TCase TBranch TTyped
+
+-- |update all case expressions in given expression
+updCases :: (CaseType -> TExpr -> [TBranchExpr] -> TExpr) -> TExpr -> TExpr
+updCases cas = trTExpr TVarE TLit TComb TLet TFree TOr cas TBranch TTyped
+
+-- |update all case branches in given expression
+updBranches :: (TPattern -> TExpr -> TBranchExpr) -> TExpr -> TExpr
+updBranches branch = trTExpr TVarE TLit TComb TLet TFree TOr TCase branch TTyped
+
+-- |update all typed expressions in given expression
+updTypeds :: (TExpr -> TypeExpr -> TExpr) -> TExpr -> TExpr
+updTypeds = trTExpr TVarE TLit TComb TLet TFree TOr TCase TBranch
+
+-- Auxiliary Functions
+
+-- |is expression a call of a function where all arguments are provided?
+isFuncCall :: TExpr -> Bool
+isFuncCall e = isTComb e && isCombTypeFuncCall (combType e)
+
+-- |is expression a partial function call?
+isFuncPartCall :: TExpr -> Bool
+isFuncPartCall e = isTComb e && isCombTypeFuncPartCall (combType e)
+
+-- |is expression a call of a constructor?
+isConsCall :: TExpr -> Bool
+isConsCall e = isTComb e && isCombTypeConsCall (combType e)
+
+-- |is expression a partial constructor call?
+isConsPartCall :: TExpr -> Bool
+isConsPartCall e = isTComb e && isCombTypeConsPartCall (combType e)
+
+-- |is expression fully evaluated?
+isGround :: TExpr -> Bool
+isGround e
+  = case e of
+      TComb _ ConsCall _ args -> all isGround args
+      _ -> isTLit e
+
+-- |get all variables (also pattern variables) in expression
+allVars :: TExpr -> [(VarIndex, TypeExpr)]
+allVars e = trTExpr var lit comb lt fr (.) cas branch typ e []
+ where
+  var a v = (:) (v, a)
+  lit = const (const id)
+  comb _ _ _ = foldr (.) id
+  lt bs e' = e' . foldr (.) id (map (\(n,ns) -> (n:) . ns) bs)
+  fr vs e' = (vs++) . e'
+  cas _ e' bs = e' . foldr (.) id bs
+  branch pat e' = (args pat ++) . e'
+  typ = const
+  args pat | isConsPattern pat = tPatArgs pat
+           | otherwise = []
+
+-- |rename all variables (also in patterns) in expression
+rnmAllVars :: Update TExpr VarIndex
+rnmAllVars f = trTExpr var TLit TComb lt fr TOr TCase branch TTyped
+ where
+   var a = TVarE a . f
+   lt = TLet . map (\((n, b), e) -> ((f n, b), e))
+   fr = TFree . map (\(b, c) -> (f b, c))
+   branch = TBranch . updTPatArgs (map (\(a, b) -> (f a, b)))
+
+-- |update all qualified names in expression
+updQNames :: Update TExpr QName
+updQNames f = trTExpr TVarE TLit comb TLet TFree TOr TCase branch TTyped
+ where
+  comb ty ct name args = TComb ty ct (f name) args
+  branch = TBranch . updTPatCons f
+
+-- TBranchExpr ----------------------------------------------------------------
+
+-- |transform branch expression
+trTBranch :: (TPattern -> TExpr -> b) -> TBranchExpr -> b
+trTBranch branch (TBranch pat e) = branch pat e
+
+-- Selectors
+
+-- |get pattern from branch expression
+tBranchTPattern :: TBranchExpr -> TPattern
+tBranchTPattern = trTBranch const
+
+-- |get expression from branch expression
+tBranchTExpr :: TBranchExpr -> TExpr
+tBranchTExpr = trTBranch (\_ e -> e)
+
+-- Update Operations
+
+-- |update branch expression
+updTBranch :: (TPattern -> TPattern) -> (TExpr -> TExpr) -> TBranchExpr -> TBranchExpr
+updTBranch fp fe = trTBranch branch
+ where
+  branch pat e = TBranch (fp pat) (fe e)
+
+-- |update pattern of branch expression
+updTBranchTPattern :: Update TBranchExpr TPattern
+updTBranchTPattern f = updTBranch f id
+
+-- |update expression of branch expression
+updTBranchTExpr :: Update TBranchExpr TExpr
+updTBranchTExpr = updTBranch id
+
+-- TPattern -------------------------------------------------------------------
+
+-- |transform pattern
+trTPattern :: (TypeExpr -> QName -> [(VarIndex, TypeExpr)] -> b) -> (TypeExpr -> Literal -> b) -> TPattern -> b
+trTPattern pat _ (TPattern ty name args) = pat ty name args
+trTPattern _ lpat (TLPattern a l) = lpat a l
+
+-- Selectors
+
+-- |get name from constructor pattern
+tPatCons :: TPattern -> QName
+tPatCons = trTPattern (\_ name _ -> name) undefined
+
+-- |get arguments from constructor pattern
+tPatArgs :: TPattern -> [(VarIndex, TypeExpr)]
+tPatArgs = trTPattern (\_ _ args -> args) undefined
+
+-- |get literal from literal pattern
+tPatLiteral :: TPattern -> Literal
+tPatLiteral = trTPattern undefined (const id)
+
+-- Test Operations
+
+-- |is pattern a constructor pattern?
+isConsPattern :: TPattern -> Bool
+isConsPattern = trTPattern (\_ _ _ -> True) (\_ _ -> False)
+
+-- Update Operations
+
+-- |update pattern
+updTPattern :: (TypeExpr -> TypeExpr) ->
+               (QName -> QName) ->
+               ([(VarIndex, TypeExpr)] -> [(VarIndex, TypeExpr)]) ->
+               (Literal -> Literal) -> TPattern -> TPattern
+updTPattern fannot fn fa fl = trTPattern pattern lpattern
+ where
+  pattern ty name args = TPattern (fannot ty) (fn name) (fa args)
+  lpattern ty l = TLPattern (fannot ty) (fl l)
+
+-- |update TypeExpr of pattern
+updTPatType :: (TypeExpr -> TypeExpr) -> TPattern -> TPattern
+updTPatType f = updTPattern f id id id
+
+-- |update constructors name of pattern
+updTPatCons :: (QName -> QName) -> TPattern -> TPattern
+updTPatCons f = updTPattern id f id id
+
+-- |update arguments of constructor pattern
+updTPatArgs :: ([(VarIndex, TypeExpr)] -> [(VarIndex, TypeExpr)]) -> TPattern -> TPattern
+updTPatArgs f = updTPattern id id f id
+
+-- |update literal of pattern
+updTPatLiteral :: (Literal -> Literal) -> TPattern -> TPattern
+updTPatLiteral = updTPattern id id id
+
+-- Auxiliary Functions
+
+-- |build expression from pattern
+tPatExpr :: TPattern -> TExpr
+tPatExpr = trTPattern (\ty name -> TComb ty ConsCall name . map (uncurry (flip TVarE))) TLit
diff --git a/src/Curry/FlatCurry/Typed/Type.hs b/src/Curry/FlatCurry/Typed/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/FlatCurry/Typed/Type.hs
@@ -0,0 +1,146 @@
+{- |
+    Module      : $Header$
+    Description : Representation of annotated FlatCurry.
+    Copyright   : (c) 2016 - 2017 Finn Teegen
+                      2018        Kai-Oliver Prott
+    License     : BSD-3-clause
+
+    Maintainer  : fte@informatik.uni-kiel.de
+    Stability   : experimental
+    Portability : portable
+
+    This library contains a version of FlatCurry's abstract syntax tree
+    modified with type information
+
+    For more information about the abstract syntax tree of `FlatCurry`,
+    see the documentation of the respective module.
+-}
+
+module Curry.FlatCurry.Typed.Type
+  ( module Curry.FlatCurry.Typed.Type
+  , module Curry.FlatCurry.Typeable
+  , module Curry.FlatCurry.Type
+  ) where
+
+import Data.Binary
+import Control.Monad
+
+import Curry.FlatCurry.Typeable
+import Curry.FlatCurry.Type ( QName, VarIndex, Visibility (..), TVarIndex
+                            , TypeDecl (..), Kind (..), OpDecl (..), Fixity (..)
+                            , TypeExpr (..), ConsDecl (..), NewConsDecl (..)
+                            , Literal (..), CombType (..), CaseType (..)
+                            )
+
+data TProg = TProg String [String] [TypeDecl] [TFuncDecl] [OpDecl]
+  deriving (Eq, Read, Show)
+
+data TFuncDecl = TFunc QName Int Visibility TypeExpr TRule
+  deriving (Eq, Read, Show)
+
+data TRule
+  = TRule     [(VarIndex, TypeExpr)] TExpr
+  | TExternal TypeExpr String
+  deriving (Eq, Read, Show)
+
+data TExpr
+  = TVarE  TypeExpr VarIndex -- otherwise name clash with TypeExpr's TVar
+  | TLit   TypeExpr Literal
+  | TComb  TypeExpr CombType QName [TExpr]
+  | TLet   [((VarIndex, TypeExpr), TExpr)] TExpr
+  | TFree  [(VarIndex, TypeExpr)] TExpr
+  | TOr    TExpr TExpr
+  | TCase  CaseType TExpr [TBranchExpr]
+  | TTyped TExpr TypeExpr
+  deriving (Eq, Read, Show)
+
+data TBranchExpr = TBranch TPattern TExpr
+  deriving (Eq, Read, Show)
+
+data TPattern
+  = TPattern  TypeExpr QName [(VarIndex, TypeExpr)]
+  | TLPattern TypeExpr Literal
+  deriving (Eq, Read, Show)
+
+instance Typeable TRule where
+  typeOf (TRule args e) = foldr (FuncType . snd) (typeOf e) args
+  typeOf (TExternal ty _) = ty
+
+instance Typeable TExpr where
+  typeOf (TVarE ty _) = ty
+  typeOf (TLit ty _) = ty
+  typeOf (TComb  ty _ _ _) = ty
+  typeOf (TLet _ e) = typeOf e
+  typeOf (TFree _ e) = typeOf e
+  typeOf (TOr e _) = typeOf e
+  typeOf (TCase _ _ (e:_)) = typeOf e
+  typeOf (TTyped _ ty) = ty
+  typeOf (TCase _ _ []) = error $ "Curry.FlatCurry.Typed.Type.typeOf: " ++
+                                  "empty list in case expression"
+
+instance Typeable TPattern where
+  typeOf (TPattern ty _ _) = ty
+  typeOf (TLPattern ty _) = ty
+
+instance Typeable TBranchExpr where
+  typeOf (TBranch _ e) = typeOf e
+
+instance Binary TProg where
+  put (TProg mid im tys fus ops) =
+    put mid >> put im >> put tys >> put fus >> put ops
+  get = TProg <$> get <*> get <*> get <*> get <*> get
+
+instance Binary TFuncDecl where
+  put (TFunc qid arity vis ty r) =
+    put qid >> put arity >> put vis >> put ty >> put r
+  get = TFunc <$> get <*> get <*> get <*> get <*> get
+
+instance Binary TRule where
+  put (TRule     alts e) = putWord8 0 >> put alts >> put e
+  put (TExternal ty n  ) = putWord8 1 >> put ty   >> put n
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 TRule get get
+      1 -> liftM2 TExternal get get
+      _ -> fail "Invalid encoding for TRule"
+
+instance Binary TExpr where
+  put (TVarE ty v) = putWord8 0 >> put ty >> put v
+  put (TLit  ty l) = putWord8 1 >> put ty >> put l
+  put (TComb ty cty qid es) =
+    putWord8 2 >> put ty >> put cty >> put qid >> put es
+  put (TLet  bs e) = putWord8 3 >> put bs >> put e
+  put (TFree vs e) = putWord8 4 >> put vs >> put e
+  put (TOr  e1 e2) = putWord8 5 >> put e1 >> put e2
+  put (TCase cty ty as) = putWord8 6 >> put cty >> put ty >> put as
+  put (TTyped e ty) = putWord8 7 >> put e >> put ty
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 TVarE get get
+      1 -> liftM2 TLit get get
+      2 -> liftM4 TComb get get get get
+      3 -> liftM2 TLet get get
+      4 -> liftM2 TFree get get
+      5 -> liftM2 TOr get get
+      6 -> liftM3 TCase get get get
+      7 -> liftM2 TTyped get get
+      _ -> fail "Invalid encoding for TExpr"
+
+instance Binary TBranchExpr where
+  put (TBranch p e) = put p >> put e
+  get = liftM2 TBranch get get
+
+instance Binary TPattern where
+  put (TPattern  ty qid vs) = putWord8 0 >> put ty >> put qid >> put vs
+  put (TLPattern ty l     ) = putWord8 1 >> put ty >> put l
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM3 TPattern get get get
+      1 -> liftM2 TLPattern get get
+      _ -> fail "Invalid encoding for TPattern"
diff --git a/src/Curry/Syntax.hs b/src/Curry/Syntax.hs
--- a/src/Curry/Syntax.hs
+++ b/src/Curry/Syntax.hs
@@ -1,43 +1,81 @@
-{-
-  A simple interface for reading and manipulating Curry
-  source code.
+{- |
+    Module      :  $Header$
+    Description :  Interface for reading and manipulating Curry source code
+    Copyright   :  (c) 2009        Holger Siegel
+                       2011 - 2013 Björn Peemöller
+                       2016        Finn Teegen
+                       2016        Jan Tikovsky
+    License     :  BSD-3-clause
 
-  (c) 2009, Holger Siegel.
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
 -}
-
 module Curry.Syntax
   ( module Curry.Syntax.Type
-  , parseModule
-  , parseHeader
+  , module Curry.Syntax.Utils
+  , L.Token (..), L.Category (..), L.Attributes (..)
+  , unlit, unlitLexSource, unlitParseHeader, unlitParsePragmas, unlitParseModule
+  , lexSource, parseInterface, parseHeader, parsePragmas, parseModule, parseGoal
+  , pPrint, pPrintPrec
+  , showModule
   ) where
 
-import Control.Monad
-import Data.List
+import           Curry.Base.Monad             (CYM)
+import           Curry.Base.Span              (Span)
+import           Curry.Base.Pretty            (pPrint, pPrintPrec)
+import qualified Curry.Files.Unlit       as U (unlit)
 
-import Curry.Base.MessageMonad
-import Curry.Syntax.Type
-import qualified Curry.Syntax.Parser as CSP
-import Curry.Syntax.Unlit
+import qualified Curry.Syntax.Lexer      as L
+import qualified Curry.Syntax.Parser     as P
+import           Curry.Syntax.Pretty          ()
+import           Curry.Syntax.ShowModule      (showModule)
+import           Curry.Syntax.Type
+import           Curry.Syntax.Utils
 
--- | Parses a curry module.
-parseModule :: Bool -> FilePath -> String -> MsgMonad Module
-parseModule likeFlat fn =
-  unlitLiterate fn >=> CSP.parseSource likeFlat fn
+-- |Unliterate a LiterateCurry file, identity on normal Curry file.
+unlit :: FilePath -> String -> CYM String
+unlit = U.unlit
 
--- | Pares a curry header
-parseHeader :: FilePath -> String -> MsgMonad Module
-parseHeader fn =
-  unlitLiterate fn >=> CSP.parseHeader fn
+-- |Unliterate and return the result of a lexical analysis of the source
+-- program @src@.
+-- The result is a list of tuples consisting of a 'Span' and a 'Token'.
+unlitLexSource :: FilePath -> String -> CYM [(Span, L.Token)]
+unlitLexSource fn src = U.unlit fn src >>= L.lexSource fn
 
--- Literate source files use the extension ".lcurry"
-unlitLiterate :: FilePath -> String -> MsgMonad String
-unlitLiterate fn s
-  | isLiterateSource fn = unlit fn s
-  | otherwise = return s
+-- |Unliterate and parse only pragmas of a Curry 'Module'
+unlitParsePragmas :: FilePath -> String -> CYM (Module ())
+unlitParsePragmas fn src = U.unlit fn src >>= P.parsePragmas fn
 
--- | Compute if a file contains literate curry by its extension
-isLiterateSource :: FilePath -> Bool
-isLiterateSource fn = litExt `isSuffixOf` fn
+-- |Unliterate and parse a Curry 'Module' header
+unlitParseHeader :: FilePath -> String -> CYM (Module ())
+unlitParseHeader fn src = U.unlit fn src >>= P.parseHeader fn
 
-litExt = ".lcurry"
+-- |Unliterate and parse a Curry 'Module'
+unlitParseModule :: FilePath -> String -> CYM (Module ())
+unlitParseModule fn src = U.unlit fn src >>= P.parseSource fn
 
+-- |Return the result of a lexical analysis of the source program @src@.
+-- The result is a list of tuples consisting of a 'Span' and a 'Token'.
+lexSource :: FilePath -> String -> CYM [(Span, L.Token)]
+lexSource = L.lexSource
+
+-- |Parse a Curry 'Interface'
+parseInterface :: FilePath -> String -> CYM Interface
+parseInterface = P.parseInterface
+
+-- |Parse only pragmas of a Curry 'Module'
+parsePragmas :: FilePath -> String -> CYM (Module ())
+parsePragmas = P.parsePragmas
+
+-- |Parse a Curry 'Module' header
+parseHeader :: FilePath -> String -> CYM (Module ())
+parseHeader = P.parseHeader
+
+-- |Parse a Curry 'Module'
+parseModule :: FilePath -> String -> CYM (Module ())
+parseModule = P.parseSource
+
+-- |Parse a 'Goal', i.e. an expression with (optional) local declarations
+parseGoal :: String -> CYM (Goal ())
+parseGoal = P.parseGoal
diff --git a/src/Curry/Syntax/Extension.hs b/src/Curry/Syntax/Extension.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Syntax/Extension.hs
@@ -0,0 +1,120 @@
+{- |
+    Module      :  $Header$
+    Description :  Curry language extensions
+    Copyright   :  (c) 2013 - 2014 Björn Peemöller
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module provides the data structures for Curry language extensions.
+-}
+
+module Curry.Syntax.Extension
+  ( -- * Extensions
+    Extension (..), KnownExtension (..), classifyExtension, kielExtensions
+    -- * Tools
+  , Tool (..), classifyTool
+  ) where
+
+import Data.Binary
+import Data.Char           (toUpper)
+import Control.Monad
+
+import Curry.Base.Ident    (Ident (..))
+import Curry.Base.Position
+import Curry.Base.SpanInfo
+
+-- |Specified language extensions, either known or unknown.
+data Extension
+  = KnownExtension   SpanInfo KnownExtension -- ^ a known extension
+  | UnknownExtension SpanInfo String         -- ^ an unknown extension
+    deriving (Eq, Read, Show)
+
+instance HasSpanInfo Extension where
+  getSpanInfo (KnownExtension   spi _) = spi
+  getSpanInfo (UnknownExtension spi _) = spi
+  
+  setSpanInfo spi (KnownExtension   _ ke) = KnownExtension spi ke
+  setSpanInfo spi (UnknownExtension _ s)  = UnknownExtension spi s
+
+instance HasPosition Extension where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance Binary Extension where
+  put (KnownExtension   p e) = putWord8 0 >> put p >> put e
+  put (UnknownExtension p e) = putWord8 1 >> put p >> put e
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 KnownExtension get get
+      1 -> liftM2 UnknownExtension get get
+      _ -> fail "Invalid encoding for Extension"
+
+instance Binary KnownExtension where
+  put AnonFreeVars       = putWord8 0
+  put CPP                = putWord8 1
+  put FunctionalPatterns = putWord8 2
+  put NegativeLiterals   = putWord8 3
+  put NoImplicitPrelude  = putWord8 4
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> return AnonFreeVars
+      1 -> return CPP
+      2 -> return FunctionalPatterns
+      3 -> return NegativeLiterals
+      4 -> return NoImplicitPrelude
+      _ -> fail "Invalid encoding for KnownExtension"
+
+-- |Known language extensions of Curry.
+data KnownExtension
+  = AnonFreeVars              -- ^ anonymous free variables
+  | CPP                       -- ^ C preprocessor
+  | FunctionalPatterns        -- ^ functional patterns
+  | NegativeLiterals          -- ^ negative literals
+  | NoImplicitPrelude         -- ^ no implicit import of the prelude
+    deriving (Eq, Read, Show, Enum, Bounded)
+
+-- |Classifies a 'String' as an 'Extension'
+classifyExtension :: Ident -> Extension
+classifyExtension i = case reads extName of
+  [(e, "")] -> KnownExtension   (getSpanInfo i) e
+  _         -> UnknownExtension (getSpanInfo i) extName
+  where extName = idName i
+
+-- |'Extension's available by Kiel's Curry compilers.
+kielExtensions :: [KnownExtension]
+kielExtensions = [AnonFreeVars, FunctionalPatterns]
+
+-- |Different Curry tools which may accept compiler options.
+data Tool = KICS2 | PAKCS | CYMAKE | FRONTEND | UnknownTool String
+    deriving (Eq, Read, Show)
+
+instance Binary Tool where
+  put KICS2           = putWord8 0
+  put PAKCS           = putWord8 1
+  put CYMAKE          = putWord8 2
+  put FRONTEND        = putWord8 3
+  put (UnknownTool s) = putWord8 4 >> put s
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> return KICS2
+      1 -> return PAKCS
+      2 -> return CYMAKE
+      3 -> return FRONTEND
+      4 -> fmap UnknownTool get
+      _ -> fail "Invalid encoding for Tool"
+
+-- |Classifies a 'String' as a 'Tool'
+classifyTool :: String -> Tool
+classifyTool str = case reads (map toUpper str) of
+  [(t, "")] -> t
+  _         -> UnknownTool str
diff --git a/src/Curry/Syntax/Frontend.hs b/src/Curry/Syntax/Frontend.hs
deleted file mode 100644
--- a/src/Curry/Syntax/Frontend.hs
+++ /dev/null
@@ -1,202 +0,0 @@
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---
--- Frontend - Provides an API for dealing with several kinds of Curry
---            program representations
---
--- December 2005,
--- Martin Engelke (men@informatik.uni-kiel.de)
---
-module Curry.Syntax.Frontend (lex, parse, fullParse, typingParse)where
-
-import Data.Maybe
-import qualified Data.Map as Map
-import Control.Monad.Writer
-import Control.Monad.Error
-import Prelude hiding (lex)
-
-
-import Curry.Base.MessageMonad
-import Curry.Base.Ident
-import Curry.Base.Position
-
-import Curry.Files.Filenames
-import Curry.Files.PathUtils
-
-import qualified Curry.Syntax as CS
-import Curry.Syntax.Lexer
-
-import Modules
-import CurryBuilder
-import CurryCompilerOpts
-
-import CurryDeps
-
-import Base(ModuleEnv)
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
--- Returns the result of a lexical analysis of the source program 'src'.
--- The result is a list of tuples consisting of a position and a token
--- (see Modules "Position" and "CurryLexer")
-lex :: FilePath -> String -> MsgMonad [(Position,Token)]
-lex fn src = lexFile (first fn) src False []
-
-
--- Returns the result of a syntactical analysis of the source program 'src'.
--- The result is the syntax tree of the program (type 'Module'; see Module
--- "CurrySyntax").
-parse :: FilePath -> String -> MsgMonad CS.Module
-parse fn src = CS.parseModule True fn src >>= genCurrySyntax fn
-
-
--- Returns the syntax tree of the source program 'src' (type 'Module'; see
--- Module "CurrySyntax") after resolving the category (i.e. function,
--- constructor or variable) of an identifier. 'fullParse' always
--- searches for standard Curry libraries in the path defined in the
--- environment variable "PAKCSLIBPATH". Additional search paths can
--- be defined using the argument 'paths'.
-fullParse :: [FilePath] -> FilePath -> String -> IO (MsgMonad CS.Module)
-fullParse paths fn src = -- liftM msgmonad2result $
-                         genFullCurrySyntax simpleCheckModule paths fn (parse fn src)
-
--- Behaves like 'fullParse', but Returns the syntax tree of the source 
--- program 'src' (type 'Module'; see Module "CurrySyntax") after inferring 
--- the types of identifiers.
-typingParse :: [FilePath] -> FilePath -> String -> IO (MsgMonad CS.Module)
-typingParse paths fn src = genFullCurrySyntax checkModule paths fn (parse fn src)
-
-{-
--- Compiles the source programm 'src' to an AbstractCurry program.
--- 'fullParse' always searches for standard Curry libraries in the path 
--- defined in the environment variable "PAKCSLIBPATH". Additional search 
--- paths can be defined using the argument 'paths'.
--- Notes: Due to the lack of error handling in the current version of the
--- front end, this function may fail when an error occurs
-abstractIO :: [FilePath] -> FilePath -> String -> IO (MsgMonad ACY.CurryProg)
-abstractIO paths fn src = genAbstractIO paths fn (parse fn src)
-
--- Compiles the source program 'src' to a FlatCurry program.
--- 'fullParse' always searches for standard Curry libraries in the path 
--- defined in the environment variable "PAKCSLIBPATH". Additional search 
--- paths can be defined using the argument 'paths'.
--- Note: Due to the lack of error handling in the current version of the
--- front end, this function may fail when an error occurs
-flatIO :: [FilePath] -> FilePath -> String -> IO (MsgMonad FCY.Prog)
-flatIO paths fn src = genFlatIO paths fn (parse fn src)
--}
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--- Privates...
-
-
-opts paths = defaultOpts{ 
-                     importPaths = paths,
-		     noVerb      = True,
-		     noWarn      = True,
-		     abstract    = True
-		   }
-
-
---
-genCurrySyntax :: FilePath -> CS.Module -> MsgMonad (CS.Module)
-genCurrySyntax fn mod
-    = let mod'@(CS.Module mid _ _) = patchModuleId fn (importPrelude fn mod)
-      in if isValidModuleId fn mid
-	 then return mod'
-	 else failWith $ err_invalidModuleName mid
-
-
---
-genFullCurrySyntax :: (Options -> Base.ModuleEnv -> CS.Module -> IO (t1, t2, t3, CS.Module, t4, [WarnMsg]))
-                   -> [FilePath] -> t -> MsgMonad CS.Module -> IO (MsgMonad CS.Module)
-genFullCurrySyntax check paths fn m
-   = runMsgIO m $ \mod -> do errs <- makeInterfaces paths mod
-	                     if null errs
-	                       then do mEnv <- loadInterfaces paths mod
-		                       (_, _, _, mod', _, msgs') <- check (opts paths) mEnv mod
-		                       return (tell msgs' >> return  mod')
-	                       else return (failWith (head errs))
-
-
-{-
-genAbstractIO :: [FilePath] -> FilePath -> MsgMonad CS.Module
-	      -> IO (MsgMonad ACY.CurryProg)
-genAbstractIO paths fn m
-   = runMsgIO m $ \mod ->
-     do errs <- makeInterfaces paths mod
-	if null errs
-	   then do mEnv <- loadInterfaces paths mod
-		   (tyEnv, tcEnv, _, mod', _, msgs')
-		       <- simpleCheckModule (opts paths) mEnv mod
-		   return (tell msgs' >> return (genTypedAbstract tyEnv tcEnv mod'))
-	   else return (failWith $ head errs)
-
-
---
-genFlatIO :: [FilePath] -> FilePath -> MsgMonad CS.Module -> IO (MsgMonad FCY.Prog)
-genFlatIO paths fn m
-   = runMsgIO m $ \ mod -> 
-     do errs <- makeInterfaces paths mod
-	if null errs then
-	   (do mEnv <- loadInterfaces paths mod
-	       (tyEnv, tcEnv, aEnv, mod', intf, msgs') <- 
-	           checkModule (opts paths) mEnv mod
-	       let (il, aEnv', _) 
-	              = transModule True True False mEnv tyEnv tcEnv aEnv mod'
-	           il' = completeCase mEnv il
-	           cEnv = curryEnv mEnv tcEnv intf mod'
-	           (prog,msgs'') = genFlatCurry (opts paths) cEnv mEnv 
-	                                        tyEnv tcEnv aEnv' il'
-               return (tell msgs'' >> tell msgs' >> return prog)
-	   )
-	   else return (failWith $ head errs)
--}
-
-
--------------------------------------------------------------------------------
-
--- Generates interface files for importes modules, if they don't exist or
--- if they are not up-to-date.
-makeInterfaces ::  [FilePath] -> CS.Module -> IO [String]
-makeInterfaces paths (CS.Module mid _ decls)
-  = do let imports = [preludeMIdent | mid /= preludeMIdent] 
-		      ++ [imp | CS.ImportDecl _ imp _ _ _ <- decls]
-       (deps, errs) <- fmap flattenDeps (foldM (moduleDeps paths []) Map.empty imports)
-       when (null errs) (mapM_ (compile deps . snd) deps)
-       return errs
- where
- compile deps (Source file' mods)
-    = do smake [flatName file', flatIntName file']
-	       (file':mapMaybe (flatInterface deps) mods)
-	       (compileModule (opts paths) file')
-	       (return Nothing)
-	 return ()
- compile _ _ = return ()
-
- flatInterface deps mod 
-    = case (lookup mod deps) of
-        Just (Source file _)  -> Just (flatIntName (dropExtension file))
-	Just (Interface file) -> Just (flatIntName (dropExtension file))
-	_                     -> Nothing
-
-
--- Returns 'True', if file name and module name are equal.
-isValidModuleId :: FilePath -> ModuleIdent -> Bool
-isValidModuleId fn mid
-   = last (moduleQualifiers mid) == takeBaseName fn
-
-
--------------------------------------------------------------------------------
--- Messages
-
-err_invalidModuleName :: ModuleIdent -> String
-err_invalidModuleName mid 
-   = "module \"" ++ moduleName mid 
-     ++ "\" must be in a file \"" ++ moduleName mid ++ ".curry\""
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
diff --git a/src/Curry/Syntax/InterfaceEquivalence.hs b/src/Curry/Syntax/InterfaceEquivalence.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Syntax/InterfaceEquivalence.hs
@@ -0,0 +1,209 @@
+{- |
+    Module      :  $Header$
+    Description :  Comparison of Curry Interfaces
+    Copyright   :  (c) 2000 - 2007 Wolfgang Lux
+                       2014 - 2015 Björn Peemöller
+                       2014        Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    If a module is recompiled, the compiler has to check whether the
+    interface file must be updated. This must be done if any exported
+    entity has been changed, or an export was removed or added. The
+    function 'intfEquiv' checks whether two interfaces are
+    equivalent, i.e., whether they define the same entities.
+-}
+module Curry.Syntax.InterfaceEquivalence (fixInterface, intfEquiv) where
+
+import Data.List (deleteFirstsBy, sort)
+import qualified Data.Set as Set
+
+import Curry.Base.Ident
+import Curry.Syntax
+
+infix 4 =~=, `eqvSet`
+
+-- |Are two given interfaces equivalent?
+intfEquiv :: Interface -> Interface -> Bool
+intfEquiv = (=~=)
+
+-- |Type class to express the equivalence of two values
+class Equiv a where
+  (=~=) :: a -> a -> Bool
+
+instance Equiv a => Equiv (Maybe a) where
+  Nothing =~= Nothing = True
+  Nothing =~= Just _  = False
+  Just _  =~= Nothing = False
+  Just x  =~= Just y  = x =~= y
+
+instance Equiv a => Equiv [a] where
+  []     =~= []     = True
+  (x:xs) =~= (y:ys) = x =~= y && xs =~= ys
+  _      =~= _      = False
+
+eqvList, eqvSet :: Equiv a => [a] -> [a] -> Bool
+xs `eqvList` ys = length xs == length ys && and (zipWith (=~=) xs ys)
+xs `eqvSet` ys = null (deleteFirstsBy (=~=) xs ys ++ deleteFirstsBy (=~=) ys xs)
+
+instance Equiv Interface where
+  Interface m1 is1 ds1 =~= Interface m2 is2 ds2
+    = m1 == m2 && is1 `eqvSet` is2 && ds1 `eqvSet` ds2
+
+instance Equiv IImportDecl where
+  IImportDecl _ m1 =~= IImportDecl _ m2 = m1 == m2
+
+-- Since the kind of type constructors or type classes can be omitted
+-- in the interface when the kind is simple, i.e., it is either * or of
+-- the form * -> ... -> *, a non given kind has to be considered equivalent
+-- to a given one if the latter is simple.
+
+eqvKindExpr :: Maybe KindExpr -> Maybe KindExpr -> Bool
+Nothing  `eqvKindExpr` (Just k) = isSimpleKindExpr k
+(Just k) `eqvKindExpr` Nothing  = isSimpleKindExpr k
+k1       `eqvKindExpr` k2       = k1 == k2
+
+isSimpleKindExpr :: KindExpr -> Bool
+isSimpleKindExpr Star               = True
+isSimpleKindExpr (ArrowKind Star k) = isSimpleKindExpr k
+isSimpleKindExpr _                  = False
+
+
+instance Equiv IDecl where
+  IInfixDecl _ fix1 p1 op1 =~= IInfixDecl _ fix2 p2 op2
+    = fix1 == fix2 && p1 == p2 && op1 == op2
+  HidingDataDecl _ tc1 k1 tvs1 =~= HidingDataDecl _ tc2 k2 tvs2
+    = tc1 == tc2 && k1 `eqvKindExpr` k2 && tvs1 == tvs2
+  IDataDecl _ tc1 k1 tvs1 cs1 hs1 =~= IDataDecl _ tc2 k2 tvs2 cs2 hs2
+    = tc1 == tc2 && k1 `eqvKindExpr` k2 && tvs1 == tvs2 && cs1 =~= cs2 &&
+      hs1 `eqvSet` hs2
+  INewtypeDecl _ tc1 k1 tvs1 nc1 hs1 =~= INewtypeDecl _ tc2 k2 tvs2 nc2 hs2
+    = tc1 == tc2 && k1 `eqvKindExpr` k2 && tvs1 == tvs2 && nc1 =~= nc2 &&
+      hs1 `eqvSet` hs2
+  ITypeDecl _ tc1 k1 tvs1 ty1 =~= ITypeDecl _ tc2 k2 tvs2 ty2
+    = tc1 == tc2 && k1 `eqvKindExpr` k2 && tvs1 == tvs2 && ty1 == ty2
+  IFunctionDecl _ f1 cm1 n1 qty1 =~= IFunctionDecl _ f2 cm2 n2 qty2
+    = f1 == f2 && cm1 == cm2 && n1 == n2 && qty1 == qty2
+  HidingClassDecl _ cx1 cls1 k1 _ =~= HidingClassDecl _ cx2 cls2 k2 _
+    = cx1 == cx2 && cls1 == cls2 && k1 `eqvKindExpr` k2
+  IClassDecl _ cx1 cls1 k1 _ ms1 hs1 =~= IClassDecl _ cx2 cls2 k2 _ ms2 hs2
+    = cx1 == cx2 && cls1 == cls2 && k1 `eqvKindExpr` k2 &&
+      ms1 `eqvList` ms2 && hs1 `eqvSet` hs2
+  IInstanceDecl _ cx1 cls1 ty1 is1 m1 =~= IInstanceDecl _ cx2 cls2 ty2 is2 m2
+    = cx1 == cx2 && cls1 == cls2 && ty1 == ty2 && sort is1 == sort is2 &&
+      m1 == m2
+  _ =~= _ = False
+
+instance Equiv ConstrDecl where
+  ConstrDecl _ c1 tys1 =~= ConstrDecl _ c2 tys2
+    = c1 == c2 && tys1 == tys2
+  ConOpDecl _ ty11 op1 ty12 =~= ConOpDecl _ ty21 op2 ty22
+    = op1 == op2 && ty11 == ty21 && ty12 == ty22
+  RecordDecl _ c1 fs1 =~= RecordDecl _ c2 fs2
+    = c1 == c2 && fs1 `eqvList` fs2
+  _ =~= _ = False
+
+instance Equiv FieldDecl where
+  FieldDecl _ ls1 ty1 =~= FieldDecl _ ls2 ty2 = ls1 == ls2 && ty1 == ty2
+
+instance Equiv NewConstrDecl where
+  NewConstrDecl _ c1 ty1 =~= NewConstrDecl _ c2 ty2 = c1 == c2 && ty1 == ty2
+  NewRecordDecl _ c1 fld1 =~= NewRecordDecl _ c2 fld2 = c1 == c2 && fld1 == fld2
+  _ =~= _ = False
+
+instance Equiv IMethodDecl where
+  IMethodDecl _ f1 a1 qty1 =~= IMethodDecl _ f2 a2 qty2
+    = f1 == f2 && a1 == a2 && qty1 == qty2
+
+instance Equiv Ident where
+  (=~=) = (==)
+
+-- If we check for a change in the interface, we do not need to check the
+-- interface declarations, but still must disambiguate (nullary) type
+-- constructors and type variables in type expressions. This is handled
+-- by function 'fixInterface' and the associated type class 'FixInterface'.
+
+-- |Disambiguate nullary type constructors and type variables.
+fixInterface :: Interface -> Interface
+fixInterface (Interface m is ds) = Interface m is $
+  fix (Set.fromList (typeConstructors ds)) ds
+
+class FixInterface a where
+  fix :: Set.Set Ident -> a -> a
+
+instance FixInterface a => FixInterface (Maybe a) where
+  fix tcs = fmap (fix tcs)
+
+instance FixInterface a => FixInterface [a] where
+  fix tcs = map (fix tcs)
+
+instance FixInterface IDecl where
+  fix tcs (IDataDecl p tc k vs cs hs) =
+    IDataDecl p tc k vs (fix tcs cs) hs
+  fix tcs (INewtypeDecl p tc k vs nc hs) =
+    INewtypeDecl p tc k vs (fix tcs nc) hs
+  fix tcs (ITypeDecl p tc k vs ty) =
+    ITypeDecl p tc k vs (fix tcs ty)
+  fix tcs (IFunctionDecl p f cm n qty) =
+    IFunctionDecl p f cm n (fix tcs qty)
+  fix tcs (HidingClassDecl p cx cls k tv) =
+    HidingClassDecl p (fix tcs cx) cls k tv
+  fix tcs (IClassDecl p cx cls k tv ms hs) =
+    IClassDecl p (fix tcs cx) cls k tv (fix tcs ms) hs
+  fix tcs (IInstanceDecl p cx cls inst is m) =
+    IInstanceDecl p (fix tcs cx) cls (fix tcs inst) is m
+  fix _ d = d
+
+instance FixInterface ConstrDecl where
+  fix tcs (ConstrDecl p      c tys) = ConstrDecl p c (fix tcs tys)
+  fix tcs (ConOpDecl  p ty1 op ty2) = ConOpDecl  p   (fix tcs ty1)
+                                                op   (fix tcs ty2)
+  fix tcs (RecordDecl p c fs)       = RecordDecl p c (fix tcs fs)
+
+instance FixInterface FieldDecl where
+  fix tcs (FieldDecl p ls ty) = FieldDecl p ls (fix tcs ty)
+
+instance FixInterface NewConstrDecl where
+  fix tcs (NewConstrDecl p c ty    ) = NewConstrDecl p c (fix tcs ty)
+  fix tcs (NewRecordDecl p c (i,ty)) = NewRecordDecl p c (i, fix tcs ty)
+
+instance FixInterface IMethodDecl where
+  fix tcs (IMethodDecl p f a qty) = IMethodDecl p f a (fix tcs qty)
+
+instance FixInterface QualTypeExpr where
+  fix tcs (QualTypeExpr spi cx ty) = QualTypeExpr spi (fix tcs cx) (fix tcs ty)
+
+instance FixInterface Constraint where
+  fix tcs (Constraint spi qcls ty) = Constraint spi qcls (fix tcs ty)
+
+instance FixInterface TypeExpr where
+  fix tcs (ConstructorType spi tc)
+    | not (isQualified tc) && not (isPrimTypeId tc) && tc' `Set.notMember` tcs
+    = VariableType spi tc'
+    | otherwise = ConstructorType spi tc
+    where tc' = unqualify tc
+  fix tcs (ApplyType  spi ty1 ty2) = ApplyType spi (fix tcs ty1) (fix tcs ty2)
+  fix tcs (VariableType    spi tv)
+    | tv `Set.member` tcs = ConstructorType spi (qualify tv)
+    | otherwise           = VariableType spi tv
+  fix tcs (TupleType      spi tys) = TupleType spi (fix tcs tys)
+  fix tcs (ListType        spi ty) = ListType  spi (fix tcs ty)
+  fix tcs (ArrowType  spi ty1 ty2) = ArrowType spi (fix tcs ty1) (fix tcs ty2)
+  fix tcs (ParenType       spi ty) = ParenType spi (fix tcs ty)
+  fix tcs (ForallType   spi vs ty) = ForallType spi vs (fix tcs ty)
+
+typeConstructors :: [IDecl] -> [Ident]
+typeConstructors ds = [tc | (QualIdent _ Nothing tc) <- foldr tyCons [] ds]
+  where tyCons (IInfixDecl          _ _ _ _) tcs = tcs
+        tyCons (HidingDataDecl     _ tc _ _) tcs = tc : tcs
+        tyCons (IDataDecl      _ tc _ _ _ _) tcs = tc : tcs
+        tyCons (INewtypeDecl   _ tc _ _ _ _) tcs = tc : tcs
+        tyCons (ITypeDecl        _ tc _ _ _) tcs = tc : tcs
+        tyCons (IFunctionDecl     _ _ _ _ _) tcs = tcs
+        tyCons (HidingClassDecl   _ _ _ _ _) tcs = tcs
+        tyCons (IClassDecl    _ _ _ _ _ _ _) tcs = tcs
+        tyCons (IInstanceDecl   _ _ _ _ _ _) tcs = tcs
diff --git a/src/Curry/Syntax/LLParseComb.lhs b/src/Curry/Syntax/LLParseComb.lhs
deleted file mode 100644
--- a/src/Curry/Syntax/LLParseComb.lhs
+++ /dev/null
@@ -1,288 +0,0 @@
-% $Id: LLParseComb.lhs,v 1.26 2004/02/15 23:11:30 wlux Exp $
-%
-% Copyright (c) 1999-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-\nwfilename{LLParseComb.lhs}
-\section{Parsing Combinators}\label{sec:ll-parsecomb}
-The parsing combinators implemented in the module \texttt{LLParseComb}
-are based on the LL(1) parsing combinators developed by Swierstra and
-Duponcheel~\cite{SwierstraDuponcheel96:Parsers}. They have been
-adapted to using continuation passing style in order to work with the
-lexing combinators described in the previous section. In addition, the
-facilities for error correction are omitted in this implementation.
-
-The two functions \texttt{applyParser} and \texttt{prefixParser} use
-the specified parser for parsing a string. When \texttt{applyParser}
-is used, an error is reported if the parser does not consume the whole
-string, whereas \texttt{prefixParser} discards the rest of the input
-string in this case.
-\begin{verbatim}
-
-> module Curry.Syntax.LLParseComb(Symbol(..),Parser,
->                    applyParser,prefixParser, position,succeed,symbol,
->                    (<?>),(<|>),(<|?>),(<*>),(<\>),(<\\>),
->                    opt,(<$>),(<$->),(<*->),(<-*>),(<**>),(<??>),(<.>),
->                    many,many1, sepBy,sepBy1, chainr,chainr1,chainl,chainl1,
->                    bracket,ops, layoutOn,layoutOff,layoutEnd) where
-
-> import Control.Monad
-> import Data.Maybe
-> import qualified Data.Set as Set
-> import qualified Data.Map as Map
-
-> import Curry.Syntax.LexComb
-> import Curry.Base.MessageMonad
-> import Curry.Base.Position
-
-
-> infixl 5 <\>, <\\>
-> infixl 4 <*>, <$>, <$->, <*->, <-*>, <**>, <??>, <.>
-> infixl 3 <|>, <|?>
-> infixl 2 <?>, `opt`
-
-\end{verbatim}
-\paragraph{Parser types}
-\begin{verbatim}
-
-> class (Ord s,Show s) => Symbol s where
->   isEOF :: s -> Bool
-
-> type SuccessCont s a = Position -> s -> P a
-> type FailureCont a = Position -> String -> P a
-> type Lexer s a = SuccessCont s a -> FailureCont a -> P a
-> type ParseFun s a b = (a -> SuccessCont s b) -> FailureCont b
->                     -> SuccessCont s b
-
-> data Parser s a b = Parser (Maybe (ParseFun s a b))
->                            (Map.Map s (Lexer s b -> ParseFun s a b))
-
-> instance Symbol s => Show (Parser s a b) where
->   showsPrec p (Parser e ps) = showParen (p >= 10) $
->     showString "Parser " . shows (isJust e) .
->     showChar ' ' . shows (Map.keysSet ps)
-
-> applyParser :: Symbol s => Parser s a a -> Lexer s a -> FilePath -> String
->             -> MsgMonad a
-> applyParser p lexer = parse (lexer (choose p lexer done failP) failP)
->   where done x pos s
->           | isEOF s = returnP x
->           | otherwise = failP pos (unexpected s)
-
-> prefixParser :: Symbol s => Parser s a a -> Lexer s a -> FilePath -> String
->              -> MsgMonad a
-> prefixParser p lexer = parse (lexer (choose p lexer discard failP) failP)
->   where discard x _ _ = returnP x
-
-> choose :: Symbol s => Parser s a b -> Lexer s b -> ParseFun s a b
-> choose (Parser e ps) lexer success fail pos s =
->   case Map.lookup s ps of
->     Just p -> p lexer success fail pos s
->     Nothing ->
->       case e of
->         Just p -> p success fail pos s
->         Nothing -> fail pos (unexpected s)
-
-> unexpected :: Symbol s => s -> String
-> unexpected s
->   | isEOF s = "Unexpected end-of-file"
->   | otherwise = "Unexpected token " ++ show s
-
-\end{verbatim}
-\paragraph{Basic combinators}
-\begin{verbatim}
-
-> position :: Symbol s => Parser s Position b
-> position = Parser (Just p) Map.empty
->   where p success _ pos = success pos pos
-
-> succeed :: Symbol s => a -> Parser s a b
-> succeed x = Parser (Just p) Map.empty
->   where p success _ = success x
-
-> symbol :: Symbol s => s -> Parser s s a
-> symbol s = Parser Nothing (Map.singleton s p)
->   where p lexer success fail pos s = lexer (success s) fail
-
-> (<?>) :: Symbol s => Parser s a b -> String -> Parser s a b
-> p <?> msg = p <|> Parser (Just pfail) Map.empty
->   where pfail _ fail pos _ = fail pos msg
-
-> (<|>) :: Symbol s => Parser s a b -> Parser s a b -> Parser s a b
-> Parser e1 ps1 <|> Parser e2 ps2
->   | isJust e1 && isJust e2 = error "Ambiguous parser for empty word"
->   | not (Set.null common) = error ("Ambiguous parser for " ++ show common)
->   | otherwise = Parser (e1 `mplus` e2) (Map.union ps1 ps2)
->   where common = Map.keysSet ps1 `Set.intersection` Map.keysSet ps2
-
-\end{verbatim}
-The parsing combinators presented so far require that the grammar
-being parsed is LL(1). In some cases it may be difficult or even
-impossible to transform a grammar into LL(1) form. As a remedy, we
-include a non-deterministic version of the choice combinator in
-addition to the deterministic combinator adapted from the paper. For
-every symbol from the intersection of the parser's first sets, the
-combinator \texttt{(<|?>)} applies both parsing functions to the input
-stream and uses that one which processes the longer prefix of the
-input stream irrespective of whether it succeeds or fails. If both
-functions recognize the same prefix, we choose the one that succeeds
-and report an ambiguous parse error if both succeed.
-\begin{verbatim}
-
-> (<|?>) :: Symbol s => Parser s a b -> Parser s a b -> Parser s a b
-> Parser e1 ps1 <|?> Parser e2 ps2
->   | isJust e1 && isJust e2 = error "Ambiguous parser for empty word"
->   | otherwise = Parser (e1 `mplus` e2) (Map.union ps1' ps2)
->   where ps1' = Map.fromList [(s,maybe p (try p) (Map.lookup s ps2))
->                           | (s,p) <- Map.toList ps1]
->         try p1 p2 lexer success fail pos s =
->           closeP1 p2s `thenP` \p2s' ->
->           closeP1 p2f `thenP` \p2f' ->
->           parse p1 (retry p2s') (retry p2f')
->           where p2s r1 = parse p2 (select True r1) (select False r1)
->                 p2f r1 = parse p2 (flip (select False) r1) (select False r1)
->                 parse p psucc pfail =
->                   p lexer (successK psucc) (failK pfail) pos s
->                 successK k x pos s = k (pos,success x pos s)
->                 failK k pos msg = k (pos,fail pos msg)
->                 retry k (pos,p) = closeP0 p `thenP` curry k pos
->         select suc (pos1,p1) (pos2,p2) =
->           case pos1 `compare` pos2 of
->             GT -> p1
->             EQ
->               | suc -> error ("Ambiguous parse before " ++ show pos1)
->               | otherwise -> p1
->             LT -> p2
-
-> (<*>) :: Symbol s => Parser s (a -> b) c -> Parser s a c -> Parser s b c
-> Parser (Just p1) ps1 <*> ~p2@(Parser e2 ps2) =
->   Parser (fmap (seqEE p1) e2)
->          (Map.union (fmap (flip seqPP p2) ps1) (fmap (seqEP p1) ps2))
-> Parser Nothing ps1 <*> p2 = Parser Nothing (fmap (flip seqPP p2) ps1)
-
-> seqEE :: Symbol s => ParseFun s (a -> b) c -> ParseFun s a c
->       -> ParseFun s b c
-> seqEE p1 p2 success fail = p1 (\f -> p2 (success . f) fail) fail
-
-> seqEP :: Symbol s => ParseFun s (a -> b) c -> (Lexer s c -> ParseFun s a c)
->       -> Lexer s c -> ParseFun s b c
-> seqEP p1 p2 lexer success fail = p1 (\f -> p2 lexer (success . f) fail) fail
-
-> seqPP :: Symbol s => (Lexer s c -> ParseFun s (a -> b) c) -> Parser s a c
->       -> Lexer s c -> ParseFun s b c
-> seqPP p1 p2 lexer success fail =
->   p1 lexer (\f -> choose p2 lexer (success . f) fail) fail
-
-\end{verbatim}
-The combinators \verb|<\\>| and \verb|<\>| can be used to restrict
-the first set of a parser. This is useful for combining two parsers
-with an overlapping first set with the deterministic combinator <|>.
-\begin{verbatim}
-
-> (<\>) :: Symbol s => Parser s a c -> Parser s b c -> Parser s a c
-> p <\> Parser _ ps = p <\\> Map.keys ps
-
-> (<\\>) :: Symbol s => Parser s a b -> [s] -> Parser s a b
-> Parser e ps <\\> xs = Parser e (foldr Map.delete ps xs)
-
-\end{verbatim}
-\paragraph{Other combinators.}
-Note that some of these combinators have not been published in the
-paper, but were taken from the implementation found on the web.
-\begin{verbatim}
-
-> opt :: Symbol s => Parser s a b -> a -> Parser s a b
-> p `opt` x = p <|> succeed x
-
-> (<$>) :: Symbol s => (a -> b) -> Parser s a c -> Parser s b c
-> f <$> p = succeed f <*> p
-
-> (<$->) :: Symbol s => a -> Parser s b c -> Parser s a c
-> f <$-> p = const f <$> p
-
-> (<*->) :: Symbol s => Parser s a c -> Parser s b c -> Parser s a c
-> p <*-> q = const <$> p <*> q
-
-> (<-*>) :: Symbol s => Parser s a c -> Parser s b c -> Parser s b c
-> p <-*> q = const id <$> p <*> q
-
-> (<**>) :: Symbol s => Parser s a c -> Parser s (a -> b) c -> Parser s b c
-> p <**> q = flip ($) <$> p <*> q
-
-> (<??>) :: Symbol s => Parser s a b -> Parser s (a -> a) b -> Parser s a b
-> p <??> q = p <**> (q `opt` id)
-
-> (<.>) :: Symbol s => Parser s (a -> b) d -> Parser s (b -> c) d
->       -> Parser s (a -> c) d
-> p1 <.> p2 = p1 <**> ((.) <$> p2)
-
-> many :: Symbol s => Parser s a b -> Parser s [a] b
-> many p = many1 p `opt` []
-
-> many1 :: Symbol s => Parser s a b -> Parser s [a] b
-> -- many1 p = (:) <$> p <*> many p
-> many1 p = (:) <$> p <*> (many1 p `opt` [])
-
-\end{verbatim}
-The first definition of \texttt{many1} is commented out because it
-does not compile under nhc. This is due to a -- known -- bug in the
-type checker of nhc which expects a default declaration when compiling
-mutually recursive functions with class constraints. However, no such
-default can be given in the above case because neither of the types
-involved is a numeric type.
-\begin{verbatim}
-
-> sepBy :: Symbol s => Parser s a c -> Parser s b c -> Parser s [a] c
-> p `sepBy` q = p `sepBy1` q `opt` []
-
-> sepBy1 :: Symbol s => Parser s a c -> Parser s b c -> Parser s [a] c
-> p `sepBy1` q = (:) <$> p <*> many (q <-*> p)
-
-> chainr :: Symbol s => Parser s a b -> Parser s (a -> a -> a) b -> a
->        -> Parser s a b
-> chainr p op x = chainr1 p op `opt` x
-
-> chainr1 :: Symbol s => Parser s a b -> Parser s (a -> a -> a) b
->         -> Parser s a b
-> chainr1 p op = r
->   where r = p <**> (flip <$> op <*> r `opt` id)
-
-> chainl :: Symbol s => Parser s a b -> Parser s (a -> a -> a) b -> a
->        -> Parser s a b
-> chainl p op x = chainl1 p op `opt` x
-
-> chainl1 :: Symbol s => Parser s a b -> Parser s (a -> a -> a) b
->         -> Parser s a b
-> chainl1 p op = foldF <$> p <*> many (flip <$> op <*> p)
->   where foldF x [] = x
->         foldF x (f:fs) = foldF (f x) fs
-
-> bracket :: Symbol s => Parser s a c -> Parser s b c -> Parser s a c
->         -> Parser s b c
-> bracket open p close = open <-*> p <*-> close
-
-> ops :: Symbol s => [(s,a)] -> Parser s a b
-> ops [] = error "internal error: ops"
-> ops [(s,x)] = x <$-> symbol s
-> ops ((s,x):rest) = x <$-> symbol s <|> ops rest
-
-\end{verbatim}
-\paragraph{Layout combinators}
-Note that the layout functions grab the next token (and its position).
-After modifying the layout context, the continuation is called with
-the same token and an undefined result.
-\begin{verbatim}
-
-> layoutOn :: Symbol s => Parser s a b
-> layoutOn = Parser (Just on) Map.empty
->   where on success _ pos = pushContext (column pos) . success undefined pos
-
-> layoutOff :: Symbol s => Parser s a b
-> layoutOff = Parser (Just off) Map.empty
->   where off success _ pos = pushContext (-1) . success undefined pos
-
-> layoutEnd :: Symbol s => Parser s a b
-> layoutEnd = Parser (Just end) Map.empty
->   where end success _ pos = popContext . success undefined pos
-
-\end{verbatim}
diff --git a/src/Curry/Syntax/LexComb.lhs b/src/Curry/Syntax/LexComb.lhs
deleted file mode 100644
--- a/src/Curry/Syntax/LexComb.lhs
+++ /dev/null
@@ -1,104 +0,0 @@
-% -*- LaTeX -*-
-% $Id: LexComb.lhs,v 1.16 2004/01/20 16:44:14 wlux Exp $
-%
-% Copyright (c) 1999-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-\nwfilename{LexComb.lhs}
-\section{Lexing combinators}
-The module \texttt{LexComb} provides the basic types and combinators
-to implement the lexers. The combinators use continuation passing code
-in a monadic style. The first argument of the continuation function is
-the current position, and the second is the string to be parsed. The third
-argument is a flag which signals the lexer that it is lexing the
-beginning of a line and therefore has to check for layout tokens. The
-fourth argument is a stack of indentations that is used to handle
-nested layout groups.
-\begin{verbatim}
-
-> module Curry.Syntax.LexComb where
-
-> import Data.Char
-
-> import Curry.Base.MessageMonad
-> import Curry.Base.Position
-
-> infixl 1 `thenP`, `thenP_`
-
-> type Indent = Int
-> type Context = [Indent]
-> type P a = Position -> String -> Bool -> Context -> MsgMonad a
-
-> parse :: P a -> FilePath -> String -> MsgMonad a
-> parse p fn s = p (first fn) s False []
-
-\end{verbatim}
-Monad functions for the lexer.
-\begin{verbatim}
-
-> returnP :: a -> P a
-> returnP x _ _ _ _ = return x
-
-> thenP :: P a -> (a -> P b) -> P b
-> thenP lex k pos s bol ctxt = lex pos s bol ctxt >>= \x -> k x pos s bol ctxt
-
-> thenP_ :: P a -> P b -> P b
-> p1 `thenP_` p2 = p1 `thenP` \_ -> p2
-
-> failP :: Position -> String -> P a
-> failP pos msg _ _ _ _ = failWith (parseError pos msg)
-
-> closeP0 :: P a -> P (P a)
-> closeP0 lex pos s bol ctxt = return (\_ _ _ _ -> lex pos s bol ctxt)
-
-> closeP1 :: (a -> P b) -> P (a -> P b)
-> closeP1 f pos s bol ctxt = return (\x _ _ _ _ -> f x pos s bol ctxt)
-
-> parseError :: Position -> String -> String
-> parseError p what = "\n" ++ show p ++ ": " ++ what
-
-\end{verbatim}
-Combinators that handle layout.
-\begin{verbatim}
-
-> pushContext :: Int -> P a -> P a
-> pushContext col cont pos s bol ctxt = cont pos s bol (col:ctxt)
-
-> popContext :: P a -> P a
-> popContext cont pos s bol (_:ctxt) = cont pos s bol ctxt
-> popContext cont pos s bol [] =
->    error "parse error: popping layout from empty context stack. \
->          \Perhaps you have inserted too many '}'?"
-
-\end{verbatim}
-Conversions from strings into numbers.
-\begin{verbatim}
-
-> convertSignedIntegral :: Num a => a -> String -> a
-> convertSignedIntegral b ('+':s) = convertIntegral b s
-> convertSignedIntegral b ('-':s) = - convertIntegral b s
-> convertSignedIntegral b s = convertIntegral b s
-
-> convertIntegral :: Num a => a -> String -> a
-> convertIntegral b = foldl op 0
->   where m `op` n | isDigit n = b * m + fromIntegral (ord n - ord0)
->                  | isUpper n = b * m + fromIntegral (ord n - ordA)
->                  | otherwise = b * m + fromIntegral (ord n - orda)
->         ord0 = ord '0'
->         ordA = ord 'A' - 10
->         orda = ord 'a' - 10
-
-> convertSignedFloating :: Fractional a => String -> String -> Int -> a
-> convertSignedFloating ('+':m) f e = convertFloating m f e
-> convertSignedFloating ('-':m) f e = - convertFloating m f e
-> convertSignedFloating m f e = convertFloating m f e
-
-> convertFloating :: Fractional a => String -> String -> Int -> a
-> convertFloating m f e
->   | e' == 0 = m'
->   | e' > 0  = m' * 10^e'
->   | otherwise = m' / 10^(-e')
->   where m' = convertIntegral 10 (m ++ f)
->         e' = e - length f
-
-\end{verbatim}
diff --git a/src/Curry/Syntax/Lexer.hs b/src/Curry/Syntax/Lexer.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Syntax/Lexer.hs
@@ -0,0 +1,889 @@
+{- |
+    Module      :  $Header$
+    Description :  A lexer for Curry
+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux
+                       2005        Martin Engelke
+                       2011 - 2013 Björn Peemöller
+                       2016        Finn Teegen
+                       2016        Jan Tikovsky
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+-}
+module Curry.Syntax.Lexer
+  ( -- * Data types for tokens
+    Token (..), Category (..), Attributes (..)
+
+    -- * lexing functions
+  , lexSource, lexer, fullLexer
+  ) where
+
+import Prelude hiding (fail)
+import Data.Char
+  ( chr, ord, isAlpha, isAlphaNum, isDigit, isHexDigit, isOctDigit
+  , isSpace, isUpper, toLower
+  )
+import Data.List (intercalate)
+import qualified Data.Map as Map
+  (Map, union, lookup, findWithDefault, fromList)
+
+import Curry.Base.LexComb
+import Curry.Base.Position
+import Curry.Base.Span
+
+-- ---------------------------------------------------------------------------
+-- Tokens. Note that the equality and ordering instances of Token disregard
+-- the attributes, as so that the parser decides about accepting a token
+-- just by its category.
+-- ---------------------------------------------------------------------------
+
+-- |Data type for curry lexer tokens
+data Token = Token Category Attributes
+
+instance Eq Token where
+  Token c1 _ == Token c2 _ = c1 == c2
+
+instance Ord Token where
+  Token c1 _ `compare` Token c2 _ = c1 `compare` c2
+
+instance Symbol Token where
+  isEOF (Token c _) = c == EOF
+
+  dist _ (Token VSemicolon         _) = (0,  0)
+  dist _ (Token VRightBrace        _) = (0,  0)
+  dist _ (Token EOF                _) = (0,  0)
+  dist _ (Token DotDot             _) = (0,  1)
+  dist _ (Token DoubleColon        _) = (0,  1)
+  dist _ (Token LeftArrow          _) = (0,  1)
+  dist _ (Token RightArrow         _) = (0,  1)
+  dist _ (Token DoubleArrow        _) = (0,  1)
+  dist _ (Token KW_do              _) = (0,  1)
+  dist _ (Token KW_if              _) = (0,  1)
+  dist _ (Token KW_in              _) = (0,  1)
+  dist _ (Token KW_of              _) = (0,  1)
+  dist _ (Token Id_as              _) = (0,  1)
+  dist _ (Token KW_let             _) = (0,  2)
+  dist _ (Token PragmaEnd          _) = (0,  2)
+  dist _ (Token KW_case            _) = (0,  3)
+  dist _ (Token KW_class           _) = (0,  4)
+  dist _ (Token KW_data            _) = (0,  3)
+  dist _ (Token KW_default         _) = (0,  6)
+  dist _ (Token KW_deriving        _) = (0,  7)
+  dist _ (Token KW_else            _) = (0,  3)
+  dist _ (Token KW_free            _) = (0,  3)
+  dist _ (Token KW_then            _) = (0,  3)
+  dist _ (Token KW_type            _) = (0,  3)
+  dist _ (Token KW_fcase           _) = (0,  4)
+  dist _ (Token KW_infix           _) = (0,  4)
+  dist _ (Token KW_instance        _) = (0,  7)
+  dist _ (Token KW_where           _) = (0,  4)
+  dist _ (Token Id_ccall           _) = (0,  4)
+  dist _ (Token KW_import          _) = (0,  5)
+  dist _ (Token KW_infixl          _) = (0,  5)
+  dist _ (Token KW_infixr          _) = (0,  5)
+  dist _ (Token KW_module          _) = (0,  5)
+  dist _ (Token Id_forall          _) = (0,  5)
+  dist _ (Token Id_hiding          _) = (0,  5)
+  dist _ (Token KW_newtype         _) = (0,  6)
+  dist _ (Token KW_external        _) = (0,  7)
+  dist _ (Token Id_interface       _) = (0,  8)
+  dist _ (Token Id_primitive       _) = (0,  8)
+  dist _ (Token Id_qualified       _) = (0,  8)
+  dist _ (Token PragmaHiding       _) = (0,  9)
+  dist _ (Token PragmaLanguage     _) = (0, 11)
+  dist _ (Token Id                 a) = distAttr False a
+  dist _ (Token QId                a) = distAttr False a
+  dist _ (Token Sym                a) = distAttr False a
+  dist _ (Token QSym               a) = distAttr False a
+  dist _ (Token IntTok             a) = distAttr False a
+  dist _ (Token FloatTok           a) = distAttr False a
+  dist _ (Token CharTok            a) = distAttr False a
+  dist c (Token StringTok          a) = updColDist c (distAttr False a)
+  dist _ (Token LineComment        a) = distAttr True  a
+  dist c (Token NestedComment      a) = updColDist c (distAttr True  a)
+  dist _ (Token PragmaOptions      a) = let (ld, cd) = distAttr False a
+                                        in  (ld, cd + 11)
+  dist _ _                            = (0, 0)
+
+-- TODO: Comment
+updColDist :: Int -> Distance -> Distance
+updColDist c (ld, cd) = (ld, if ld == 0 then cd else cd - c + 1)
+
+distAttr :: Bool -> Attributes -> Distance
+distAttr isComment attr = case attr of
+  NoAttributes              -> (0, 0)
+  CharAttributes     _ orig -> (0, length orig + 1)
+  IntAttributes      _ orig -> (0, length orig - 1)
+  FloatAttributes    _ orig -> (0, length orig - 1)
+  StringAttributes   _ orig
+      -- comment without surrounding quotes
+    | isComment             -> (ld, cd)
+      -- string with one ending double quote or two surrounding double quotes
+      -- (column distance + 1 / + 2)
+    | '\n' `elem` orig      -> (ld, cd + 1)
+    | otherwise             -> (ld, cd + 2)
+    where ld = length (filter    (== '\n') orig)
+          cd = length (takeWhile (/= '\n') (reverse orig)) - 1
+  IdentAttributes    mid i  -> (0, length (intercalate "." (mid ++ [i])) - 1)
+  OptionsAttributes mt args -> case mt of
+                                 Nothing -> (0, distArgs + 1)
+                                 Just t  -> (0, length t + distArgs + 2)
+    where distArgs = length args
+
+-- |Category of curry tokens
+data Category
+  -- literals
+  = CharTok
+  | IntTok
+  | FloatTok
+  | StringTok
+
+  -- identifiers
+  | Id   -- identifier
+  | QId  -- qualified identifier
+  | Sym  -- symbol
+  | QSym -- qualified symbol
+
+  -- punctuation symbols
+  | LeftParen     -- (
+  | RightParen    -- )
+  | Semicolon     -- ;
+  | LeftBrace     -- {
+  | RightBrace    -- }
+  | LeftBracket   -- [
+  | RightBracket  -- ]
+  | Comma         -- ,
+  | Underscore    -- _
+  | Backquote     -- `
+
+  -- layout
+  | VSemicolon         -- virtual ;
+  | VRightBrace        -- virtual }
+
+  -- reserved keywords
+  | KW_case
+  | KW_class
+  | KW_data
+  | KW_default
+  | KW_deriving
+  | KW_do
+  | KW_else
+  | KW_external
+  | KW_fcase
+  | KW_free
+  | KW_if
+  | KW_import
+  | KW_in
+  | KW_infix
+  | KW_infixl
+  | KW_infixr
+  | KW_instance
+  | KW_let
+  | KW_module
+  | KW_newtype
+  | KW_of
+  | KW_then
+  | KW_type
+  | KW_where
+
+  -- reserved operators
+  | At           -- @
+  | Colon        -- :
+  | DotDot       -- ..
+  | DoubleColon  -- ::
+  | Equals       -- =
+  | Backslash    -- \
+  | Bar          -- |
+  | LeftArrow    -- <-
+  | RightArrow   -- ->
+  | Tilde        -- ~
+  | DoubleArrow  -- =>
+
+  -- special identifiers
+  | Id_as
+  | Id_ccall
+  | Id_forall
+  | Id_hiding
+  | Id_interface
+  | Id_primitive
+  | Id_qualified
+
+  -- special operators
+  | SymDot      -- .
+  | SymMinus    -- -
+
+  -- special symbols
+  | SymStar -- kind star (*)
+
+  -- pragmas
+  | PragmaLanguage -- {-# LANGUAGE
+  | PragmaOptions  -- {-# OPTIONS
+  | PragmaHiding   -- {-# HIDING
+  | PragmaMethod   -- {-# METHOD
+  | PragmaModule   -- {-# MODULE
+  | PragmaEnd      -- #-}
+
+
+  -- comments (only for full lexer) inserted by men & bbr
+  | LineComment
+  | NestedComment
+
+  -- end-of-file token
+  | EOF
+    deriving (Eq, Ord)
+
+-- There are different kinds of attributes associated with the tokens.
+-- Most attributes simply save the string corresponding to the token.
+-- However, for qualified identifiers, we also record the list of module
+-- qualifiers. The values corresponding to a literal token are properly
+-- converted already. To simplify the creation and extraction of
+-- attribute values, we make use of records.
+
+-- |Attributes associated to a token
+data Attributes
+  = NoAttributes
+  | CharAttributes    { cval     :: Char        , original :: String }
+  | IntAttributes     { ival     :: Integer     , original :: String }
+  | FloatAttributes   { fval     :: Double      , original :: String }
+  | StringAttributes  { sval     :: String      , original :: String }
+  | IdentAttributes   { modulVal :: [String]    , sval     :: String }
+  | OptionsAttributes { toolVal  :: Maybe String, toolArgs :: String }
+
+instance Show Attributes where
+  showsPrec _ NoAttributes             = showChar '_'
+  showsPrec _ (CharAttributes    cv _) = shows cv
+  showsPrec _ (IntAttributes     iv _) = shows iv
+  showsPrec _ (FloatAttributes   fv _) = shows fv
+  showsPrec _ (StringAttributes  sv _) = shows sv
+  showsPrec _ (IdentAttributes  mid i) = showsEscaped
+                                       $ intercalate "." $ mid ++ [i]
+  showsPrec _ (OptionsAttributes mt s) = showsTool mt
+                                       . showChar ' ' . showString s
+    where showsTool = maybe id (\t -> showChar '_' . showString t)
+
+
+-- ---------------------------------------------------------------------------
+-- The 'Show' instance of 'Token' is designed to display all tokens in their
+-- source representation.
+-- ---------------------------------------------------------------------------
+
+showsEscaped :: String -> ShowS
+showsEscaped s = showChar '`' . showString s . showChar '\''
+
+showsIdent :: Attributes -> ShowS
+showsIdent a = showString "identifier " . shows a
+
+showsSpecialIdent :: String -> ShowS
+showsSpecialIdent s = showString "identifier " . showsEscaped s
+
+showsOperator :: Attributes -> ShowS
+showsOperator a = showString "operator " . shows a
+
+showsSpecialOperator :: String -> ShowS
+showsSpecialOperator s = showString "operator " . showsEscaped s
+
+instance Show Token where
+  showsPrec _ (Token Id                 a) = showsIdent a
+  showsPrec _ (Token QId                a) = showString "qualified "
+                                           . showsIdent a
+  showsPrec _ (Token Sym                a) = showsOperator a
+  showsPrec _ (Token QSym               a) = showString "qualified "
+                                           . showsOperator a
+  showsPrec _ (Token IntTok             a) = showString "integer "   . shows a
+  showsPrec _ (Token FloatTok           a) = showString "float "     . shows a
+  showsPrec _ (Token CharTok            a) = showString "character " . shows a
+  showsPrec _ (Token StringTok          a) = showString "string "    . shows a
+  showsPrec _ (Token LeftParen          _) = showsEscaped "("
+  showsPrec _ (Token RightParen         _) = showsEscaped ")"
+  showsPrec _ (Token Semicolon          _) = showsEscaped ";"
+  showsPrec _ (Token LeftBrace          _) = showsEscaped "{"
+  showsPrec _ (Token RightBrace         _) = showsEscaped "}"
+  showsPrec _ (Token LeftBracket        _) = showsEscaped "["
+  showsPrec _ (Token RightBracket       _) = showsEscaped "]"
+  showsPrec _ (Token Comma              _) = showsEscaped ","
+  showsPrec _ (Token Underscore         _) = showsEscaped "_"
+  showsPrec _ (Token Backquote          _) = showsEscaped "`"
+  showsPrec _ (Token VSemicolon         _)
+    = showsEscaped ";" . showString " (inserted due to layout)"
+  showsPrec _ (Token VRightBrace        _)
+    = showsEscaped "}" . showString " (inserted due to layout)"
+  showsPrec _ (Token At                 _) = showsEscaped "@"
+  showsPrec _ (Token Colon              _) = showsEscaped ":"
+  showsPrec _ (Token DotDot             _) = showsEscaped ".."
+  showsPrec _ (Token DoubleArrow        _) = showsEscaped "=>"
+  showsPrec _ (Token DoubleColon        _) = showsEscaped "::"
+  showsPrec _ (Token Equals             _) = showsEscaped "="
+  showsPrec _ (Token Backslash          _) = showsEscaped "\\"
+  showsPrec _ (Token Bar                _) = showsEscaped "|"
+  showsPrec _ (Token LeftArrow          _) = showsEscaped "<-"
+  showsPrec _ (Token RightArrow         _) = showsEscaped "->"
+  showsPrec _ (Token Tilde              _) = showsEscaped "~"
+  showsPrec _ (Token SymDot             _) = showsSpecialOperator "."
+  showsPrec _ (Token SymMinus           _) = showsSpecialOperator "-"
+  showsPrec _ (Token SymStar            _) = showsEscaped "*"
+  showsPrec _ (Token KW_case            _) = showsEscaped "case"
+  showsPrec _ (Token KW_class           _) = showsEscaped "class"
+  showsPrec _ (Token KW_data            _) = showsEscaped "data"
+  showsPrec _ (Token KW_default         _) = showsEscaped "default"
+  showsPrec _ (Token KW_deriving        _) = showsEscaped "deriving"
+  showsPrec _ (Token KW_do              _) = showsEscaped "do"
+  showsPrec _ (Token KW_else            _) = showsEscaped "else"
+  showsPrec _ (Token KW_external        _) = showsEscaped "external"
+  showsPrec _ (Token KW_fcase           _) = showsEscaped "fcase"
+  showsPrec _ (Token KW_free            _) = showsEscaped "free"
+  showsPrec _ (Token KW_if              _) = showsEscaped "if"
+  showsPrec _ (Token KW_import          _) = showsEscaped "import"
+  showsPrec _ (Token KW_in              _) = showsEscaped "in"
+  showsPrec _ (Token KW_infix           _) = showsEscaped "infix"
+  showsPrec _ (Token KW_infixl          _) = showsEscaped "infixl"
+  showsPrec _ (Token KW_infixr          _) = showsEscaped "infixr"
+  showsPrec _ (Token KW_instance        _) = showsEscaped "instance"
+  showsPrec _ (Token KW_let             _) = showsEscaped "let"
+  showsPrec _ (Token KW_module          _) = showsEscaped "module"
+  showsPrec _ (Token KW_newtype         _) = showsEscaped "newtype"
+  showsPrec _ (Token KW_of              _) = showsEscaped "of"
+  showsPrec _ (Token KW_then            _) = showsEscaped "then"
+  showsPrec _ (Token KW_type            _) = showsEscaped "type"
+  showsPrec _ (Token KW_where           _) = showsEscaped "where"
+  showsPrec _ (Token Id_as              _) = showsSpecialIdent "as"
+  showsPrec _ (Token Id_ccall           _) = showsSpecialIdent "ccall"
+  showsPrec _ (Token Id_forall          _) = showsSpecialIdent "forall"
+  showsPrec _ (Token Id_hiding          _) = showsSpecialIdent "hiding"
+  showsPrec _ (Token Id_interface       _) = showsSpecialIdent "interface"
+  showsPrec _ (Token Id_primitive       _) = showsSpecialIdent "primitive"
+  showsPrec _ (Token Id_qualified       _) = showsSpecialIdent "qualified"
+  showsPrec _ (Token PragmaLanguage     _) = showString "{-# LANGUAGE"
+  showsPrec _ (Token PragmaOptions      a) = showString "{-# OPTIONS"
+                                           . shows a
+  showsPrec _ (Token PragmaHiding       _) = showString "{-# HIDING"
+  showsPrec _ (Token PragmaMethod       _) = showString "{-# METHOD"
+  showsPrec _ (Token PragmaModule       _) = showString "{-# MODULE"
+  showsPrec _ (Token PragmaEnd          _) = showString "#-}"
+  showsPrec _ (Token LineComment        a) = shows a
+  showsPrec _ (Token NestedComment      a) = shows a
+  showsPrec _ (Token EOF                _) = showString "<end-of-file>"
+
+-- ---------------------------------------------------------------------------
+-- The following functions can be used to construct tokens with
+-- specific attributes.
+-- ---------------------------------------------------------------------------
+
+-- |Construct a simple 'Token' without 'Attributes'
+tok :: Category -> Token
+tok t = Token t NoAttributes
+
+-- |Construct a 'Token' for a single 'Char'
+charTok :: Char -> String -> Token
+charTok c o = Token CharTok CharAttributes { cval = c, original = o }
+
+-- |Construct a 'Token' for an int value
+intTok :: Integer -> String -> Token
+intTok base digits = Token IntTok IntAttributes
+  { ival = convertIntegral base digits, original = digits }
+
+-- |Construct a 'Token' for a float value
+floatTok :: String -> String -> Int -> String -> Token
+floatTok mant frac expo rest = Token FloatTok FloatAttributes
+  { fval     = convertFloating mant frac expo
+  , original = mant ++ "." ++ frac ++ rest }
+
+-- |Construct a 'Token' for a string value
+stringTok :: String -> String -> Token
+stringTok cs s = Token StringTok StringAttributes { sval = cs, original = s }
+
+-- |Construct a 'Token' for identifiers
+idTok :: Category -> [String] -> String -> Token
+idTok t mIdent ident = Token t
+  IdentAttributes { modulVal = mIdent, sval = ident }
+
+-- TODO
+pragmaOptionsTok :: Maybe String -> String -> Token
+pragmaOptionsTok mbTool s = Token PragmaOptions
+  OptionsAttributes { toolVal = mbTool, toolArgs = s }
+
+-- |Construct a 'Token' for a line comment
+lineCommentTok :: String -> Token
+lineCommentTok s = Token LineComment
+  StringAttributes { sval = s, original = s }
+
+-- |Construct a 'Token' for a nested comment
+nestedCommentTok :: String -> Token
+nestedCommentTok s = Token NestedComment
+  StringAttributes { sval = s, original = s }
+
+-- ---------------------------------------------------------------------------
+-- Tables for reserved operators and identifiers
+-- ---------------------------------------------------------------------------
+
+-- |Map of reserved operators
+reservedOps:: Map.Map String Category
+reservedOps = Map.fromList
+  [ ("@" , At         )
+  , (":" , Colon      )
+  , ("=>", DoubleArrow)
+  , ("::", DoubleColon)
+  , ("..", DotDot     )
+  , ("=" , Equals     )
+  , ("\\", Backslash  )
+  , ("|" , Bar        )
+  , ("<-", LeftArrow  )
+  , ("->", RightArrow )
+  , ("~" , Tilde      )
+  ]
+
+-- |Map of reserved and special operators
+reservedSpecialOps :: Map.Map String Category
+reservedSpecialOps = Map.union reservedOps $ Map.fromList
+  [ ("." , SymDot     )
+  , ("-" , SymMinus   )
+  , ("*" , SymStar    )
+  ]
+
+-- |Map of keywords
+keywords :: Map.Map String Category
+keywords = Map.fromList
+  [ ("case"    , KW_case    )
+  , ("class"   , KW_class   )
+  , ("data"    , KW_data    )
+  , ("default" , KW_default )
+  , ("deriving", KW_deriving)
+  , ("do"      , KW_do      )
+  , ("else"    , KW_else    )
+  , ("external", KW_external)
+  , ("fcase"   , KW_fcase   )
+  , ("free"    , KW_free    )
+  , ("if"      , KW_if      )
+  , ("import"  , KW_import  )
+  , ("in"      , KW_in      )
+  , ("infix"   , KW_infix   )
+  , ("infixl"  , KW_infixl  )
+  , ("infixr"  , KW_infixr  )
+  , ("instance", KW_instance)
+  , ("let"     , KW_let     )
+  , ("module"  , KW_module  )
+  , ("newtype" , KW_newtype )
+  , ("of"      , KW_of      )
+  , ("then"    , KW_then    )
+  , ("type"    , KW_type    )
+  , ("where"   , KW_where   )
+  ]
+
+-- |Map of keywords and special identifiers
+keywordsSpecialIds :: Map.Map String Category
+keywordsSpecialIds = Map.union keywords $ Map.fromList
+  [ ("as"       , Id_as       )
+  , ("ccall"    , Id_ccall    )
+  , ("forall"   , Id_forall   )
+  , ("hiding"   , Id_hiding   )
+  , ("interface", Id_interface)
+  , ("primitive", Id_primitive)
+  , ("qualified", Id_qualified)
+  ]
+
+pragmas :: Map.Map String Category
+pragmas = Map.fromList
+  [ ("language", PragmaLanguage)
+  , ("options" , PragmaOptions )
+  , ("hiding"  , PragmaHiding  )
+  , ("method"  , PragmaMethod  )
+  , ("module"  , PragmaModule  )
+  ]
+
+
+-- ---------------------------------------------------------------------------
+-- Character classes
+-- ---------------------------------------------------------------------------
+
+-- |Check whether a 'Char' is allowed for identifiers
+isIdentChar :: Char -> Bool
+isIdentChar c = isAlphaNum c || c `elem` "'_"
+
+-- |Check whether a 'Char' is allowed for symbols
+isSymbolChar :: Char -> Bool
+isSymbolChar c = c `elem` "~!@#$%^&*+-=<>:?./|\\"
+
+-- ---------------------------------------------------------------------------
+-- Lexing functions
+-- ---------------------------------------------------------------------------
+
+-- |Lex source code
+lexSource :: FilePath -> String -> CYM [(Span, Token)]
+lexSource = parse (applyLexer fullLexer)
+
+-- |CPS-Lexer for Curry
+lexer :: Lexer Token a
+lexer = skipWhiteSpace True -- skip comments
+
+-- |CPS-Lexer for Curry which also lexes comments.
+-- This lexer is useful for documentation tools.
+fullLexer :: Lexer Token a
+fullLexer = skipWhiteSpace False -- lex comments
+
+-- |Lex the source code and skip whitespaces
+skipWhiteSpace :: Bool -> Lexer Token a
+skipWhiteSpace skipComments suc fail = skip
+  where
+  skip sp   []              bol = suc sp (tok EOF)                   sp            [] bol
+  skip sp c@('-':'-':_)     _   = lexLineComment     sucComment fail sp            c  True
+  skip sp c@('{':'-':'#':_) bol = lexPragma noPragma suc        fail sp            c  bol
+  skip sp c@('{':'-':_)     bol = lexNestedComment   sucComment fail sp            c  bol
+  skip sp cs@(c:s)          bol
+    | c == '\t'                = warnP sp "Tab character" skip       (tabSpan  sp) s  bol
+    | c == '\n'                = skip                                (nlSpan   sp) s  True
+    | isSpace c                = skip                                (nextSpan sp) s  bol
+    | bol                      = lexBOL             suc        fail  sp            cs bol
+    | otherwise                = lexToken           suc        fail  sp            cs bol
+  sucComment = if skipComments then (\ _suc _fail -> skip) else suc
+  noPragma   = lexNestedComment sucComment fail
+
+-- Lex a line comment
+lexLineComment :: Lexer Token a
+lexLineComment suc _ sp str = case break (== '\n') str of
+  (c, s ) -> suc sp (lineCommentTok c) (incrSpan sp $ length c) s
+
+lexPragma :: P a -> Lexer Token a
+lexPragma noPragma suc fail sp0 str = pragma (incrSpan sp0 3) (drop 3 str)
+  where
+  skip = noPragma sp0 str
+  pragma sp []         = fail sp0 "Unterminated pragma" sp []
+  pragma sp cs@(c : s)
+    | c == '\t' = pragma (tabSpan  sp) s
+    | c == '\n' = pragma (nlSpan   sp) s
+    | isSpace c = pragma (nextSpan sp) s
+    | isAlpha c = case Map.lookup (map toLower prag) pragmas of
+        Nothing            -> skip
+        Just PragmaOptions -> lexOptionsPragma sp0 suc fail sp1 rest
+        Just t             -> suc sp0 (tok t)               sp1 rest
+    | otherwise = skip
+    where
+    (prag, rest) = span isAlphaNum cs
+    sp1          = incrSpan sp (length prag)
+
+lexOptionsPragma :: Span -> Lexer Token a
+lexOptionsPragma sp0 _   fail sp [] = fail sp0 "Unterminated Options pragma" sp []
+lexOptionsPragma sp0 suc fail sp (c : s)
+  | c == '\t' = lexArgs Nothing (tabSpan  sp) s
+  | c == '\n' = lexArgs Nothing (nlSpan   sp) s
+  | isSpace c = lexArgs Nothing (nextSpan sp) s
+  | c == '_'  = let (tool, s1) = span isIdentChar s
+                in  lexArgs (Just tool) (incrSpan sp (length tool + 1)) s1
+  | otherwise = fail sp0 "Malformed Options pragma" sp s
+  where
+  lexArgs mbTool = lexRaw ""
+    where
+    lexRaw s0 sp1 r = case hash of
+      []            -> fail sp0 "End-of-file inside pragma" (incrSpan sp1 len) []
+      '#':'-':'}':_ -> token  (trim $ s0 ++ opts) (incrSpan sp1 len)       hash
+      _             -> lexRaw (s0 ++ opts ++ "#") (incrSpan sp1 (len + 1)) (drop 1 hash)
+      where
+      (opts, hash) = span (/= '#') r
+      len = length opts
+      token = suc sp0 . pragmaOptionsTok mbTool
+      trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace
+
+-- Lex a nested comment
+lexNestedComment :: Lexer Token a
+lexNestedComment suc fail sp0 = lnc (0 :: Integer) id sp0
+  where
+  -- d   : nesting depth
+  -- comm: comment already lexed as functional list
+  lnc d comm sp str = case (d, str) of
+    (_,        []) -> fail sp0    "Unterminated nested comment"  sp          []
+    (1, '-':'}':s) -> suc  sp0    (nestedCommentTok (comm "-}")) (incrSpan sp 2) s
+    (_, '{':'-':s) -> cont (d+1) ("{-" ++)                       (incrSpan sp 2) s
+    (_, '-':'}':s) -> cont (d-1) ("-}" ++)                       (incrSpan sp 2) s
+    (_, c@'\t' :s) -> cont d     (c:)                            (tabSpan    sp) s
+    (_, c@'\n' :s) -> cont d     (c:)                            (nlSpan     sp) s
+    (_, c      :s) -> cont d     (c:)                            (nextSpan   sp) s
+    where cont d' comm' = lnc d' (comm . comm')
+
+-- Lex tokens at the beginning of a line, managing layout.
+lexBOL :: Lexer Token a
+lexBOL suc fail sp s _ []            = lexToken suc fail sp s False []
+lexBOL suc fail sp s _ ctxt@(n:rest)
+  | col <  n  = suc sp (tok VRightBrace) sp s True  rest
+  | col == n  = lexSemiOrWhere suc fail  sp s False ctxt
+  | otherwise = lexToken       suc fail  sp s False ctxt
+  where col = column (span2Pos sp)
+
+lexSemiOrWhere :: Lexer Token a
+lexSemiOrWhere suc _ sp ('w':'h':'e':'r':'e':s@(c:_))
+  | not (isIdentChar c)   = suc sp (tok KW_where)   sp s
+lexSemiOrWhere suc _ sp s = suc sp (tok VSemicolon) sp s
+
+-- Lex a single 'Token'
+lexToken :: Lexer Token a
+lexToken suc _    sp []       = suc sp (tok EOF) sp []
+lexToken suc fail sp cs@(c:s)
+  | take 3 cs == "#-}" = suc sp (tok PragmaEnd) (incrSpan sp 3) (drop 3 cs)
+  | c == '('           = token LeftParen
+  | c == ')'           = token RightParen
+  | c == ','           = token Comma
+  | c == ';'           = token Semicolon
+  | c == '['           = token LeftBracket
+  | c == ']'           = token RightBracket
+  | c == '_'           = token Underscore
+  | c == '`'           = token Backquote
+  | c == '{'           = token LeftBrace
+  | c == '}'           = lexRightBrace (suc sp) (nextSpan sp) s
+  | c == '\''          = lexChar   sp suc fail  (nextSpan sp) s
+  | c == '\"'          = lexString sp suc fail  (nextSpan sp) s
+  | isAlpha      c     = lexIdent      (suc sp) sp            cs
+  | isSymbolChar c     = lexSymbol     (suc sp) sp            cs
+  | isDigit      c     = lexNumber     (suc sp) sp            cs
+  | otherwise          = fail sp ("Illegal character " ++ show c) sp s
+  where token t = suc sp (tok t) (nextSpan sp) s
+
+-- Lex a right brace and pop from the context stack
+lexRightBrace :: (Token -> P a) -> P a
+lexRightBrace cont sp s bol ctxt = cont (tok RightBrace) sp s bol (drop 1 ctxt)
+
+-- Lex an identifier
+lexIdent :: (Token -> P a) -> P a
+lexIdent cont sp s = maybe (lexOptQual cont (token Id) [ident]) (cont . token)
+                          (Map.lookup ident keywordsSpecialIds)
+                          (incrSpan sp $ length ident) rest
+  where (ident, rest) = span isIdentChar s
+        token t       = idTok t [] ident
+
+-- Lex a symbol
+lexSymbol :: (Token -> P a) -> P a
+lexSymbol cont sp s = cont
+  (idTok (Map.findWithDefault Sym sym reservedSpecialOps) [] sym)
+  (incrSpan sp $ length sym) rest
+  where (sym, rest) = span isSymbolChar s
+
+-- Lex an optionally qualified entity (identifier or symbol).
+lexOptQual :: (Token -> P a) -> Token -> [String] -> P a
+lexOptQual cont token mIdent sp cs@('.':c:s)
+  | isAlpha  c                 = lexQualIdent cont identCont mIdent
+                                   (nextSpan sp) (c:s)
+  | isSymbolChar c && c /= '.' = lexQualSymbol cont identCont mIdent
+                                   (nextSpan sp) (c:s)
+--   | c `elem` ":[("   = lexQualPrimitive cont token     mIdent (nextSpan sp) (c:s)
+  where identCont _ _ = cont token sp cs
+lexOptQual cont token mIdent sp cs@('.':'.':c:s)
+  |       isSymbolChar c =       lexQualSymbol cont identCont mIdent
+                                   (nextSpan sp) ('.':c:s)
+  | not $ isIdentChar  c =       lexQualSymbol cont identCont mIdent
+                                   (nextSpan sp) ('.':c:s)
+  where identCont _ _ = cont token sp cs
+lexOptQual cont token _      sp cs = cont token sp cs
+
+-- Lex a qualified identifier.
+lexQualIdent :: (Token -> P a) -> P a -> [String] -> P a
+lexQualIdent cont identCont mIdent sp s =
+  maybe (lexOptQual cont (idTok QId mIdent ident) (mIdent ++ [ident]))
+        (const identCont)
+        (Map.lookup ident keywords)
+        (incrSpan sp (length ident)) rest
+  where (ident, rest) = span isIdentChar s
+
+-- Lex a qualified symbol.
+lexQualSymbol :: (Token -> P a) -> P a -> [String] -> P a
+lexQualSymbol cont identCont mIdent sp s =
+  maybe (cont (idTok QSym mIdent sym)) (const identCont)
+        (Map.lookup sym reservedOps)
+        (incrSpan sp (length sym)) rest
+  where (sym, rest) = span isSymbolChar s
+
+-- ---------------------------------------------------------------------------
+-- /Note:/ since Curry allows an unlimited range of integer numbers,
+-- read numbers must be converted to Haskell type 'Integer'.
+-- ---------------------------------------------------------------------------
+
+-- Lex a numeric literal.
+lexNumber :: (Token -> P a) -> P a
+lexNumber cont sp ('0':c:s)
+  | c `elem` "bB"  = lexBinary      cont nullCont (incrSpan sp 2) s
+  | c `elem` "oO"  = lexOctal       cont nullCont (incrSpan sp 2) s
+  | c `elem` "xX"  = lexHexadecimal cont nullCont (incrSpan sp 2) s
+  where nullCont _ _ = cont (intTok 10 "0") (nextSpan sp) (c:s)
+lexNumber cont sp s = lexOptFraction cont (intTok 10 digits) digits
+                     (incrSpan sp $ length digits) rest
+  where (digits, rest) = span isDigit s
+
+-- Lex a binary literal.
+lexBinary :: (Token -> P a) -> P a -> P a
+lexBinary cont nullCont sp s
+  | null digits = nullCont undefined undefined
+  | otherwise   = cont (intTok 2 digits) (incrSpan sp $ length digits) rest
+  where (digits, rest) = span isBinDigit s
+        isBinDigit c   = c >= '0' && c <= '1'
+
+-- Lex an octal literal.
+lexOctal :: (Token -> P a) -> P a -> P a
+lexOctal cont nullCont sp s
+  | null digits = nullCont undefined undefined
+  | otherwise   = cont (intTok 8 digits) (incrSpan sp $ length digits) rest
+  where (digits, rest) = span isOctDigit s
+
+-- Lex a hexadecimal literal.
+lexHexadecimal :: (Token -> P a) -> P a -> P a
+lexHexadecimal cont nullCont sp s
+  | null digits = nullCont undefined undefined
+  | otherwise   = cont (intTok 16 digits) (incrSpan sp $ length digits) rest
+  where (digits, rest) = span isHexDigit s
+
+-- Lex an optional fractional part (float literal).
+lexOptFraction :: (Token -> P a) -> Token -> String -> P a
+lexOptFraction cont _ mant sp ('.':c:s)
+  | isDigit c = lexOptExponent cont (floatTok mant frac 0 "") mant frac
+                               (incrSpan sp (length frac+1)) rest
+  where (frac,rest) = span isDigit (c:s)
+lexOptFraction cont token mant sp (c:s)
+  | c `elem` "eE" = lexSignedExponent cont intCont mant "" [c] (nextSpan sp) s
+  where intCont _ _ = cont token sp (c:s)
+lexOptFraction cont token _ sp s = cont token sp s
+
+-- Lex an optional exponent (float literal).
+lexOptExponent :: (Token -> P a) -> Token -> String -> String -> P a
+lexOptExponent cont token mant frac sp (c:s)
+  | c `elem` "eE" = lexSignedExponent cont floatCont mant frac [c] (nextSpan sp) s
+  where floatCont _ _ = cont token sp (c:s)
+lexOptExponent cont token _    _    sp s = cont token sp s
+
+-- Lex an exponent with sign (float literal).
+lexSignedExponent :: (Token -> P a) -> P a -> String -> String -> String
+                  -> P a
+lexSignedExponent cont floatCont mant frac e sp str = case str of
+  ('+':c:s) | isDigit c -> lexExpo (e ++ "+") id     (nextSpan sp) (c:s)
+  ('-':c:s) | isDigit c -> lexExpo (e ++ "-") negate (nextSpan sp) (c:s)
+  (c:_)     | isDigit c -> lexExpo e          id     sp            str
+  _                     -> floatCont                 sp            str
+  where lexExpo = lexExponent cont mant frac
+
+-- Lex an exponent without sign (float literal).
+lexExponent :: (Token -> P a) -> String -> String -> String -> (Int -> Int)
+            -> P a
+lexExponent cont mant frac e expSign sp s =
+  cont (floatTok mant frac expo (e ++ digits)) (incrSpan sp $ length digits) rest
+  where (digits, rest) = span isDigit s
+        expo           = expSign (convertIntegral 10 digits)
+
+-- Lex a character literal.
+lexChar :: Span -> Lexer Token a
+lexChar sp0 _       fail sp []    = fail sp0 "Illegal character constant" sp []
+lexChar sp0 success fail sp (c:s)
+  | c == '\\' = lexEscape sp (\d o -> lexCharEnd d o sp0 success fail)
+                          fail (nextSpan sp) s
+  | c == '\n' = fail sp0 "Illegal character constant" sp (c:s)
+  | c == '\t' = lexCharEnd c "\t" sp0 success fail (tabSpan  sp) s
+  | otherwise = lexCharEnd c [c]  sp0 success fail (nextSpan sp) s
+
+-- Lex the end of a character literal.
+lexCharEnd :: Char -> String -> Span -> Lexer Token a
+lexCharEnd c o sp0 suc _    sp ('\'':s) = suc sp0 (charTok c o) (nextSpan sp) s
+lexCharEnd _ _ sp0 _   fail sp s        =
+  fail sp0 "Improperly terminated character constant" sp s
+
+-- Lex a String literal.
+lexString :: Span -> Lexer Token a
+lexString sp0 suc fail = lexStringRest "" id
+  where
+  lexStringRest _  _  sp []    = improperTermination sp
+  lexStringRest s0 so sp (c:s)
+    | c == '\n' = improperTermination sp
+    | c == '\"' = suc sp0 (stringTok (reverse s0) (so "")) (nextSpan sp) s
+    | c == '\\' = lexStringEscape sp s0 so lexStringRest fail (nextSpan sp) s
+    | c == '\t' = lexStringRest (c:s0) (so . (c:)) (tabSpan  sp) s
+    | otherwise = lexStringRest (c:s0) (so . (c:)) (nextSpan sp) s
+  improperTermination sp = fail sp0 "Improperly terminated string constant" sp []
+
+-- Lex an escaped character inside a string.
+lexStringEscape ::  Span -> String -> (String -> String)
+                -> (String -> (String -> String) -> P a)
+                -> FailP a -> P a
+lexStringEscape sp0 _  _  _   fail sp []      = lexEscape sp0 undefined fail sp []
+lexStringEscape sp0 s0 so suc fail sp cs@(c:s)
+    -- The escape sequence represents an empty character of length zero
+  | c == '&'  = suc s0 (so . ("\\&" ++)) (nextSpan sp) s
+  | isSpace c = lexStringGap so (suc s0) fail sp cs
+  | otherwise = lexEscape sp0 (\ c' s' -> suc (c': s0) (so . (s' ++))) fail sp cs
+
+-- Lex a string gap.
+lexStringGap :: (String -> String) -> ((String -> String) -> P a)
+             -> FailP a -> P a
+lexStringGap _  _   fail sp []    = fail sp "End-of-file in string gap" sp []
+lexStringGap so suc fail sp (c:s)
+  | c == '\\' = suc          (so . (c:))          (nextSpan sp) s
+  | c == '\t' = lexStringGap (so . (c:)) suc fail (tabSpan  sp) s
+  | c == '\n' = lexStringGap (so . (c:)) suc fail (nlSpan   sp) s
+  | isSpace c = lexStringGap (so . (c:)) suc fail (nextSpan sp) s
+  | otherwise = fail sp ("Illegal character in string gap: " ++ show c) sp s
+
+-- Lex an escaped character.
+lexEscape :: Span -> (Char -> String -> P a) -> FailP a -> P a
+lexEscape sp0 suc fail sp str = case str of
+  -- character escape
+  ('a' :s) -> suc '\a' "\\a"  (nextSpan sp) s
+  ('b' :s) -> suc '\b' "\\b"  (nextSpan sp) s
+  ('f' :s) -> suc '\f' "\\f"  (nextSpan sp) s
+  ('n' :s) -> suc '\n' "\\n"  (nextSpan sp) s
+  ('r' :s) -> suc '\r' "\\r"  (nextSpan sp) s
+  ('t' :s) -> suc '\t' "\\t"  (nextSpan sp) s
+  ('v' :s) -> suc '\v' "\\v"  (nextSpan sp) s
+  ('\\':s) -> suc '\\' "\\\\" (nextSpan sp) s
+  ('"' :s) -> suc '\"' "\\\"" (nextSpan sp) s
+  ('\'':s) -> suc '\'' "\\\'" (nextSpan sp) s
+  -- control characters
+  ('^':c:s) | isControlEsc c -> controlEsc c (incrSpan sp 2) s
+  -- numeric escape
+  ('o':c:s) | isOctDigit c   -> numEsc  8 isOctDigit ("\\o" ++) (nextSpan sp) (c:s)
+  ('x':c:s) | isHexDigit c   -> numEsc 16 isHexDigit ("\\x" ++) (nextSpan sp) (c:s)
+  (c:s)     | isDigit    c   -> numEsc 10 isDigit    ("\\"  ++) sp            (c:s)
+  -- ascii escape
+  _        -> asciiEscape sp0 suc fail sp str
+  where numEsc         = numEscape sp0 suc fail
+        controlEsc   c = suc (chr (ord c `mod` 32)) ("\\^" ++ [c])
+        isControlEsc c = isUpper c || c `elem` "@[\\]^_"
+
+numEscape :: Span -> (Char -> String -> P a) -> FailP a -> Int
+          -> (Char -> Bool) -> (String -> String) -> P a
+numEscape sp0 suc fail b isDigit' so sp s
+  | n >= ord minBound && n <= ord maxBound
+   = suc (chr n) (so digits) (incrSpan sp $ length digits) rest
+  | otherwise
+  = fail sp0 "Numeric escape out-of-range" sp s
+  where (digits, rest) = span isDigit' s
+        n = convertIntegral b digits
+
+asciiEscape :: Span -> (Char -> String -> P a) -> FailP a -> P a
+asciiEscape sp0 suc fail sp str = case str of
+  ('N':'U':'L':s) -> suc '\NUL' "\\NUL" (incrSpan sp 3) s
+  ('S':'O':'H':s) -> suc '\SOH' "\\SOH" (incrSpan sp 3) s
+  ('S':'T':'X':s) -> suc '\STX' "\\STX" (incrSpan sp 3) s
+  ('E':'T':'X':s) -> suc '\ETX' "\\ETX" (incrSpan sp 3) s
+  ('E':'O':'T':s) -> suc '\EOT' "\\EOT" (incrSpan sp 3) s
+  ('E':'N':'Q':s) -> suc '\ENQ' "\\ENQ" (incrSpan sp 3) s
+  ('A':'C':'K':s) -> suc '\ACK' "\\ACK" (incrSpan sp 3) s
+  ('B':'E':'L':s) -> suc '\BEL' "\\BEL" (incrSpan sp 3) s
+  ('B':'S'    :s) -> suc '\BS'  "\\BS"  (incrSpan sp 2) s
+  ('H':'T'    :s) -> suc '\HT'  "\\HT"  (incrSpan sp 2) s
+  ('L':'F'    :s) -> suc '\LF'  "\\LF"  (incrSpan sp 2) s
+  ('V':'T'    :s) -> suc '\VT'  "\\VT"  (incrSpan sp 2) s
+  ('F':'F'    :s) -> suc '\FF'  "\\FF"  (incrSpan sp 2) s
+  ('C':'R'    :s) -> suc '\CR'  "\\CR"  (incrSpan sp 2) s
+  ('S':'O'    :s) -> suc '\SO'  "\\SO"  (incrSpan sp 2) s
+  ('S':'I'    :s) -> suc '\SI'  "\\SI"  (incrSpan sp 2) s
+  ('D':'L':'E':s) -> suc '\DLE' "\\DLE" (incrSpan sp 3) s
+  ('D':'C':'1':s) -> suc '\DC1' "\\DC1" (incrSpan sp 3) s
+  ('D':'C':'2':s) -> suc '\DC2' "\\DC2" (incrSpan sp 3) s
+  ('D':'C':'3':s) -> suc '\DC3' "\\DC3" (incrSpan sp 3) s
+  ('D':'C':'4':s) -> suc '\DC4' "\\DC4" (incrSpan sp 3) s
+  ('N':'A':'K':s) -> suc '\NAK' "\\NAK" (incrSpan sp 3) s
+  ('S':'Y':'N':s) -> suc '\SYN' "\\SYN" (incrSpan sp 3) s
+  ('E':'T':'B':s) -> suc '\ETB' "\\ETB" (incrSpan sp 3) s
+  ('C':'A':'N':s) -> suc '\CAN' "\\CAN" (incrSpan sp 3) s
+  ('E':'M'    :s) -> suc '\EM'  "\\EM"  (incrSpan sp 2) s
+  ('S':'U':'B':s) -> suc '\SUB' "\\SUB" (incrSpan sp 3) s
+  ('E':'S':'C':s) -> suc '\ESC' "\\ESC" (incrSpan sp 3) s
+  ('F':'S'    :s) -> suc '\FS'  "\\FS"  (incrSpan sp 2) s
+  ('G':'S'    :s) -> suc '\GS'  "\\GS"  (incrSpan sp 2) s
+  ('R':'S'    :s) -> suc '\RS'  "\\RS"  (incrSpan sp 2) s
+  ('U':'S'    :s) -> suc '\US'  "\\US"  (incrSpan sp 2) s
+  ('S':'P'    :s) -> suc '\SP'  "\\SP"  (incrSpan sp 2) s
+  ('D':'E':'L':s) -> suc '\DEL' "\\DEL" (incrSpan sp 3) s
+  s               -> fail sp0 "Illegal escape sequence" sp s
diff --git a/src/Curry/Syntax/Lexer.lhs b/src/Curry/Syntax/Lexer.lhs
deleted file mode 100644
--- a/src/Curry/Syntax/Lexer.lhs
+++ /dev/null
@@ -1,630 +0,0 @@
-
-% $Id: CurryLexer.lhs,v 1.40 2004/03/04 22:39:12 wlux Exp $
-%
-% Copyright (c) 1999-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{CurryLexer.lhs}
-\section{A Lexer for Curry}
-In this section a lexer for Curry is implemented.
-\begin{verbatim}
- 
-> module Curry.Syntax.Lexer (lexFile,lexer, Token (..), Category(..), Attributes(..)) where
-
-> import Data.Char 
-> import Data.List
-> import qualified Data.Map as Map
-
-> import Curry.Syntax.LexComb
-> import Curry.Base.Position
-
-
-
-\end{verbatim}
-\paragraph{Tokens} Note that the equality and ordering instances of
-\texttt{Token} disregard the attributes.
-\begin{verbatim}
-
-> data Token = Token Category Attributes
-
-> instance Eq Token where
->   Token t1 _ == Token t2 _ = t1 == t2
-> instance Ord Token where
->   Token t1 _ `compare` Token t2 _ = t1 `compare` t2
-
-> data Category =
->   -- literals
->     CharTok | IntTok | FloatTok | IntegerTok | StringTok
->   -- identifiers
->   | Id | QId | Sym | QSym
->   -- punctuation symbols
->   | LeftParen | RightParen | Semicolon | LeftBrace | RightBrace
->   | LeftBracket | RightBracket | Comma | Underscore | Backquote
->   -- turn off layout (inserted by bbr)
->   | LeftBraceSemicolon
->   -- virtual punctation (inserted by layout)
->   | VSemicolon | VRightBrace
->   -- reserved identifiers
->   | KW_case | KW_choice | KW_data | KW_do | KW_else | KW_eval | KW_external
->   | KW_free | KW_if | KW_import | KW_in | KW_infix | KW_infixl | KW_infixr
->   | KW_let | KW_module | KW_newtype | KW_of | KW_rigid | KW_then | KW_type
->   | KW_where
->   -- reserved operators
->   | At | Colon | DotDot | DoubleColon | Equals | Backslash | Bar
->   | LeftArrow | RightArrow | Tilde | Binds
->   -- special identifiers
->   | Id_as | Id_ccall | Id_forall | Id_hiding | Id_interface | Id_primitive
->   | Id_qualified
->   -- special operators
->   | Sym_Dot | Sym_Minus | Sym_MinusDot
->   -- end-of-file token
->   | EOF
->   -- comments (only for full lexer) inserted by men & bbr
->   | LineComment | NestedComment 
->   deriving (Eq,Ord)
-
-\end{verbatim}
-There are different kinds of attributes associated with the tokens.
-Most attributes simply save the string corresponding to the token.
-However, for qualified identifiers, we also record the list of module
-qualifiers. The values corresponding to a literal token are properly
-converted already. To simplify the creation and extraction of
-attribute values we make use of records.
-\begin{verbatim}
-
-> data Attributes =
->     NoAttributes
->   | CharAttributes{ cval :: Char, original :: String}
->   | IntAttributes{ ival :: Int , original :: String}
->   | FloatAttributes{ fval :: Double, original :: String}
->   | IntegerAttributes{ intval :: Integer, original :: String}
->   | StringAttributes{ sval :: String, original :: String}
->   | IdentAttributes{ modul :: [String], sval :: String}
-
-> instance Show Attributes where
->   showsPrec _ NoAttributes = showChar '_'
->   showsPrec _ (CharAttributes cval _) = shows cval
->   showsPrec _ (IntAttributes ival _) = shows ival
->   showsPrec _ (FloatAttributes fval _) = shows fval
->   showsPrec _ (IntegerAttributes intval _) = shows intval
->   showsPrec _ (StringAttributes sval _) = shows sval
->   showsPrec _ (IdentAttributes mIdent ident) =
->     showString ("`" ++ concat (intersperse "." (mIdent ++ [ident])) ++ "'")
-
-\end{verbatim}
-The following functions can be used to construct tokens with
-specific attributes.
-\begin{verbatim}
-
-> tok :: Category -> Token
-> tok t = Token t NoAttributes
-
-> idTok :: Category -> [String] -> String -> Token
-> idTok t mIdent ident = Token t IdentAttributes{ modul = mIdent, sval = ident }
-
-> charTok :: Char -> String -> Token
-> charTok c o = Token CharTok CharAttributes{ cval = c, original = o }
-
-> intTok :: Int -> String -> Token
-> intTok base digits =
->   Token IntTok IntAttributes{ ival = convertIntegral base digits,
->                               original = digits}
-
-> floatTok :: String -> String -> Int -> String -> Token
-> floatTok mant frac exp rest =
->   Token FloatTok FloatAttributes{ fval = convertFloating mant frac exp, 
->                                   original = mant++"."++frac++rest}
- 
-> integerTok :: Integer -> String -> Token
-> integerTok base digits =
->   Token IntegerTok
->         IntegerAttributes{intval = (convertIntegral base digits) :: Integer,
->                           original = digits}
-
-> stringTok :: String -> String -> Token
-> stringTok cs o = Token StringTok StringAttributes{ sval = cs, original = o }
-
-> lineCommentTok :: String -> Token
-> lineCommentTok s = Token LineComment StringAttributes{ sval = s, original = s}
-
-> nestedCommentTok :: String -> Token
-> nestedCommentTok s = Token NestedComment StringAttributes{ sval = s, original = s }
-
-\end{verbatim}
-The \texttt{Show} instance of \texttt{Token} is designed to display
-all tokens in their source representation.
-\begin{verbatim}
-
-> instance Show Token where
->   showsPrec _ (Token Id a) = showString "identifier " . shows a
->   showsPrec _ (Token QId a) = showString "qualified identifier " . shows a
->   showsPrec _ (Token Sym a) = showString "operator " . shows a
->   showsPrec _ (Token QSym a) = showString "qualified operator " . shows a
->   showsPrec _ (Token IntTok a) = showString "integer " . shows a
->   showsPrec _ (Token FloatTok a) = showString "float " . shows a
->   showsPrec _ (Token CharTok a) = showString "character " . shows a
->   showsPrec _ (Token IntegerTok a) = showString "integer " . shows a
->   showsPrec _ (Token StringTok a) = showString "string " . shows a
->   showsPrec _ (Token LeftParen _) = showString "`('"
->   showsPrec _ (Token RightParen _) = showString "`)'"
->   showsPrec _ (Token Semicolon _) = showString "`;'"
->   showsPrec _ (Token LeftBrace _) = showString "`{'"
->   showsPrec _ (Token RightBrace _) = showString "`}'"
->   showsPrec _ (Token LeftBracket _) = showString "`['"
->   showsPrec _ (Token RightBracket _) = showString "`]'"
->   showsPrec _ (Token Comma _) = showString "`,'"
->   showsPrec _ (Token Underscore _) = showString "`_'"
->   showsPrec _ (Token Backquote _) = showString "``'"
->   showsPrec _ (Token VSemicolon _) =
->     showString "`;' (inserted due to layout)"
->   showsPrec _ (Token VRightBrace _) =
->     showString "`}' (inserted due to layout)"
->   showsPrec _ (Token At _) = showString "`@'"
->   showsPrec _ (Token Colon _) = showString "`:'"
->   showsPrec _ (Token DotDot _) = showString "`..'"
->   showsPrec _ (Token DoubleColon _) = showString "`::'"
->   showsPrec _ (Token Equals _) = showString "`='"
->   showsPrec _ (Token Backslash _) = showString "`\\'"
->   showsPrec _ (Token Bar _) = showString "`|'"
->   showsPrec _ (Token LeftArrow _) = showString "`<-'"
->   showsPrec _ (Token RightArrow _) = showString "`->'"
->   showsPrec _ (Token Tilde _) = showString "`~'"
->   showsPrec _ (Token Binds _) = showString "`:='"
->   showsPrec _ (Token Sym_Dot _) = showString "operator `.'"
->   showsPrec _ (Token Sym_Minus _) = showString "operator `-'"
->   showsPrec _ (Token Sym_MinusDot _) = showString "operator `-.'"
->   showsPrec _ (Token KW_case _) = showString "`case'"
->   showsPrec _ (Token KW_choice _) = showString "`choice'"
->   showsPrec _ (Token KW_data _) = showString "`data'"
->   showsPrec _ (Token KW_do _) = showString "`do'"
->   showsPrec _ (Token KW_else _) = showString "`else'"
->   showsPrec _ (Token KW_eval _) = showString "`eval'"
->   showsPrec _ (Token KW_external _) = showString "`external'"
->   showsPrec _ (Token KW_free _) = showString "`free'"
->   showsPrec _ (Token KW_if _) = showString "`if'"
->   showsPrec _ (Token KW_import _) = showString "`import'"
->   showsPrec _ (Token KW_in _) = showString "`in'"
->   showsPrec _ (Token KW_infix _) = showString "`infix'"
->   showsPrec _ (Token KW_infixl _) = showString "`infixl'"
->   showsPrec _ (Token KW_infixr _) = showString "`infixr'"
->   showsPrec _ (Token KW_let _) = showString "`let'"
->   showsPrec _ (Token KW_module _) = showString "`module'"
->   showsPrec _ (Token KW_newtype _) = showString "`newtype'"
->   showsPrec _ (Token KW_of _) = showString "`of'"
->   showsPrec _ (Token KW_rigid _) = showString "`rigid'"
->   showsPrec _ (Token KW_then _) = showString "`then'"
->   showsPrec _ (Token KW_type _) = showString "`type'"
->   showsPrec _ (Token KW_where _) = showString "`where'"
->   showsPrec _ (Token Id_as _) = showString "identifier `as'"
->   showsPrec _ (Token Id_ccall _) = showString "identifier `ccall'"
->   showsPrec _ (Token Id_forall _) = showString "identifier `forall'"
->   showsPrec _ (Token Id_hiding _) = showString "identifier `hiding'"
->   showsPrec _ (Token Id_interface _) = showString "identifier `interface'"
->   showsPrec _ (Token Id_primitive _) = showString "identifier `primitive'"
->   showsPrec _ (Token Id_qualified _) = showString "identifier `qualified'"
->   showsPrec _ (Token EOF _) = showString "<end-of-file>"
->   showsPrec _ (Token LineComment a) = shows a
->   showsPrec _ (Token NestedComment a) = shows a
-
-\end{verbatim}
-Tables for reserved operators and identifiers
-\begin{verbatim}
-
-> reserved_ops, reserved_and_special_ops :: Map.Map String Category
-> reserved_ops = Map.fromList [
->     ("@",  At),
->     ("::", DoubleColon),
->     ("..", DotDot),
->     ("=",  Equals),
->     ("\\", Backslash),
->     ("|",  Bar),
->     ("<-", LeftArrow),
->     ("->", RightArrow),
->     ("~",  Tilde),
->     (":=", Binds)
->   ]
-> reserved_and_special_ops = foldr (uncurry Map.insert) reserved_ops [
->     (":",  Colon),
->     (".",  Sym_Dot),
->     ("-",  Sym_Minus),
->     ("-.", Sym_MinusDot)
->   ]
-
-> reserved_ids, reserved_and_special_ids :: Map.Map String Category
-> reserved_ids = Map.fromList [
->     ("case",     KW_case),
->     ("choice",   KW_choice),
->     ("data",     KW_data),
->     ("do",       KW_do),
->     ("else",     KW_else),
->     ("eval",     KW_eval),
->     ("external", KW_external),
->     ("free",     KW_free),
->     ("if",       KW_if),
->     ("import",   KW_import),
->     ("in",       KW_in),
->     ("infix",    KW_infix),
->     ("infixl",   KW_infixl),
->     ("infixr",   KW_infixr),
->     ("let",      KW_let),
->     ("module",   KW_module),
->     ("newtype",  KW_newtype),
->     ("of",       KW_of),
->     ("rigid",    KW_rigid),
->     ("then",     KW_then),
->     ("type",     KW_type),
->     ("where",    KW_where)
->   ]
-> reserved_and_special_ids = foldr (uncurry Map.insert) reserved_ids [
->     ("as",        Id_as),
->     ("ccall",     Id_ccall),
->     ("forall",    Id_forall),
->     ("hiding",    Id_hiding),
->     ("interface", Id_interface),
->     ("primitive", Id_primitive),
->     ("qualified", Id_qualified)
->   ]
-
-\end{verbatim}
-Character classes
-\begin{verbatim}
-
-> isIdent, isSym, isOctit, isHexit :: Char -> Bool
-> isIdent c = isAlphaNum c || c `elem` "'_"
-> isSym c = c `elem` "~!@#$%^&*+-=<>:?./|\\"
-> isOctit c = c >= '0' && c <= '7'
-> isHexit c = isDigit c || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'
-
-inserted for full lexing (men&bbr)
-
-> isLineComment, isNestedComment :: String -> Bool
-> isLineComment ('-':'-':_) = True
-> isLineComment _ = False
-> isNestedComment ('{':'-':s) = True
-> isNestedComment _ = False
-
-
-\end{verbatim}
-Lexing functions
-\begin{verbatim}
-
-> type SuccessP a = Position -> Token -> P a
-> type FailP a = Position -> String -> P a
-
-> lexFile :: P [(Position,Token)]
-> lexFile = fullLexer tokens failP
->   where tokens p t@(Token c _)
->           | c == EOF = returnP [(p,t)]
->           | otherwise = lexFile `thenP` returnP . ((p,t):)
-
-> lexer :: SuccessP a -> FailP a -> P a
-> lexer success fail = skipBlanks
->   where -- skipBlanks moves past whitespace and comments
->         skipBlanks p [] bol = success p (tok EOF) p [] bol
->         skipBlanks p ('\t':s) bol = skipBlanks (tab p) s bol
->         skipBlanks p ('\n':s) bol = skipBlanks (nl p) s True
->         skipBlanks p ('-':'-':s) bol =
->           skipBlanks (nl p) (tail' (dropWhile (/= '\n') s)) True
->         skipBlanks p ('{':'-':s) bol =
->           nestedComment p skipBlanks fail (incr p 2) s bol
->         skipBlanks p (c:s) bol
->           | isSpace c = skipBlanks (next p) s bol
->           | otherwise =
->               (if bol then lexBOL else lexToken) success fail p (c:s) bol
->         tail' [] = []
->         tail' (_:tl) = tl
-
-> fullLexer :: SuccessP a -> FailP a -> P a
-> fullLexer success fail = skipBlanks
->   where -- skipBlanks moves past whitespace 
->         skipBlanks p [] bol = success p (tok EOF) p [] bol
->         skipBlanks p ('\t':s) bol = skipBlanks (tab p) s bol
->         skipBlanks p ('\n':s) bol = skipBlanks (nl p) s True
->         skipBlanks p s@('-':'-':_) bol = lexLineComment success p s bol
->         skipBlanks p s@('{':'-':_) bol =
->           lexNestedComment 0 id p success fail p s bol
->         skipBlanks p (c:s) bol
->           | isSpace c = skipBlanks (next p) s bol
->           | otherwise =
->               (if bol then lexBOL else lexToken) success fail p (c:s) bol
->         tail' [] = []
->         tail' (_:tl) = tl
-
-> lexLineComment :: SuccessP a -> P a
-> lexLineComment success p s = case break (=='\n') s of
->   (comment,rest) -> success p (lineCommentTok comment) (incr p (length comment)) rest
- 
-> lexNestedComment :: Int -> (String -> String) -> 
->                     Position -> SuccessP a -> FailP a -> P a
-> lexNestedComment 1 comment p0 success fail p ('-':'}':s) = 
->   success p0 (nestedCommentTok (comment "-}") ) (incr p 2) s 
-> lexNestedComment n comment p0 success fail p ('{':'-':s) = 
->   lexNestedComment (n+1) (comment . ("{-"++)) p0 success fail (incr p 2) s
-> lexNestedComment n comment p0 success fail p ('-':'}':s) = 
->   lexNestedComment (n-1) (comment . ("-}"++)) p0 success fail (incr p 2) s
-> lexNestedComment n comment p0 success fail p (c@'\t':s) = 
->   lexNestedComment n (comment . (c:)) p0 success fail (tab p) s
-> lexNestedComment n comment p0 success fail p (c@'\n':s) = 
->   lexNestedComment n (comment . (c:)) p0 success fail (nl p) s
-> lexNestedComment n comment p0 success fail p (c:s) = 
->   lexNestedComment n (comment . (c:)) p0 success fail (next p) s
-> lexNestedComment n comment p0 success fail p "" = 
->   fail p0 "Unterminated nested comment" p []
-
-> nestedComment :: Position -> P a -> FailP a -> P a
-> nestedComment p0 success fail p ('-':'}':s) = success (incr p 2) s
-> nestedComment p0 success fail p ('{':'-':s) =
->   nestedComment p (nestedComment p0 success fail) fail (incr p 2) s
-> nestedComment p0 success fail p ('\t':s) =
->   nestedComment p0 success fail (tab p) s
-> nestedComment p0 success fail p ('\n':s) =
->   nestedComment p0 success fail (nl p) s
-> nestedComment p0 success fail p (_:s) =
->   nestedComment p0 success fail (next p) s
-> nestedComment p0 success fail p [] =
->   fail p0 "Unterminated nested comment at end-of-file" p []
-
-
-> lexBOL :: SuccessP a -> FailP a -> P a
-> lexBOL success fail p s _ [] = lexToken success fail p s False []
-> lexBOL success fail p s _ ctxt@(n:rest)
->   | col < n = success p (tok VRightBrace) p s True rest
->   | col == n = success p (tok VSemicolon) p s False ctxt
->   | otherwise = lexToken success fail p s False ctxt
->   where col = column p
-
-> lexToken :: SuccessP a -> FailP a -> P a
-> lexToken success fail p [] = success p (tok EOF) p []
-> lexToken success fail p (c:s)
->   | c == '(' = token LeftParen
->   | c == ')' = token RightParen
->   | c == ',' = token Comma
->   | c == ';' = token Semicolon
->   | c == '[' = token LeftBracket
->   | c == ']' = token RightBracket
->   | c == '_' = token Underscore
->   | c == '`' = token Backquote
->   | c == '{' = lexLeftBrace (token LeftBrace) (next p) (success p) s 
->   | c == '}' = \bol -> token RightBrace bol . drop 1
->   | c == '\'' = lexChar p success fail (next p) s
->   | c == '\"' = lexString p success fail (next p) s
->   | isAlpha c = lexIdent (success p) p (c:s)
->   | isSym c = lexSym (success p) p (c:s)
->   | isDigit c = lexNumber (success p) p (c:s)
->   | otherwise = fail p ("Illegal character " ++ show c) p s
->   where token t = success p (tok t) (next p) s
-
-> lexIdent :: (Token -> P a) -> P a
-> lexIdent cont p s =
->   maybe (lexOptQual cont (token Id) [ident]) (cont . token)
->         (Map.lookup ident reserved_and_special_ids)
->         (incr p (length ident)) rest
->   where (ident,rest) = span isIdent s
->         token t = idTok t [] ident
-
-> lexSym :: (Token -> P a) -> P a
-> lexSym cont p s =
->   cont (idTok (maybe Sym id (Map.lookup sym reserved_and_special_ops)) [] sym)
->        (incr p (length sym)) rest
->   where (sym,rest) = span isSym s
-
-> lexLeftBrace leftBrace _ _       []    = leftBrace
-> lexLeftBrace leftBrace p cont (c:s) 
->   | c==';'    = cont (tok LeftBraceSemicolon) (next p) s
->   | otherwise = leftBrace
-
-\end{verbatim}
-{\em Note:} the function \texttt{lexOptQual} has been extended to provide
-the qualified use of the Prelude list operators and tuples.
-\begin{verbatim}
-
-> lexOptQual :: (Token -> P a) -> Token -> [String] -> P a
-> lexOptQual cont token mIdent p ('.':c:s)
->   | isAlpha c = lexQualIdent cont identCont mIdent (next p) (c:s)
->   | isSym c = lexQualSym cont identCont mIdent (next p) (c:s)
->   | c=='(' || c=='[' 
->     = lexQualPreludeSym cont token identCont mIdent (next p) (c:s)
->  where identCont _ _ = cont token p ('.':c:s)
-> lexOptQual cont token mIdent p s = cont token p s
-
-> lexQualIdent :: (Token -> P a) -> P a -> [String] -> P a
-> lexQualIdent cont identCont mIdent p s =
->   maybe (lexOptQual cont (idTok QId mIdent ident) (mIdent ++ [ident]))
->         (const identCont)
->         (Map.lookup ident reserved_ids)
->         (incr p (length ident)) rest
->   where (ident,rest) = span isIdent s
-
-> lexQualSym :: (Token -> P a) -> P a -> [String] -> P a
-> lexQualSym cont identCont mIdent p s =
->   maybe (cont (idTok QSym mIdent sym)) (const identCont)
->         (Map.lookup sym reserved_ops)
->         (incr p (length sym)) rest
->   where (sym,rest) = span isSym s
-
-
-> lexQualPreludeSym :: (Token -> P a) -> Token -> P a -> [String] -> P a
-> lexQualPreludeSym cont _ identCont mIdent p ('[':']':rest) =
->   cont (idTok QId mIdent "[]") (incr p 2) rest
-> lexQualPreludeSym cont _ identCont mIdent p ('(':rest)
->   | not (null rest') && head rest'==')' 
->   = cont (idTok QId mIdent ('(':tup++")")) (incr p (length tup+2)) (tail rest')
->   where (tup,rest') = span (==',') rest
-> lexQualPreludeSym cont token _ _ p s =  cont token p s
-
-
-\end{verbatim}
-{\em Note:} since Curry allows an unlimited range of integer numbers,
-read numbers must be converted to Haskell type \texttt{Integer}.
-\begin{verbatim}
-
-> lexNumber :: (Token -> P a) -> P a
-> lexNumber cont p ('0':c:s)
->   | c `elem` "oO" = lexOctal cont nullCont (incr p 2) s
->   | c `elem` "xX" = lexHexadecimal cont nullCont (incr p 2) s
->   where nullCont _ _ = cont (intTok 10 "0") (next p) (c:s)
-> lexNumber cont p s
->     = lexOptFraction cont (integerTok 10 digits) digits
->                      (incr p (length digits)) rest
->   where (digits,rest) = span isDigit s
->         num           = (read digits) :: Integer
-
-> lexOctal :: (Token -> P a) -> P a -> P a
-> lexOctal cont nullCont p s
->   | null digits = nullCont undefined undefined
->   | otherwise = cont (integerTok 8 digits) (incr p (length digits)) rest
->   where (digits,rest) = span isOctit s
-
-> lexHexadecimal :: (Token -> P a) -> P a -> P a
-> lexHexadecimal cont nullCont p s
->   | null digits = nullCont undefined undefined
->   | otherwise = cont (integerTok 16 digits) (incr p (length digits)) rest
->   where (digits,rest) = span isHexit s
-
-> lexOptFraction :: (Token -> P a) -> Token -> String -> P a
-> lexOptFraction cont _ mant p ('.':c:s)
->   | isDigit c = lexOptExponent cont (floatTok mant frac 0 "") mant frac
->                                (incr p (length frac+1)) rest
->   where (frac,rest) = span isDigit (c:s)
-> lexOptFraction cont token mant p (c:s)
->   | c `elem` "eE" = lexSignedExponent cont intCont mant "" [c] (next p) s
->   where intCont _ _ = cont token p (c:s)
-> lexOptFraction cont token _ p s = cont token p s
-
-> lexOptExponent :: (Token -> P a) -> Token -> String -> String -> P a
-> lexOptExponent cont token mant frac p (c:s)
->   | c `elem` "eE" = lexSignedExponent cont floatCont mant frac [c] (next p) s
->   where floatCont _ _ = cont token p (c:s)
-> lexOptExponent cont token mant frac p s = cont token p s
-
-> lexSignedExponent :: (Token -> P a) -> P a -> String -> String -> String -> P a
-> lexSignedExponent cont floatCont mant frac e p ('+':c:s)
->   | isDigit c = lexExponent cont mant frac (e++"+") id (next p) (c:s)
-> lexSignedExponent cont floatCont mant frac e p ('-':c:s)
->   | isDigit c = lexExponent cont mant frac (e++"-") negate (next p) (c:s)
-> lexSignedExponent cont floatCont mant frac e p (c:s)
->   | isDigit c = lexExponent cont mant frac e id p (c:s)
-> lexSignedExponent cont floatCont mant frac e p s = floatCont p s
-
-> lexExponent :: (Token -> P a) -> String -> String -> String -> (Int -> Int) -> P a
-> lexExponent cont mant frac e expSign p s =
->   cont (floatTok mant frac exp (e++digits)) (incr p (length digits)) rest
->   where (digits,rest) = span isDigit s
->         exp = expSign (convertIntegral 10 digits)
-
-> lexChar :: Position -> SuccessP a -> FailP a -> P a
-> lexChar p0 success fail p [] = fail p0 "Illegal character constant" p []
-> lexChar p0 success fail p (c:s)
->   | c == '\\' = lexEscape p (lexCharEnd p0 success fail) fail (next p) s
->   | c == '\n' = fail p0 "Illegal character constant" p (c:s)
->   | c == '\t' = lexCharEnd p0 success fail c "\t" (tab p) s
->   | otherwise = lexCharEnd p0 success fail c [c] (next p) s
-
-> lexCharEnd :: Position -> SuccessP a -> FailP a -> Char -> String -> P a
-> lexCharEnd p0 success fail c o p ('\'':s) = success p0 (charTok c o) (next p) s
-> lexCharEnd p0 success fail c o p s =
->   fail p0 "Improperly terminated character constant" p s
-
-> lexString :: Position -> SuccessP a -> FailP a -> P a
-> lexString p0 success fail = lexStringRest p0 success fail "" id
-
-> lexStringRest :: Position -> SuccessP a -> FailP a -> String -> (String -> String) -> P a
-> lexStringRest p0 success fail s0 so p [] = 
->   fail p0 "Improperly terminated string constant" p []
-> lexStringRest p0 success fail s0 so p (c:s)
->   | c == '\\' =
->       lexStringEscape p (lexStringRest p0 success fail) fail s0 so (next p) s
->   | c == '\"' = success p0 (stringTok (reverse s0) (so "")) (next p) s
->   | c == '\n' = fail p0 "Improperly terminated string constant" p []
->   | c == '\t' = lexStringRest p0 success fail (c:s0) (so . (c:)) (tab p) s
->   | otherwise = lexStringRest p0 success fail (c:s0) (so . (c:)) (next p) s
-
-> lexStringEscape ::  Position -> (String -> (String -> String) -> P a) -> FailP a -> 
->                                  String -> (String -> String) -> P a
-> lexStringEscape p0 success fail s0 so p [] = lexEscape p0 undefined fail p []
-> lexStringEscape p0 success fail s0 so p (c:s)
->   | c == '&' = success s0 (so . ("\\&"++)) (next p) s
->   | isSpace c = lexStringGap (success s0) fail so p (c:s)
->   | otherwise = lexEscape p0 (\ c' s' -> success (c':s0) (so . (s'++))) fail p (c:s)
-
-> lexStringGap :: ((String -> String) -> P a) -> FailP a -> (String -> String) -> P a
-> lexStringGap success fail so p [] = fail p "End of file in string gap" p []
-> lexStringGap success fail so p (c:s)
->   | c == '\\' = success (so . (c:)) (next p) s
->   | c == '\t' = lexStringGap success fail (so . (c:)) (tab p) s
->   | c == '\n' = lexStringGap success fail (so . (c:)) (nl p) s
->   | isSpace c = lexStringGap success fail (so . (c:)) (next p) s
->   | otherwise = fail p ("Illegal character in string gap " ++ show c) p s
-
-> lexEscape :: Position -> (Char -> String -> P a) -> FailP a -> P a
-> lexEscape p0 success fail p ('a':s) = success '\a' "\\a" (next p) s
-> lexEscape p0 success fail p ('b':s) = success '\b' "\\b" (next p) s
-> lexEscape p0 success fail p ('f':s) = success '\f' "\\f" (next p) s
-> lexEscape p0 success fail p ('n':s) = success '\n' "\\n" (next p) s
-> lexEscape p0 success fail p ('r':s) = success '\r' "\\r" (next p) s
-> lexEscape p0 success fail p ('t':s) = success '\t' "\\t" (next p) s
-> lexEscape p0 success fail p ('v':s) = success '\v' "\\v" (next p) s
-> lexEscape p0 success fail p ('\\':s) = success '\\' "\\\\" (next p) s
-> lexEscape p0 success fail p ('"':s) = success '\"' "\\\"" (next p) s
-> lexEscape p0 success fail p ('\'':s) = success '\'' "\\\'" (next p) s
-> lexEscape p0 success fail p ('^':c:s)
->   | isUpper c || c `elem` "@[\\]^_" =
->       success (chr (ord c `mod` 32)) ("\\^"++[c]) (incr p 2) s
-> lexEscape p0 success fail p ('o':c:s)
->   | isOctit c = numEscape p0 success fail 8 isOctit ("\\o"++) (next p) (c:s)
-> lexEscape p0 success fail p ('x':c:s)
->   | isHexit c = numEscape p0 success fail 16 isHexit ("\\x"++) (next p) (c:s)
-> lexEscape p0 success fail p (c:s)
->   | isDigit c = numEscape p0 success fail 10 isDigit ("\\"++) p (c:s)
-> lexEscape p0 success fail p s = asciiEscape p0 success fail p s
-
-> asciiEscape :: Position -> (Char -> String -> P a) -> FailP a -> P a
-> asciiEscape p0 success fail p ('N':'U':'L':s) = success '\NUL' "\\NUL" (incr p 3) s
-> asciiEscape p0 success fail p ('S':'O':'H':s) = success '\SOH' "\\SOH" (incr p 3) s
-> asciiEscape p0 success fail p ('S':'T':'X':s) = success '\STX' "\\STX" (incr p 3) s
-> asciiEscape p0 success fail p ('E':'T':'X':s) = success '\ETX' "\\ETX" (incr p 3) s
-> asciiEscape p0 success fail p ('E':'O':'T':s) = success '\EOT' "\\EOT" (incr p 3) s
-> asciiEscape p0 success fail p ('E':'N':'Q':s) = success '\ENQ' "\\ENQ" (incr p 3) s
-> asciiEscape p0 success fail p ('A':'C':'K':s) = success '\ACK' "\\ACK" (incr p 3) s 
-> asciiEscape p0 success fail p ('B':'E':'L':s) = success '\BEL' "\\BEL" (incr p 3) s
-> asciiEscape p0 success fail p ('B':'S':s) = success '\BS' "\\BS" (incr p 2) s
-> asciiEscape p0 success fail p ('H':'T':s) = success '\HT' "\\HT" (incr p 2) s
-> asciiEscape p0 success fail p ('L':'F':s) = success '\LF' "\\LF" (incr p 2) s
-> asciiEscape p0 success fail p ('V':'T':s) = success '\VT' "\\VT" (incr p 2) s
-> asciiEscape p0 success fail p ('F':'F':s) = success '\FF' "\\FF" (incr p 2) s
-> asciiEscape p0 success fail p ('C':'R':s) = success '\CR' "\\CR" (incr p 2) s
-> asciiEscape p0 success fail p ('S':'O':s) = success '\SO' "\\SO" (incr p 2) s
-> asciiEscape p0 success fail p ('S':'I':s) = success '\SI' "\\SI" (incr p 2) s
-> asciiEscape p0 success fail p ('D':'L':'E':s) = success '\DLE' "\\DLE" (incr p 3) s 
-> asciiEscape p0 success fail p ('D':'C':'1':s) = success '\DC1' "\\DC1" (incr p 3) s
-> asciiEscape p0 success fail p ('D':'C':'2':s) = success '\DC2' "\\DC2" (incr p 3) s
-> asciiEscape p0 success fail p ('D':'C':'3':s) = success '\DC3' "\\DC3" (incr p 3) s
-> asciiEscape p0 success fail p ('D':'C':'4':s) = success '\DC4' "\\DC4" (incr p 3) s
-> asciiEscape p0 success fail p ('N':'A':'K':s) = success '\NAK' "\\NAK" (incr p 3) s
-> asciiEscape p0 success fail p ('S':'Y':'N':s) = success '\SYN' "\\SYN" (incr p 3) s
-> asciiEscape p0 success fail p ('E':'T':'B':s) = success '\ETB' "\\ETB" (incr p 3) s
-> asciiEscape p0 success fail p ('C':'A':'N':s) = success '\CAN' "\\CAN" (incr p 3) s 
-> asciiEscape p0 success fail p ('E':'M':s) = success '\EM' "\\EM" (incr p 2) s
-> asciiEscape p0 success fail p ('S':'U':'B':s) = success '\SUB' "\\SUB" (incr p 3) s
-> asciiEscape p0 success fail p ('E':'S':'C':s) = success '\ESC' "\\ESC" (incr p 3) s
-> asciiEscape p0 success fail p ('F':'S':s) = success '\FS' "\\FS" (incr p 2) s
-> asciiEscape p0 success fail p ('G':'S':s) = success '\GS' "\\GS" (incr p 2) s
-> asciiEscape p0 success fail p ('R':'S':s) = success '\RS' "\\RS" (incr p 2) s
-> asciiEscape p0 success fail p ('U':'S':s) = success '\US' "\\US" (incr p 2) s
-> asciiEscape p0 success fail p ('S':'P':s) = success '\SP' "\\SP" (incr p 2) s
-> asciiEscape p0 success fail p ('D':'E':'L':s) = success '\DEL' "\\DEL" (incr p 3) s
-> asciiEscape p0 success fail p s = fail p0 "Illegal escape sequence" p s
-
-> numEscape :: Position -> (Char -> String -> P a) -> FailP a -> Int
->           -> (Char -> Bool) -> (String -> String) -> P a
-> numEscape p0 success fail b isDigit so p s
->   | n >= min && n <= max = success (chr n) (so digits) (incr p (length digits)) rest
->   | otherwise = fail p0 "Numeric escape out-of-range" p s
->   where (digits,rest) = span isDigit s
->         n = convertIntegral b digits
->         min = ord minBound
->         max = ord maxBound
-
-\end{verbatim}
diff --git a/src/Curry/Syntax/Parser.hs b/src/Curry/Syntax/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Syntax/Parser.hs
@@ -0,0 +1,1428 @@
+{- |
+    Module      :  $Header$
+    Description :  A Parser for Curry
+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux
+                       2005        Martin Engelke
+                       2011 - 2015 Björn Peemöller
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    The Curry parser is implemented using the (mostly) LL(1) parsing
+    combinators implemented in 'Curry.Base.LLParseComb'.
+-}
+module Curry.Syntax.Parser
+  ( parseSource, parseHeader, parsePragmas, parseInterface, parseGoal
+  ) where
+
+import Curry.Base.Ident
+import Curry.Base.Monad       (CYM)
+import Curry.Base.Position    (Position(..), getPosition, setPosition, incr)
+import Curry.Base.LLParseComb
+import Curry.Base.Span        hiding (file) -- clash with Position.file
+import Curry.Base.SpanInfo
+
+import Curry.Syntax.Extension
+import Curry.Syntax.Lexer (Token (..), Category (..), Attributes (..), lexer)
+import Curry.Syntax.Type
+
+-- |Parse a 'Module'
+parseSource :: FilePath -> String -> CYM (Module ())
+parseSource = fullParser (mkMod <$> moduleHeader <*> layout moduleDecls) lexer
+  where mkMod f ((im, ds), lay) = f lay im ds
+
+-- |Parse only pragmas of a 'Module'
+parsePragmas :: FilePath -> String -> CYM (Module ())
+parsePragmas
+  = prefixParser ((\ps sp -> setEndPosition NoPos
+                              (Module (spanInfo sp []) WhitespaceLayout
+                                 ps mainMIdent Nothing [] []))
+                    <$> modulePragmas <*> spanPosition)
+      lexer
+
+-- |Parse a 'Module' header
+parseHeader :: FilePath -> String -> CYM (Module ())
+parseHeader = prefixParser
+  (mkMod <$> moduleHeader <*> startLayout importDecls) lexer
+  where
+    importDecls = mkImport <$> many ((,) <$> importDecl
+                                         <*> many (spanPosition <*-> semicolon))
+    mkImport xs = let (im, spss) = unzip xs in (im, concat spss)
+    mkMod f (im, lay) = f lay im []
+
+-- |Parse an 'Interface'
+parseInterface :: FilePath -> String -> CYM Interface
+parseInterface = fullParser interface lexer
+
+-- |Parse a 'Goal'
+parseGoal :: String -> CYM (Goal ())
+parseGoal = fullParser goal lexer ""
+
+-- ---------------------------------------------------------------------------
+-- Module header
+-- ---------------------------------------------------------------------------
+
+-- |Parser for a module header
+moduleHeader :: Parser a Token
+                  (LayoutInfo -> [ImportDecl] -> [Decl b] -> Module b)
+moduleHeader =
+  (\sp ps (m, es, inf) lay is ds -> updateEndPos $
+      Module (spanInfo sp inf) lay ps m es is ds)
+    <$> spanPosition
+    <*> modulePragmas
+    <*> header
+  where header = (\sp1 m es sp2 -> (m, es, [sp1,sp2]))
+                    <$>  tokenSpan KW_module
+                    <*>  modIdent
+                    <*>  option exportSpec
+                    <*>  spanPosition
+                    <*-> expectWhere
+                `opt` (mainMIdent, Nothing, [])
+
+modulePragmas :: Parser a Token [ModulePragma]
+modulePragmas = many (languagePragma <|> optionsPragma)
+
+languagePragma :: Parser a Token ModulePragma
+languagePragma =   languagePragma'
+              <$>  tokenSpan PragmaLanguage
+              <*>  (languageExtension `sepBy1Sp` comma)
+              <*>  tokenSpan PragmaEnd
+  where languageExtension = classifyExtension <$> ident
+        languagePragma' sp1 (ex, ss) sp2 = updateEndPos $
+          LanguagePragma (spanInfo sp1 (sp1 : ss ++ [sp2])) ex
+
+-- TODO The span info is not 100% complete due to the lexer
+-- combining OPTIONS, toolVal and toolArgs
+optionsPragma :: Parser a Token ModulePragma
+optionsPragma = optionsPragma'
+           <$>  spanPosition
+           <*>  token PragmaOptions
+           <*>  tokenSpan PragmaEnd
+  where optionsPragma' sp1 a sp2 = updateEndPos $
+          OptionsPragma (spanInfo sp1 [sp1, sp2])
+                        (classifyTool <$> toolVal a)
+                        (toolArgs a)
+
+-- |Parser for an export specification
+exportSpec :: Parser a Token ExportSpec
+exportSpec = exportSpec' <$> spanPosition <*> parensSp (export `sepBySp` comma)
+  where exportSpec' sp1 ((ex, ss),sp2,sp3) = updateEndPos $
+          Exporting (spanInfo sp1 (sp2:(ss ++ [sp3]))) ex
+
+-- |Parser for an export item
+export :: Parser a Token Export
+export =  qtycon <**> (tcExportWith <$> parensSp spec `opt` tcExport)
+      <|> tcExport <$> qfun <\> qtycon
+      <|> exportModule' <$> tokenSpan KW_module <*> modIdent
+  where spec =  (\sp      -> (ExportTypeAll    , [sp])) <$> tokenSpan DotDot
+            <|> (\(c, ss) -> (exportTypeWith' c,  ss )) <$> con `sepBySp` comma
+        tcExport qtc = updateEndPos $ Export (fromSrcSpan (getSrcSpan qtc)) qtc
+        tcExportWith ((spc, ss), sp1, sp2) qtc =
+          updateEndPos $ setSrcInfoPoints (sp1 : (ss ++ [sp2])) $
+          spc (fromSrcSpan (getSrcSpan qtc)) qtc
+        exportTypeWith' c spi qtc = ExportTypeWith spi qtc c
+        exportModule' sp = updateEndPos . ExportModule (spanInfo sp [sp])
+
+moduleDecls :: Parser a Token (([ImportDecl], [Decl ()]), [Span])
+moduleDecls = mkImpDecl <$> importDecl
+                        <*> (moduleDecls' `opt` ([], [], []))
+          <|> mkTopDecl <$> topDecls
+  where
+    mkImpDecl i (is, ds, sps) = ((i:is, ds), sps)
+    mkTopDecl (ds, sps) = (([], ds), sps)
+
+    moduleDecls' = mkDecls <$> spanPosition <*-> semicolon <*> moduleDecls
+    mkDecls sp ((im, ds), sps) = (im, ds, sp:sps)
+
+-- |Parser for a single import declaration
+importDecl :: Parser a Token ImportDecl
+importDecl =  importDecl'
+          <$> tokenSpan KW_import
+          <*> option (tokenSpan Id_qualified)
+          <*> modIdent
+          <*> option ((,) <$> tokenSpan Id_as <*> modIdent)
+          <*> option importSpec
+  where
+    importDecl' sp1 (Just sp2) mid (Just (sp3, alias)) = updateEndPos .
+      ImportDecl (spanInfo sp1 [sp1, sp2, sp3]) mid True  (Just alias)
+    importDecl' sp1 Nothing    mid (Just (sp3, alias)) = updateEndPos .
+      ImportDecl (spanInfo sp1      [sp1, sp3]) mid False (Just alias)
+    importDecl' sp1 (Just sp2) mid Nothing             = updateEndPos .
+      ImportDecl (spanInfo sp1      [sp1, sp2]) mid True  Nothing
+    importDecl' sp1 Nothing    mid Nothing             = updateEndPos .
+      ImportDecl (spanInfo sp1           [sp1]) mid False Nothing
+
+-- |Parser for an import specification
+importSpec :: Parser a Token ImportSpec
+importSpec =   spanPosition
+          <**> (hiding' <$-> token Id_hiding `opt` importing')
+          <*>  parensSp (importSp `sepBySp` comma)
+  where
+    hiding' sp1 ((specs, ss), sp2, sp3) = updateEndPos $
+      Hiding    (spanInfo sp1 (sp1 : sp2 : (ss ++ [sp3]))) specs
+    importing' sp1 ((specs, ss), sp2, sp3) = updateEndPos $
+      Importing (spanInfo sp1 (      sp2 : (ss ++ [sp3]))) specs
+
+importSp :: Parser a Token Import
+importSp = tycon <**> (tcImportWith <$> parensSp spec `opt` tcImport)
+      <|> tcImport <$> fun <\> tycon
+  where spec =  (\sp      -> (ImportTypeAll    , [sp])) <$> tokenSpan DotDot
+            <|> (\(c, ss) -> (importTypeWith' c,  ss )) <$> con `sepBySp` comma
+        tcImport tc = updateEndPos $ Import (fromSrcSpan (getSrcSpan tc)) tc
+        tcImportWith ((spc, ss), sp1, sp2) tc =
+          updateEndPos $ setSrcInfoPoints (sp1 : (ss ++ [sp2])) $
+          spc (fromSrcSpan (getSrcSpan tc)) tc
+        importTypeWith' c spi tc = ImportTypeWith spi tc c
+-- ---------------------------------------------------------------------------
+-- Interfaces
+-- ---------------------------------------------------------------------------
+
+-- |Parser for an interface
+interface :: Parser a Token Interface
+interface = uncurry <$> intfHeader <*> braces intfDecls
+
+intfHeader :: Parser a Token ([IImportDecl] -> [IDecl] -> Interface)
+intfHeader = Interface <$-> token Id_interface <*> modIdent <*-> expectWhere
+
+intfDecls :: Parser a Token ([IImportDecl], [IDecl])
+intfDecls = impDecl <$> iImportDecl
+                    <*> (semicolon <-*> intfDecls `opt` ([], []))
+        <|> (,) [] <$> intfDecl `sepBy` semicolon
+  where impDecl i (is, ds) = (i:is, ds)
+
+-- |Parser for a single interface import declaration
+iImportDecl :: Parser a Token IImportDecl
+iImportDecl = IImportDecl <$> tokenPos KW_import <*> modIdent
+
+-- |Parser for a single interface declaration
+intfDecl :: Parser a Token IDecl
+intfDecl = choice [ iInfixDecl, iHidingDecl, iDataDecl, iNewtypeDecl
+                  , iTypeDecl , iFunctionDecl <\> token Id_hiding
+                  , iClassDecl, iInstanceDecl ]
+
+-- |Parser for an interface infix declaration
+iInfixDecl :: Parser a Token IDecl
+iInfixDecl = infixDeclLhs iInfixDecl' <*> integer <*> qfunop
+  where iInfixDecl' sp = IInfixDecl (span2Pos sp)
+
+-- |Parser for an interface hiding declaration
+iHidingDecl :: Parser a Token IDecl
+iHidingDecl = tokenPos Id_hiding <**> (hDataDecl <|> hClassDecl)
+  where
+  hDataDecl = hiddenData <$-> token KW_data <*> withKind qtycon <*> many tyvar
+  hClassDecl = hiddenClass <$> classInstHead KW_class (withKind qtycls) clsvar
+  hiddenData (tc, k) tvs p = HidingDataDecl p tc k tvs
+  hiddenClass (_, _, cx, (qcls, k), tv) p = HidingClassDecl p cx qcls k tv
+
+-- |Parser for an interface data declaration
+iDataDecl :: Parser a Token IDecl
+iDataDecl = iTypeDeclLhs IDataDecl KW_data <*> constrs <*> iHiddenPragma
+  where constrs = equals <-*> constrDecl `sepBy1` bar `opt` []
+
+-- |Parser for an interface newtype declaration
+iNewtypeDecl :: Parser a Token IDecl
+iNewtypeDecl = iTypeDeclLhs INewtypeDecl KW_newtype
+               <*-> equals <*> newConstrDecl <*> iHiddenPragma
+
+-- |Parser for an interface type synonym declaration
+iTypeDecl :: Parser a Token IDecl
+iTypeDecl = iTypeDeclLhs ITypeDecl KW_type
+            <*-> equals <*> type0
+
+-- |Parser for an interface hiding pragma
+iHiddenPragma :: Parser a Token [Ident]
+iHiddenPragma = token PragmaHiding
+                <-*> (con `sepBy` comma)
+                <*-> token PragmaEnd
+                `opt` []
+
+-- |Parser for an interface function declaration
+iFunctionDecl :: Parser a Token IDecl
+iFunctionDecl = IFunctionDecl <$> position <*> qfun <*> option iMethodPragma
+                <*> arity <*-> token DoubleColon <*> qualType
+
+-- |Parser for an interface method pragma
+iMethodPragma :: Parser a Token Ident
+iMethodPragma = token PragmaMethod <-*> clsvar <*-> token PragmaEnd
+
+-- |Parser for function's arity
+arity :: Parser a Token Int
+arity = int `opt` 0
+
+iTypeDeclLhs :: (Position -> QualIdent -> Maybe KindExpr -> [Ident] -> a)
+             -> Category -> Parser b Token a
+iTypeDeclLhs f kw = f' <$> tokenPos kw <*> withKind qtycon <*> many tyvar
+  where f' p (tc, k) = f p tc k
+
+-- |Parser for an interface class declaration
+iClassDecl :: Parser a Token IDecl
+iClassDecl = (\(sp, _, cx, (qcls, k), tv) ->
+               IClassDecl (span2Pos sp) cx qcls k tv)
+        <$> classInstHead KW_class (withKind qtycls) clsvar
+        <*> braces (iMethod `sepBy` semicolon)
+        <*> iClassHidden
+
+-- |Parser for an interface method declaration
+iMethod :: Parser a Token IMethodDecl
+iMethod = IMethodDecl <$> position
+                      <*> fun <*> option int <*-> token DoubleColon <*> qualType
+
+-- |Parser for an interface hiding pragma
+iClassHidden :: Parser a Token [Ident]
+iClassHidden = token PragmaHiding
+          <-*> (fun `sepBy` comma)
+          <*-> token PragmaEnd
+          `opt` []
+
+-- |Parser for an interface instance declaration
+iInstanceDecl :: Parser a Token IDecl
+iInstanceDecl = (\(sp, _, cx, qcls, inst) ->
+                   IInstanceDecl (span2Pos sp) cx qcls inst)
+           <$> classInstHead KW_instance qtycls type2
+           <*> braces (iImpl `sepBy` semicolon)
+           <*> option iModulePragma
+
+-- |Parser for an interface method implementation
+iImpl :: Parser a Token IMethodImpl
+iImpl = (,) <$> fun <*> arity
+
+iModulePragma :: Parser a Token ModuleIdent
+iModulePragma = token PragmaModule <-*> modIdent <*-> token PragmaEnd
+
+-- ---------------------------------------------------------------------------
+-- Top-Level Declarations
+-- ---------------------------------------------------------------------------
+
+topDecls :: Parser a Token ([Decl ()], [Span])
+topDecls = topDecl `sepBySp` semicolon
+
+topDecl :: Parser a Token (Decl ())
+topDecl = choice [ dataDecl, externalDataDecl, newtypeDecl, typeDecl
+                 , classDecl, instanceDecl, defaultDecl
+                 , infixDecl, functionDecl ]
+
+dataDecl :: Parser a Token (Decl ())
+dataDecl = combineWithSpans
+             <$> typeDeclLhs dataDecl' KW_data
+             <*> ((addSpan <$> tokenSpan Equals <*> constrs) `opt` ([],[]))
+             <*> deriv
+  where constrs = constrDecl `sepBy1Sp` bar
+        dataDecl' sp = DataDecl (spanInfo sp [sp])
+
+externalDataDecl :: Parser a Token (Decl ())
+externalDataDecl = decl <$> tokenSpan KW_external <*> typeDeclLhs (,,) KW_data
+  where decl sp1 (sp2, tc, tvs) = updateEndPos $
+          ExternalDataDecl (spanInfo sp1 [sp1, sp2]) tc tvs
+
+newtypeDecl :: Parser a Token (Decl ())
+newtypeDecl = combineWithSpans
+             <$> typeDeclLhs newtypeDecl' KW_newtype
+             <*> ((\sp c -> (c, [sp]))  <$> tokenSpan Equals <*> newConstrDecl)
+             <*> deriv
+  where newtypeDecl' sp = NewtypeDecl (spanInfo sp [sp])
+
+combineWithSpans :: HasSpanInfo a =>
+                    (t1 -> t2 -> a) -> (t1, [Span]) -> (t2, [Span]) -> a
+combineWithSpans df (cs, sps1) (cls, sps2)
+  = updateEndPos $ setSrcInfoPoints (getSrcInfoPoints res ++ sps1 ++ sps2) res
+  where res = df cs cls
+
+typeDecl :: Parser a Token (Decl ())
+typeDecl = typeDeclLhs typeDecl' KW_type <*> tokenSpan Equals <*> type0
+  where typeDecl' sp1 tyc tyv sp2 txp = updateEndPos $
+          TypeDecl (spanInfo sp1 [sp1, sp2]) tyc tyv txp
+
+typeDeclLhs :: (Span -> Ident -> [Ident] -> a) -> Category
+            -> Parser b Token a
+typeDeclLhs f kw = f <$> tokenSpan kw <*> tycon <*> many anonOrTyvar
+
+constrDecl :: Parser a Token ConstrDecl
+constrDecl = spanPosition <**> constr
+  where
+  constr =  conId     <**> identDecl
+        <|> tokenSpan LeftParen <**> parenDecl
+        <|> type1 <\> conId <\> leftParen <**> opDecl
+  identDecl =  many type2 <**> (conType <$> opDecl `opt` conDecl)
+           <|> recDecl <$> recFields
+  parenDecl =  conOpDeclPrefix
+           <$> conSym    <*>   tokenSpan RightParen <*> type2 <*> type2
+           <|> tupleType <**> (tokenSpan RightParen <**> opDeclParen)
+  opDecl = conOpDecl <$> conop <*> type1
+  opDeclParen = conOpDeclParen <$> conop <*> type1
+  recFields = layoutOff <-*> bracesSp (fieldDecl `sepBySp` comma)
+  conType f tys c = f $ foldl mkApply (mkConstructorType $ qualify c) tys
+  mkApply t1 t2 = updateEndPos $ ApplyType (fromSrcSpan (getSrcSpan t1)) t1 t2
+  mkConstructorType qid = ConstructorType (fromSrcSpan (getSrcSpan qid)) qid
+  conDecl tys c sp = updateEndPos $
+    ConstrDecl (SpanInfo sp []) c tys
+  conOpDecl op ty2 ty1 sp = updateEndPos $
+    ConOpDecl (SpanInfo sp []) ty1 op ty2
+  conOpDeclParen op ty2 sp1 ty1 sp2 sp5 = updateEndPos $
+    ConOpDecl (SpanInfo sp5 [sp2, sp1]) ty1 op ty2
+  conOpDeclPrefix op sp1 ty1 ty2 sp2 sp3 = updateEndPos $
+    ConOpDecl (SpanInfo sp3 [sp2, sp1]) ty1 op ty2
+  recDecl ((fs, ss), sp1, sp2) c sp3 = updateEndPos $
+    RecordDecl (SpanInfo sp3 (sp1 : ss ++ [sp2])) c fs
+
+fieldDecl :: Parser a Token FieldDecl
+fieldDecl = mkFieldDecl <$> spanPosition <*> labels
+                        <*> tokenSpan DoubleColon <*> type0
+  where labels = fun `sepBy1Sp` comma
+        mkFieldDecl sp1 (idt,ss) sp2 ty = updateEndPos $
+          FieldDecl (spanInfo sp1 (ss ++ [sp2])) idt ty
+
+newConstrDecl :: Parser a Token NewConstrDecl
+newConstrDecl = spanPosition <**> (con <**> newConstr)
+  where newConstr =  newConDecl <$> type2
+                 <|> newRecDecl <$> newFieldDecl
+        newConDecl ty  c sp = updateEndPos $ NewConstrDecl (spanInfo sp []) c ty
+        newRecDecl ((idt, sp2, ty), sp3, sp4) c sp1 = updateEndPos $
+          NewRecordDecl (spanInfo sp1 [sp3,sp2,sp4]) c (idt, ty)
+
+newFieldDecl :: Parser a Token ((Ident, Span, TypeExpr), Span, Span)
+newFieldDecl = layoutOff <-*> bracesSp labelDecl
+  where labelDecl = (,,) <$> fun <*> tokenSpan DoubleColon <*> type0
+
+deriv :: Parser a Token ([QualIdent], [Span])
+deriv = (addSpan <$> tokenSpan KW_deriving <*> classes) `opt` ([], [])
+  where classes = ((\q -> ([q], [])) <$> qtycls)
+               <|> ((\sp1 (qs, ss) sp2 -> (qs, sp1 : (ss ++ [sp2])))
+                      <$> tokenSpan LeftParen
+                      <*> (qtycls `sepBySp` comma)
+                      <*> tokenSpan RightParen)
+
+functionDecl :: Parser a Token (Decl ())
+functionDecl = spanPosition <**> decl
+  where decl = fun `sepBy1Sp` comma <**> funListDecl <|?> funRule
+
+funRule :: Parser a Token (Span -> Decl ())
+funRule = mkFunDecl <$> lhs <*> declRhs
+  where lhs = (\f ->
+                 (f, updateEndPos $ FunLhs (fromSrcSpan (getSrcSpan f)) f []))
+                 <$> fun <|?> funLhs
+
+funListDecl :: Parser a Token (([Ident],[Span]) -> Span -> Decl ())
+funListDecl = typeSig <|> mkExtFun <$> tokenSpan KW_external
+  where mkExtFun sp1 (vs,ss) sp2 = updateEndPos $
+          ExternalDecl (spanInfo sp2 (ss++[sp1])) (map (Var ()) vs)
+
+
+typeSig :: Parser a Token (([Ident],[Span]) -> Span -> Decl ())
+typeSig = sig <$> tokenSpan DoubleColon <*> qualType
+  where sig sp1 qty (vs,ss) sp2 = updateEndPos $
+          TypeSig (spanInfo sp2 (ss++[sp1])) vs qty
+
+mkFunDecl :: (Ident, Lhs ()) -> Rhs () -> Span -> Decl ()
+mkFunDecl (f, lhs) rhs' p = updateEndPos $
+    FunctionDecl (spanInfo p []) () f [updateEndPos $
+                                         Equation (spanInfo p []) lhs rhs']
+
+funLhs :: Parser a Token (Ident, Lhs ())
+funLhs = mkFunLhs    <$> fun      <*> many1 pattern2
+    <|?> flip ($ updateEndPos) <$> pattern1 <*> opLhs
+    <|?> curriedLhs
+  where
+  opLhs  =                opLHS funSym (gConSym <\> funSym)
+       <|> tokenSpan Backquote <**>
+             opLHSSp ((,) <$> funId            <*>  spanPosition
+                                               <*-> expectBackquote)
+                     ((,) <$> qConId <\> funId <*>  spanPosition
+                                               <*-> expectBackquote)
+  opLHS funP consP   = mkOpLhs       <$> funP  <*> pattern0
+                    <|> mkInfixPat   <$> consP <*> pattern1 <*> opLhs
+  opLHSSp funP consP = mkOpLhsSp     <$> funP  <*> pattern0
+                    <|> mkInfixPatSp <$> consP <*> pattern1 <*> opLhs
+  mkFunLhs f ts = (f , updateEndPos $ FunLhs (fromSrcSpan (getSrcSpan f)) f ts)
+  mkOpLhs op t2 f t1      =
+    let t1' = f t1
+    in (op, updateEndPos $ OpLhs (fromSrcSpan (getSrcSpan t1')) t1' op t2)
+  mkInfixPat op t2 f g t1 =
+    f (g . InfixPattern (fromSrcSpan (getSrcSpan t1)) () t1 op) t2
+  mkOpLhsSp (op, sp1)    t2   sp2 f t1 =
+    let t1' = f t1
+    in (op, updateEndPos $
+              OpLhs (spanInfo (getSrcSpan t1') [sp2, sp1]) t1' op t2)
+
+  mkInfixPatSp (op, sp1) t2 g sp2 f t1 =
+    g (f . InfixPattern (spanInfo (getSrcSpan t1) [sp2, sp1]) () t1 op) t2
+
+
+curriedLhs :: Parser a Token (Ident, Lhs ())
+curriedLhs = apLhs <$> parensSp funLhs <*> many1 pattern2
+  where apLhs ((f, lhs), sp1, sp2) ts =
+          let spi = fromSrcSpan sp1
+          in (f, updateEndPos $ setSrcInfoPoints [sp1, sp2] $ ApLhs spi lhs ts)
+
+declRhs :: Parser a Token (Rhs ())
+declRhs = rhs equals
+
+rhs :: Parser a Token b -> Parser a Token (Rhs ())
+rhs eq = rhsExpr <*> localDecls
+  where rhsExpr =  mkSimpleRhs  <$> spanPosition <*-> eq <*> expr
+               <|> mkGuardedRhs <$> spanPosition <*>  many1 (condExpr eq)
+        mkSimpleRhs  sp1 e  (Just sp2, ds, li) = updateEndPos $
+          SimpleRhs  (SpanInfo sp1 [sp1, sp2]) li e ds
+        mkSimpleRhs  sp1 e  (Nothing, ds, li) = updateEndPos $
+          SimpleRhs  (SpanInfo sp1 [sp1]) li e ds
+        mkGuardedRhs sp1 ce (Just sp2, ds, li) = updateEndPos $
+          GuardedRhs (SpanInfo sp1 [sp1, sp2]) li ce ds
+        mkGuardedRhs sp1 ce (Nothing, ds, li) = updateEndPos $
+          GuardedRhs (SpanInfo sp1 [sp1]) li ce ds
+
+whereClause :: Parser a Token b -> Parser a Token (Maybe Span, [b], LayoutInfo)
+whereClause decl = (\sp (ds, li) -> (Just sp, ds, li))
+  <$> tokenSpan KW_where
+  <*> layoutWhere decl `opt` (Nothing, [], WhitespaceLayout)
+
+localDecls :: Parser a Token (Maybe Span, [Decl ()], LayoutInfo)
+localDecls = whereClause valueOrInfixDecl
+
+valueDecls :: Parser a Token ([Decl ()], [Span])
+valueDecls = valueOrInfixDecl `sepBySp` semicolon
+
+valueOrInfixDecl :: Parser a Token (Decl ())
+valueOrInfixDecl = choice [infixDecl, valueDecl]
+
+infixDecl :: Parser a Token (Decl ())
+infixDecl = infixDeclLhs infixDecl'
+              <*> option ((,) <$> spanPosition <*> integer)
+              <*> funop `sepBy1Sp` comma
+  where infixDecl' sp1 inf (Just (sp2, pr)) (ids, ss) =
+          updateEndPos $ InfixDecl (spanInfo sp1 (sp1:sp2:ss)) inf (Just pr) ids
+        infixDecl' sp1 inf Nothing          (ids, ss) =
+          updateEndPos $ InfixDecl (spanInfo sp1 (sp1    :ss)) inf Nothing   ids
+
+infixDeclLhs :: (Span -> Infix -> a) -> Parser b Token a
+infixDeclLhs f = f <$> spanPosition <*> tokenOps infixKW
+  where infixKW = [(KW_infix, Infix), (KW_infixl, InfixL), (KW_infixr, InfixR)]
+
+valueDecl :: Parser a Token (Decl ())
+valueDecl = spanPosition <**> decl
+  where
+  decl =   var `sepBy1Sp` comma       <**> valListDecl
+      <|?> patOrFunDecl <$> pattern0   <*> declRhs
+      <|?> mkFunDecl    <$> curriedLhs <*> declRhs
+
+  valListDecl =  funListDecl
+             <|> mkFree <$> tokenSpan KW_free
+    where mkFree sp1 (vs, ss) sp2 = updateEndPos $
+            FreeDecl (spanInfo sp2 (ss ++ [sp1])) (map (Var ()) vs)
+
+  patOrFunDecl (ConstructorPattern spi _ c ts)
+    | not (isConstrId c) = mkFunDecl (f, FunLhs spi f ts)
+    where f = unqualify c
+  patOrFunDecl t = patOrOpDecl updateEndPos t
+
+  patOrOpDecl f (InfixPattern spi a t1 op t2)
+    | isConstrId op = patOrOpDecl (f . InfixPattern spi a t1 op) t2
+    | otherwise     = mkFunDecl (op', updateEndPos $ OpLhs spi (f t1) op' t2)
+    where op' = unqualify op
+  patOrOpDecl f t = mkPatDecl (f t)
+
+  mkPatDecl t rhs' sp = updateEndPos $ PatternDecl (fromSrcSpan sp) t rhs'
+
+  isConstrId c = c == qConsId || isQualified c || isQTupleId c
+
+defaultDecl :: Parser a Token (Decl ())
+defaultDecl = mkDefaultDecl <$> tokenSpan KW_default
+                            <*> parensSp (type0 `sepBySp` comma)
+  where mkDefaultDecl sp1 ((ty, ss), sp2, sp3) = updateEndPos $
+          DefaultDecl (spanInfo sp1 (sp1 : sp2 : (ss ++ [sp3]))) ty
+
+classInstHead :: Category -> Parser a Token b -> Parser a Token c
+              -> Parser a Token (Span, [Span], Context, b, c)
+classInstHead kw cls ty = f <$> tokenSpan kw
+                            <*> optContext (,,) ((,) <$> cls <*> ty)
+  where f sp (cx, ss, (cls', ty')) = (sp, ss, cx, cls', ty')
+
+classDecl :: Parser a Token (Decl ())
+classDecl = mkClass
+        <$> classInstHead KW_class tycls clsvar
+        <*> whereClause innerDecl
+  where
+    --TODO: Refactor by left-factorization
+    --TODO: Support infixDecl
+    innerDecl = foldr1 (<|?>)
+      [ spanPosition <**> (fun `sepBy1Sp` comma <**> typeSig)
+      , spanPosition <**> funRule
+      {-, infixDecl-} ]
+    mkClass (sp1, ss, cx, cls, tv) (Just sp2, ds, li) = updateEndPos $
+      ClassDecl (SpanInfo sp1 (sp1 : (ss ++ [sp2]))) li cx cls tv ds
+    mkClass (sp1, ss, cx, cls, tv) (Nothing, ds, li) = updateEndPos $
+      ClassDecl (SpanInfo sp1 (sp1 : ss)) li cx cls tv ds
+
+instanceDecl :: Parser a Token (Decl ())
+instanceDecl = mkInstance
+           <$> classInstHead KW_instance qtycls type2
+           <*> whereClause innerDecl
+  where
+    innerDecl = spanPosition <**> funRule
+    mkInstance (sp1, ss, cx, qcls, inst) (Just sp2, ds, li) = updateEndPos $
+      InstanceDecl (SpanInfo sp1 (sp1 : (ss ++ [sp2]))) li cx qcls inst ds
+    mkInstance (sp1, ss, cx, qcls, inst) (Nothing, ds, li) = updateEndPos $
+      InstanceDecl (SpanInfo sp1 (sp1 : ss)) li cx qcls inst ds
+-- ---------------------------------------------------------------------------
+-- Type classes
+-- ---------------------------------------------------------------------------
+
+optContext :: (Context -> [Span] -> a -> b)
+           -> Parser c Token a
+           -> Parser c Token b
+optContext f p = combine <$> context <*> tokenSpan DoubleArrow <*> p
+            <|?> f [] [] <$> p
+  where combine (ctx, ss) sp = f ctx (ss ++ [sp])
+
+context :: Parser a Token (Context, [Span])
+context = (\c -> ([c], [])) <$> constraint
+      <|> combine <$> parensSp (constraint `sepBySp` comma)
+  where combine ((ctx, ss), sp1, sp2) = (ctx, sp1 : (ss ++ [sp2]))
+
+constraint :: Parser a Token Constraint
+constraint = mkConstraint <$> spanPosition <*> qtycls <*> conType
+  where varType = mkVariableType <$> spanPosition <*> clsvar
+        conType = fmap ((,) []) varType
+               <|> mk <$> parensSp
+                            (foldl mkApplyType <$> varType <*> many1 type2)
+        mkConstraint sp qtc (ss, ty) = updateEndPos $
+          Constraint (spanInfo sp ss) qtc ty
+        mkVariableType sp = VariableType (fromSrcSpan sp)
+        mkApplyType t1 t2 =
+          ApplyType (fromSrcSpan (combineSpans (getSrcSpan t1)
+                                               (getSrcSpan t2)))
+                    t1 t2
+        mk (a, sp1, sp2) = ([sp1, sp2], a)
+
+-- ---------------------------------------------------------------------------
+-- Kinds
+-- ---------------------------------------------------------------------------
+
+withKind :: Parser a Token b -> Parser a Token (b, Maybe KindExpr)
+withKind p = implicitKind <$> p
+        <|?> parens (explicitKind <$> p <*-> token DoubleColon <*> kind0)
+  where implicitKind x   = (x, Nothing)
+        explicitKind x k = (x, Just k)
+
+-- kind0 ::= kind1 ['->' kind0]
+kind0 :: Parser a Token KindExpr
+kind0 = kind1 `chainr1` (ArrowKind <$-> token RightArrow)
+
+-- kind1 ::= * | '(' kind0 ')'
+kind1 :: Parser a Token KindExpr
+kind1 = Star <$-> token SymStar
+    <|> parens kind0
+
+-- ---------------------------------------------------------------------------
+-- Types
+-- ---------------------------------------------------------------------------
+
+-- qualType ::= [context '=>']  type0
+qualType :: Parser a Token QualTypeExpr
+qualType = mkQualTypeExpr <$> spanPosition <*> optContext (,,) type0
+  where mkQualTypeExpr sp (cx, ss, ty) = updateEndPos $
+          QualTypeExpr (spanInfo sp ss) cx ty
+
+-- type0 ::= type1 ['->' type0]
+type0 :: Parser a Token TypeExpr
+type0 = type1 `chainr1` (mkArrowType <$> tokenSpan RightArrow)
+  where mkArrowType sp ty1 ty2 = updateEndPos $
+          ArrowType (spanInfo (getSrcSpan ty1) [sp]) ty1 ty2
+
+-- type1 ::= [type1] type2
+type1 :: Parser a Token TypeExpr
+type1 = foldl1 mkApplyType <$> many1 type2
+  where mkApplyType ty1 ty2 = updateEndPos $
+          ApplyType (fromSrcSpan (getSrcSpan ty1)) ty1 ty2
+
+-- type2 ::= anonType | identType | parenType | bracketType
+type2 :: Parser a Token TypeExpr
+type2 = anonType <|> identType <|> parenType <|> bracketType
+
+-- anonType ::= '_'
+anonType :: Parser a Token TypeExpr
+anonType = mkVariableType <$> spanPosition <*> anonIdent
+  where mkVariableType sp = VariableType (fromSrcSpan sp)
+
+-- identType ::= <identifier>
+identType :: Parser a Token TypeExpr
+identType =  mkVariableType    <$> spanPosition <*> tyvar
+         <|> mkConstructorType <$> spanPosition <*> qtycon <\> tyvar
+  where mkVariableType    sp = VariableType    (fromSrcSpan sp)
+        mkConstructorType sp = ConstructorType (fromSrcSpan sp)
+
+-- parenType ::= '(' tupleType ')'
+parenType :: Parser a Token TypeExpr
+parenType = fmap updateSpanWithBrackets (parensSp tupleType)
+
+-- tupleType ::= type0                         (parenthesized type)
+--            |  type0 ',' type0 { ',' type0 } (tuple type)
+--            |  '->'                          (function type constructor)
+--            |  ',' { ',' }                   (tuple type constructor)
+--            |                                (unit type)
+tupleType :: Parser a Token TypeExpr
+tupleType = type0 <**> (mkTuple <$> many1 ((,) <$> tokenSpan Comma <*> type0)
+                          `opt` ParenType NoSpanInfo)
+        <|> tokenSpan RightArrow <**> succeed (mkConstructorType qArrowId)
+        <|> mkConstructorTupleType <$> many1 (tokenSpan Comma)
+        <|> succeed (ConstructorType NoSpanInfo qUnitId)
+  where mkTuple stys ty = let (ss, tys) = unzip stys
+                          in TupleType (fromSrcInfoPoints ss) (ty : tys)
+        mkConstructorType qid sp = ConstructorType (fromSrcInfoPoints [sp]) qid
+        mkConstructorTupleType ss = ConstructorType (fromSrcInfoPoints ss)
+                                                    (qTupleId (length ss + 1))
+
+-- bracketType ::= '[' listType ']'
+bracketType :: Parser a Token TypeExpr
+bracketType = fmap updateSpanWithBrackets (bracketsSp listType)
+
+-- listType ::= type0 (list type)
+--           |        (list type constructor)
+listType :: Parser a Token TypeExpr
+listType = ListType NoSpanInfo <$> type0
+             `opt` ConstructorType NoSpanInfo qListId
+
+-- ---------------------------------------------------------------------------
+-- Literals
+-- ---------------------------------------------------------------------------
+
+-- literal ::= '\'' <escaped character> '\''
+--          |  <integer>
+--          |  <float>
+--          |  '"' <escaped string> '"'
+literal :: Parser a Token Literal
+literal = Char   <$> char
+      <|> Int    <$> integer
+      <|> Float  <$> float
+      <|> String <$> string
+
+-- ---------------------------------------------------------------------------
+-- Patterns
+-- ---------------------------------------------------------------------------
+
+-- pattern0 ::= pattern1 [ gconop pattern0 ]
+pattern0 :: Parser a Token (Pattern ())
+pattern0 = pattern1 `chainr1` (mkInfixPattern <$> gconop)
+  where mkInfixPattern qid p1 p2 =
+          InfixPattern (fromSrcSpan (combineSpans (getSrcSpan p1)
+                                                  (getSrcSpan p2)))
+            () p1 qid p2
+
+-- pattern1 ::= varId
+--           |  QConId { pattern2 }
+--           |  '-'  Integer
+--           |  '-.' Float
+--           |  '(' parenPattern'
+--           | pattern2
+pattern1 :: Parser a Token (Pattern ())
+pattern1 = varId <**> identPattern'            -- unqualified
+        <|> qConId <\> varId <**> constrPattern -- qualified
+        <|> mkNegNum <$> minus <*> negNum
+        <|> tokenSpan LeftParen <**> parenPattern'
+        <|> pattern2  <\> qConId <\> leftParen
+  where
+  identPattern' =  optAsRecPattern
+               <|> mkConsPattern qualify <$> many1 pattern2
+
+  constrPattern =  mkConsPattern id <$> many1 pattern2
+               <|> optRecPattern
+
+
+  parenPattern' =  minus <**> minusPattern
+      <|> mkGconPattern <$> gconId <*> tokenSpan RightParen <*> many pattern2
+      <|> mkFunIdentP <$> funSym <\> minus <*> tokenSpan RightParen
+                                           <*> identPattern'
+      <|> mkParenTuple <$> parenTuplePattern <\> minus <*> tokenSpan RightParen
+  minusPattern = flip mkParenMinus <$> tokenSpan RightParen <*> identPattern'
+         <|> mkParenMinus <$> parenMinusPattern <*> tokenSpan RightParen
+
+  mkNegNum idt = setEndPosition (end (getSrcSpan idt))
+  mkParenTuple p sp1 sp2 =
+    setSpanInfo (spanInfo (combineSpans sp2 sp1) [sp2, sp1]) p
+  mkFunIdentP idt sp1 f sp2 = setSrcSpan (combineSpans sp2 sp1) (f idt)
+  mkParenMinus f sp1 idt sp2 = setSrcSpan (combineSpans sp2 sp1) (f idt)
+  mkConsPattern f ts c = updateEndPos $
+    ConstructorPattern (fromSrcSpan (getSrcSpan (f c))) () (f c) ts
+  mkGconPattern qid sp1 ps sp2 = updateEndPos $
+    ConstructorPattern (spanInfo (getSrcSpan qid) [sp2,sp1]) () qid ps
+
+pattern2 :: Parser a Token (Pattern ())
+pattern2 =  literalPattern <|> anonPattern <|> identPattern
+        <|> parenPattern   <|> listPattern <|> lazyPattern
+
+-- literalPattern ::= <integer> | <char> | <float> | <string>
+literalPattern :: Parser a Token (Pattern ())
+literalPattern = flip LiteralPattern () <$> fmap fromSrcSpan spanPosition
+                                        <*> literal
+
+-- anonPattern ::= '_'
+anonPattern :: Parser a Token (Pattern ())
+anonPattern = flip VariablePattern () <$> fmap fromSrcSpan spanPosition
+                                      <*> anonIdent
+
+-- identPattern ::= Variable [ '@' pattern2 | '{' fields '}'
+--               |  qConId   [ '{' fields '}' ]
+identPattern :: Parser a Token (Pattern ())
+identPattern =  varId <**> optAsRecPattern -- unqualified
+            <|> qConId <\> varId <**> optRecPattern               -- qualified
+
+-- TODO: document me!
+parenPattern :: Parser a Token (Pattern ())
+parenPattern = tokenSpan LeftParen <**> parenPattern'
+  where
+  parenPattern' = minus <**> minusPattern
+      <|> mkConstructorPattern <$> gconId <*> tokenSpan RightParen
+      <|> mkFunAsRec <$> funSym <\> minus <*> tokenSpan RightParen
+                     <*> optAsRecPattern
+      <|> mkParenTuple <$> parenTuplePattern <\> minus <*> tokenSpan RightParen
+  minusPattern = mkOptAsRec <$> tokenSpan RightParen <*> optAsRecPattern
+      <|> mkParen <$> parenMinusPattern <*> tokenSpan RightParen
+
+  mkConstructorPattern qid sp1 sp2 =
+    ConstructorPattern (fromSrcSpan (combineSpans sp2 sp1)) () qid []
+  mkFunAsRec = flip (flip . mkOptAsRec)
+  mkParenTuple p sp1 sp2 =
+    let ss  = getSrcInfoPoints p
+        spi = spanInfo (combineSpans sp2 sp1) (sp2 : (ss ++ [sp1]))
+    in setSpanInfo spi p
+  mkOptAsRec sp1 f idt sp2 =
+    let p   = f idt
+        ss  = getSrcInfoPoints p
+        spi = spanInfo (combineSpans sp2 sp1) ([sp2, sp1] ++ ss)
+    in setSpanInfo spi p
+  mkParen f sp1 idt sp2 =
+    let p   = f idt
+        ss  = getSrcInfoPoints p
+        spi = spanInfo (combineSpans sp2 sp1) (sp2 : (ss ++ [sp1]))
+    in setSpanInfo spi p
+
+-- listPattern ::= '[' pattern0s ']'
+-- pattern0s   ::= {- empty -}
+--              |  pattern0 ',' pattern0s
+listPattern :: Parser a Token (Pattern ())
+listPattern = mkListPattern <$> bracketsSp (pattern0 `sepBySp` comma)
+  where mkListPattern ((ps, ss), sp1, sp2) = updateEndPos $
+          ListPattern (spanInfo sp1 (sp1 : (ss ++ [sp2]))) () ps
+
+-- lazyPattern ::= '~' pattern2
+lazyPattern :: Parser a Token (Pattern ())
+lazyPattern = mkLazyPattern <$> tokenSpan Tilde <*> pattern2
+  where mkLazyPattern sp p = updateEndPos $ LazyPattern (spanInfo sp [sp]) p
+
+-- optRecPattern ::= [ '{' fields '}' ]
+optRecPattern :: Parser a Token (QualIdent -> Pattern ())
+optRecPattern = mkRecordPattern <$> fieldsSp pattern0 `opt` mkConPattern
+  where
+  mkRecordPattern ((fs, ss), sp1, sp2) c = updateEndPos $
+    RecordPattern (spanInfo (getSrcSpan c) (sp1 : (ss ++ [sp2]))) () c fs
+  mkConPattern c = ConstructorPattern (fromSrcSpan (getSrcSpan c)) () c []
+
+-- ---------------------------------------------------------------------------
+-- Partial patterns used in the combinators above, but also for parsing
+-- the left-hand side of a declaration.
+-- ---------------------------------------------------------------------------
+
+gconId :: Parser a Token QualIdent
+gconId = colon <|> tupleCommas
+
+negNum :: Parser a Token (Pattern ())
+negNum = mkNegativePattern <$> spanPosition <*>
+                             (Int <$> integer <|> Float <$> float)
+  where mkNegativePattern sp = NegativePattern (fromSrcSpan sp) ()
+
+optAsRecPattern :: Parser a Token (Ident -> Pattern ())
+optAsRecPattern =  mkAsPattern     <$> tokenSpan At <*> pattern2
+               <|> mkRecordPattern <$> fieldsSp pattern0
+               `opt` mkVariablePattern
+  where mkRecordPattern ((fs,ss),sp1,sp2) v =
+          let s = getPosition v
+              e = end sp2
+              f = file s
+              spi = spanInfo (Span f s e) (sp1 : (ss ++ [sp2]))
+          in updateEndPos $ RecordPattern spi () (qualify v) fs
+        mkAsPattern sp p idt =
+          AsPattern (spanInfo (getSrcSpan idt) [sp]) idt p
+        mkVariablePattern idt =
+          VariablePattern (fromSrcSpan (getSrcSpan idt)) () idt
+
+optInfixPattern :: Parser a Token (Pattern () -> Pattern ())
+optInfixPattern = mkInfixPat <$> gconop <*> pattern0
+            `opt` id
+  where mkInfixPat op t2 t1 =
+          let s = getPosition t1
+              e = getSrcSpanEnd t2
+              f = file s
+          in InfixPattern (fromSrcSpan (Span f s e)) () t1 op t2
+
+optTuplePattern :: Parser a Token (Pattern () -> Pattern ())
+optTuplePattern = mkTuple <$> many1 ((,) <$> tokenSpan Comma <*> pattern0)
+            `opt` ParenPattern NoSpanInfo
+  where mkTuple ts t = let (ss, ps) = unzip ts
+                       in TuplePattern (fromSrcInfoPoints ss) (t:ps)
+
+parenMinusPattern :: Parser a Token (Ident -> Pattern ())
+parenMinusPattern = mkNeg <$> negNum <.> optInfixPattern <.> optTuplePattern
+  where mkNeg neg idt = setEndPosition (end (getSrcSpan idt)) neg
+
+parenTuplePattern :: Parser a Token (Pattern ())
+parenTuplePattern = pattern0 <**> optTuplePattern
+              `opt` ConstructorPattern NoSpanInfo () qUnitId []
+
+-- ---------------------------------------------------------------------------
+-- Expressions
+-- ---------------------------------------------------------------------------
+
+-- condExpr ::= '|' expr0 eq expr
+--
+-- Note: The guard is an `expr0` instead of `expr` since conditional expressions
+-- may also occur in case expressions, and an expression like
+-- @
+-- case a of { _ -> True :: Bool -> a }
+-- @
+-- can not be parsed with a limited parser lookahead.
+condExpr :: Parser a Token b -> Parser a Token (CondExpr ())
+condExpr eq = mkCondExpr <$> spanPosition <*-> bar <*> expr0
+                         <*> spanPosition <*-> eq  <*> expr
+  where mkCondExpr sp1 e1 sp2 e2 = updateEndPos $
+          CondExpr (spanInfo sp1 [sp1, sp2]) e1 e2
+
+-- expr ::= expr0 [ '::' type0 ]
+expr :: Parser a Token (Expression ())
+expr = expr0 <??> (mkTyped <$> tokenSpan DoubleColon <*> qualType)
+  where mkTyped sp qty e = updateEndPos $ setSrcSpan (getSrcSpan e) $
+          Typed (fromSrcInfoPoints [sp]) e qty
+
+-- expr0 ::= expr1 { infixOp expr1 }
+expr0 :: Parser a Token (Expression ())
+expr0 = expr1 `chainr1` (mkInfixApply <$> infixOp)
+  where mkInfixApply op e1 e2 = InfixApply
+          (fromSrcSpan (combineSpans (getSrcSpan e1) (getSrcSpan e2))) e1 op e2
+
+-- expr1 ::= - expr2 | -. expr2 | expr2
+expr1 :: Parser a Token (Expression ())
+expr1 =  mkUnaryMinus <$> minus <*> expr2
+     <|> expr2
+  where mkUnaryMinus idt ex =
+          let p = getPosition idt
+              e = getSrcSpanEnd ex
+              f = file p
+          in UnaryMinus (spanInfo (Span f p e) [Span f p (incr p 1)]) ex
+
+-- expr2 ::= lambdaExpr | letExpr | doExpr | ifExpr | caseExpr | expr3
+expr2 :: Parser a Token (Expression ())
+expr2 = choice [ lambdaExpr, letExpr, doExpr, ifExpr, caseExpr
+               , foldl1 mkApply <$> many1 expr3
+               ]
+  where mkApply e1 e2 = updateEndPos $ Apply (fromSrcSpan (getSrcSpan e1)) e1 e2
+
+expr3 :: Parser a Token (Expression ())
+expr3 = foldl mkRecordUpdate <$> expr4 <*> many recUpdate
+  where recUpdate = layoutOff <-*> bracesSp (field expr0 `sepBy1Sp` comma)
+        mkRecordUpdate e ((fs,ss), sp1, sp2) = updateEndPos $
+          setSrcInfoPoints (sp1 : (ss ++ [sp2])) $
+          RecordUpdate (fromSrcSpan (getSrcSpan e)) e fs
+
+expr4 :: Parser a Token (Expression ())
+expr4 = choice
+  [constant, anonFreeVariable, variable, parenExpr, listExpr]
+
+constant :: Parser a Token (Expression ())
+constant = mkLiteral <$> spanPosition <*> literal
+  where mkLiteral sp = Literal (fromSrcSpan sp) ()
+
+anonFreeVariable :: Parser a Token (Expression ())
+anonFreeVariable =  (\ p v -> mkVariable $ qualify $ addPositionIdent p v)
+                <$> position <*> anonIdent
+  where mkVariable qid = Variable (fromSrcSpan (getSrcSpan qid)) () qid
+
+variable :: Parser a Token (Expression ())
+variable = qFunId <**> optRecord
+  where optRecord = mkRecord <$> fieldsSp expr0 `opt` mkVariable
+        mkRecord ((fs,ss), sp1, sp2) qid =
+          let spi = spanInfo (getSrcSpan qid) (sp1 : (ss ++ [sp2]))
+          in updateEndPos $ Record spi () qid fs
+        mkVariable qid = Variable (fromSrcSpan (getSrcSpan qid)) () qid
+
+parenExpr :: Parser a Token (Expression ())
+parenExpr = fmap updateSpanWithBrackets (parensSp pExpr)
+  where
+  pExpr = minus <**> minusOrTuple
+      <|> mkConstructor () <$> tupleCommas
+      <|> leftSectionOrTuple <\> minus
+      <|> opOrRightSection <\> minus
+      `opt` Constructor (fromSrcInfoPoints []) () qUnitId
+  minusOrTuple = mkUnaryMinus <$> expr1 <.> infixOrTuple
+            `opt` mkVariable . qualify
+  leftSectionOrTuple = expr1 <**> infixOrTuple
+  infixOrTuple = ($ updateEndPos) <$> infixOrTuple'
+  infixOrTuple' = infixOp <**> leftSectionOrExp
+              <|> (.) <$> (optType <.> tupleExpr)
+  leftSectionOrExp = expr1 <**> (infixApp <$> infixOrTuple')
+                `opt` leftSection
+  optType   = mkTyped <$> tokenSpan DoubleColon <*> qualType `opt` id
+  tupleExpr = mkTuple <$> many1 ((,) <$> tokenSpan Comma <*> expr)
+               `opt` Paren NoSpanInfo
+  opOrRightSection =  qFunSym <**> optRightSection
+                  <|> colon   <**> optCRightSection
+                  <|> infixOp <\> colon <\> qFunSym <**> rightSection
+  optRightSection  = (. InfixOp ()    ) <$> rightSection
+                       `opt` Variable NoSpanInfo ()
+  optCRightSection = (. InfixConstr ()) <$> rightSection
+                       `opt` Constructor NoSpanInfo ()
+  rightSection     = mkRightSection <$> expr0
+  infixApp f e2 op g e1 = f (g . mkInfixApply e1 op) e2
+  leftSection op f e = mkLeftSection (f e) op
+  mkTuple ses e = let (ss,es) = unzip ses
+                  in Tuple (fromSrcInfoPoints ss) (e:es)
+  mkConstructor = Constructor NoSpanInfo
+  mkTyped sp ty e = Typed (fromSrcInfoPoints [sp]) e ty
+  mkRightSection = flip (RightSection NoSpanInfo)
+  mkLeftSection  = LeftSection  NoSpanInfo
+  mkInfixApply e1 op e2 = InfixApply (fromSrcSpan
+    (combineSpans (getSrcSpan e1) (getSrcSpan e2))) e1 op e2
+  mkVariable = Variable NoSpanInfo ()
+  mkUnaryMinus ex idt =
+    let p = getPosition idt
+        e = getSrcSpanEnd ex
+        f = file p
+    in UnaryMinus (spanInfo (Span f p e) [Span f p (incr p 1)]) ex
+
+infixOp :: Parser a Token (InfixOp ())
+infixOp = InfixOp () <$> qfunop <|> InfixConstr () <$> colon
+
+listExpr :: Parser a Token (Expression ())
+listExpr = updateSpanWithBrackets <$>
+             bracketsSp (elements `opt` List (fromSrcInfoPoints []) () [])
+  where
+  elements = expr <**> rest
+  rest = comprehension
+      <|> enumeration mkEnumFromTo mkEnumFrom
+      <|> (tokenSpan Comma <**> (expr <**>(
+           enumeration mkEnumFromThenTo mkEnumFromThen
+          <|> list <$> many ((,) <$> tokenSpan Comma <*> expr)))
+    `opt` (\ e -> List (fromSrcInfoPoints []) () [e]))
+  comprehension = mkListCompr <$> tokenSpan Bar <*> quals
+  enumeration enumTo enum =
+    tokenSpan DotDot <**> (enumTo <$> expr `opt` enum)
+
+  mkEnumFrom                 sp     =
+    EnumFrom (fromSrcInfoPoints [sp])
+  mkEnumFromTo            e1 sp  e2 =
+    EnumFromTo (fromSrcInfoPoints [sp]) e2 e1
+  mkEnumFromThen      sp1 e1 sp2 e2 =
+    EnumFromThen (fromSrcInfoPoints [sp2,sp1]) e2 e1
+  mkEnumFromThenTo e1 sp1 e2 sp2 e3 =
+    EnumFromThenTo (fromSrcInfoPoints [sp2,sp1]) e3 e2 e1
+  mkListCompr sp qu e = ListCompr (fromSrcInfoPoints [sp]) e qu
+
+  list xs e2 sp e1 = let (ss, es) = unzip xs
+                     in List (fromSrcInfoPoints (sp:ss)) () (e1:e2:es)
+
+updateSpanWithBrackets :: HasSpanInfo a => (a, Span, Span) -> a
+updateSpanWithBrackets (ex, sp1, sp2) =
+  let ss = getSrcInfoPoints ex
+      s  = getPosition sp1
+      e  = end sp2
+      f  = file s
+      spi = spanInfo (Span f s e) (sp1 : (ss ++ [sp2]))
+  in setSpanInfo spi ex
+
+lambdaExpr :: Parser a Token (Expression ())
+lambdaExpr = mkLambda <$> tokenSpan Backslash <*> many1 pattern2
+                      <*> spanPosition <*-> expectRightArrow
+                      <*> expr
+  where mkLambda sp1 ps sp2 e = updateEndPos $ Lambda (spanInfo sp1 [sp1, sp2]) ps e
+
+letExpr :: Parser a Token (Expression ())
+letExpr = mkLet <$>  tokenSpan KW_let <*> layout valueDecls
+                <*> (tokenSpan KW_in <?> "in expected") <*> expr
+  where
+    mkLet sp1 (ds, lay) sp2 e = updateEndPos $
+      Let (spanInfo sp1 [sp1, sp2])lay ds e
+
+doExpr :: Parser a Token (Expression ())
+doExpr = mkDo <$> tokenSpan KW_do <*> layout stmts
+  where
+    mkDo sp ((stms, ex), lay) = updateEndPos $
+      Do (spanInfo sp [sp]) lay stms ex
+
+ifExpr :: Parser a Token (Expression ())
+ifExpr = mkIfThenElse
+    <$>  tokenSpan KW_if                        <*> expr
+    <*> (tokenSpan KW_then <?> "then expected") <*> expr
+    <*> (tokenSpan KW_else <?> "else expected") <*> expr
+  where mkIfThenElse sp1 e1 sp2 e2 sp3 e3 = updateEndPos $
+          IfThenElse (spanInfo sp1 [sp1, sp2, sp3]) e1 e2 e3
+
+caseExpr :: Parser a Token (Expression ())
+caseExpr = (mkCase Flex  <$> tokenSpan KW_fcase
+        <|> mkCase Rigid <$> tokenSpan KW_case)
+          <*> expr
+          <*> (tokenSpan KW_of <?> "of expected")
+          <*> layout (alt `sepBy1Sp` semicolon)
+  where
+    mkCase ct sp1 e sp2 (alts, lay) = updateEndPos $
+      Case (spanInfo sp1 [sp1, sp2]) lay ct e alts
+
+alt :: Parser a Token (Alt ())
+alt = mkAlt <$> spanPosition <*> pattern0
+            <*> spanPosition <*> rhs expectRightArrow
+  where mkAlt sp1 p sp2 = updateEndPos . Alt (spanInfo sp1 [sp2]) p
+
+fieldsSp :: Parser a Token b -> Parser a Token (([Field b], [Span]), Span, Span)
+fieldsSp p = layoutOff <-*> bracesSp (field p `sepBySp` comma)
+
+field :: Parser a Token b -> Parser a Token (Field b)
+field p = mkField <$> spanPosition <*> qfun
+                  <*> spanPosition <*-> expectEquals
+                  <*> p
+  where mkField sp1 q sp2 = updateEndPos . Field (spanInfo sp1 [sp2]) q
+
+-- ---------------------------------------------------------------------------
+-- \paragraph{Statements in list comprehensions and \texttt{do} expressions}
+-- Parsing statements is a bit difficult because the syntax of patterns
+-- and expressions largely overlaps. The parser will first try to
+-- recognize the prefix \emph{Pattern}~\texttt{<-} of a binding statement
+-- and if this fails fall back into parsing an expression statement. In
+-- addition, we have to be prepared that the sequence
+-- \texttt{let}~\emph{LocalDefs} can be either a let-statement or the
+-- prefix of a let expression.
+-- ---------------------------------------------------------------------------
+
+stmts :: Parser a Token (([Statement ()], Expression ()), [Span])
+stmts = stmt reqStmts optStmts
+
+reqStmts :: Parser a Token (Statement ()
+                        -> (([Statement ()], Expression ()), [Span]))
+reqStmts = mkStmts <$> spanPosition <*-> semicolon <*> stmts
+  where mkStmts sp ((sts, e), sps) st = ((st : sts, e), sp:sps)
+
+optStmts :: Parser a Token (Expression ()
+                        -> (([Statement ()], Expression ()), [Span]))
+optStmts = succeed mkStmtExpr <.> reqStmts `opt` (\e -> (([], e), []))
+  where mkStmtExpr e = StmtExpr (fromSrcSpan (getSrcSpan e)) e
+
+quals :: Parser a Token [Statement ()]
+quals = stmt (succeed id) (succeed mkStmtExpr) `sepBy1` comma
+  where mkStmtExpr e = StmtExpr (fromSrcSpan (getSrcSpan e)) e
+
+stmt :: Parser a Token (Statement () -> b)
+     -> Parser a Token (Expression () -> b) -> Parser a Token b
+stmt stmtCont exprCont =  letStmt stmtCont exprCont
+                      <|> exprOrBindStmt stmtCont exprCont
+
+letStmt :: Parser a Token (Statement () -> b)
+        -> Parser a Token (Expression () -> b) -> Parser a Token b
+letStmt stmtCont exprCont = ((,) <$> tokenSpan KW_let <*> layout valueDecls)
+                              <**> optExpr
+  where optExpr =  let' <$> tokenSpan KW_in <*> expr <.> exprCont
+               <|> succeed stmtDecl' <.> stmtCont
+          where
+            let' sp1 e (sp2, (ds, lay)) = updateEndPos $
+              Let (spanInfo sp2 [sp2, sp1]) lay ds e
+            stmtDecl'  (sp2, (ds, lay)) = updateEndPos $
+              StmtDecl (spanInfo sp2 [sp2]) lay ds
+
+exprOrBindStmt :: Parser a Token (Statement () -> b)
+               -> Parser a Token (Expression () -> b)
+               -> Parser a Token b
+exprOrBindStmt stmtCont exprCont =
+       stmtBind' <$> spanPosition <*> pattern0 <*> tokenSpan LeftArrow <*> expr
+         <**> stmtCont
+  <|?> expr <\> token KW_let <**> exprCont
+  where
+    stmtBind' sp1 p sp2 e = updateEndPos $
+      StmtBind (spanInfo sp1 [sp2]) p e
+
+-- ---------------------------------------------------------------------------
+-- Goals
+-- ---------------------------------------------------------------------------
+
+goal :: Parser a Token (Goal ())
+goal = mkGoal <$> spanPosition <*> expr <*> localDecls
+  where
+    mkGoal sp1 ex (Just sp2, ds, li) = updateEndPos $
+      Goal (SpanInfo sp1 [sp2]) li ex ds
+    mkGoal sp1 ex (Nothing, ds, li) = updateEndPos $
+            Goal (SpanInfo sp1 []) li ex ds
+
+-- ---------------------------------------------------------------------------
+-- Literals, identifiers, and (infix) operators
+-- ---------------------------------------------------------------------------
+
+char :: Parser a Token Char
+char = cval <$> token CharTok
+
+float :: Parser a Token Double
+float = fval <$> token FloatTok
+
+int :: Parser a Token Int
+int = fromInteger <$> integer
+
+integer :: Parser a Token Integer
+integer = ival <$> token IntTok
+
+string :: Parser a Token String
+string = sval <$> token StringTok
+
+tycon :: Parser a Token Ident
+tycon = conId
+
+anonOrTyvar :: Parser a Token Ident
+anonOrTyvar = anonIdent <|> tyvar
+
+tyvar :: Parser a Token Ident
+tyvar = varId
+
+clsvar :: Parser a Token Ident
+clsvar = tyvar
+
+tycls :: Parser a Token Ident
+tycls = conId
+
+qtycls :: Parser a Token QualIdent
+qtycls = qConId
+
+qtycon :: Parser a Token QualIdent
+qtycon = qConId
+
+varId :: Parser a Token Ident
+varId = ident
+
+funId :: Parser a Token Ident
+funId = ident
+
+conId :: Parser a Token Ident
+conId = ident
+
+funSym :: Parser a Token Ident
+funSym = sym
+
+conSym :: Parser a Token Ident
+conSym = sym
+
+modIdent :: Parser a Token ModuleIdent
+modIdent = mIdent <?> "module name expected"
+
+var :: Parser a Token Ident
+var = varId <|> updateSpanWithBrackets
+                     <$> parensSp (funSym <?> "operator symbol expected")
+
+fun :: Parser a Token Ident
+fun = funId <|> updateSpanWithBrackets
+                     <$> parensSp (funSym <?> "operator symbol expected")
+
+con :: Parser a Token Ident
+con = conId <|> updateSpanWithBrackets
+                     <$> parensSp (conSym <?> "operator symbol expected")
+
+funop :: Parser a Token Ident
+funop = funSym <|> updateSpanWithBrackets
+                     <$> backquotesSp (funId <?> "operator name expected")
+
+conop :: Parser a Token Ident
+conop = conSym <|> updateSpanWithBrackets
+                     <$> backquotesSp (conId <?> "operator name expected")
+
+qFunId :: Parser a Token QualIdent
+qFunId = qIdent
+
+qConId :: Parser a Token QualIdent
+qConId = qIdent
+
+qFunSym :: Parser a Token QualIdent
+qFunSym = qSym
+
+qConSym :: Parser a Token QualIdent
+qConSym = qSym
+
+gConSym :: Parser a Token QualIdent
+gConSym = qConSym <|> colon
+
+qfun :: Parser a Token QualIdent
+qfun = qFunId <|> updateSpanWithBrackets
+                     <$> parensSp (qFunSym <?> "operator symbol expected")
+
+qfunop :: Parser a Token QualIdent
+qfunop = qFunSym <|> updateSpanWithBrackets
+                     <$> backquotesSp (qFunId <?> "operator name expected")
+
+gconop :: Parser a Token QualIdent
+gconop = gConSym <|> updateSpanWithBrackets
+                     <$> backquotesSp (qConId <?> "operator name expected")
+
+anonIdent :: Parser a Token Ident
+anonIdent = (`setSpanInfo` anonId) . fromSrcSpanBoth <$> tokenSpan Underscore
+
+mIdent :: Parser a Token ModuleIdent
+mIdent = mIdent' <$> spanPosition <*>
+     tokens [Id,QId,Id_as,Id_ccall,Id_forall,Id_hiding,
+             Id_interface,Id_primitive,Id_qualified]
+  where mIdent' sp a = ModuleIdent (fromSrcSpanBoth sp) (modulVal a ++ [sval a])
+
+ident :: Parser a Token Ident
+ident = (\ sp t -> setSpanInfo (fromSrcSpanBoth sp) (mkIdent (sval t)))
+          <$> spanPosition <*> tokens [Id,Id_as,Id_ccall,Id_forall,Id_hiding,
+                                       Id_interface,Id_primitive,Id_qualified]
+
+qIdent :: Parser a Token QualIdent
+qIdent = qualify <$> ident <|> qIdentWith QId
+
+sym :: Parser a Token Ident
+sym = (\ sp t -> setSpanInfo (fromSrcSpanBoth sp) (mkIdent (sval t)))
+        <$> spanPosition <*> tokens [Sym, SymDot, SymMinus, SymStar]
+
+qSym :: Parser a Token QualIdent
+qSym = qualify <$> sym <|> qIdentWith QSym
+
+qIdentWith :: Category -> Parser a Token QualIdent
+qIdentWith c = mkQIdent <$> spanPosition <*> token c
+  where mkQIdent :: Span -> Attributes -> QualIdent
+        mkQIdent sp a =
+          let mid  = ModuleIdent (fromSrcSpan sp) (modulVal a)
+              p    = incr (getPosition sp) (mIdentLength mid - 1)
+              mid' = setEndPosition p mid
+              idt  = setSrcSpan sp $ mkIdent (sval a)
+              idt' = setPosition (incr p 1) idt
+          in QualIdent (fromSrcSpanBoth sp) (Just mid') idt'
+
+colon :: Parser a Token QualIdent
+colon = qualify . (`setSpanInfo` consId) . fromSrcSpanBoth <$> tokenSpan Colon
+
+minus :: Parser a Token Ident
+minus = (`setSpanInfo` minusId) . fromSrcSpanBoth <$> tokenSpan SymMinus
+
+tupleCommas :: Parser a Token QualIdent
+tupleCommas = (\ sp ss -> qualify $ updateEndPos $ setSpanInfo (spanInfo sp ss)
+                                  $ tupleId      $ succ $ length  ss)
+              <$> spanPosition <*> many1 (tokenSpan Comma)
+
+-- ---------------------------------------------------------------------------
+-- Layout
+-- ---------------------------------------------------------------------------
+
+-- |This function starts a new layout block but does not wait for its end.
+-- This is only used for parsing the module header.
+startLayout :: Parser a Token (b, [Span]) -> Parser a Token (b, LayoutInfo)
+startLayout p =  layoutOff <-*>
+                   (createExpli1Layout <$> tokenSpan LeftBrace <*> p)
+             <|> layoutOn  <-*>
+                   (createWhiteLayout  <$> p)
+
+layout :: Parser a Token (b, [Span]) -> Parser a Token (b, LayoutInfo)
+layout p =  (createExpliLayout
+              <$> (layoutOff <-*> bracesSp p))
+        <|> (createWhiteLayout
+              <$> (layoutOn  <-*> p <*-> (token VRightBrace <|> layoutEnd)))
+
+createExpli1Layout :: Span -> (b, [Span]) -> (b, LayoutInfo)
+createExpli1Layout sp1 (b, ss) = (b, ExplicitLayout (sp1:ss))
+
+createExpliLayout :: ((b, [Span]), Span, Span) -> (b, LayoutInfo)
+createExpliLayout ((b, ss), sp1, spe) = (b, ExplicitLayout (sp1:ss ++ [spe]))
+
+createWhiteLayout :: (b, [Span]) -> (b, LayoutInfo)
+createWhiteLayout (b, _) = (b, WhitespaceLayout)
+
+-- We have to remove an additional context on an empty where-clause
+layoutWhere :: Parser a Token b -> Parser a Token ([b], LayoutInfo)
+layoutWhere p =  (createExpliLayout
+                    <$> (layoutOff <-*> bracesSp (p `sepBySp` semicolon)))
+             <|> (createWhiteLayout
+                    <$> (layoutOn  <-*> (p `sepBy1Sp` semicolon)
+                                   <*-> (token VRightBrace <|> layoutEnd)))
+             <|> succeed ([], WhitespaceLayout)
+
+-- ---------------------------------------------------------------------------
+-- Bracket combinators
+-- ---------------------------------------------------------------------------
+
+braces :: Parser a Token b -> Parser a Token b
+braces p = between leftBrace p rightBrace
+
+bracesSp :: Parser a Token b -> Parser a Token (b, Span, Span)
+bracesSp p = (\sp1 b sp2 -> (b, sp1, sp2))
+               <$> tokenSpan LeftBrace
+               <*> p
+               <*> tokenSpan RightBrace
+
+bracketsSp :: Parser a Token b -> Parser a Token (b, Span, Span)
+bracketsSp p = (\sp1 b sp2 -> (b, sp1, sp2))
+                 <$> tokenSpan LeftBracket
+                 <*> p
+                 <*> tokenSpan RightBracket
+
+parens :: Parser a Token b -> Parser a Token b
+parens p = between leftParen p rightParen
+
+parensSp :: Parser a Token b -> Parser a Token (b, Span, Span)
+parensSp p = (\sp1 b sp2 -> (b, sp1, sp2))
+               <$> tokenSpan LeftParen
+               <*> p
+               <*> tokenSpan RightParen
+
+backquotesSp :: Parser a Token b -> Parser a Token (b, Span, Span)
+backquotesSp p = (\sp1 b sp2 -> (b, sp1, sp2))
+                   <$> tokenSpan Backquote
+                   <*> p
+                   <*> spanPosition <*-> expectBackquote
+
+-- ---------------------------------------------------------------------------
+-- Simple token parsers
+-- ---------------------------------------------------------------------------
+
+token :: Category -> Parser a Token Attributes
+token c = attr <$> symbol (Token c NoAttributes)
+  where attr (Token _ a) = a
+
+tokens :: [Category] -> Parser a Token Attributes
+tokens = foldr1 (<|>) . map token
+
+tokenPos :: Category -> Parser a Token Position
+tokenPos c = position <*-> token c
+
+tokenSpan :: Category -> Parser a Token Span
+tokenSpan c = spanPosition <*-> token c
+
+tokenOps :: [(Category, b)] -> Parser a Token b
+tokenOps cs = ops [(Token c NoAttributes, x) | (c, x) <- cs]
+
+comma :: Parser a Token Attributes
+comma = token Comma
+
+semicolon :: Parser a Token Attributes
+semicolon = token Semicolon <|> token VSemicolon
+
+bar :: Parser a Token Attributes
+bar = token Bar
+
+equals :: Parser a Token Attributes
+equals = token Equals
+
+expectEquals :: Parser a Token Attributes
+expectEquals = equals <?> "= expected"
+
+expectWhere :: Parser a Token Attributes
+expectWhere = token KW_where <?> "where expected"
+
+expectRightArrow :: Parser a Token Attributes
+expectRightArrow  = token RightArrow <?> "-> expected"
+
+backquote :: Parser a Token Attributes
+backquote = token Backquote
+
+expectBackquote :: Parser a Token Attributes
+expectBackquote = backquote <?> "backquote (`) expected"
+
+leftParen :: Parser a Token Attributes
+leftParen = token LeftParen
+
+rightParen :: Parser a Token Attributes
+rightParen = token RightParen
+
+leftBrace :: Parser a Token Attributes
+leftBrace = token LeftBrace
+
+rightBrace :: Parser a Token Attributes
+rightBrace = token RightBrace
diff --git a/src/Curry/Syntax/Parser.lhs b/src/Curry/Syntax/Parser.lhs
deleted file mode 100644
--- a/src/Curry/Syntax/Parser.lhs
+++ /dev/null
@@ -1,806 +0,0 @@
-
-% $Id: CurryParser.lhs,v 1.75 2004/02/15 23:11:28 wlux Exp $
-%
-% Copyright (c) 1999-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{CurryParser.lhs}
-\section{A Parser for Curry}
-The Curry parser is implemented using the (mostly) LL(1) parsing
-combinators described in appendix~\ref{sec:ll-parsecomb}.
-\begin{verbatim}
-
-> module Curry.Syntax.Parser where
-
-> import Curry.Base.Ident
-> import Curry.Base.Position
-> import Curry.Base.MessageMonad
-> import Curry.Syntax.LLParseComb
-> import Curry.Syntax.Type
-> import Curry.Syntax.Lexer
-
-> instance Symbol Token where
->   isEOF (Token c _) = c == EOF
-
-\end{verbatim}
-\paragraph{Modules}
-\begin{verbatim}
-
-> parseSource :: Bool -> FilePath -> String -> MsgMonad Module
-> parseSource flat path = 
->    fmap addSrcRefs . applyParser ( moduleHeader <*> decls flat) lexer path
-
-> parseHeader :: FilePath -> String -> MsgMonad Module
-> parseHeader = prefixParser (moduleHeader <*->
->                             (leftBrace `opt` undefined) <*>
->                             many (importDecl <*-> many semicolon))
->                            lexer
-
-> moduleHeader :: Parser Token ([Decl] -> Module) a
-> moduleHeader = Module <$-> token KW_module
->                       <*> (mIdent <?> "module name expected")
->                       <*> ((Just <$> exportSpec) `opt` Nothing)
->                       <*-> (token KW_where <?> "where expected")
->          `opt` Module mainMIdent Nothing
-
-> exportSpec :: Parser Token ExportSpec a
-> exportSpec = Exporting <$> position <*> parens (export `sepBy` comma)
-
-> export :: Parser Token Export a
-> export = qtycon <**> (parens spec `opt` Export)
->      <|> Export <$> qfun <\> qtycon
->      <|> ExportModule <$-> token KW_module <*> mIdent
->   where spec = ExportTypeAll <$-> token DotDot
->            <|> flip ExportTypeWith <$> con `sepBy` comma
-
-\end{verbatim}
-\paragraph{Interfaces}
-Since this modified version of MCC uses FlatCurry interfaces instead of
-".icurry" files, a separate parser is not required any longer.
-\begin{verbatim}
-
-> --parseInterface :: FilePath -> String -> Error Interface
-> --parseInterface fn s = applyParser parseIface lexer fn s
-
-> --parseIface :: Parser Token Interface a
-> --parseIface = Interface <$-> token Id_interface
-> --                       <*> (mIdent <?> "module name expected")
-> --                       <*-> (token KW_where <?> "where expected")
-> --                       <*> braces intfDecls
-
-\end{verbatim}
-
-
-
-\paragraph{Declarations}
-\begin{verbatim}
-
-> decls :: Bool -> Parser Token [Decl] a
-> decls = layout . globalDecls
-
-> globalDecls :: Bool -> Parser Token [Decl] a
-> globalDecls flat =
->       (:) <$> importDecl <*> (semicolon <-*> globalDecls flat `opt` [])
->   <|> topDecl flat `sepBy` semicolon
-
-> topDecl :: Bool -> Parser Token Decl a
-> topDecl flat
->   | flat = infixDecl <|> dataDecl flat <|> typeDecl <|> functionDecl flat
->   | otherwise = infixDecl
->             <|> dataDecl flat <|> newtypeDecl <|> typeDecl
->             <|> functionDecl flat <|> externalDecl
-
-> localDefs :: Bool -> Parser Token [Decl] a
-> localDefs flat = token KW_where <-*> layout (valueDecls flat)
->            `opt` []
-
-> valueDecls :: Bool -> Parser Token [Decl] a
-> valueDecls flat = localDecl flat `sepBy` semicolon
->   where localDecl flat
->           | flat = infixDecl <|> valueDecl flat
->           | otherwise = infixDecl <|> valueDecl flat <|> externalDecl
-
-> importDecl :: Parser Token Decl a
-> importDecl =
->   flip . ImportDecl <$> position <*-> token KW_import 
->                     <*> (True <$-> token Id_qualified `opt` False)
->                     <*> mIdent
->                     <*> (Just <$-> token Id_as <*> mIdent `opt` Nothing)
->                     <*> (Just <$> importSpec `opt` Nothing)
-
-> importSpec :: Parser Token ImportSpec a
-> importSpec = position <**> (Hiding <$-> token Id_hiding `opt` Importing)
->                       <*> parens (spec `sepBy` comma)
->   where spec = tycon <**> (parens constrs `opt` Import)
->            <|> Import <$> fun <\> tycon
->         constrs = ImportTypeAll <$-> token DotDot
->               <|> flip ImportTypeWith <$> con `sepBy` comma
-
-> infixDecl :: Parser Token Decl a
-> infixDecl = infixDeclLhs InfixDecl <*> funop `sepBy1` comma
-
-> infixDeclLhs :: (Position -> Infix -> Integer -> a) -> Parser Token a b
-> infixDeclLhs f = f <$> position <*> tokenOps infixKW <*> integer
->   where infixKW = [(KW_infix,Infix),(KW_infixl,InfixL),(KW_infixr,InfixR)]
-
-> dataDecl :: Bool -> Parser Token Decl a
-> dataDecl flat = typeDeclLhs DataDecl KW_data <*> constrs
->   where constrs = equals <-*> constrDecl flat `sepBy1` bar
->             `opt` []
-
-> newtypeDecl :: Parser Token Decl a
-> newtypeDecl =
->   typeDeclLhs NewtypeDecl KW_newtype <*-> equals <*> newConstrDecl
-
-> typeDecl :: Parser Token Decl a
-> typeDecl = typeDeclLhs TypeDecl KW_type <*-> equals <*> typeDeclRhs --type0
-
-> typeDeclLhs :: (Position -> Ident -> [Ident] -> a) -> Category
->             -> Parser Token a b
-> typeDeclLhs f kw = f <$> position <*-> token kw <*> tycon <*> many typeVar
->   where typeVar = tyvar <|> anonId <$-> token Underscore
-
-> typeDeclRhs :: Parser Token TypeExpr a
-> typeDeclRhs = type0
->	        <|> flip RecordType Nothing
->		   <$> (layoutOff <-*> braces (labelDecls `sepBy` comma))
-
-> labelDecls = (,) <$> labId `sepBy1` comma <*-> token DoubleColon <*> type0
-
-> constrDecl :: Bool -> Parser Token ConstrDecl a
-> constrDecl flat = position <**> (existVars <**> constr)
->   where constr = conId <**> identDecl
->              <|> leftParen <-*> parenDecl
->              <|> type1 <\> conId <\> leftParen <**> opDecl
->         identDecl = many type2 <**> (conType <$> opDecl `opt` conDecl)
->         parenDecl = conOpDeclPrefix 
->	              <$> conSym <*-> rightParen <*> type2 <*> type2
->                 <|> tupleType <*-> rightParen <**> opDecl
->         opDecl = conOpDecl <$> conop <*> type1
->         conType f tys c = f (ConstructorType (qualify c) tys)
->         conDecl tys c tvs p = ConstrDecl p tvs c tys
->         conOpDecl op ty2 ty1 tvs p = ConOpDecl p tvs ty1 op ty2
->         conOpDeclPrefix op ty1 ty2 tvs p = ConOpDecl p tvs ty1 op ty2
-
-> newConstrDecl :: Parser Token NewConstrDecl a
-> newConstrDecl =
->   NewConstrDecl <$> position <*> existVars <*> con <*> type2
-
-> existVars :: Parser Token [Ident] a
-> {-
-> existVars flat
->   | flat = succeed []
->   | otherwise = token Id_forall <-*> many1 tyvar <*-> dot `opt` []
-> -}
-> existVars = succeed []
-
-> functionDecl :: Bool -> Parser Token Decl a
-> functionDecl flat = position <**> decl
->   where decl = fun `sepBy1` comma <**> funListDecl flat
->           <|?> funDecl <$> lhs <*> declRhs flat
->         lhs = (\f -> (f,FunLhs f [])) <$> fun
->          <|?> funLhs
-
-> valueDecl :: Bool -> Parser Token Decl a
-> valueDecl flat = position <**> decl
->   where decl = var `sepBy1` comma <**> valListDecl flat
->           <|?> valDecl <$> constrTerm0 <*> declRhs flat
->           <|?> funDecl <$> curriedLhs <*> declRhs flat
->         valDecl t@(ConstructorPattern c ts)
->           | not (isConstrId c) = funDecl (f,FunLhs f ts)
->           where f = unqualify c
->         valDecl t = opDecl id t
->         opDecl f (InfixPattern t1 op t2)
->           | isConstrId op = opDecl (f . InfixPattern t1 op) t2
->           | otherwise = funDecl (op',OpLhs (f t1) op' t2)
->           where op' = unqualify op
->         opDecl f t = patDecl (f t)
->         isConstrId c = c == qConsId || isQualified c || isQTupleId c
-
-> funDecl :: (Ident,Lhs) -> Rhs -> Position -> Decl
-> funDecl (f,lhs) rhs p = FunctionDecl p f [Equation p lhs rhs]
-
-> patDecl :: ConstrTerm -> Rhs -> Position -> Decl
-> patDecl t rhs p = PatternDecl p t rhs
-
-> funListDecl :: Bool -> Parser Token ([Ident] -> Position -> Decl) a
-> funListDecl flat
->   | flat = typeSig <$-> token DoubleColon <*> type0
->        <|> evalAnnot <$-> token KW_eval <*> tokenOps evalKW
->        <|> externalDecl <$-> token KW_external
->   | otherwise = typeSig <$-> token DoubleColon <*> type0
->             <|> evalAnnot <$-> token KW_eval <*> tokenOps evalKW
->   where typeSig ty vs p = TypeSig p vs ty
->         evalAnnot ev vs p = EvalAnnot p vs ev
->         evalKW = [(KW_rigid,EvalRigid),(KW_choice,EvalChoice)]
->         externalDecl vs p = FlatExternalDecl p vs
-
-> valListDecl :: Bool -> Parser Token ([Ident] -> Position -> Decl) a
-> valListDecl flat = funListDecl flat <|> extraVars <$-> token KW_free
->   where extraVars vs p = ExtraVariables p vs
-
-> funLhs :: Parser Token (Ident,Lhs) a
-> funLhs = funLhs <$> fun <*> many1 constrTerm2
->     <|?> flip ($ id) <$> constrTerm1 <*> opLhs'
->     <|?> curriedLhs
->   where opLhs' = opLhs <$> funSym <*> constrTerm0
->              <|> infixPat <$> gConSym <\> funSym <*> constrTerm1 <*> opLhs'
->              <|> backquote <-*> opIdLhs
->         opIdLhs = opLhs <$> funId <*-> checkBackquote <*> constrTerm0
->               <|> infixPat <$> qConId <\> funId <*-> backquote <*> constrTerm1
->                            <*> opLhs'
->         funLhs f ts = (f,FunLhs f ts)
->         opLhs op t2 f t1 = (op,OpLhs (f t1) op t2)
->         infixPat op t2 f g t1 = f (g . InfixPattern t1 op) t2
-
-> curriedLhs :: Parser Token (Ident,Lhs) a
-> curriedLhs = apLhs <$> parens funLhs <*> many1 constrTerm2
->   where apLhs (f,lhs) ts = (f,ApLhs lhs ts)
-
-> declRhs :: Bool -> Parser Token Rhs a
-> declRhs flat = rhs flat equals
-
-> rhs :: Bool -> Parser Token a b -> Parser Token Rhs b
-> rhs flat eq = rhsExpr <*> localDefs flat
->   where rhsExpr = SimpleRhs <$-> eq <*> position <*> expr flat
->               <|> GuardedRhs <$> many1 (condExpr flat eq)
-
-> externalDecl :: Parser Token Decl a
-> externalDecl =
->   ExternalDecl <$> position <*-> token KW_external
->                <*> callConv <*> (Just <$> string `opt` Nothing)
->                <*> fun <*-> token DoubleColon <*> type0
->   where callConv = CallConvPrimitive <$-> token Id_primitive
->                <|> CallConvCCall <$-> token Id_ccall
->                <?> "Unsupported calling convention"
-
-\end{verbatim}
-\paragraph{Interface declarations}
-\begin{verbatim}
-
-> --intfDecls :: Parser Token [IDecl] a
-> --intfDecls = (:) <$> iImportDecl <*> (semicolon <-*> intfDecls `opt` [])
-> --        <|> intfDecl `sepBy` semicolon
-
-> --intfDecl :: Parser Token IDecl a
-> --intfDecl = iInfixDecl
-> --       <|> iHidingDecl <|> iDataDecl <|> iNewtypeDecl <|> iTypeDecl
-> --       <|> iFunctionDecl <\> token Id_hiding
-
-> --iImportDecl :: Parser Token IDecl a
-> --iImportDecl = IImportDecl <$> position <*-> token KW_import <*> mIdent
-
-> --iInfixDecl :: Parser Token IDecl a
-> --iInfixDecl = infixDeclLhs IInfixDecl <*> qfunop
-
-> --iHidingDecl :: Parser Token IDecl a
-> --iHidingDecl = position <*-> token Id_hiding <**> (dataDecl <|> funcDecl)
-> --  where dataDecl = hiddenData <$-> token KW_data <*> tycon <*> many tyvar
-> --        funcDecl = hidingFunc <$-> token DoubleColon <*> type0
-> --        hiddenData tc tvs p = HidingDataDecl p tc tvs
-> --        hidingFunc ty p = IFunctionDecl p hidingId ty
-> --        hidingId = qualify (mkIdent "hiding")
-
-> --iDataDecl :: Parser Token IDecl a
-> --iDataDecl = iTypeDeclLhs IDataDecl KW_data <*> constrs
-> --  where constrs = equals <-*> iConstrDecl `sepBy1` bar
-> --            `opt` []
-> --        iConstrDecl = Just <$> constrDecl False <\> token Underscore
-> --                  <|> Nothing <$-> token Underscore
-
-> --iNewtypeDecl :: Parser Token IDecl a
-> --iNewtypeDecl =
-> --  iTypeDeclLhs INewtypeDecl KW_newtype <*-> equals <*> newConstrDecl
-
-> --iTypeDecl :: Parser Token IDecl a
-> --iTypeDecl = iTypeDeclLhs ITypeDecl KW_type <*-> equals <*> type0
-
-> --iTypeDeclLhs :: (Position -> QualIdent -> [Ident] -> a) -> Category
-> --             -> Parser Token a b
-> --iTypeDeclLhs f kw = f <$> position <*-> token kw <*> qtycon <*> many tyvar
-
-> --iFunctionDecl :: Parser Token IDecl a
-> --iFunctionDecl = IFunctionDecl <$> position <*> qfun <*-> token DoubleColon
-> --                              <*> type0
-
-\end{verbatim}
-\paragraph{Types}
-\begin{verbatim}
-
-> type0 :: Parser Token TypeExpr a
-> type0 = type1 `chainr1` (ArrowType <$-> token RightArrow)
-
-> type1 :: Parser Token TypeExpr a
-> type1 = ConstructorType <$> qtycon <*> many type2
->     <|> type2 <\> qtycon
-
-> type2 :: Parser Token TypeExpr a
-> type2 = anonType <|> identType <|> parenType <|> listType
-
-> anonType :: Parser Token TypeExpr a
-> anonType = VariableType anonId <$-> token Underscore
-
-> identType :: Parser Token TypeExpr a
-> identType = VariableType <$> tyvar
->         <|> flip ConstructorType [] <$> qtycon <\> tyvar
-
-> parenType :: Parser Token TypeExpr a
-> parenType = parens tupleType
-
-> tupleType :: Parser Token TypeExpr a
-> tupleType = type0 <??> (tuple <$> many1 (comma <-*> type0))
->       `opt` TupleType []
->   where tuple tys ty = TupleType (ty:tys)
-
-> listType :: Parser Token TypeExpr a
-> listType = ListType <$> brackets type0
-
-\end{verbatim}
-\paragraph{Literals}
-\begin{verbatim}
-
-> literal :: Parser Token Literal a
-> literal = mk Char   <$> char
->       <|> mkInt     <$> integer
->       <|> mk Float  <$> float
->       <|> mk String <$> string
-
-\end{verbatim}
-\paragraph{Patterns}
-\begin{verbatim}
-
-> constrTerm0 :: Parser Token ConstrTerm a
-> constrTerm0 = constrTerm1 `chainr1` (flip InfixPattern <$> gconop)
-
-> constrTerm1 :: Parser Token ConstrTerm a
-> constrTerm1 = varId <**> identPattern
->	    <|> ConstructorPattern <$> qConId <\> varId <*> many constrTerm2
->           <|> minus <**> negNum
->           <|> fminus <**> negFloat
->           <|> leftParen <-*> parenPattern
->           <|> constrTerm2 <\> qConId <\> leftParen
->   where identPattern = optAsPattern
->                    <|> conPattern <$> many1 constrTerm2
->         parenPattern = minus <**> minusPattern negNum
->                    <|> fminus <**> minusPattern negFloat
->                    <|> gconPattern
->                    <|> funSym <\> minus <\> fminus <*-> rightParen
->                                                    <**> identPattern
->                    <|> parenTuplePattern <\> minus <\> fminus <*-> rightParen
->         minusPattern p = rightParen <-*> identPattern
->                      <|> parenMinusPattern p <*-> rightParen
->         gconPattern = ConstructorPattern <$> gconId <*-> rightParen
->                                          <*> many constrTerm2
->         conPattern ts = flip ConstructorPattern ts . qualify
-
-> constrTerm2 :: Parser Token ConstrTerm a
-> constrTerm2 = literalPattern <|> anonPattern <|> identPattern
->           <|> parenPattern <|> listPattern <|> lazyPattern
->	    <|> recordPattern
-
-> literalPattern :: Parser Token ConstrTerm a
-> literalPattern = LiteralPattern <$> literal
-
-> anonPattern :: Parser Token ConstrTerm a
-> anonPattern = VariablePattern anonId <$-> token Underscore
-
-> identPattern :: Parser Token ConstrTerm a
-> identPattern = varId <**> optAsPattern
->            <|> flip ConstructorPattern [] <$> qConId <\> varId
-
-> parenPattern :: Parser Token ConstrTerm a
-> parenPattern = leftParen <-*> parenPattern
->   where parenPattern = minus <**> minusPattern negNum
->                    <|> fminus <**> minusPattern negFloat
->                    <|> flip ConstructorPattern [] <$> gconId <*-> rightParen
->                    <|> funSym <\> minus <\> fminus <*-> rightParen
->                                                    <**> optAsPattern
->                    <|> parenTuplePattern <\> minus <\> fminus <*-> rightParen
->         minusPattern p = rightParen <-*> optAsPattern
->                      <|> parenMinusPattern p <*-> rightParen
-
-> listPattern :: Parser Token ConstrTerm a
-> listPattern = mk' ListPattern <$> brackets (constrTerm0 `sepBy` comma)
-
-> lazyPattern :: Parser Token ConstrTerm a
-> lazyPattern = mk LazyPattern <$-> token Tilde <*> constrTerm2
-
-> recordPattern :: Parser Token ConstrTerm a
-> recordPattern = layoutOff <-*> braces content
->   where
->   content = RecordPattern <$> fields <*> record
->   fields = fieldPatt `sepBy` comma
->   fieldPatt = Field <$> position <*> labId <*-> checkEquals <*> constrTerm0
->   record = Just <$-> checkBar <*> constrTerm2 `opt` Nothing
-
-\end{verbatim}
-Partial patterns used in the combinators above, but also for parsing
-the left-hand side of a declaration.
-\begin{verbatim}
-
-> gconId :: Parser Token QualIdent a
-> gconId = colon <|> tupleCommas
-
-> negNum,negFloat :: Parser Token (Ident -> ConstrTerm) a
-> negNum = flip NegativePattern 
->          <$> (mkInt <$> integer <|> mk Float <$> float)
-> negFloat = flip NegativePattern . mk Float 
->            <$> (fromIntegral <$> integer <|> float)
-
-> optAsPattern :: Parser Token (Ident -> ConstrTerm) a
-> optAsPattern = flip AsPattern <$-> token At <*> constrTerm2
->          `opt` VariablePattern
-
-> optInfixPattern :: Parser Token (ConstrTerm -> ConstrTerm) a
-> optInfixPattern = infixPat <$> gconop <*> constrTerm0
->             `opt` id
->   where infixPat op t2 t1 = InfixPattern t1 op t2
-
-> optTuplePattern :: Parser Token (ConstrTerm -> ConstrTerm) a
-> optTuplePattern = tuple <$> many1 (comma <-*> constrTerm0)
->             `opt` ParenPattern
->   where tuple ts t = mk TuplePattern (t:ts)
-
-> parenMinusPattern :: Parser Token (Ident -> ConstrTerm) a
->                   -> Parser Token (Ident -> ConstrTerm) a
-> parenMinusPattern p = p <.> optInfixPattern <.> optTuplePattern
-
-> parenTuplePattern :: Parser Token ConstrTerm a
-> parenTuplePattern = constrTerm0 <**> optTuplePattern
->               `opt` mk TuplePattern []
-
-\end{verbatim}
-\paragraph{Expressions}
-\begin{verbatim}
-
-> condExpr :: Bool -> Parser Token a b -> Parser Token CondExpr b
-> condExpr flat eq =
->   CondExpr <$> position <*-> bar <*> expr0 flat <*-> eq <*> expr flat
-
-> expr :: Bool -> Parser Token Expression a
-> expr flat = expr0 flat <??> (flip Typed <$-> token DoubleColon <*> type0)
-
-> expr0 :: Bool -> Parser Token Expression a
-> expr0 flat = expr1 flat `chainr1` (flip InfixApply <$> infixOp)
-
-> expr1 :: Bool -> Parser Token Expression a
-> expr1 flat = UnaryMinus <$> (minus <|> fminus) <*> expr2 flat
->          <|> expr2 flat
-
-> expr2 :: Bool -> Parser Token Expression a
-> expr2 flat = lambdaExpr flat <|> letExpr flat <|> doExpr flat
->          <|> ifExpr flat <|> caseExpr flat
->          <|> expr3 flat <**> applicOrSelect
->   where
->   applicOrSelect = flip RecordSelection 
->	                  <$-> (token RightArrow <?> "-> expected")
->			  <*> labId
->		 <|?> (\es e -> foldl1 Apply (e:es))
->		          <$> many (expr3 flat) 
-
-> expr3 :: Bool -> Parser Token Expression a
-> expr3 flat = expr3' 
->   where
->   expr3' = constant <|> variable <|> parenExpr flat
->        <|> listExpr flat <|> recordExpr flat
-
-> constant :: Parser Token Expression a
-> constant = Literal <$> literal
-
-> variable :: Parser Token Expression a
-> variable = Variable <$> qFunId
-
-> parenExpr :: Bool -> Parser Token Expression a
-> parenExpr flat = parens pExpr
->   where pExpr = (minus <|> fminus) <**> minusOrTuple
->             <|> Constructor <$> tupleCommas
->             <|> leftSectionOrTuple <\> minus <\> fminus
->             <|> opOrRightSection <\> minus <\> fminus
->           `opt` mk Tuple []
->         minusOrTuple = flip UnaryMinus <$> expr1 flat <.> infixOrTuple
->                  `opt` Variable . qualify
->         leftSectionOrTuple = expr1 flat <**> infixOrTuple
->         infixOrTuple = ($ id) <$> infixOrTuple'
->         infixOrTuple' = infixOp <**> leftSectionOrExp
->                     <|> (.) <$> (optType <.> tupleExpr)
->         leftSectionOrExp = expr1 flat <**> (infixApp <$> infixOrTuple')
->                      `opt` leftSection
->         optType = flip Typed <$-> token DoubleColon <*> type0
->             `opt` id
->         tupleExpr = tuple <$> many1 (comma <-*> expr flat)
->               `opt` Paren
->         opOrRightSection = qFunSym <**> optRightSection
->                        <|> colon <**> optCRightSection
->                        <|> infixOp <\> colon <\> qFunSym <**> rightSection
->         optRightSection = (. InfixOp) <$> rightSection `opt` Variable
->         optCRightSection = (. InfixConstr) <$> rightSection `opt` Constructor
->         rightSection = flip RightSection <$> expr0 flat
->         infixApp f e2 op g e1 = f (g . InfixApply e1 op) e2
->         leftSection op f e = LeftSection (f e) op
->         tuple es e = mk Tuple (e:es)
-
-> infixOp :: Parser Token InfixOp a
-> infixOp = InfixOp <$> qfunop
->       <|> InfixConstr <$> colon
-
-> listExpr :: Bool -> Parser Token Expression a
-> listExpr flat = brackets (elements `opt` mk' List [])
->   where elements = expr flat <**> rest
->         rest = comprehension
->            <|> enumeration (flip EnumFromTo) EnumFrom
->            <|> comma <-*> expr flat <**>
->                (enumeration (flip3 EnumFromThenTo) (flip EnumFromThen)
->                <|> list <$> many (comma <-*> expr flat))
->          `opt` (\e -> mk' List [e])
->         comprehension = flip (mk ListCompr) <$-> bar <*> quals flat
->         enumeration enumTo enum =
->           token DotDot <-*> (enumTo <$> expr flat `opt` enum)
->         list es e2 e1 = mk' List (e1:e2:es)
->         flip3 f x y z = f z y x
-
-> recordExpr :: Bool -> Parser Token Expression a
-> recordExpr flat = layoutOff <-*> braces content
->   where content = RecordConstr <$> fieldConstr `sepBy` comma
->	            <|?> RecordUpdate <$> fieldUpdate `sepBy` comma
->		                      <*-> checkBar <*> expr flat
->	  fieldConstr = Field <$> position <*> labId 
->		              <*-> checkEquals <*> expr flat
->	  fieldUpdate = Field <$> position <*> labId 
->		              <*-> checkBinds <*> expr flat
-
-> lambdaExpr :: Bool -> Parser Token Expression a
-> lambdaExpr flat =
->   mk Lambda <$-> token Backslash <*> many1 constrTerm2
->          <*-> (token RightArrow <?> "-> expected") <*> expr flat
-
-> letExpr :: Bool -> Parser Token Expression a
-> letExpr flat = Let <$-> token KW_let <*> layout (valueDecls flat)
->                    <*-> (token KW_in <?> "in expected") <*> expr flat
-
-> doExpr :: Bool -> Parser Token Expression a
-> doExpr flat = uncurry Do <$-> token KW_do <*> layout (stmts flat)
-
-> ifExpr :: Bool -> Parser Token Expression a
-> ifExpr flat =
->   mk IfThenElse <$-> token KW_if <*> expr flat
->              <*-> (token KW_then <?> "then expected") <*> expr flat
->              <*-> (token KW_else <?> "else expected") <*> expr flat
-
-> caseExpr :: Bool -> Parser Token Expression a
-> caseExpr flat = mk Case <$-> token KW_case <*> expr flat
->                 <*-> (token KW_of <?> "of expected") <*> layout (alts flat)
-
-> alts :: Bool -> Parser Token [Alt] a
-> alts flat = alt flat `sepBy1` semicolon
-
-> alt :: Bool -> Parser Token Alt a
-> alt flat = Alt <$> position <*> constrTerm0
->                <*> rhs flat (token RightArrow <?> "-> expected")
-
-\end{verbatim}
-\paragraph{Statements in list comprehensions and \texttt{do} expressions}
-Parsing statements is a bit difficult because the syntax of patterns
-and expressions largely overlaps. The parser will first try to
-recognize the prefix \emph{Pattern}~\texttt{<-} of a binding statement
-and if this fails fall back into parsing an expression statement. In
-addition, we have to be prepared that the sequence
-\texttt{let}~\emph{LocalDefs} can be either a let-statement or the
-prefix of a let expression.
-\begin{verbatim}
-
-> stmts :: Bool -> Parser Token ([Statement],Expression) a
-> stmts flat = stmt flat (reqStmts flat) (optStmts flat)
-
-> reqStmts :: Bool -> Parser Token (Statement -> ([Statement],Expression)) a
-> reqStmts flat = (\(sts,e) st -> (st : sts,e)) <$-> semicolon <*> stmts flat
-
-> optStmts :: Bool -> Parser Token (Expression -> ([Statement],Expression)) a
-> optStmts flat = succeed (mk StmtExpr) <.> reqStmts flat
->           `opt` (,) []
-
-> quals :: Bool -> Parser Token [Statement] a
-> quals flat = stmt flat (succeed id) (succeed $ mk StmtExpr) `sepBy1` comma
-
-> stmt :: Bool -> Parser Token (Statement -> a) b
->      -> Parser Token (Expression -> a) b -> Parser Token a b
-> stmt flat stmtCont exprCont = letStmt flat stmtCont exprCont
->                           <|> exprOrBindStmt flat stmtCont exprCont
-
-> letStmt :: Bool -> Parser Token (Statement -> a) b
->         -> Parser Token (Expression -> a) b -> Parser Token a b
-> letStmt flat stmtCont exprCont =
->   token KW_let <-*> layout (valueDecls flat) <**> optExpr
->   where optExpr = flip Let <$-> token KW_in <*> expr flat <.> exprCont
->               <|> succeed StmtDecl <.> stmtCont
-
-> exprOrBindStmt :: Bool -> Parser Token (Statement -> a) b
->                -> Parser Token (Expression -> a) b
->                -> Parser Token a b
-> exprOrBindStmt flat stmtCont exprCont =
->        mk StmtBind <$> constrTerm0 <*-> leftArrow <*> expr flat <**> stmtCont
->   <|?> expr flat <\> token KW_let <**> exprCont
-
-\end{verbatim}
-\paragraph{Literals, identifiers, and (infix) operators}
-\begin{verbatim}
-
-> char :: Parser Token Char a
-> char = cval <$> token CharTok
-
-> int, checkInt :: Parser Token Int a
-> int = ival <$> token IntTok
-> checkInt = int <?> "integer number expected"
-
-> float, checkFloat :: Parser Token Double a
-> float = fval <$> token FloatTok
-> checkFloat = float <?> "floating point number expected"
-
-> integer, checkInteger :: Parser Token Integer a
-> integer = intval <$> token IntegerTok
-> checkInteger = integer <?> "integer number expected"
-
-> string :: Parser Token String a
-> string = sval <$> token StringTok
-
-> tycon, tyvar :: Parser Token Ident a
-> tycon = conId
-> tyvar = varId
-
-> qtycon :: Parser Token QualIdent a
-> qtycon = qConId
-
-> varId, funId, conId, labId :: Parser Token Ident a
-> varId = ident
-> funId = ident
-> conId = ident
-> labId = renameLabel <$> ident
-
-> funSym, conSym :: Parser Token Ident a
-> funSym = sym
-> conSym = sym
-
-> var, fun, con :: Parser Token Ident a
-> var = varId <|> parens (funSym <?> "operator symbol expected")
-> fun = funId <|> parens (funSym <?> "operator symbol expected")
-> con = conId <|> parens (conSym <?> "operator symbol expected")
-
-> funop, conop :: Parser Token Ident a
-> funop = funSym <|> backquotes (funId <?> "operator name expected")
-> conop = conSym <|> backquotes (conId <?> "operator name expected")
-
-> qFunId, qConId, qLabId :: Parser Token QualIdent a
-> qFunId = qIdent
-> qConId = qIdent
-> qLabId = qIdent
-
-> qFunSym, qConSym :: Parser Token QualIdent a
-> qFunSym = qSym
-> qConSym = qSym
-> gConSym = qConSym <|> colon
-
-> qfun, qcon :: Parser Token QualIdent a
-> qfun = qFunId <|> parens (qFunSym <?> "operator symbol expected")
-> qcon = qConId <|> parens (qConSym <?> "operator symbol expected")
-
-> qfunop, qconop, gconop :: Parser Token QualIdent a
-> qfunop = qFunSym <|> backquotes (qFunId <?> "operator name expected")
-> qconop = qConSym <|> backquotes (qConId <?> "operator name expected")
-> gconop = gConSym <|> backquotes (qConId <?> "operator name expected")
-
-> ident :: Parser Token Ident a
-> ident = (\ pos -> mkIdentPosition pos . sval) <$> position <*> 
->        tokens [Id,Id_as,Id_ccall,Id_forall,Id_hiding,
->                Id_interface,Id_primitive,Id_qualified]
-
-> qIdent :: Parser Token QualIdent a
-> qIdent = qualify <$> ident <|> mkQIdent <$> position <*> token QId
->   where mkQIdent p a = qualifyWith (mkMIdent (modul a)) 
->                                    (mkIdentPosition p (sval a))
-
-> mIdent :: Parser Token ModuleIdent a
-> mIdent = mIdent <$> position <*> 
->      tokens [Id,QId,Id_as,Id_ccall,Id_forall,Id_hiding,
->              Id_interface,Id_primitive,Id_qualified]
->   where mIdent p a = addPositionModuleIdent p $ 
->                      mkMIdent (modul a ++ [sval a])
-
-> sym :: Parser Token Ident a
-> sym = (\ pos -> mkIdentPosition pos . sval) <$> position <*> 
->       tokens [Sym,Sym_Dot,Sym_Minus,Sym_MinusDot]
-
-> qSym :: Parser Token QualIdent a
-> qSym = qualify <$> sym <|> mkQIdent <$> position <*> token QSym
->   where mkQIdent p a = qualifyWith (mkMIdent (modul a)) 
->                                    (mkIdentPosition p (sval a))
-
-> colon :: Parser Token QualIdent a
-> colon = (\ p _ -> qualify $ addPositionIdent p consId) <$> 
->         position <*> token Colon
-
-> minus :: Parser Token Ident a
-> minus = (\ p _ -> addPositionIdent p minusId) <$> 
->         position <*> token Sym_Minus
-
-> fminus :: Parser Token Ident a
-> fminus = (\ p _ -> addPositionIdent p fminusId) <$> 
->         position <*> token Sym_MinusDot
-
-> tupleCommas :: Parser Token QualIdent a
-> tupleCommas = (\ p -> qualify . addPositionIdent p . tupleId . succ . length )
->               <$> position <*> many1 comma
-
-\end{verbatim}
-\paragraph{Layout}
-\begin{verbatim}
-
-> layout :: Parser Token a b -> Parser Token a b
-> layout p = layoutOff <-*> bracket leftBraceSemicolon p rightBrace
->        <|> layoutOn <-*> p <*-> (token VRightBrace <|> layoutEnd)
-
-\end{verbatim}
-\paragraph{More combinators}
-\begin{verbatim}
-
-> braces, brackets, parens, backquotes :: Parser Token a b -> Parser Token a b
-> braces p = bracket leftBrace p rightBrace
-> brackets p = bracket leftBracket p rightBracket
-> parens p = bracket leftParen p rightParen
-> backquotes p = bracket backquote p checkBackquote
-
-\end{verbatim}
-\paragraph{Simple token parsers}
-\begin{verbatim}
-
-> token :: Category -> Parser Token Attributes a
-> token c = attr <$> symbol (Token c NoAttributes)
->   where attr (Token _ a) = a
-
-> tokens :: [Category] -> Parser Token Attributes a
-> tokens = foldr1 (<|>) . map token
-
-> tokenOps :: [(Category,a)] -> Parser Token a b
-> tokenOps cs = ops [(Token c NoAttributes,x) | (c,x) <- cs]
-
-> dot, comma, semicolon, bar, equals, binds :: Parser Token Attributes a
-> dot = token Sym_Dot
-> comma = token Comma
-> semicolon = token Semicolon <|> token VSemicolon
-> bar = token Bar
-> equals = token Equals
-> binds = token Binds
-
-> checkBar, checkEquals, checkBinds :: Parser Token Attributes a
-> checkBar = bar <?> "| expected"
-> checkEquals = equals <?> "= expected"
-> checkBinds = binds <?> ":= expected"
-
-> backquote, checkBackquote :: Parser Token Attributes a
-> backquote = token Backquote
-> checkBackquote = backquote <?> "backquote (`) expected"
-
-> leftParen, rightParen :: Parser Token Attributes a
-> leftParen = token LeftParen
-> rightParen = token RightParen
-
-> leftBracket, rightBracket :: Parser Token Attributes a
-> leftBracket = token LeftBracket
-> rightBracket = token RightBracket
-
-> leftBrace, leftBraceSemicolon, rightBrace :: Parser Token Attributes a
-> leftBrace = token LeftBrace
-> leftBraceSemicolon = token LeftBraceSemicolon
-> rightBrace = token RightBrace
-
-> leftArrow :: Parser Token Attributes a
-> leftArrow = token LeftArrow
-
-\end{verbatim}
-\paragraph{Ident}
-\begin{verbatim}
-
-> mkIdentPosition :: Position -> String -> Ident
-> mkIdentPosition pos = addPositionIdent pos . mkIdent
-
-\end{verbatim}
diff --git a/src/Curry/Syntax/Pretty.hs b/src/Curry/Syntax/Pretty.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Syntax/Pretty.hs
@@ -0,0 +1,463 @@
+{- |
+    Module      :  $Header$
+    Description :  A pretty printer for Curry
+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux
+                       2005        Martin Engelke
+                       2011 - 2015 Björn Peemöller
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module implements a pretty printer for Curry expressions. It was
+    derived from the Haskell pretty printer provided in Simon Marlow's
+    Haskell parser.
+-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+module Curry.Syntax.Pretty
+  ( pPrint, pPrintPrec, ppContext, ppInstanceType, ppIMethodImpl
+  , ppIdent, ppQIdent, ppInfixOp, ppQInfixOp, ppMIdent
+  ) where
+
+import Prelude hiding ((<>))
+
+import Curry.Base.Ident
+import Curry.Base.Pretty
+
+import Curry.Syntax.Type
+import Curry.Syntax.Utils (opName)
+
+instance Pretty (Module a) where
+  pPrint (Module _ _ ps m es is ds) = ppModuleHeader ps m es is $$ ppSepBlock ds
+
+ppModuleHeader :: [ModulePragma] -> ModuleIdent -> Maybe ExportSpec
+               -> [ImportDecl] -> Doc
+ppModuleHeader ps m es is
+  | null is   = header
+  | otherwise = header $+$ text "" $+$ vcat (map pPrint is)
+  where header = vcat (map pPrint ps)
+                 $+$ text "module" <+> ppMIdent m
+                 <+> maybePP pPrint es <+> text "where"
+
+instance Pretty ModulePragma where
+  pPrint (LanguagePragma _      exts) =
+    ppPragma "LANGUAGE" $ list $ map pPrint exts
+  pPrint (OptionsPragma  _ tool args) =
+    ppPragma "OPTIONS" $ maybe empty ((text "_" <>) . pPrint) tool <+> text args
+
+ppPragma :: String -> Doc -> Doc
+ppPragma kw doc = text "{-#" <+> text kw <+> doc <+> text "#-}"
+
+instance Pretty Extension where
+  pPrint (KnownExtension   _ e) = text (show e)
+  pPrint (UnknownExtension _ e) = text e
+
+instance Pretty Tool where
+  pPrint (UnknownTool t) = text t
+  pPrint t               = text (show t)
+
+instance Pretty ExportSpec where
+  pPrint (Exporting _ es) = parenList (map pPrint es)
+
+instance Pretty Export where
+  pPrint (Export             _ x) = ppQIdent x
+  pPrint (ExportTypeWith _ tc cs) = ppQIdent tc <> parenList (map ppIdent cs)
+  pPrint (ExportTypeAll     _ tc) = ppQIdent tc <> text "(..)"
+  pPrint (ExportModule       _ m) = text "module" <+> ppMIdent m
+
+instance Pretty ImportDecl where
+  pPrint (ImportDecl _ m q asM is) =
+    text "import" <+> ppQualified q <+> ppMIdent m <+> maybePP ppAs asM
+                  <+> maybePP pPrint is
+    where
+      ppQualified q' = if q' then text "qualified" else empty
+      ppAs m' = text "as" <+> ppMIdent m'
+
+instance Pretty ImportSpec where
+  pPrint (Importing _ is) = parenList (map pPrint is)
+  pPrint (Hiding    _ is) = text "hiding" <+> parenList (map pPrint is)
+
+instance Pretty Import where
+  pPrint (Import             _ x) = ppIdent x
+  pPrint (ImportTypeWith _ tc cs) = ppIdent tc <> parenList (map ppIdent cs)
+  pPrint (ImportTypeAll     _ tc) = ppIdent tc <> text "(..)"
+
+ppBlock :: Pretty a => [a] -> Doc
+ppBlock = vcat . map pPrint
+
+ppSepBlock :: Pretty a => [a] -> Doc
+ppSepBlock = vcat . map (\d -> text "" $+$ pPrint d)
+
+instance Pretty (Decl a) where
+  pPrint (InfixDecl _ fix p ops) = ppPrec fix p <+> list (map ppInfixOp ops)
+  pPrint (DataDecl _ tc tvs cs clss) =
+    sep (ppTypeDeclLhs "data" tc tvs :
+      map indent (zipWith (<+>) (equals : repeat vbar) (map pPrint cs) ++
+                   [ppDeriving clss]))
+  pPrint (ExternalDataDecl _ tc tvs) = ppTypeDeclLhs "external data" tc tvs
+  pPrint (NewtypeDecl _ tc tvs nc clss) =
+    sep (ppTypeDeclLhs "newtype" tc tvs <+> equals :
+      map indent [pPrint nc, ppDeriving clss])
+  pPrint (TypeDecl _ tc tvs ty) =
+    sep [ppTypeDeclLhs "type" tc tvs <+> equals,indent (pPrintPrec 0 ty)]
+  pPrint (TypeSig _ fs ty) =
+    list (map ppIdent fs) <+> text "::" <+> pPrintPrec 0 ty
+  pPrint (FunctionDecl _ _ _ eqs) = vcat (map pPrint eqs)
+  pPrint (ExternalDecl   _ vs) = list (map pPrint vs) <+> text "external"
+  pPrint (PatternDecl _ t rhs) = ppRule (pPrintPrec 0 t) equals rhs
+  pPrint (FreeDecl       _ vs) = list (map pPrint vs) <+> text "free"
+  pPrint (DefaultDecl   _ tys) =
+    text "default" <+> parenList (map (pPrintPrec 0) tys)
+  pPrint (ClassDecl _ _ cx cls clsvar ds) =
+    ppClassInstHead "class" cx (ppIdent cls) (ppIdent clsvar) <+>
+      ppIf (not $ null ds) (text "where") $$
+      ppIf (not $ null ds) (indent $ ppBlock ds)
+  pPrint (InstanceDecl _ _ cx qcls inst ds) =
+    ppClassInstHead "instance" cx (ppQIdent qcls) (ppInstanceType inst) <+>
+      ppIf (not $ null ds) (text "where") $$
+      ppIf (not $ null ds) (indent $ ppBlock ds)
+
+ppClassInstHead :: String -> Context -> Doc -> Doc -> Doc
+ppClassInstHead kw cx cls ty = text kw <+> ppContext cx <+> cls <+> ty
+
+ppContext :: Context -> Doc
+ppContext []  = empty
+ppContext [c] = pPrint c <+> darrow
+ppContext cs  = parenList (map pPrint cs) <+> darrow
+
+instance Pretty Constraint where
+  pPrint (Constraint _ qcls ty) = ppQIdent qcls <+> pPrintPrec 2 ty
+
+ppInstanceType :: InstanceType -> Doc
+ppInstanceType = pPrintPrec 2
+
+ppDeriving :: [QualIdent] -> Doc
+ppDeriving []     = empty
+ppDeriving [qcls] = text "deriving" <+> ppQIdent qcls
+ppDeriving qclss  = text "deriving" <+> parenList (map ppQIdent qclss)
+
+ppPrec :: Infix -> Maybe Precedence -> Doc
+ppPrec fix p = pPrint fix <+> ppPrio p
+  where
+    ppPrio Nothing   = empty
+    ppPrio (Just p') = integer p'
+
+ppTypeDeclLhs :: String -> Ident -> [Ident] -> Doc
+ppTypeDeclLhs kw tc tvs = text kw <+> ppIdent tc <+> hsep (map ppIdent tvs)
+
+instance Pretty ConstrDecl where
+  pPrint (ConstrDecl     _ c tys) =
+    sep [ ppIdent c <+> fsep (map (pPrintPrec 2) tys) ]
+  pPrint (ConOpDecl _ ty1 op ty2) =
+    sep [ pPrintPrec 1 ty1, ppInfixOp op <+> pPrintPrec 1 ty2 ]
+  pPrint (RecordDecl _ c fs)      =
+    sep [ ppIdent c <+> record (list (map pPrint fs)) ]
+
+instance Pretty FieldDecl where
+  pPrint (FieldDecl _ ls ty) = list (map ppIdent ls)
+                            <+> text "::" <+> pPrintPrec 0 ty
+
+instance Pretty NewConstrDecl where
+  pPrint (NewConstrDecl _ c ty) = sep [ppIdent c <+> pPrintPrec 2 ty]
+  pPrint (NewRecordDecl _ c (i,ty)) =
+    sep [ppIdent c <+> record (ppIdent i <+> text "::" <+> pPrintPrec 0 ty)]
+
+ppQuantifiedVars :: [Ident] -> Doc
+ppQuantifiedVars tvs
+  | null tvs = empty
+  | otherwise = text "forall" <+> hsep (map ppIdent tvs) <+> char '.'
+
+instance Pretty (Equation a) where
+  pPrint (Equation _ lhs rhs) = ppRule (pPrint lhs) equals rhs
+
+instance Pretty (Lhs a) where
+  pPrint (FunLhs   _ f ts) =
+    ppIdent f <+> fsep (map (pPrintPrec 2) ts)
+  pPrint (OpLhs _ t1 f t2) =
+    pPrintPrec 1 t1 <+> ppInfixOp f <+> pPrintPrec 1 t2
+  pPrint (ApLhs  _ lhs ts) =
+    parens (pPrint lhs) <+> fsep (map (pPrintPrec 2) ts)
+
+ppRule :: Doc -> Doc -> Rhs a -> Doc
+ppRule lhs eq (SimpleRhs _ _ e ds) =
+  sep [lhs <+> eq, indent (pPrintPrec 0 e)] $$ ppLocalDefs ds
+ppRule lhs eq (GuardedRhs _ _ es ds) =
+  sep [lhs, indent (vcat (map (ppCondExpr eq) es))] $$ ppLocalDefs ds
+
+ppLocalDefs :: [Decl a] -> Doc
+ppLocalDefs ds
+  | null ds   = empty
+  | otherwise = indent (text "where" <+> ppBlock ds)
+
+-- ---------------------------------------------------------------------------
+-- Interfaces
+-- ---------------------------------------------------------------------------
+
+instance Pretty Interface where
+  pPrint (Interface m is ds) =
+    text "interface" <+> ppMIdent m <+> text "where" <+> lbrace
+      $$ vcat (punctuate semi $ map pPrint is ++ map pPrint ds)
+      $$ rbrace
+
+instance Pretty IImportDecl where
+  pPrint (IImportDecl _ m) = text "import" <+> ppMIdent m
+
+instance Pretty IDecl where
+  pPrint (IInfixDecl   _ fix p op) = ppPrec fix (Just p) <+> ppQInfixOp op
+  pPrint (HidingDataDecl _ tc k tvs) =
+    text "hiding" <+> ppITypeDeclLhs "data" tc k tvs
+  pPrint (IDataDecl   _ tc k tvs cs hs) =
+    sep (ppITypeDeclLhs "data" tc k tvs :
+      map indent (zipWith (<+>) (equals : repeat vbar) (map pPrint cs)) ++
+      [indent (ppHiding hs)])
+  pPrint (INewtypeDecl _ tc k tvs nc hs) =
+    sep [ ppITypeDeclLhs "newtype" tc k tvs <+> equals
+        , indent (pPrint nc)
+        , indent (ppHiding hs)
+        ]
+  pPrint (ITypeDecl _ tc k tvs ty) =
+    sep [ppITypeDeclLhs "type" tc k tvs <+> equals,indent (pPrintPrec 0 ty)]
+  pPrint (IFunctionDecl _ f cm a ty) =
+    sep [ ppQIdent f, maybePP (ppPragma "METHOD" . ppIdent) cm
+        , int a, text "::", pPrintPrec 0 ty ]
+  pPrint (HidingClassDecl _ cx qcls k clsvar) = text "hiding" <+>
+    ppClassInstHead "class" cx (ppQIdentWithKind qcls k) (ppIdent clsvar)
+  pPrint (IClassDecl _ cx qcls k clsvar ms hs) =
+    ppClassInstHead "class" cx (ppQIdentWithKind qcls k) (ppIdent clsvar) <+>
+      lbrace $$
+      vcat (punctuate semi $ map (indent . pPrint) ms) $$
+      rbrace <+> ppHiding hs
+  pPrint (IInstanceDecl _ cx qcls inst impls m) =
+    ppClassInstHead "instance" cx (ppQIdent qcls) (ppInstanceType inst) <+>
+      lbrace $$
+      vcat (punctuate semi $ map (indent . ppIMethodImpl) impls) $$
+      rbrace <+> maybePP (ppPragma "MODULE" . ppMIdent) m
+
+ppITypeDeclLhs :: String -> QualIdent -> Maybe KindExpr -> [Ident] -> Doc
+ppITypeDeclLhs kw tc k tvs =
+  text kw <+> ppQIdentWithKind tc k <+> hsep (map ppIdent tvs)
+
+instance Pretty IMethodDecl where
+  pPrint (IMethodDecl _ f a qty) =
+    ppIdent f <+> maybePP int a <+> text "::" <+> pPrintPrec 0 qty
+
+ppIMethodImpl :: IMethodImpl -> Doc
+ppIMethodImpl (f, a) = ppIdent f <+> int a
+
+ppQIdentWithKind :: QualIdent -> Maybe KindExpr -> Doc
+ppQIdentWithKind tc (Just k) =
+  parens $ ppQIdent tc <+> text "::" <+> pPrintPrec 0 k
+ppQIdentWithKind tc Nothing  = ppQIdent tc
+
+ppHiding :: [Ident] -> Doc
+ppHiding hs
+  | null hs   = empty
+  | otherwise = ppPragma "HIDING" $ list $ map ppIdent hs
+
+-- ---------------------------------------------------------------------------
+-- Kinds
+-- ---------------------------------------------------------------------------
+
+instance Pretty KindExpr where
+  pPrintPrec _ Star              = char '*'
+  pPrintPrec p (ArrowKind k1 k2) =
+    parenIf (p > 0) (fsep (ppArrowKind (ArrowKind k1 k2)))
+    where
+      ppArrowKind (ArrowKind k1' k2') =
+        pPrintPrec 1 k1' <+> rarrow : ppArrowKind k2'
+      ppArrowKind k =
+        [pPrintPrec 0 k]
+
+-- ---------------------------------------------------------------------------
+-- Types
+-- ---------------------------------------------------------------------------
+
+instance Pretty QualTypeExpr where
+  pPrint (QualTypeExpr _ cx ty) = ppContext cx <+> pPrintPrec 0 ty
+
+instance Pretty TypeExpr where
+  pPrintPrec _ (ConstructorType _ tc) = ppQIdent tc
+  pPrintPrec p (ApplyType  _ ty1 ty2) = parenIf (p > 1) (ppApplyType ty1 [ty2])
+     where
+      ppApplyType (ApplyType _ ty1' ty2') tys =
+        ppApplyType ty1' (ty2' : tys)
+      ppApplyType ty                      tys =
+        pPrintPrec 1 ty <+> fsep (map (pPrintPrec 2) tys)
+  pPrintPrec _ (VariableType    _ tv) = ppIdent tv
+  pPrintPrec _ (TupleType      _ tys) = parenList (map (pPrintPrec 0) tys)
+  pPrintPrec _ (ListType        _ ty) = brackets (pPrintPrec 0 ty)
+  pPrintPrec p (ArrowType  spi ty1 ty2) = parenIf (p > 0)
+    (fsep (ppArrowType (ArrowType spi ty1 ty2)))
+    where
+      ppArrowType (ArrowType _ ty1' ty2') =
+        pPrintPrec 1 ty1' <+> rarrow : ppArrowType ty2'
+      ppArrowType ty                      =
+        [pPrintPrec 0 ty]
+  pPrintPrec _ (ParenType       _ ty) = parens (pPrintPrec 0 ty)
+  pPrintPrec p (ForallType   _ vs ty)
+    | null vs   = pPrintPrec p ty
+    | otherwise = parenIf (p > 0) $ ppQuantifiedVars vs <+> pPrintPrec 0 ty
+
+-- ---------------------------------------------------------------------------
+-- Literals
+-- ---------------------------------------------------------------------------
+
+instance Pretty Literal where
+  pPrint (Char   c) = text (show c)
+  pPrint (Int    i) = integer i
+  pPrint (Float  f) = double f
+  pPrint (String s) = text (show s)
+
+-- ---------------------------------------------------------------------------
+-- Patterns
+-- ---------------------------------------------------------------------------
+
+instance Pretty (Pattern a) where
+  pPrintPrec p (LiteralPattern _ _ l) =
+    parenIf (p > 1 && isNegative l) (pPrint l)
+    where
+      isNegative (Char   _) = False
+      isNegative (Int    i) = i < 0
+      isNegative (Float  f) = f < 0.0
+      isNegative (String _) = False
+  pPrintPrec p (NegativePattern        _ _ l) = parenIf (p > 1)
+    (ppInfixOp minusId <> pPrint l)
+  pPrintPrec _ (VariablePattern        _ _ v) = ppIdent v
+  pPrintPrec p (ConstructorPattern  _ _ c ts) = parenIf (p > 1 && not (null ts))
+    (ppQIdent c <+> fsep (map (pPrintPrec 2) ts))
+  pPrintPrec p (InfixPattern     _ _ t1 c t2) = parenIf (p > 0)
+    (sep [pPrintPrec 1 t1 <+> ppQInfixOp c, indent (pPrintPrec 0 t2)])
+  pPrintPrec _ (ParenPattern             _ t) = parens (pPrintPrec 0 t)
+  pPrintPrec _ (TuplePattern            _ ts) =
+    parenList (map (pPrintPrec 0) ts)
+  pPrintPrec _ (ListPattern           _ _ ts) =
+    bracketList (map (pPrintPrec 0) ts)
+  pPrintPrec _ (AsPattern              _ v t) =
+    ppIdent v <> char '@' <> pPrintPrec 2 t
+  pPrintPrec _ (LazyPattern              _ t) = char '~' <> pPrintPrec 2 t
+  pPrintPrec p (FunctionPattern     _ _ f ts) = parenIf (p > 1 && not (null ts))
+    (ppQIdent f <+> fsep (map (pPrintPrec 2) ts))
+  pPrintPrec p (InfixFuncPattern _ _ t1 f t2) = parenIf (p > 0)
+    (sep [pPrintPrec 1 t1 <+> ppQInfixOp f, indent (pPrintPrec 0 t2)])
+  pPrintPrec p (RecordPattern       _ _ c fs) = parenIf (p > 1)
+    (ppQIdent c <+> record (list (map pPrint fs)))
+
+instance Pretty a => Pretty (Field a) where
+  pPrint (Field _ l t) = ppQIdent l <+> equals <+> pPrintPrec 0 t
+
+-- ---------------------------------------------------------------------------
+-- Expressions
+-- ---------------------------------------------------------------------------
+
+ppCondExpr :: Doc -> CondExpr a -> Doc
+ppCondExpr eq (CondExpr _ g e) =
+  vbar <+> sep [pPrintPrec 0 g <+> eq, indent (pPrintPrec 0 e)]
+
+instance Pretty (Expression a) where
+  pPrintPrec _ (Literal        _ _ l) = pPrint l
+  pPrintPrec _ (Variable       _ _ v) = ppQIdent v
+  pPrintPrec _ (Constructor    _ _ c) = ppQIdent c
+  pPrintPrec _ (Paren            _ e) = parens (pPrintPrec 0 e)
+  pPrintPrec p (Typed        _ e ty)  =
+    parenIf (p > 0) (pPrintPrec 0 e <+> text "::" <+> pPrintPrec 0 ty)
+  pPrintPrec _ (Tuple           _ es) = parenList (map (pPrintPrec 0) es)
+  pPrintPrec _ (List          _ _ es) = bracketList (map (pPrintPrec 0) es)
+  pPrintPrec _ (ListCompr     _ e qs) =
+    brackets (pPrintPrec 0 e <+> vbar <+> list (map pPrint qs))
+  pPrintPrec _ (EnumFrom              _ e) =
+    brackets (pPrintPrec 0 e <+> text "..")
+  pPrintPrec _ (EnumFromThen      _ e1 e2) =
+    brackets (pPrintPrec 0 e1 <> comma <+> pPrintPrec 0 e2 <+> text "..")
+  pPrintPrec _ (EnumFromTo        _ e1 e2) =
+    brackets (pPrintPrec 0 e1 <+> text ".." <+> pPrintPrec 0 e2)
+  pPrintPrec _ (EnumFromThenTo _ e1 e2 e3) =
+    brackets (pPrintPrec 0 e1 <> comma <+> pPrintPrec 0 e2
+      <+> text ".." <+> pPrintPrec 0 e3)
+  pPrintPrec p (UnaryMinus          _ e) =
+    parenIf (p > 1) (ppInfixOp minusId <> pPrintPrec 1 e)
+  pPrintPrec p (Apply           _ e1 e2) =
+    parenIf (p > 1) (sep [pPrintPrec 1 e1, indent (pPrintPrec 2 e2)])
+  pPrintPrec p (InfixApply   _ e1 op e2) = parenIf (p > 0)
+    (sep [pPrintPrec 1 e1 <+> ppQInfixOp (opName op), indent (pPrintPrec 1 e2)])
+  pPrintPrec _ (LeftSection      _ e op) =
+    parens (pPrintPrec 1 e <+> ppQInfixOp (opName op))
+  pPrintPrec _ (RightSection     _ op e) =
+    parens (ppQInfixOp (opName op) <+> pPrintPrec 1 e)
+  pPrintPrec p (Lambda            _ t e) = parenIf (p > 0) $
+    sep [backsl <> fsep (map (pPrintPrec 2) t) <+> rarrow,
+         indent (pPrintPrec 0 e)]
+  pPrintPrec p (Let            _ _ ds e) = parenIf (p > 0)
+    (sep [text "let" <+> ppBlock ds, text "in" <+> pPrintPrec 0 e])
+  pPrintPrec p (Do            _ _ sts e) = parenIf (p > 0)
+    (text "do" <+> (vcat (map pPrint sts) $$ pPrintPrec 0 e))
+  pPrintPrec p (IfThenElse   _ e1 e2 e3) = parenIf (p > 0)
+    (text "if" <+>
+     sep [pPrintPrec 0 e1,
+          text "then" <+> pPrintPrec 0 e2,
+          text "else" <+> pPrintPrec 0 e3])
+  pPrintPrec p (Case    _ _ ct e alts) = parenIf (p > 0)
+           (pPrint ct <+> pPrintPrec 0 e <+> text "of" $$
+            indent (vcat (map pPrint alts)))
+  pPrintPrec p (Record     _ _ c fs) = parenIf (p > 0)
+    (ppQIdent c <+> record (list (map pPrint fs)))
+  pPrintPrec _ (RecordUpdate _ e fs) =
+    pPrintPrec 0 e <+> record (list (map pPrint fs))
+
+instance Pretty (Statement a) where
+  pPrint (StmtExpr   _ e) = pPrintPrec 0 e
+  pPrint (StmtBind _ t e) =
+    sep [pPrintPrec 0 t <+> larrow, indent (pPrintPrec 0 e)]
+  pPrint (StmtDecl  _ _ ds) = text "let" <+> ppBlock ds
+
+instance Pretty CaseType where
+  pPrint Rigid = text "case"
+  pPrint Flex  = text "fcase"
+
+instance Pretty (Alt a) where
+  pPrint (Alt _ t rhs) = ppRule (pPrintPrec 0 t) rarrow rhs
+
+instance Pretty (Var a) where
+  pPrint (Var _ ident) = ppIdent ident
+
+instance Pretty (InfixOp a) where
+  pPrint (InfixOp     _ op) = ppQInfixOp op
+  pPrint (InfixConstr _ op) = ppQInfixOp op
+
+-- ---------------------------------------------------------------------------
+-- Names
+-- ---------------------------------------------------------------------------
+
+-- |Pretty print an identifier
+ppIdent :: Ident -> Doc
+ppIdent x = parenIf (isInfixOp x) (text (idName x))
+
+ppQIdent :: QualIdent -> Doc
+ppQIdent x = parenIf (isQInfixOp x) (text (qualName x))
+
+ppInfixOp :: Ident -> Doc
+ppInfixOp x = bquotesIf (not (isInfixOp x)) (text (idName x))
+
+ppQInfixOp :: QualIdent -> Doc
+ppQInfixOp x = bquotesIf (not (isQInfixOp x)) (text (qualName x))
+
+ppMIdent :: ModuleIdent -> Doc
+ppMIdent m = text (moduleName m)
+
+-- ---------------------------------------------------------------------------
+-- Print printing utilities
+-- ---------------------------------------------------------------------------
+
+indent :: Doc -> Doc
+indent = nest 2
+
+parenList :: [Doc] -> Doc
+parenList = parens . list
+
+record :: Doc -> Doc
+record doc | isEmpty doc = braces empty
+           | otherwise   = braces $ space <> doc <> space
+
+bracketList :: [Doc] -> Doc
+bracketList = brackets . list
diff --git a/src/Curry/Syntax/Pretty.lhs b/src/Curry/Syntax/Pretty.lhs
deleted file mode 100644
--- a/src/Curry/Syntax/Pretty.lhs
+++ /dev/null
@@ -1,368 +0,0 @@
-
-% $Id: CurryPP.lhs,v 1.50 2004/02/15 22:10:27 wlux Exp $
-%
-% Copyright (c) 1999-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{CurryPP.lhs}
-\section{A Pretty Printer for Curry}\label{sec:CurryPP}
-This module implements a pretty printer for Curry expressions. It was
-derived from the Haskell pretty printer provided in Simon Marlow's
-Haskell parser.
-\begin{verbatim}
-
-> module Curry.Syntax.Pretty where
-
-> import Text.PrettyPrint.HughesPJ
-
-> import Curry.Base.Ident
-> import Curry.Syntax.Type
-
-
-\end{verbatim}
-Pretty print a module
-\begin{verbatim}
-
-> ppModule :: Module -> Doc
-> ppModule (Module m es ds) = ppModuleHeader m es $$ ppBlock ds
-
-\end{verbatim}
-Module header
-\begin{verbatim}
-
-> ppModuleHeader :: ModuleIdent -> Maybe ExportSpec -> Doc
-> ppModuleHeader m es =
->   text "module" <+> ppMIdent m <+> maybePP ppExportSpec es <+> text "where"
-
-> ppExportSpec :: ExportSpec -> Doc
-> ppExportSpec (Exporting _ es) = parenList (map ppExport es)
-
-> ppExport :: Export -> Doc
-> ppExport (Export x) = ppQIdent x
-> ppExport (ExportTypeWith tc cs) = ppQIdent tc <> parenList (map ppIdent cs)
-> ppExport (ExportTypeAll tc) = ppQIdent tc <> text "(..)"
-> ppExport (ExportModule m) = text "module" <+> ppMIdent m
-
-\end{verbatim}
-Declarations
-\begin{verbatim}
-
-> ppBlock :: [Decl] -> Doc
-> ppBlock = vcat . map ppDecl
-
-> ppDecl :: Decl -> Doc
-> ppDecl (ImportDecl _ m q asM is) =
->   text "import" <+> ppQualified q <+> ppMIdent m <+> maybePP ppAs asM
->                 <+> maybePP ppImportSpec is
->   where ppQualified q = if q then text "qualified" else empty
->         ppAs m = text "as" <+> ppMIdent m
-> ppDecl (InfixDecl _ fix p ops) = ppPrec fix p <+> list (map ppInfixOp ops)
-> ppDecl (DataDecl _ tc tvs cs) =
->   sep (ppTypeDeclLhs "data" tc tvs :
->        map indent (zipWith (<+>) (equals : repeat vbar) (map ppConstr cs)))
-> ppDecl (NewtypeDecl _ tc tvs nc) =
->   sep [ppTypeDeclLhs "newtype" tc tvs <+> equals,indent (ppNewConstr nc)]
-> ppDecl (TypeDecl _ tc tvs ty) =
->   sep [ppTypeDeclLhs "type" tc tvs <+> equals,indent (ppTypeExpr 0 ty)]
-> ppDecl (TypeSig _ fs ty) =
->   list (map ppIdent fs) <+> text "::" <+> ppTypeExpr 0 ty
-> ppDecl (EvalAnnot _ fs ev) =
->   list (map ppIdent fs) <+> text "eval" <+> ppEval ev
->   where ppEval EvalRigid = text "rigid"
->         ppEval EvalChoice = text "choice"
-> ppDecl (FunctionDecl _ _ eqs) = vcat (map ppEquation eqs)
-> ppDecl (ExternalDecl p cc impent f ty) =
->   sep [text "external" <+> ppCallConv cc <+> maybePP (text . show) impent,
->        indent (ppDecl (TypeSig p [f] ty))]
->   where ppCallConv CallConvPrimitive = text "primitive"
->         ppCallConv CallConvCCall = text "ccall"
-> ppDecl (FlatExternalDecl _ fs) = list (map ppIdent fs) <+> text "external"
-> ppDecl (PatternDecl _ t rhs) = ppRule (ppConstrTerm 0 t) equals rhs
-> ppDecl (ExtraVariables _ vs) = list (map ppIdent vs) <+> text "free"
-
-> ppImportSpec :: ImportSpec -> Doc
-> ppImportSpec (Importing _ is) = parenList (map ppImport is)
-> ppImportSpec (Hiding _ is) = text "hiding" <+> parenList (map ppImport is)
-
-> ppImport :: Import -> Doc
-> ppImport (Import x) = ppIdent x
-> ppImport (ImportTypeWith tc cs) = ppIdent tc <> parenList (map ppIdent cs)
-> ppImport (ImportTypeAll tc) = ppIdent tc <> text "(..)"
-
-> ppPrec :: Infix -> Integer -> Doc
-> ppPrec fix p = ppAssoc fix <+> ppPrio p
->   where ppAssoc InfixL = text "infixl"
->         ppAssoc InfixR = text "infixr"
->         ppAssoc Infix = text "infix"
->         ppPrio p = if p < 0 then empty else integer p
-
-> ppTypeDeclLhs :: String -> Ident -> [Ident] -> Doc
-> ppTypeDeclLhs kw tc tvs = text kw <+> ppIdent tc <+> hsep (map ppIdent tvs)
-
-> ppConstr :: ConstrDecl -> Doc
-> ppConstr (ConstrDecl _ tvs c tys) =
->   sep [ppExistVars tvs,ppIdent c <+> fsep (map (ppTypeExpr 2) tys)]
-> ppConstr (ConOpDecl _ tvs ty1 op ty2) =
->   sep [ppExistVars tvs,ppTypeExpr 1 ty1,ppInfixOp op <+> ppTypeExpr 1 ty2]
-
-> ppNewConstr :: NewConstrDecl -> Doc
-> ppNewConstr (NewConstrDecl _ tvs c ty) =
->   sep [ppExistVars tvs,ppIdent c <+> ppTypeExpr 2 ty]
-
-> ppExistVars :: [Ident] -> Doc
-> ppExistVars tvs
->   | null tvs = empty
->   | otherwise = text "forall" <+> hsep (map ppIdent tvs) <+> char '.'
-
-> ppEquation :: Equation -> Doc
-> ppEquation (Equation _ lhs rhs) = ppRule (ppLhs lhs) equals rhs
-
-> ppLhs :: Lhs -> Doc
-> ppLhs (FunLhs f ts) = ppIdent f <+> fsep (map (ppConstrTerm 2) ts)
-> ppLhs (OpLhs t1 f t2) =
->   ppConstrTerm 1 t1 <+> ppInfixOp f <+> ppConstrTerm 1 t2
-> ppLhs (ApLhs lhs ts) = parens (ppLhs lhs) <+> fsep (map (ppConstrTerm 2) ts)
-
-> ppRule :: Doc -> Doc -> Rhs -> Doc
-> ppRule lhs eq (SimpleRhs _ e ds) =
->   sep [lhs <+> eq,indent (ppExpr 0 e)] $$ ppLocalDefs ds
-> ppRule lhs eq (GuardedRhs es ds) =
->   sep [lhs,indent (vcat (map (ppCondExpr eq) es))] $$ ppLocalDefs ds
-
-> ppLocalDefs :: [Decl] -> Doc
-> ppLocalDefs ds
->   | null ds = empty
->   | otherwise = indent (text "where" <+> ppBlock ds)
-
-\end{verbatim}
-Interfaces
-\begin{verbatim}
-
-> ppInterface :: Interface -> Doc
-> ppInterface (Interface m ds) =
->   text "interface" <+> ppMIdent m <+> text "where" <+> lbrace
->     $$ vcat (punctuate semi (map ppIDecl ds)) $$ rbrace
-
-> ppIDecl :: IDecl -> Doc
-> ppIDecl (IImportDecl _ m) = text "import" <+> ppMIdent m
-> ppIDecl (IInfixDecl _ fix p op) = ppPrec fix p <+> ppQInfixOp op
-> ppIDecl (HidingDataDecl _ tc tvs) =
->   text "hiding" <+> ppITypeDeclLhs "data" (qualify tc) tvs
-> ppIDecl (IDataDecl _ tc tvs cs) =
->   sep (ppITypeDeclLhs "data" tc tvs :
->        map indent (zipWith (<+>) (equals : repeat vbar) (map ppIConstr cs)))
->   where ppIConstr = maybe (char '_') ppConstr
-> ppIDecl (INewtypeDecl _ tc tvs nc) =
->   sep [ppITypeDeclLhs "newtype" tc tvs <+> equals,indent (ppNewConstr nc)]
-> ppIDecl (ITypeDecl _ tc tvs ty) =
->   sep [ppITypeDeclLhs "type" tc tvs <+> equals,indent (ppTypeExpr 0 ty)]
-> ppIDecl (IFunctionDecl _ f _ ty) = ppQIdent f <+> text "::" <+> ppTypeExpr 0 ty
-
-> ppITypeDeclLhs :: String -> QualIdent -> [Ident] -> Doc
-> ppITypeDeclLhs kw tc tvs = text kw <+> ppQIdent tc <+> hsep (map ppIdent tvs)
-
-\end{verbatim}
-Types
-\begin{verbatim}
-
-> ppTypeExpr :: Int -> TypeExpr -> Doc
-> ppTypeExpr p (ConstructorType tc tys) =
->   parenExp (p > 1 && not (null tys))
->            (ppQIdent tc <+> fsep (map (ppTypeExpr 2) tys))
-> ppTypeExpr _ (VariableType tv) = ppIdent tv
-> ppTypeExpr _ (TupleType tys) = parenList (map (ppTypeExpr 0) tys)
-> ppTypeExpr _ (ListType ty) = brackets (ppTypeExpr 0 ty)
-> ppTypeExpr p (ArrowType ty1 ty2) =
->   parenExp (p > 0) (fsep (ppArrowType (ArrowType ty1 ty2)))
->   where ppArrowType (ArrowType ty1 ty2) =
->           ppTypeExpr 1 ty1 <+> rarrow : ppArrowType ty2
->         ppArrowType ty = [ppTypeExpr 0 ty]
-> ppTypeExpr p (RecordType fs rty) = 
->   braces (list (map ppTypedField fs) 
->           <> maybe empty (\ty -> space <> char '|' <+> ppTypeExpr 0 ty) rty)
->   where
->   ppTypedField (ls,ty) = 
->     list (map ppIdent ls) <> text "::" <> ppTypeExpr 0 ty
-
-
-
-\end{verbatim}
-Literals
-\begin{verbatim}
-
-> ppLiteral :: Literal -> Doc
-> ppLiteral (Char _ c)   = text (show c)
-> ppLiteral (Int _ i)    = integer i
-> ppLiteral (Float _ f)  = double f
-> ppLiteral (String _ s) = text (show s)
-
-\end{verbatim}
-Patterns
-\begin{verbatim}
-
-> ppConstrTerm :: Int -> ConstrTerm -> Doc
-> ppConstrTerm p (LiteralPattern l) =
->   parenExp (p > 1 && isNegative l) (ppLiteral l)
->   where isNegative (Char _ _)   = False
->         isNegative (Int _ i)    = i < 0
->         isNegative (Float _ f)  = f < 0.0
->         isNegative (String _ _) = False
-> ppConstrTerm p (NegativePattern op l) =
->   parenExp (p > 1) (ppInfixOp op <> ppLiteral l)
-> ppConstrTerm _ (VariablePattern v) = ppIdent v
-> ppConstrTerm p (ConstructorPattern c ts) =
->   parenExp (p > 1 && not (null ts))
->            (ppQIdent c <+> fsep (map (ppConstrTerm 2) ts))
-> ppConstrTerm p (InfixPattern t1 c t2) =
->   parenExp (p > 0)
->            (sep [ppConstrTerm 1 t1 <+> ppQInfixOp c,
->                  indent (ppConstrTerm 0 t2)])
-> ppConstrTerm _ (ParenPattern t) = parens (ppConstrTerm 0 t)
-> ppConstrTerm _ (TuplePattern _ ts) = parenList (map (ppConstrTerm 0) ts)
-> ppConstrTerm _ (ListPattern _ ts) = bracketList (map (ppConstrTerm 0) ts)
-> ppConstrTerm _ (AsPattern v t) = ppIdent v <> char '@' <> ppConstrTerm 2 t
-> ppConstrTerm _ (LazyPattern _ t) = char '~' <> ppConstrTerm 2 t
-> ppConstrTerm p (FunctionPattern f ts) =
->   parenExp (p > 1 && not (null ts))
->            (ppQIdent f <+> fsep (map (ppConstrTerm 2) ts))
-> ppConstrTerm p (InfixFuncPattern t1 f t2) =
->   parenExp (p > 0)
->            (sep [ppConstrTerm 1 t1 <+> ppQInfixOp f,
->                  indent (ppConstrTerm 0 t2)])
-> ppConstrTerm p (RecordPattern fs rt) =
->   braces (list (map ppFieldPatt fs)
->          <> (maybe empty (\t -> space <> char '|' <+> ppConstrTerm 0 t) rt))
-
-> ppFieldPatt :: Field ConstrTerm -> Doc
-> ppFieldPatt (Field _ l t) = ppIdent l <> equals <> ppConstrTerm 0 t
-
-\end{verbatim}
-Expressions
-\begin{verbatim}
-
-> ppCondExpr :: Doc -> CondExpr -> Doc
-> ppCondExpr eq (CondExpr _ g e) =
->   vbar <+> sep [ppExpr 0 g <+> eq,indent (ppExpr 0 e)]
-
-> ppExpr :: Int -> Expression -> Doc
-> ppExpr _ (Literal l) = ppLiteral l
-> ppExpr _ (Variable v) = ppQIdent v
-> ppExpr _ (Constructor c) = ppQIdent c
-> ppExpr _ (Paren e) = parens (ppExpr 0 e)
-> ppExpr p (Typed e ty) =
->   parenExp (p > 0) (ppExpr 0 e <+> text "::" <+> ppTypeExpr 0 ty)
-> ppExpr _ (Tuple _ es) = parenList (map (ppExpr 0) es)
-> ppExpr _ (List _ es) = bracketList (map (ppExpr 0) es)
-> ppExpr _ (ListCompr _ e qs) =
->   brackets (ppExpr 0 e <+> vbar <+> list (map ppStmt qs))
-> ppExpr _ (EnumFrom e) = brackets (ppExpr 0 e <+> text "..")
-> ppExpr _ (EnumFromThen e1 e2) =
->   brackets (ppExpr 0 e1 <> comma <+> ppExpr 0 e2 <+> text "..")
-> ppExpr _ (EnumFromTo e1 e2) =
->   brackets (ppExpr 0 e1 <+> text ".." <+> ppExpr 0 e2)
-> ppExpr _ (EnumFromThenTo e1 e2 e3) =
->   brackets (ppExpr 0 e1 <> comma <+> ppExpr 0 e2
->               <+> text ".." <+> ppExpr 0 e3)
-> ppExpr p (UnaryMinus op e) = parenExp (p > 1) (ppInfixOp op <> ppExpr 1 e)
-> ppExpr p (Apply e1 e2) =
->   parenExp (p > 1) (sep [ppExpr 1 e1,indent (ppExpr 2 e2)])
-> ppExpr p (InfixApply e1 op e2) =
->   parenExp (p > 0) (sep [ppExpr 1 e1 <+> ppQInfixOp (opName op),
->                          indent (ppExpr 1 e2)])
-> ppExpr _ (LeftSection e op) = parens (ppExpr 1 e <+> ppQInfixOp (opName op))
-> ppExpr _ (RightSection op e) = parens (ppQInfixOp (opName op) <+> ppExpr 1 e)
-> ppExpr p (Lambda _ t e) =
->   parenExp (p > 0)
->            (sep [backsl <> fsep (map (ppConstrTerm 2) t) <+> rarrow,
->                  indent (ppExpr 0 e)])
-> ppExpr p (Let ds e) =
->   parenExp (p > 0)
->            (sep [text "let" <+> ppBlock ds <+> text "in",ppExpr 0 e])
-> ppExpr p (Do sts e) =
->   parenExp (p > 0) (text "do" <+> (vcat (map ppStmt sts) $$ ppExpr 0 e))
-> ppExpr p (IfThenElse _ e1 e2 e3) =
->   parenExp (p > 0)
->            (text "if" <+>
->             sep [ppExpr 0 e1,
->                  text "then" <+> ppExpr 0 e2,
->                  text "else" <+> ppExpr 0 e3])
-> ppExpr p (Case _ e alts) =
->   parenExp (p > 0)
->            (text "case" <+> ppExpr 0 e <+> text "of" $$
->             indent (vcat (map ppAlt alts)))
-> ppExpr p (RecordConstr fs) =
->   braces (list (map (ppFieldExpr equals) fs))
-> ppExpr p (RecordSelection e l) =
->   parenExp (p > 0)
->            (ppExpr 1 e <+> text "->" <+> ppIdent l)
-> ppExpr p (RecordUpdate fs e) =
->   braces (list (map (ppFieldExpr (text ":=")) fs)
->          <+> char '|' <+> ppExpr 0 e)
-
-> ppStmt :: Statement -> Doc
-> ppStmt (StmtExpr _ e) = ppExpr 0 e
-> ppStmt (StmtBind _ t e) = sep [ppConstrTerm 0 t <+> larrow,indent (ppExpr 0 e)]
-> ppStmt (StmtDecl ds) = text "let" <+> ppBlock ds
-
-> ppAlt :: Alt -> Doc
-> ppAlt (Alt _ t rhs) = ppRule (ppConstrTerm 0 t) rarrow rhs
-
-> ppFieldExpr :: Doc -> Field Expression -> Doc
-> ppFieldExpr comb (Field _ l e) = ppIdent l <> comb <> ppExpr 0 e
-
-> ppOp :: InfixOp -> Doc
-> ppOp (InfixOp op) = ppQInfixOp op
-> ppOp (InfixConstr op) = ppQInfixOp op
-
-\end{verbatim}
-
-Names
-\begin{verbatim}
-
-> ppIdent :: Ident -> Doc
-> ppIdent x = parenExp (isInfixOp x) (text (name x))
-
-> ppQIdent :: QualIdent -> Doc
-> ppQIdent x = parenExp (isQInfixOp x) (text (qualName x))
-
-> ppInfixOp :: Ident -> Doc
-> ppInfixOp x = backQuoteExp (not (isInfixOp x)) (text (name x))
-
-> ppQInfixOp :: QualIdent -> Doc
-> ppQInfixOp x = backQuoteExp (not (isQInfixOp x)) (text (qualName x))
-
-> ppMIdent :: ModuleIdent -> Doc
-> ppMIdent m = text (moduleName m)
-
-\end{verbatim}
-Print printing utilities
-\begin{verbatim}
-
-> indent :: Doc -> Doc
-> indent = nest 2
-
-> maybePP :: (a -> Doc) -> Maybe a -> Doc
-> maybePP pp = maybe empty pp
-
-> parenExp :: Bool -> Doc -> Doc
-> parenExp b doc = if b then parens doc else doc
-
-> backQuoteExp :: Bool -> Doc -> Doc
-> backQuoteExp b doc = if b then backQuote <> doc <> backQuote else doc
-
-> list, parenList, bracketList, braceList :: [Doc] -> Doc
-> list = fsep . punctuate comma
-> parenList = parens . list
-> bracketList = brackets . list
-> braceList = braces . list
-
-> backQuote,backsl,vbar,rarrow,larrow :: Doc
-> backQuote = char '`'
-> backsl = char '\\'
-> vbar = char '|'
-> rarrow = text "->"
-> larrow = text "<-"
-
-\end{verbatim}
diff --git a/src/Curry/Syntax/ShowModule.hs b/src/Curry/Syntax/ShowModule.hs
--- a/src/Curry/Syntax/ShowModule.hs
+++ b/src/Curry/Syntax/ShowModule.hs
@@ -1,462 +1,732 @@
---- Transform a CurrySyntax module into a string representation without any
---- pretty printing.
---- Behaves like a derived Show instance even on parts with a specific one.
---- 
---- @author Sebastian Fischer (sebf@informatik.uni-kiel.de)
---- @version December 2008
---- bug fixed by bbr
+{- |
+    Module      :  $Header$
+    Copyright   :  (c) 2008        Sebastian Fischer
+                       2011 - 2015 Björn Peemöller
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
 
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
 
-module Curry.Syntax.ShowModule ( showModule ) where
+    Transform a CurrySyntax module into a string representation without any
+    pretty printing.
 
+    Behaves like a derived Show instance even on parts with a specific one.
+-}
+module Curry.Syntax.ShowModule (showModule) where
+
 import Curry.Base.Ident
 import Curry.Base.Position
+import Curry.Base.Span
+import Curry.Base.SpanInfo
+
 import Curry.Syntax.Type
 
-showModule :: Module -> String
+-- |Show a Curry module like by an devired 'Show' instance
+showModule :: Show a => Module a -> String
 showModule m = showsModule m "\n"
 
-showsModule :: Module -> ShowS
-showsModule (Module mident espec decls)
+showsModule :: Show a => Module a -> ShowS
+showsModule (Module spi li ps mident espec imps decls)
   = showsString "Module "
+  . showsLayoutInfo li . space
+  . showsSpanInfo spi . space
+  . showsList (\p -> showsPragma p . newline) ps . space
   . showsModuleIdent mident . newline
   . showsMaybe showsExportSpec espec . newline
+  . showsList (\i -> showsImportDecl i . newline) imps
   . showsList (\d -> showsDecl d . newline) decls
 
-showsPosition :: Position -> ShowS
-showsPosition Position{line=row,column=col} = showsPair shows shows (row,col)
--- showsPosition (Position file row col)
---   = showsString "(Position "
---   . shows file . space
---   . shows row . space
---   . shows col
---   . showsString ")"
+showsPragma :: ModulePragma -> ShowS
+showsPragma (LanguagePragma pos exts)
+  = showsString "(LanguagePragma "
+  . showsSpanInfo pos . space
+  . showsList showsExtension exts
+  . showsString ")"
+showsPragma (OptionsPragma pos mbTool args)
+  = showsString "(OptionsPragma "
+  . showsSpanInfo pos . space
+  . showsMaybe shows mbTool
+  . shows args
+  . showsString ")"
 
+showsExtension :: Extension -> ShowS
+showsExtension (KnownExtension p e)
+  = showsString "(KnownExtension "
+  . showsSpanInfo p . space
+  . shows e
+  . showString ")"
+showsExtension (UnknownExtension p s)
+  = showsString "(UnknownExtension "
+  . showsSpanInfo p . space
+  . shows s
+  . showString ")"
+
 showsExportSpec :: ExportSpec -> ShowS
 showsExportSpec (Exporting pos exports)
   = showsString "(Exporting "
-  . showsPosition pos . space
+  . showsSpanInfo pos . space
   . showsList showsExport exports
   . showsString ")"
 
 showsExport :: Export -> ShowS
-showsExport (Export qident)
-  = showsString "(Export " . showsQualIdent qident . showsString ")"
-showsExport (ExportTypeWith qident ids)
+showsExport (Export spi qident)
+  = showsString "(Export "
+  . showsSpanInfo spi . space
+  . showsQualIdent qident
+  . showsString ")"
+showsExport (ExportTypeWith spi qident ids)
   = showsString "(ExportTypeWith "
+  . showsSpanInfo spi . space
   . showsQualIdent qident . space
   . showsList showsIdent ids
   . showsString ")"
-showsExport (ExportTypeAll qident)
-  = showsString "(ExportTypeAll " . showsQualIdent qident . showsString ")"
-showsExport (ExportModule m) 
-  = showsString "(ExportModule " . showsModuleIdent m . showChar ')'
+showsExport (ExportTypeAll spi qident)
+  = showsString "(ExportTypeAll "
+  . showsSpanInfo spi . space
+  . showsQualIdent qident
+  . showsString ")"
+showsExport (ExportModule spi m)
+  = showsString "(ExportModule "
+  . showsSpanInfo spi . space
+  . showsModuleIdent m
+  . showsString ")"
 
+showsImportDecl :: ImportDecl -> ShowS
+showsImportDecl (ImportDecl spi mident quali mmident mimpspec)
+  = showsString "(ImportDecl "
+  . showsSpanInfo spi . space
+  . showsModuleIdent mident . space
+  . shows quali . space
+  . showsMaybe showsModuleIdent mmident . space
+  . showsMaybe showsImportSpec mimpspec
+  . showsString ")"
+
 showsImportSpec :: ImportSpec -> ShowS
-showsImportSpec (Importing pos imports)
+showsImportSpec (Importing spi imports)
   = showsString "(Importing "
-  . showsPosition pos . space
+  . showsSpanInfo spi . space
   . showsList showsImport imports
   . showsString ")"
-showsImportSpec (Hiding pos imports)
+showsImportSpec (Hiding spi imports)
   = showsString "(Hiding "
-  . showsPosition pos . space
+  . showsSpanInfo spi . space
   . showsList showsImport imports
   . showsString ")"
 
 showsImport :: Import -> ShowS
-showsImport (Import ident)
-  = showsString "(Import " . showsIdent ident . showsString ")"
-showsImport (ImportTypeWith ident idents)
+showsImport (Import spi ident)
+  = showsString "(Import "
+  . showsSpanInfo spi . space
+  . showsIdent ident
+  . showsString ")"
+showsImport (ImportTypeWith spi ident idents)
   = showsString "(ImportTypeWith "
+  . showsSpanInfo spi . space
   . showsIdent ident . space
   . showsList showsIdent idents
   . showsString ")"
-showsImport (ImportTypeAll ident)
-  = showsString "(ImportTypeAll " . showsIdent ident . showsString ")"
-
-showsDecl :: Decl -> ShowS
-showsDecl (ImportDecl pos mident quali mmident mimpspec)
-  = showsString "(ImportDecl "
-  . showsPosition pos . space
-  . showsModuleIdent mident . space
-  . shows quali . space
-  . showsMaybe showsModuleIdent mmident . space
-  . showsMaybe showsImportSpec mimpspec
+showsImport (ImportTypeAll spi ident)
+  = showsString "(ImportTypeAll "
+  . showsSpanInfo spi . space
+  . showsIdent ident
   . showsString ")"
-showsDecl (InfixDecl pos infx prec idents)
+
+showsDecl :: Show a => Decl a -> ShowS
+showsDecl (InfixDecl spi infx prec idents)
   = showsString "(InfixDecl "
-  . showsPosition pos . space
+  . showsSpanInfo spi . space
   . shows infx . space
-  . shows prec . space
+  . showsMaybe shows prec . space
   . showsList showsIdent idents
   . showsString ")"
-showsDecl (DataDecl pos ident idents consdecls)
+showsDecl (DataDecl spi ident idents consdecls classes)
   = showsString "(DataDecl "
-  . showsPosition pos . space
+  . showsSpanInfo spi . space
   . showsIdent ident . space
   . showsList showsIdent idents . space
-  . showsList showsConsDecl consdecls
+  . showsList showsConsDecl consdecls . space
+  . showsList showsQualIdent classes
   . showsString ")"
-showsDecl (NewtypeDecl pos ident idents newconsdecl)
+showsDecl (ExternalDataDecl spi ident idents)
+  = showsString "(ExternalDataDecl "
+  . showsSpanInfo spi . space
+  . showsIdent ident . space
+  . showsList showsIdent idents
+  . showsString ")"
+showsDecl (NewtypeDecl spi ident idents newconsdecl classes)
   = showsString "(NewtypeDecl "
-  . showsPosition pos . space
+  . showsSpanInfo spi . space
   . showsIdent ident . space
   . showsList showsIdent idents . space
-  . showsNewConsDecl newconsdecl
+  . showsNewConsDecl newconsdecl . space
+  . showsList showsQualIdent classes
   . showsString ")"
-showsDecl (TypeDecl pos ident idents typ)
+showsDecl (TypeDecl spi ident idents typ)
   = showsString "(TypeDecl "
-  . showsPosition pos . space
+  . showsSpanInfo spi . space
   . showsIdent ident . space
   . showsList showsIdent idents . space
   . showsTypeExpr typ
   . showsString ")"
-showsDecl (TypeSig pos idents typ)
+showsDecl (TypeSig spi idents qtype)
   = showsString "(TypeSig "
-  . showsPosition pos . space
-  . showsList showsIdent idents . space
-  . showsTypeExpr typ
-  . showsString ")"
-showsDecl (EvalAnnot pos idents annot)
-  = showsString "(EvalAnnot "
-  . showsPosition pos . space
+  . showsSpanInfo spi . space
   . showsList showsIdent idents . space
-  . shows annot
+  . showsQualTypeExpr qtype
   . showsString ")"
-showsDecl (FunctionDecl pos ident eqs)
+showsDecl (FunctionDecl spi a ident eqs)
   = showsString "(FunctionDecl "
-  . showsPosition pos . space
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
   . showsIdent ident . space
   . showsList showsEquation eqs
   . showsString ")"
-showsDecl (ExternalDecl pos cconv mstr ident typ)
+showsDecl (ExternalDecl spi vars)
   = showsString "(ExternalDecl "
-  . showsPosition pos . space
-  . shows cconv . space
-  . shows mstr . space
-  . showsIdent ident . space
-  . showsTypeExpr typ
-  . showsString ")"
-showsDecl (FlatExternalDecl pos idents)
-  = showsString "(FlatExternalDecl "
-  . showsPosition pos . space
-  . showsList showsIdent idents
+  . showsSpanInfo spi . space
+  . showsList showsVar vars
   . showsString ")"
-showsDecl (PatternDecl pos cons rhs)
+showsDecl (PatternDecl spi cons rhs)
   = showsString "(PatternDecl "
-  . showsPosition pos . space
+  . showsSpanInfo spi . space
   . showsConsTerm cons . space
   . showsRhs rhs
   . showsString ")"
-showsDecl (ExtraVariables pos idents)
-  = showsString "(ExtraVariables "
-  . showsPosition pos . space
-  . showsList showsIdent idents
+showsDecl (FreeDecl spi vars)
+  = showsString "(FreeDecl "
+  . showsSpanInfo spi . space
+  . showsList showsVar vars
   . showsString ")"
+showsDecl (DefaultDecl spi types)
+  = showsString "(DefaultDecl "
+  . showsSpanInfo spi . space
+  . showsList showsTypeExpr types
+  . showsString ")"
+showsDecl (ClassDecl spi li context cls clsvar decls)
+  = showsString "(ClassDecl "
+  . showsSpanInfo spi . space
+  . showsLayoutInfo li . space
+  . showsContext context . space
+  . showsIdent cls . space
+  . showsIdent clsvar . space
+  . showsList showsDecl decls
+  . showsString ")"
+showsDecl (InstanceDecl spi li context qcls inst decls)
+  = showsString "(InstanceDecl "
+  . showsSpanInfo spi . space
+  . showsLayoutInfo li . space
+  . showsContext context . space
+  . showsQualIdent qcls . space
+  . showsInstanceType inst . space
+  . showsList showsDecl decls
+  . showsString ")"
 
+showsContext :: Context -> ShowS
+showsContext = showsList showsConstraint
+
+showsConstraint :: Constraint -> ShowS
+showsConstraint (Constraint spi qcls ty)
+  = showsString "(Constraint "
+  . showsSpanInfo spi . space
+  . showsQualIdent qcls . space
+  . showsTypeExpr ty
+  . showsString ")"
+
+showsInstanceType :: InstanceType -> ShowS
+showsInstanceType = showsTypeExpr
+
 showsConsDecl :: ConstrDecl -> ShowS
-showsConsDecl (ConstrDecl pos idents ident types)
+showsConsDecl (ConstrDecl spi ident types)
   = showsString "(ConstrDecl "
-  . showsPosition pos . space
-  . showsList showsIdent idents . space
+  . showsSpanInfo spi . space
   . showsIdent ident . space
   . showsList showsTypeExpr types
   . showsString ")"
+showsConsDecl (ConOpDecl spi ty1 ident ty2)
+  = showsString "(ConOpDecl "
+  . showsSpanInfo spi . space
+  . showsTypeExpr ty1 . space
+  . showsIdent ident . space
+  . showsTypeExpr ty2
+  . showsString ")"
+showsConsDecl (RecordDecl spi ident fs)
+  = showsString "(RecordDecl "
+  . showsSpanInfo spi . space
+  . showsIdent ident . space
+  . showsList showsFieldDecl fs
+  . showsString ")"
 
+showsFieldDecl :: FieldDecl -> ShowS
+showsFieldDecl (FieldDecl spi labels ty)
+  = showsString "(FieldDecl "
+  . showsSpanInfo spi . space
+  . showsList showsIdent labels . space
+  . showsTypeExpr ty
+  . showsString ")"
+
 showsNewConsDecl :: NewConstrDecl -> ShowS
-showsNewConsDecl (NewConstrDecl pos idents ident typ)
+showsNewConsDecl (NewConstrDecl spi ident typ)
   = showsString "(NewConstrDecl "
-  . showsPosition pos . space
-  . showsList showsIdent idents . space
+  . showsSpanInfo spi . space
   . showsIdent ident . space
   . showsTypeExpr typ
   . showsString ")"
+showsNewConsDecl (NewRecordDecl spi ident fld)
+  = showsString "(NewRecordDecl "
+  . showsSpanInfo spi . space
+  . showsIdent ident . space
+  . showsPair showsIdent showsTypeExpr fld
+  . showsString ")"
 
+showsQualTypeExpr :: QualTypeExpr -> ShowS
+showsQualTypeExpr (QualTypeExpr spi context typ)
+  = showsString "(QualTypeExpr "
+  . showsSpanInfo spi . space
+  . showsContext context . space
+  . showsTypeExpr typ
+  . showsString ")"
+
 showsTypeExpr :: TypeExpr -> ShowS
-showsTypeExpr (ConstructorType qident types)
+showsTypeExpr (ConstructorType spi qident)
   = showsString "(ConstructorType "
+  . showsSpanInfo spi . space
   . showsQualIdent qident . space
+  . showsString ")"
+showsTypeExpr (ApplyType spi type1 type2)
+  = showsString "(ApplyType "
+  . showsSpanInfo spi . space
+  . showsTypeExpr type1 . space
+  . showsTypeExpr type2 . space
+  . showsString ")"
+showsTypeExpr (VariableType spi ident)
+  = showsString "(VariableType "
+  . showsSpanInfo spi . space
+  . showsIdent ident
+  . showsString ")"
+showsTypeExpr (TupleType spi types)
+  = showsString "(TupleType "
+  . showsSpanInfo spi . space
   . showsList showsTypeExpr types
   . showsString ")"
-showsTypeExpr (VariableType ident)
-  = showsString "(VariableType " . showsIdent ident . showsString ")"
-showsTypeExpr (TupleType types)
-  = showsString "(TupleType " . showsList showsTypeExpr types . showsString ")"
-showsTypeExpr (ListType typ)
-  = showsString "(ListType " . showsTypeExpr typ . showsString ")"
-showsTypeExpr (ArrowType dom ran)
+showsTypeExpr (ListType spi typ)
+  = showsString "(ListType "
+  . showsSpanInfo spi . space
+  . showsTypeExpr typ
+  . showsString ")"
+showsTypeExpr (ArrowType spi dom ran)
   = showsString "(ArrowType "
+  . showsSpanInfo spi . space
   . showsTypeExpr dom . space
   . showsTypeExpr ran
   . showsString ")"
-showsTypeExpr (RecordType fieldts mtyp)
-  = showsString "(RecordType "
-  . showsList (showsPair (showsList showsIdent) showsTypeExpr) fieldts . space
-  . showsMaybe showsTypeExpr mtyp
+showsTypeExpr (ParenType spi ty)
+  = showsString "(ParenType "
+  . showsSpanInfo spi . space
+  . showsTypeExpr ty
   . showsString ")"
+showsTypeExpr (ForallType spi vars ty)
+  = showsString "(ForallType "
+  . showsSpanInfo spi . space
+  . showsList showsIdent vars
+  . showsTypeExpr ty
+  . showsString ")"
 
-showsEquation :: Equation -> ShowS
-showsEquation (Equation pos lhs rhs)
+showsEquation :: Show a => Equation a -> ShowS
+showsEquation (Equation spi lhs rhs)
   = showsString "(Equation "
-  . showsPosition pos . space
+  . showsSpanInfo spi . space
   . showsLhs lhs . space
   . showsRhs rhs
   . showsString ")"
 
-showsLhs :: Lhs -> ShowS
-showsLhs (FunLhs ident conss)
+showsLhs :: Show a => Lhs a -> ShowS
+showsLhs (FunLhs spi ident conss)
   = showsString "(FunLhs "
+  . showsSpanInfo spi . space
   . showsIdent ident . space
   . showsList showsConsTerm conss
   . showsString ")"
-showsLhs (OpLhs cons1 ident cons2)
+showsLhs (OpLhs spi cons1 ident cons2)
   = showsString "(OpLhs "
+  . showsSpanInfo spi . space
   . showsConsTerm cons1 . space
   . showsIdent ident . space
   . showsConsTerm cons2
   . showsString ")"
-showsLhs (ApLhs lhs conss)
+showsLhs (ApLhs spi lhs conss)
   = showsString "(ApLhs "
+  . showsSpanInfo spi . space
   . showsLhs lhs . space
   . showsList showsConsTerm conss
   . showsString ")"
 
-showsRhs :: Rhs -> ShowS
-showsRhs (SimpleRhs pos exp decls)
+showsRhs :: Show a => Rhs a -> ShowS
+showsRhs (SimpleRhs spi li expr decls)
   = showsString "(SimpleRhs "
-  . showsPosition pos . space
-  . showsExpression exp . space
+  . showsSpanInfo spi . space
+  . showsLayoutInfo li . space
+  . showsExpression expr . space
   . showsList showsDecl decls
   . showsString ")"
-showsRhs (GuardedRhs cexps decls)
+showsRhs (GuardedRhs spi li cexps decls)
   = showsString "(GuardedRhs "
+  . showsSpanInfo spi . space
+  . showsLayoutInfo li . space
   . showsList showsCondExpr cexps . space
   . showsList showsDecl decls
   . showsString ")"
 
-showsCondExpr :: CondExpr -> ShowS
-showsCondExpr (CondExpr pos exp1 exp2)
+showsCondExpr :: Show a => CondExpr a -> ShowS
+showsCondExpr (CondExpr spi exp1 exp2)
   = showsString "(CondExpr "
-  . showsPosition pos . space
+  . showsSpanInfo spi . space
   . showsExpression exp1 . space
   . showsExpression exp2
   . showsString ")"
 
 showsLiteral :: Literal -> ShowS
-showsLiteral (Char _ c) = showsString "(Char " . shows c . showsString ")"
-showsLiteral (Int ident n)
+showsLiteral (Char c)
+  = showsString "(Char "
+  . shows c
+  . showsString ")"
+showsLiteral (Int n)
   = showsString "(Int "
-  . showsIdent ident . space
   . shows n
   . showsString ")"
-showsLiteral (Float _ x) = showsString "(Float " . shows x . showsString ")"
-showsLiteral (String _ s) = showsString "(String " . shows s . showsString ")"
+showsLiteral (Float x)
+  = showsString "(Float "
+  . shows x
+  . showsString ")"
+showsLiteral (String s)
+  = showsString "(String "
+  . shows s
+  . showsString ")"
 
-showsConsTerm :: ConstrTerm -> ShowS
-showsConsTerm (LiteralPattern lit)
+showsConsTerm :: Show a => Pattern a -> ShowS
+showsConsTerm (LiteralPattern spi a lit)
   = showsString "(LiteralPattern "
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
   . showsLiteral lit
   . showsString ")"
-showsConsTerm (NegativePattern ident lit)
+showsConsTerm (NegativePattern spi a lit)
   = showsString "(NegativePattern "
-  . showsIdent ident . space
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
   . showsLiteral lit
   . showsString ")"
-showsConsTerm (VariablePattern ident)
+showsConsTerm (VariablePattern spi a ident)
   = showsString "(VariablePattern "
-  . showsIdent ident 
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
+  . showsIdent ident
   . showsString ")"
-showsConsTerm (ConstructorPattern qident conss)
+showsConsTerm (ConstructorPattern spi a qident conss)
   = showsString "(ConstructorPattern "
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
   . showsQualIdent qident . space
   . showsList showsConsTerm conss
   . showsString ")"
-showsConsTerm (InfixPattern cons1 qident cons2)
+showsConsTerm (InfixPattern spi a cons1 qident cons2)
   = showsString "(InfixPattern "
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
   . showsConsTerm cons1 . space
   . showsQualIdent qident . space
   . showsConsTerm cons2
   . showsString ")"
-showsConsTerm (ParenPattern cons)
+showsConsTerm (ParenPattern spi cons)
   = showsString "(ParenPattern "
+  . showsSpanInfo spi . space
   . showsConsTerm cons
   . showsString ")"
-showsConsTerm (TuplePattern _ conss)
+showsConsTerm (TuplePattern spi conss)
   = showsString "(TuplePattern "
+  . showsSpanInfo spi . space
   . showsList showsConsTerm conss
   . showsString ")"
-showsConsTerm (ListPattern _ conss)
+showsConsTerm (ListPattern spi a conss)
   = showsString "(ListPattern "
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
   . showsList showsConsTerm conss
   . showsString ")"
-showsConsTerm (AsPattern ident cons)
+showsConsTerm (AsPattern spi ident cons)
   = showsString "(AsPattern "
+  . showsSpanInfo spi . space
   . showsIdent ident . space
   . showsConsTerm cons
   . showsString ")"
-showsConsTerm (LazyPattern _ cons)
+showsConsTerm (LazyPattern spi cons)
   = showsString "(LazyPattern "
+  . showsSpanInfo spi . space
   . showsConsTerm cons
   . showsString ")"
-showsConsTerm (FunctionPattern qident conss)
+showsConsTerm (FunctionPattern spi a qident conss)
   = showsString "(FunctionPattern "
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
   . showsQualIdent qident . space
   . showsList showsConsTerm conss
   . showsString ")"
-showsConsTerm (InfixFuncPattern cons1 qident cons2)
+showsConsTerm (InfixFuncPattern spi a cons1 qident cons2)
   = showsString "(InfixFuncPattern "
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
   . showsConsTerm cons1 . space
   . showsQualIdent qident . space
   . showsConsTerm cons2
   . showsString ")"
-showsConsTerm (RecordPattern cfields mcons)
-  = shows "(RecordPattern "
+showsConsTerm (RecordPattern spi a qident cfields)
+  = showsString "(RecordPattern "
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
+  . showsQualIdent qident . space
   . showsList (showsField showsConsTerm) cfields . space
-  . showsMaybe showsConsTerm mcons
   . showsString ")"
 
-showsExpression :: Expression -> ShowS
-showsExpression (Literal lit)
-  = showsString "(Literal " . showsLiteral lit . showsString ")"
-showsExpression (Variable qident)
-  = showsString "(Variable " . showsQualIdent qident . showsString ")"
-showsExpression (Constructor qident)
-  = showsString "(Constructor " . showsQualIdent qident . showsString ")"
-showsExpression (Paren exp)
-  = showsString "(Paren " . showsExpression exp . showsString ")"
-showsExpression (Typed exp typ)
+showsExpression :: Show a => Expression a -> ShowS
+showsExpression (Literal spi a lit)
+  = showsString "(Literal "
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
+  . showsLiteral lit
+  . showsString ")"
+showsExpression (Variable spi a qident)
+  = showsString "(Variable "
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
+  . showsQualIdent qident
+  . showsString ")"
+showsExpression (Constructor spi a qident)
+  = showsString "(Constructor "
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
+  . showsQualIdent qident
+  . showsString ")"
+showsExpression (Paren spi expr)
+  = showsString "(Paren "
+  . showsSpanInfo spi . space
+  . showsExpression expr
+  . showsString ")"
+showsExpression (Typed spi expr qtype)
   = showsString "(Typed "
-  . showsExpression exp . space
-  . showsTypeExpr typ
+  . showsSpanInfo spi . space
+  . showsExpression expr . space
+  . showsQualTypeExpr qtype
   . showsString ")"
-showsExpression (Tuple _ exps)
-  = showsString "(Tuple " . showsList showsExpression exps . showsString ")"
-showsExpression (List _ exps)
-  = showsString "(List " . showsList showsExpression exps . showsString ")"
-showsExpression (ListCompr _ exp stmts)
+showsExpression (Tuple spi exps)
+  = showsString "(Tuple "
+  . showsSpanInfo spi . space
+  . showsList showsExpression exps
+  . showsString ")"
+showsExpression (List spi a exps)
+  = showsString "(List "
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
+  . showsList showsExpression exps
+  . showsString ")"
+showsExpression (ListCompr spi expr stmts)
   = showsString "(ListCompr "
-  . showsExpression exp . space
+  . showsSpanInfo spi . space
+  . showsExpression expr . space
   . showsList showsStatement stmts
   . showsString ")"
-showsExpression (EnumFrom exp)
-  = showsString "(EnumFrom " . showsExpression exp . showsString ")"
-showsExpression (EnumFromThen exp1 exp2)
+showsExpression (EnumFrom spi expr)
+  = showsString "(EnumFrom "
+  . showsSpanInfo spi . space
+  . showsExpression expr
+  . showsString ")"
+showsExpression (EnumFromThen spi exp1 exp2)
   = showsString "(EnumFromThen "
+  . showsSpanInfo spi . space
   . showsExpression exp1 . space
   . showsExpression exp2
   . showsString ")"
-showsExpression (EnumFromTo exp1 exp2)
+showsExpression (EnumFromTo spi exp1 exp2)
   = showsString "(EnumFromTo "
+  . showsSpanInfo spi . space
   . showsExpression exp1 . space
   . showsExpression exp2
   . showsString ")"
-showsExpression (EnumFromThenTo exp1 exp2 exp3)
+showsExpression (EnumFromThenTo spi exp1 exp2 exp3)
   = showsString "(EnumFromThenTo "
+  . showsSpanInfo spi . space
   . showsExpression exp1 . space
   . showsExpression exp2 . space
   . showsExpression exp3
   . showsString ")"
-showsExpression (UnaryMinus ident exp)
+showsExpression (UnaryMinus spi expr)
   = showsString "(UnaryMinus "
-  . showsIdent ident . space
-  . showsExpression exp
+  . showsSpanInfo spi . space
+  . showsExpression expr
   . showsString ")"
-showsExpression (Apply exp1 exp2)
+showsExpression (Apply spi exp1 exp2)
   = showsString "(Apply "
+  . showsSpanInfo spi . space
   . showsExpression exp1 . space
   . showsExpression exp2
   . showsString ")"
-showsExpression (InfixApply exp1 op exp2)
+showsExpression (InfixApply spi exp1 op exp2)
   = showsString "(InfixApply "
+  . showsSpanInfo spi . space
   . showsExpression exp1 . space
   . showsInfixOp op . space
   . showsExpression exp2
   . showsString ")"
-showsExpression (LeftSection exp op)
+showsExpression (LeftSection spi expr op)
   = showsString "(LeftSection "
-  . showsExpression exp . space
+  . showsSpanInfo spi . space
+  . showsExpression expr . space
   . showsInfixOp op
   . showsString ")"
-showsExpression (RightSection op exp)
+showsExpression (RightSection spi op expr)
   = showsString "(RightSection "
+  . showsSpanInfo spi . space
   . showsInfixOp op . space
-  . showsExpression exp
+  . showsExpression expr
   . showsString ")"
-showsExpression (Lambda _ conss exp)
+showsExpression (Lambda spi conss expr)
   = showsString "(Lambda "
+  . showsSpanInfo spi . space
   . showsList showsConsTerm conss . space
-  . showsExpression exp 
+  . showsExpression expr
   . showsString ")"
-showsExpression (Let decls exp)
+showsExpression (Let spi li decls expr)
   = showsString "(Let "
+  . showsSpanInfo spi . space
+  . showsLayoutInfo li . space
   . showsList showsDecl decls . space
-  . showsExpression exp 
+  . showsExpression expr
   . showsString ")"
-showsExpression (Do stmts exp)
+showsExpression (Do spi li stmts expr)
   = showsString "(Do "
+  . showsSpanInfo spi . space
+  . showsLayoutInfo li . space
   . showsList showsStatement stmts . space
-  . showsExpression exp
+  . showsExpression expr
   . showsString ")"
-showsExpression (IfThenElse _ exp1 exp2 exp3)
+showsExpression (IfThenElse spi exp1 exp2 exp3)
   = showsString "(IfThenElse "
+  . showsSpanInfo spi . space
   . showsExpression exp1 . space
   . showsExpression exp2 . space
   . showsExpression exp3
   . showsString ")"
-showsExpression (Case _ exp alts)
+showsExpression (Case spi li ct expr alts)
   = showsString "(Case "
-  . showsExpression exp . space
+  . showsSpanInfo spi . space
+  . showsLayoutInfo li . space
+  . showsCaseType ct . space
+  . showsExpression expr . space
   . showsList showsAlt alts
   . showsString ")"
-showsExpression (RecordConstr efields)
-  = showsString "(RecordConstr "
+showsExpression (RecordUpdate spi expr efields)
+  = showsString "(RecordUpdate "
+  . showsSpanInfo spi . space
+  . showsExpression expr . space
   . showsList (showsField showsExpression) efields
   . showsString ")"
-showsExpression (RecordSelection exp ident)
-  = showsString "(RecordSelection "
-  . showsExpression exp . space
-  . showsIdent ident
-  . showsString ")"
-showsExpression (RecordUpdate efields exp)
-  = showsString "(RecordUpdate "
-  . showsList (showsField showsExpression) efields . space
-  . showsExpression exp
+showsExpression (Record spi a qident efields)
+  = showsString "(Record "
+  . showsSpanInfo spi . space
+  . showsPrec 11 a . space
+  . showsQualIdent qident . space
+  . showsList (showsField showsExpression) efields
   . showsString ")"
 
-showsInfixOp :: InfixOp -> ShowS
-showsInfixOp (InfixOp qident)
-  = showsString "(InfixOp " . showsQualIdent qident . showsString ")"
-showsInfixOp (InfixConstr qident)
-  = showsString "(InfixConstr " . showsQualIdent qident . showsString ")"
+showsInfixOp :: Show a => InfixOp a -> ShowS
+showsInfixOp (InfixOp a qident)
+  = showsString "(InfixOp "
+  . showsPrec 11 a . space
+  . showsQualIdent qident
+  . showsString ")"
+showsInfixOp (InfixConstr a qident)
+  = showsString "(InfixConstr "
+  . showsPrec 11 a . space
+  . showsQualIdent qident
+  . showsString ")"
 
-showsStatement :: Statement -> ShowS
-showsStatement (StmtExpr _ exp)
-  = showsString "(StmtExpr " . showsExpression exp . showsString ")"
-showsStatement (StmtDecl decls)
-  = showsString "(StmtDecl " . showsList showsDecl decls . showsString ")"
-showsStatement (StmtBind _ cons exp)
+showsStatement :: Show a => Statement a -> ShowS
+showsStatement (StmtExpr spi expr)
+  = showsString "(StmtExpr "
+  . showsSpanInfo spi . space
+  . showsExpression expr
+  . showsString ")"
+showsStatement (StmtDecl spi li decls)
+  = showsString "(StmtDecl "
+  . showsSpanInfo spi . space
+  . showsLayoutInfo li . space
+  . showsList showsDecl decls
+  . showsString ")"
+showsStatement (StmtBind spi cons expr)
   = showsString "(StmtBind "
+  . showsSpanInfo spi . space
   . showsConsTerm cons . space
-  . showsExpression exp
+  . showsExpression expr
   . showsString ")"
 
-showsAlt :: Alt -> ShowS
-showsAlt (Alt pos cons rhs)
+showsCaseType :: CaseType -> ShowS
+showsCaseType Rigid = showsString "Rigid"
+showsCaseType Flex  = showsString "Flex"
+
+showsAlt :: Show a => Alt a -> ShowS
+showsAlt (Alt spi cons rhs)
   = showsString "(Alt "
-  . showsPosition pos . space
+  . showsSpanInfo spi . space
   . showsConsTerm cons . space
   . showsRhs rhs
   . showsString ")"
 
 showsField :: (a -> ShowS) -> Field a -> ShowS
-showsField sa (Field pos ident a)
+showsField sa (Field spi ident a)
   = showsString "(Field "
-  . showsPosition pos . space
-  . showsIdent ident . space
+  . showsSpanInfo spi . space
+  . showsQualIdent ident . space
   . sa a
   . showsString ")"
 
+showsVar :: Show a => Var a -> ShowS
+showsVar (Var a ident)
+  = showsString "(Var "
+  . showsPrec 11 a . space
+  . showsIdent ident
+  . showsString ")"
+
+showsPosition :: Position -> ShowS
+showsPosition NoPos = showsString "NoPos"
+showsPosition Position { line = l, column = c }
+   = showsString "(Position "
+   . shows l . space
+   . shows c
+   . showsString ")"
+
+showsSpanInfo :: SpanInfo -> ShowS
+showsSpanInfo NoSpanInfo = showsString "NoSpanInfo"
+showsSpanInfo SpanInfo { srcSpan = sp, srcInfoPoints = ss }
+  = showsString "(SpanInfo "
+  . showsSpan sp . space
+  . showsList showsSpan ss
+  . showsString ")"
+
+showsLayoutInfo :: LayoutInfo -> ShowS
+showsLayoutInfo WhitespaceLayout = showsString "WhitespaceLayout"
+showsLayoutInfo (ExplicitLayout ss)
+  = showsString "(ExplicitLayout "
+  . showsList showsSpan ss
+  . showsString ")"
+
+showsSpan :: Span -> ShowS
+showsSpan NoSpan = showsString "NoSpan"
+showsSpan Span { start = s, end = e }
+  = showsString "(Span "
+  . showsPosition s . space
+  . showsPosition e
+  . showsString ")"
+
 showsString :: String -> ShowS
 showsString = (++)
 
@@ -467,12 +737,11 @@
 newline = showsString "\n"
 
 showsMaybe :: (a -> ShowS) -> Maybe a -> ShowS
-showsMaybe shs
-  = maybe (showsString "Nothing")
-          (\x -> showsString "(Just " . shs x . showsString ")")
+showsMaybe shs = maybe (showsString "Nothing")
+                       (\x -> showsString "(Just " . shs x . showsString ")")
 
 showsList :: (a -> ShowS) -> [a] -> ShowS
-showsList _ [] = showsString "[]"
+showsList _   [] = showsString "[]"
 showsList shs (x:xs)
   = showsString "["
   . foldl (\sys y -> sys . showsString "," . shs y) (shs x) xs
@@ -482,18 +751,27 @@
 showsPair sa sb (a,b)
   = showsString "(" . sa a . showsString "," . sb b . showsString ")"
 
-
 showsIdent :: Ident -> ShowS
-showsIdent (Ident _ name n)
-  = showsString "(Ident " . shows name . space . shows n . showsString ")"
+showsIdent (Ident spi x n)
+  = showsString "(Ident " . showsSpanInfo spi . space
+  . shows x . space . shows n . showsString ")"
 
 showsQualIdent :: QualIdent -> ShowS
-showsQualIdent (QualIdent mident ident)
-    = showsString "(QualIdent "
-      . showsMaybe showsModuleIdent mident 
-      . space
-      . showsIdent ident
-      . showsString ")"
+showsQualIdent (QualIdent spi mident ident)
+  = showsString "(QualIdent "
+  . showsSpanInfo spi . space
+  . showsMaybe showsModuleIdent mident
+  . space
+  . showsIdent ident
+  . showsString ")"
 
 showsModuleIdent :: ModuleIdent -> ShowS
-showsModuleIdent = shows . moduleName
+showsModuleIdent (ModuleIdent spi ss)
+  = showsString "(ModuleIdent "
+  . showsSpanInfo spi . space
+  . showsList (showsQuotes showsString) ss
+  . showsString ")"
+
+showsQuotes :: (a -> ShowS) -> a -> ShowS
+showsQuotes sa a
+  = showsString "\"" . sa a . showsString "\""
diff --git a/src/Curry/Syntax/Type.hs b/src/Curry/Syntax/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/Curry/Syntax/Type.hs
@@ -0,0 +1,1540 @@
+{- |
+    Module      :  $Header$
+    Description :  Abstract syntax for Curry
+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux
+                       2005        Martin Engelke
+                       2011 - 2015 Björn Peemöller
+                       2014        Jan Rasmus Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module provides the necessary data structures to maintain the
+    parsed representation of a Curry program.
+-}
+
+module Curry.Syntax.Type
+  ( -- * Module header
+    Module (..)
+    -- ** Module pragmas
+  , ModulePragma (..), Extension (..), KnownExtension (..), Tool (..)
+    -- ** Export specification
+  , ExportSpec (..), Export (..)
+    -- ** Import declarations
+  , ImportDecl (..), ImportSpec (..), Import (..), Qualified
+    -- * Interface
+  , Interface (..), IImportDecl (..), Arity, IDecl (..), KindExpr (..)
+  , IMethodDecl (..), IMethodImpl
+    -- * Declarations
+  , Decl (..), Precedence, Infix (..), ConstrDecl (..), NewConstrDecl (..)
+  , FieldDecl (..)
+  , TypeExpr (..), QualTypeExpr (..)
+  , Equation (..), Lhs (..), Rhs (..), CondExpr (..)
+  , Literal (..), Pattern (..), Expression (..), InfixOp (..)
+  , Statement (..), CaseType (..), Alt (..), Field (..), Var (..)
+    -- * Type classes
+  , Context, Constraint (..), InstanceType
+    -- * Goals
+  , Goal (..)
+  ) where
+
+import Data.Binary
+import Control.Monad
+
+import Curry.Base.Ident
+import Curry.Base.Position
+import Curry.Base.SpanInfo
+import Curry.Base.Span
+import Curry.Base.Pretty      (Pretty(..))
+
+import Curry.Syntax.Extension
+
+import Text.PrettyPrint
+
+-- ---------------------------------------------------------------------------
+-- Modules
+-- ---------------------------------------------------------------------------
+
+-- |Curry module
+data Module a = Module SpanInfo LayoutInfo [ModulePragma] ModuleIdent
+                       (Maybe ExportSpec) [ImportDecl] [Decl a]
+    deriving (Eq, Read, Show)
+
+-- |Module pragma
+data ModulePragma
+  = LanguagePragma SpanInfo [Extension]         -- ^ language pragma
+  | OptionsPragma  SpanInfo (Maybe Tool) String -- ^ options pragma
+    deriving (Eq, Read, Show)
+
+-- |Export specification
+data ExportSpec = Exporting SpanInfo [Export]
+    deriving (Eq, Read, Show)
+
+-- |Single exported entity
+data Export
+  = Export         SpanInfo QualIdent         -- f/T
+  | ExportTypeWith SpanInfo QualIdent [Ident] -- T (C1,...,Cn)
+  | ExportTypeAll  SpanInfo QualIdent         -- T (..)
+  | ExportModule   SpanInfo ModuleIdent       -- module M
+    deriving (Eq, Read, Show)
+
+-- |Import declaration
+data ImportDecl = ImportDecl SpanInfo ModuleIdent Qualified
+                             (Maybe ModuleIdent) (Maybe ImportSpec)
+    deriving (Eq, Read, Show)
+
+-- |Flag to signal qualified import
+type Qualified = Bool
+
+-- |Import specification
+data ImportSpec
+  = Importing SpanInfo [Import]
+  | Hiding    SpanInfo [Import]
+    deriving (Eq, Read, Show)
+
+-- |Single imported entity
+data Import
+  = Import         SpanInfo Ident            -- f/T
+  | ImportTypeWith SpanInfo Ident [Ident]    -- T (C1,...,Cn)
+  | ImportTypeAll  SpanInfo Ident            -- T (..)
+    deriving (Eq, Read, Show)
+
+-- ---------------------------------------------------------------------------
+-- Module interfaces
+-- ---------------------------------------------------------------------------
+
+-- | Module interface
+--
+-- Interface declarations are restricted to type declarations and signatures.
+-- Note that an interface function declaration additionaly contains the
+-- function arity (= number of parameters) in order to generate
+-- correct FlatCurry function applications.
+data Interface = Interface ModuleIdent [IImportDecl] [IDecl]
+    deriving (Eq, Read, Show)
+
+-- |Interface import declaration
+data IImportDecl = IImportDecl Position ModuleIdent
+    deriving (Eq, Read, Show)
+
+-- |Arity of a function
+type Arity = Int
+
+-- |Interface declaration
+data IDecl
+  = IInfixDecl      Position Infix Precedence QualIdent
+  | HidingDataDecl  Position QualIdent (Maybe KindExpr) [Ident]
+  | IDataDecl       Position QualIdent (Maybe KindExpr) [Ident] [ConstrDecl]  [Ident]
+  | INewtypeDecl    Position QualIdent (Maybe KindExpr) [Ident] NewConstrDecl [Ident]
+  | ITypeDecl       Position QualIdent (Maybe KindExpr) [Ident] TypeExpr
+  | IFunctionDecl   Position QualIdent (Maybe Ident) Arity QualTypeExpr
+  | HidingClassDecl Position Context QualIdent (Maybe KindExpr) Ident
+  | IClassDecl      Position Context QualIdent (Maybe KindExpr) Ident [IMethodDecl] [Ident]
+  | IInstanceDecl   Position Context QualIdent InstanceType [IMethodImpl] (Maybe ModuleIdent)
+    deriving (Eq, Read, Show)
+
+-- |Class methods
+data IMethodDecl = IMethodDecl Position Ident (Maybe Arity) QualTypeExpr
+  deriving (Eq, Read, Show)
+
+-- |Class method implementations
+type IMethodImpl = (Ident, Arity)
+
+-- |Kind expressions
+data KindExpr
+  = Star
+  | ArrowKind KindExpr KindExpr
+    deriving (Eq, Read, Show)
+
+-- ---------------------------------------------------------------------------
+-- Declarations (local or top-level)
+-- ---------------------------------------------------------------------------
+
+-- |Declaration in a module
+data Decl a
+  = InfixDecl        SpanInfo Infix (Maybe Precedence) [Ident]                   -- infixl 5 (op), `fun`
+  | DataDecl         SpanInfo Ident [Ident] [ConstrDecl] [QualIdent]             -- data C a b = C1 a | C2 b deriving (D, ...)
+  | ExternalDataDecl SpanInfo Ident [Ident]                                      -- external data C a b
+  | NewtypeDecl      SpanInfo Ident [Ident] NewConstrDecl [QualIdent]            -- newtype C a b = C a b deriving (D, ...)
+  | TypeDecl         SpanInfo Ident [Ident] TypeExpr                             -- type C a b = D a b
+  | TypeSig          SpanInfo [Ident] QualTypeExpr                               -- f, g :: Bool
+  | FunctionDecl     SpanInfo a Ident [Equation a]                               -- f True = 1 ; f False = 0
+  | ExternalDecl     SpanInfo [Var a]                                            -- f, g external
+  | PatternDecl      SpanInfo (Pattern a) (Rhs a)                                -- Just x = ...
+  | FreeDecl         SpanInfo [Var a]                                            -- x, y free
+  | DefaultDecl      SpanInfo [TypeExpr]                                         -- default (Int, Float)
+  | ClassDecl        SpanInfo LayoutInfo Context Ident Ident [Decl a]            -- class C a => D a where {TypeSig|InfixDecl|FunctionDecl}
+  | InstanceDecl     SpanInfo LayoutInfo Context QualIdent InstanceType [Decl a] -- instance C a => M.D (N.T a b c) where {FunctionDecl}
+    deriving (Eq, Read, Show)
+
+-- ---------------------------------------------------------------------------
+-- Infix declaration
+-- ---------------------------------------------------------------------------
+
+-- |Operator precedence
+type Precedence = Integer
+
+-- |Fixity of operators
+data Infix
+  = InfixL -- ^ left-associative
+  | InfixR -- ^ right-associative
+  | Infix  -- ^ no associativity
+    deriving (Eq, Read, Show)
+
+-- |Constructor declaration for algebraic data types
+data ConstrDecl
+  = ConstrDecl SpanInfo Ident [TypeExpr]
+  | ConOpDecl  SpanInfo TypeExpr Ident TypeExpr
+  | RecordDecl SpanInfo Ident [FieldDecl]
+    deriving (Eq, Read, Show)
+
+-- |Constructor declaration for renaming types (newtypes)
+data NewConstrDecl
+  = NewConstrDecl SpanInfo Ident TypeExpr
+  | NewRecordDecl SpanInfo Ident (Ident, TypeExpr)
+   deriving (Eq, Read, Show)
+
+-- |Declaration for labelled fields
+data FieldDecl = FieldDecl SpanInfo [Ident] TypeExpr
+  deriving (Eq, Read, Show)
+
+-- |Type expressions
+data TypeExpr
+  = ConstructorType SpanInfo QualIdent
+  | ApplyType       SpanInfo TypeExpr TypeExpr
+  | VariableType    SpanInfo Ident
+  | TupleType       SpanInfo [TypeExpr]
+  | ListType        SpanInfo TypeExpr
+  | ArrowType       SpanInfo TypeExpr TypeExpr
+  | ParenType       SpanInfo TypeExpr
+  | ForallType      SpanInfo [Ident] TypeExpr
+    deriving (Eq, Read, Show)
+
+-- |Qualified type expressions
+data QualTypeExpr = QualTypeExpr SpanInfo Context TypeExpr
+    deriving (Eq, Read, Show)
+
+-- ---------------------------------------------------------------------------
+-- Type classes
+-- ---------------------------------------------------------------------------
+
+type Context = [Constraint]
+
+data Constraint = Constraint SpanInfo QualIdent TypeExpr
+    deriving (Eq, Read, Show)
+
+type InstanceType = TypeExpr
+
+-- ---------------------------------------------------------------------------
+-- Functions
+-- ---------------------------------------------------------------------------
+
+-- |Function defining equation
+data Equation a = Equation SpanInfo (Lhs a) (Rhs a)
+    deriving (Eq, Read, Show)
+
+-- |Left-hand-side of an 'Equation' (function identifier and patterns)
+data Lhs a
+  = FunLhs SpanInfo Ident [Pattern a]             -- f x y
+  | OpLhs  SpanInfo (Pattern a) Ident (Pattern a) -- x $ y
+  | ApLhs  SpanInfo (Lhs a) [Pattern a]           -- ($) x y
+    deriving (Eq, Read, Show)
+
+-- |Right-hand-side of an 'Equation'
+data Rhs a
+  = SimpleRhs  SpanInfo LayoutInfo (Expression a) [Decl a] -- @expr where decls@
+  | GuardedRhs SpanInfo LayoutInfo [CondExpr a]   [Decl a] -- @| cond = expr where decls@
+    deriving (Eq, Read, Show)
+
+-- |Conditional expression (expression conditioned by a guard)
+data CondExpr a = CondExpr SpanInfo (Expression a) (Expression a)
+    deriving (Eq, Read, Show)
+
+-- |Literal
+data Literal
+  = Char   Char
+  | Int    Integer
+  | Float  Double
+  | String String
+    deriving (Eq, Read, Show)
+
+-- |Constructor term (used for patterns)
+data Pattern a
+  = LiteralPattern     SpanInfo a Literal
+  | NegativePattern    SpanInfo a Literal
+  | VariablePattern    SpanInfo a Ident
+  | ConstructorPattern SpanInfo a QualIdent [Pattern a]
+  | InfixPattern       SpanInfo a (Pattern a) QualIdent (Pattern a)
+  | ParenPattern       SpanInfo (Pattern a)
+  | RecordPattern      SpanInfo a QualIdent [Field (Pattern a)] -- C { l1 = p1, ..., ln = pn }
+  | TuplePattern       SpanInfo [Pattern a]
+  | ListPattern        SpanInfo a [Pattern a]
+  | AsPattern          SpanInfo Ident (Pattern a)
+  | LazyPattern        SpanInfo (Pattern a)
+  | FunctionPattern    SpanInfo a QualIdent [Pattern a]
+  | InfixFuncPattern   SpanInfo a (Pattern a) QualIdent (Pattern a)
+    deriving (Eq, Read, Show)
+
+-- |Expression
+data Expression a
+  = Literal           SpanInfo a Literal
+  | Variable          SpanInfo a QualIdent
+  | Constructor       SpanInfo a QualIdent
+  | Paren             SpanInfo (Expression a)
+  | Typed             SpanInfo (Expression a) QualTypeExpr
+  | Record            SpanInfo a QualIdent [Field (Expression a)]    -- C {l1 = e1,..., ln = en}
+  | RecordUpdate      SpanInfo (Expression a) [Field (Expression a)] -- e {l1 = e1,..., ln = en}
+  | Tuple             SpanInfo [Expression a]
+  | List              SpanInfo a [Expression a]
+  | ListCompr         SpanInfo (Expression a) [Statement a]   -- the ref corresponds to the main list
+  | EnumFrom          SpanInfo (Expression a)
+  | EnumFromThen      SpanInfo (Expression a) (Expression a)
+  | EnumFromTo        SpanInfo (Expression a) (Expression a)
+  | EnumFromThenTo    SpanInfo (Expression a) (Expression a) (Expression a)
+  | UnaryMinus        SpanInfo (Expression a)
+  | Apply             SpanInfo (Expression a) (Expression a)
+  | InfixApply        SpanInfo (Expression a) (InfixOp a) (Expression a)
+  | LeftSection       SpanInfo (Expression a) (InfixOp a)
+  | RightSection      SpanInfo (InfixOp a) (Expression a)
+  | Lambda            SpanInfo [Pattern a] (Expression a)
+  | Let               SpanInfo LayoutInfo [Decl a] (Expression a)
+  | Do                SpanInfo LayoutInfo [Statement a] (Expression a)
+  | IfThenElse        SpanInfo (Expression a) (Expression a) (Expression a)
+  | Case              SpanInfo LayoutInfo CaseType (Expression a) [Alt a]
+    deriving (Eq, Read, Show)
+
+-- |Infix operation
+data InfixOp a
+  = InfixOp     a QualIdent
+  | InfixConstr a QualIdent
+    deriving (Eq, Read, Show)
+
+-- |Statement (used for do-sequence and list comprehensions)
+data Statement a
+  = StmtExpr SpanInfo (Expression a)
+  | StmtDecl SpanInfo LayoutInfo [Decl a]
+  | StmtBind SpanInfo (Pattern a) (Expression a)
+    deriving (Eq, Read, Show)
+
+-- |Type of case expressions
+data CaseType
+  = Rigid
+  | Flex
+    deriving (Eq, Read, Show)
+
+-- |Single case alternative
+data Alt a = Alt SpanInfo (Pattern a) (Rhs a)
+    deriving (Eq, Read, Show)
+
+-- |Record field
+data Field a = Field SpanInfo QualIdent a
+    deriving (Eq, Read, Show)
+
+-- |Annotated identifier
+data Var a = Var a Ident
+    deriving (Eq, Read, Show)
+
+-- ---------------------------------------------------------------------------
+-- Goals
+-- ---------------------------------------------------------------------------
+
+-- |Goal in REPL (expression to evaluate)
+data Goal a = Goal SpanInfo LayoutInfo (Expression a) [Decl a]
+    deriving (Eq, Read, Show)
+
+-- ---------------------------------------------------------------------------
+-- instances
+-- ---------------------------------------------------------------------------
+
+instance Functor Module where
+  fmap f (Module sp li ps m es is ds) = Module sp li ps m es is (map (fmap f) ds)
+
+instance Functor Decl where
+  fmap _ (InfixDecl sp fix prec ops) = InfixDecl sp fix prec ops
+  fmap _ (DataDecl sp tc tvs cs clss) = DataDecl sp tc tvs cs clss
+  fmap _ (ExternalDataDecl sp tc tvs) = ExternalDataDecl sp tc tvs
+  fmap _ (NewtypeDecl sp tc tvs nc clss) = NewtypeDecl sp tc tvs nc clss
+  fmap _ (TypeDecl sp tc tvs ty) = TypeDecl sp tc tvs ty
+  fmap _ (TypeSig sp fs qty) = TypeSig sp fs qty
+  fmap f (FunctionDecl sp a f' eqs) = FunctionDecl sp (f a) f' (map (fmap f) eqs)
+  fmap f (ExternalDecl sp vs) = ExternalDecl sp (map (fmap f) vs)
+  fmap f (PatternDecl sp t rhs) = PatternDecl sp (fmap f t) (fmap f rhs)
+  fmap f (FreeDecl sp vs) = FreeDecl sp (map (fmap f) vs)
+  fmap _ (DefaultDecl sp tys) = DefaultDecl sp tys
+  fmap f (ClassDecl sp li cx cls clsvar ds) =
+    ClassDecl sp li cx cls clsvar (map (fmap f) ds)
+  fmap f (InstanceDecl sp li cx qcls inst ds) =
+    InstanceDecl sp li cx qcls inst (map (fmap f) ds)
+
+instance Functor Equation where
+  fmap f (Equation p lhs rhs) = Equation p (fmap f lhs) (fmap f rhs)
+
+instance Functor Lhs where
+  fmap f (FunLhs p f' ts) = FunLhs p f' (map (fmap f) ts)
+  fmap f (OpLhs p t1 op t2) = OpLhs p (fmap f t1) op (fmap f t2)
+  fmap f (ApLhs p lhs ts) = ApLhs p (fmap f lhs) (map (fmap f) ts)
+
+instance Functor Rhs where
+  fmap f (SimpleRhs p li e ds) = SimpleRhs p li (fmap f e) (map (fmap f) ds)
+  fmap f (GuardedRhs p li cs ds) = GuardedRhs p li (map (fmap f) cs) (map (fmap f) ds)
+
+instance Functor CondExpr where
+  fmap f (CondExpr p g e) = CondExpr p (fmap f g) (fmap f e)
+
+instance Functor Pattern where
+  fmap f (LiteralPattern p a l) = LiteralPattern p (f a) l
+  fmap f (NegativePattern p a l) = NegativePattern p (f a) l
+  fmap f (VariablePattern p a v) = VariablePattern p (f a) v
+  fmap f (ConstructorPattern p a c ts) =
+    ConstructorPattern p (f a) c (map (fmap f) ts)
+  fmap f (InfixPattern p a t1 op t2) =
+    InfixPattern p (f a) (fmap f t1) op (fmap f t2)
+  fmap f (ParenPattern p t) = ParenPattern p (fmap f t)
+  fmap f (RecordPattern p a c fs) =
+    RecordPattern p (f a) c (map (fmap (fmap f)) fs)
+  fmap f (TuplePattern p ts) = TuplePattern p (map (fmap f) ts)
+  fmap f (ListPattern p a ts) = ListPattern p (f a) (map (fmap f) ts)
+  fmap f (AsPattern p v t) = AsPattern p v (fmap f t)
+  fmap f (LazyPattern p t) = LazyPattern p (fmap f t)
+  fmap f (FunctionPattern p a f' ts) =
+    FunctionPattern p (f a) f' (map (fmap f) ts)
+  fmap f (InfixFuncPattern p a t1 op t2) =
+    InfixFuncPattern p (f a) (fmap f t1) op (fmap f t2)
+
+instance Functor Expression where
+  fmap f (Literal p a l) = Literal p (f a) l
+  fmap f (Variable p a v) = Variable p (f a) v
+  fmap f (Constructor p a c) = Constructor p (f a) c
+  fmap f (Paren p e) = Paren p (fmap f e)
+  fmap f (Typed p e qty) = Typed p (fmap f e) qty
+  fmap f (Record p a c fs) = Record p (f a) c (map (fmap (fmap f)) fs)
+  fmap f (RecordUpdate p e fs) = RecordUpdate p (fmap f e) (map (fmap (fmap f)) fs)
+  fmap f (Tuple p es) = Tuple p (map (fmap f) es)
+  fmap f (List p a es) = List p (f a) (map (fmap f) es)
+  fmap f (ListCompr p e stms) = ListCompr p (fmap f e) (map (fmap f) stms)
+  fmap f (EnumFrom p e) = EnumFrom p (fmap f e)
+  fmap f (EnumFromThen p e1 e2) = EnumFromThen p (fmap f e1) (fmap f e2)
+  fmap f (EnumFromTo p e1 e2) = EnumFromTo p (fmap f e1) (fmap f e2)
+  fmap f (EnumFromThenTo p e1 e2 e3) =
+    EnumFromThenTo p (fmap f e1) (fmap f e2) (fmap f e3)
+  fmap f (UnaryMinus p e) = UnaryMinus p (fmap f e)
+  fmap f (Apply p e1 e2) = Apply p (fmap f e1) (fmap f e2)
+  fmap f (InfixApply p e1 op e2) =
+    InfixApply p (fmap f e1) (fmap f op) (fmap f e2)
+  fmap f (LeftSection p e op) = LeftSection p (fmap f e) (fmap f op)
+  fmap f (RightSection p op e) = RightSection p (fmap f op) (fmap f e)
+  fmap f (Lambda p ts e) = Lambda p (map (fmap f) ts) (fmap f e)
+  fmap f (Let p li ds e) = Let p li (map (fmap f) ds) (fmap f e)
+  fmap f (Do p li stms e) = Do p li (map (fmap f) stms) (fmap f e)
+  fmap f (IfThenElse p e1 e2 e3) =
+    IfThenElse p (fmap f e1) (fmap f e2) (fmap f e3)
+  fmap f (Case p li ct e as) = Case p li ct (fmap f e) (map (fmap f) as)
+
+instance Functor InfixOp where
+  fmap f (InfixOp a op) = InfixOp (f a) op
+  fmap f (InfixConstr a op) = InfixConstr (f a) op
+
+instance Functor Statement where
+  fmap f (StmtExpr p e) = StmtExpr p (fmap f e)
+  fmap f (StmtDecl p li ds) = StmtDecl p li (map (fmap f) ds)
+  fmap f (StmtBind p t e) = StmtBind p (fmap f t) (fmap f e)
+
+instance Functor Alt where
+  fmap f (Alt p t rhs) = Alt p (fmap f t) (fmap f rhs)
+
+instance Functor Field where
+  fmap f (Field p l x) = Field p l (f x)
+
+instance Functor Var where
+  fmap f (Var a v) = Var (f a) v
+
+instance Functor Goal where
+  fmap f (Goal p li e ds) = Goal p li (fmap f e) (map (fmap f) ds)
+
+instance Pretty Infix where
+  pPrint InfixL = text "infixl"
+  pPrint InfixR = text "infixr"
+  pPrint Infix  = text "infix"
+
+instance HasSpanInfo (Module a) where
+  getSpanInfo (Module sp _ _ _ _ _ _) = sp
+
+  setSpanInfo sp (Module _ li ps m es is ds) = Module sp li ps m es is ds
+
+  updateEndPos m@(Module _ _ _ _ _ _ (d:ds)) =
+    setEndPosition (getSrcSpanEnd (last (d:ds))) m
+  updateEndPos m@(Module _ _ _ _ _ (i:is) _) =
+    setEndPosition (getSrcSpanEnd (last (i:is))) m
+  updateEndPos m@(Module (SpanInfo _ (s:ss)) _ _ _ _ _ _) =
+    setEndPosition (end (last (s:ss))) m
+  updateEndPos m@(Module _ _ (p:ps) _ _ _ _) =
+    setEndPosition (getSrcSpanEnd (last (p:ps))) m
+  updateEndPos m = m
+
+  getLayoutInfo (Module _ li _ _ _ _ _) = li
+
+instance HasSpanInfo (Decl a) where
+  getSpanInfo (InfixDecl        sp _ _ _)   = sp
+  getSpanInfo (DataDecl         sp _ _ _ _) = sp
+  getSpanInfo (ExternalDataDecl sp _ _)     = sp
+  getSpanInfo (NewtypeDecl      sp _ _ _ _) = sp
+  getSpanInfo (TypeDecl         sp _ _ _)   = sp
+  getSpanInfo (TypeSig          sp _ _)     = sp
+  getSpanInfo (FunctionDecl     sp _ _ _)   = sp
+  getSpanInfo (ExternalDecl     sp _)       = sp
+  getSpanInfo (PatternDecl      sp _ _)     = sp
+  getSpanInfo (FreeDecl         sp _)       = sp
+  getSpanInfo (DefaultDecl      sp _)       = sp
+  getSpanInfo (ClassDecl        sp _ _ _ _ _) = sp
+  getSpanInfo (InstanceDecl     sp _ _ _ _ _) = sp
+
+  setSpanInfo sp (InfixDecl _ fix prec ops) = InfixDecl sp fix prec ops
+  setSpanInfo sp (DataDecl _ tc tvs cs clss) = DataDecl sp tc tvs cs clss
+  setSpanInfo sp (ExternalDataDecl _ tc tvs) = ExternalDataDecl sp tc tvs
+  setSpanInfo sp (NewtypeDecl _ tc tvs nc clss) = NewtypeDecl sp tc tvs nc clss
+  setSpanInfo sp (TypeDecl _ tc tvs ty) = TypeDecl sp tc tvs ty
+  setSpanInfo sp (TypeSig _ fs qty) = TypeSig sp fs qty
+  setSpanInfo sp (FunctionDecl _ a f' eqs) = FunctionDecl sp a f' eqs
+  setSpanInfo sp (ExternalDecl _ vs) = ExternalDecl sp vs
+  setSpanInfo sp (PatternDecl _ t rhs) = PatternDecl sp t rhs
+  setSpanInfo sp (FreeDecl _ vs) = FreeDecl sp vs
+  setSpanInfo sp (DefaultDecl _ tys) = DefaultDecl sp tys
+  setSpanInfo sp (ClassDecl _ li cx cls clsvar ds) = ClassDecl sp li cx cls clsvar ds
+  setSpanInfo sp (InstanceDecl _ li cx qcls inst ds) = InstanceDecl sp li cx qcls inst ds
+
+  updateEndPos d@(InfixDecl _ _ _ ops) =
+    let i' = last ops
+    in setEndPosition (incr (getPosition i') (identLength i' - 1)) d
+  updateEndPos d@(DataDecl _ _ _ _ (c:cs)) =
+    let i' = last (c:cs)
+    in setEndPosition (incr (getPosition i') (qIdentLength i' - 1)) d
+  updateEndPos d@(DataDecl _ _ _ (c:cs) _) =
+    setEndPosition (getSrcSpanEnd (last (c:cs))) d
+  updateEndPos d@(DataDecl _ _ (i:is) _ _) =
+    let i' = last (i:is)
+    in setEndPosition (incr (getPosition i') (identLength i' - 1)) d
+  updateEndPos d@(DataDecl _ i _ _ _) =
+    setEndPosition (incr (getPosition i) (identLength i - 1)) d
+  updateEndPos d@(ExternalDataDecl _ _ (i:is)) =
+    let i' = last (i:is)
+    in setEndPosition (incr (getPosition i') (identLength i' - 1)) d
+  updateEndPos d@(ExternalDataDecl _ i _) =
+    setEndPosition (incr (getPosition i) (identLength i - 1)) d
+  updateEndPos d@(NewtypeDecl _ _ _ _ (c:cs)) =
+    let i' = last (c:cs)
+    in setEndPosition (incr (getPosition i') (qIdentLength i' - 1)) d
+  updateEndPos d@(NewtypeDecl _ _ _ c _) =
+    setEndPosition (getSrcSpanEnd c) d
+  updateEndPos d@(TypeDecl _ _ _ ty) =
+    setEndPosition (getSrcSpanEnd ty) d
+  updateEndPos d@(TypeSig _ _ qty) =
+    setEndPosition (getSrcSpanEnd qty) d
+  updateEndPos d@(FunctionDecl _ _ _ eqs) =
+    setEndPosition (getSrcSpanEnd (last eqs)) d
+  updateEndPos d@(ExternalDecl (SpanInfo _ ss) _) =
+    setEndPosition (end (last ss)) d
+  updateEndPos d@(ExternalDecl _ _) = d
+  updateEndPos d@(PatternDecl _ _ rhs) =
+    setEndPosition (getSrcSpanEnd rhs) d
+  updateEndPos d@(FreeDecl (SpanInfo _ ss) _) =
+    setEndPosition (end (last ss)) d
+  updateEndPos d@(FreeDecl _ _) = d
+  updateEndPos d@(DefaultDecl (SpanInfo _ ss) _) =
+    setEndPosition (end (last ss)) d
+  updateEndPos d@(DefaultDecl _ _) = d
+  updateEndPos d@(ClassDecl _ _ _ _ _ (d':ds)) =
+    setEndPosition (getSrcSpanEnd (last (d':ds))) d
+  updateEndPos d@(ClassDecl (SpanInfo _ ss) _ _ _ _ _) =
+    setEndPosition (end (last ss)) d
+  updateEndPos d@(ClassDecl _ _ _ _ _ _) = d
+  updateEndPos d@(InstanceDecl _ _ _ _ _ (d':ds)) =
+    setEndPosition (getSrcSpanEnd (last (d':ds))) d
+  updateEndPos d@(InstanceDecl (SpanInfo _ ss) _ _ _ _ _) =
+    setEndPosition (end (last ss)) d
+  updateEndPos d@(InstanceDecl _ _ _ _ _ _) = d
+
+  getLayoutInfo (ClassDecl _ li _ _ _ _) = li
+  getLayoutInfo (InstanceDecl _ li _ _ _ _) = li
+  getLayoutInfo _ = WhitespaceLayout
+
+instance HasSpanInfo (Equation a) where
+  getSpanInfo (Equation spi _ _) = spi
+  setSpanInfo spi (Equation _ lhs rhs) = Equation spi lhs rhs
+  updateEndPos e@(Equation _ _ rhs) =
+    setEndPosition (getSrcSpanEnd rhs) e
+
+instance HasSpanInfo ModulePragma where
+  getSpanInfo (LanguagePragma sp _  ) = sp
+  getSpanInfo (OptionsPragma  sp _ _) = sp
+
+  setSpanInfo sp (LanguagePragma _ ex ) = LanguagePragma sp ex
+  setSpanInfo sp (OptionsPragma  _ t a) = OptionsPragma sp t a
+
+  updateEndPos p@(LanguagePragma (SpanInfo _ ss) _) =
+    setEndPosition (end (last ss)) p
+  updateEndPos p@(LanguagePragma _ _) = p
+  updateEndPos p@(OptionsPragma (SpanInfo _ ss) _ _) =
+    setEndPosition (end (last ss)) p
+  updateEndPos p@(OptionsPragma _ _ _) = p
+
+instance HasSpanInfo ExportSpec where
+  getSpanInfo (Exporting sp _) = sp
+  setSpanInfo sp (Exporting _ ex) = Exporting sp ex
+
+  updateEndPos e@(Exporting (SpanInfo _ ss) _) =
+    setEndPosition (end (last ss)) e
+  updateEndPos e@(Exporting _ _) = e
+
+instance HasSpanInfo Export where
+  getSpanInfo (Export sp _)           = sp
+  getSpanInfo (ExportTypeWith sp _ _) = sp
+  getSpanInfo (ExportTypeAll sp _)    = sp
+  getSpanInfo (ExportModule sp _)     = sp
+
+  setSpanInfo sp (Export _ qid)            = Export sp qid
+  setSpanInfo sp (ExportTypeWith _ qid cs) = ExportTypeWith sp qid cs
+  setSpanInfo sp (ExportTypeAll _ qid)     = ExportTypeAll sp qid
+  setSpanInfo sp (ExportModule _ mid)      = ExportModule sp mid
+
+  updateEndPos e@(Export _ idt) =
+    setEndPosition (incr (getPosition idt) (qIdentLength idt - 1)) e
+  updateEndPos e@(ExportTypeWith (SpanInfo _ ss) _ _) =
+    setEndPosition (end (last ss)) e
+  updateEndPos e@(ExportTypeWith _ _ _) = e
+  updateEndPos e@(ExportTypeAll (SpanInfo _ ss) _) =
+    setEndPosition (end (last ss)) e
+  updateEndPos e@(ExportTypeAll _ _) = e
+  updateEndPos e@(ExportModule _ mid) =
+    setEndPosition (incr (getPosition mid) (mIdentLength mid - 1)) e
+
+instance HasSpanInfo ImportDecl where
+  getSpanInfo (ImportDecl sp _ _ _ _) = sp
+  setSpanInfo sp (ImportDecl _ mid q as spec) = ImportDecl sp mid q as spec
+
+  updateEndPos i@(ImportDecl _ _ _ _ (Just spec)) =
+    setEndPosition (getSrcSpanEnd spec) i
+  updateEndPos i@(ImportDecl _ _ _ (Just mid) _) =
+    setEndPosition (incr (getPosition mid) (mIdentLength mid - 1)) i
+  updateEndPos i@(ImportDecl _ mid _ _ _) =
+    setEndPosition (incr (getPosition mid) (mIdentLength mid - 1)) i
+
+instance HasSpanInfo ImportSpec where
+  getSpanInfo (Importing sp _) = sp
+  getSpanInfo (Hiding    sp _) = sp
+
+  setSpanInfo sp (Importing _ im) = Importing sp im
+  setSpanInfo sp (Hiding    _ im) = Hiding sp im
+
+  updateEndPos i@(Importing (SpanInfo _ ss) _) =
+    setEndPosition (end (last ss)) i
+  updateEndPos i@(Importing _ _) = i
+  updateEndPos i@(Hiding (SpanInfo _ ss) _) =
+    setEndPosition (end (last ss)) i
+  updateEndPos i@(Hiding _ _) = i
+
+instance HasSpanInfo Import where
+  getSpanInfo (Import sp _)           = sp
+  getSpanInfo (ImportTypeWith sp _ _) = sp
+  getSpanInfo (ImportTypeAll sp _)    = sp
+
+  setSpanInfo sp (Import _ qid)            = Import sp qid
+  setSpanInfo sp (ImportTypeWith _ qid cs) = ImportTypeWith sp qid cs
+  setSpanInfo sp (ImportTypeAll _ qid)     = ImportTypeAll sp qid
+
+  updateEndPos i@(Import _ idt) =
+    setEndPosition (incr (getPosition idt) (identLength idt - 1)) i
+  updateEndPos i@(ImportTypeWith (SpanInfo _ ss) _ _) =
+    setEndPosition (end (last ss)) i
+  updateEndPos i@(ImportTypeWith _ _ _) = i
+  updateEndPos i@(ImportTypeAll (SpanInfo _ ss) _) =
+    setEndPosition (end (last ss)) i
+  updateEndPos i@(ImportTypeAll _ _) = i
+
+instance HasSpanInfo ConstrDecl where
+  getSpanInfo (ConstrDecl sp _ _)   = sp
+  getSpanInfo (ConOpDecl  sp _ _ _) = sp
+  getSpanInfo (RecordDecl sp _ _)   = sp
+
+  setSpanInfo sp (ConstrDecl _ idt ty) = ConstrDecl sp idt ty
+  setSpanInfo sp (ConOpDecl  _ ty1 idt ty2) = ConOpDecl sp ty1 idt ty2
+  setSpanInfo sp (RecordDecl _ idt fd) = RecordDecl sp idt fd
+
+  updateEndPos c@(ConstrDecl _ _ (t:ts)) =
+    setEndPosition (getSrcSpanEnd (last (t:ts))) c
+  updateEndPos c@(ConstrDecl _ idt _) =
+    setEndPosition (incr (getPosition idt) (identLength idt - 1)) c
+  updateEndPos c@(ConOpDecl _ _ _ ty) =
+    setEndPosition (getSrcSpanEnd ty) c
+  updateEndPos c@(RecordDecl (SpanInfo _ ss) _ _) =
+    setEndPosition (end (last ss)) c
+  updateEndPos c@(RecordDecl _ _ _) = c
+
+instance HasSpanInfo NewConstrDecl where
+  getSpanInfo (NewConstrDecl sp _ _)   = sp
+  getSpanInfo (NewRecordDecl sp _ _)   = sp
+
+  setSpanInfo sp (NewConstrDecl _ idt ty)  = NewConstrDecl sp idt ty
+  setSpanInfo sp (NewRecordDecl _ idt fty) = NewRecordDecl sp idt fty
+
+  updateEndPos c@(NewConstrDecl _ _ ty) =
+    setEndPosition (getSrcSpanEnd ty) c
+  updateEndPos c@(NewRecordDecl (SpanInfo _ ss) _ _) =
+    setEndPosition (end (last ss)) c
+  updateEndPos c@(NewRecordDecl _ _ _) = c
+
+instance HasSpanInfo FieldDecl where
+    getSpanInfo (FieldDecl sp _ _) = sp
+    setSpanInfo sp (FieldDecl _ idt ty) = FieldDecl sp idt ty
+    updateEndPos d@(FieldDecl _ _ ty) =
+      setEndPosition (getSrcSpanEnd ty) d
+
+instance HasSpanInfo TypeExpr where
+  getSpanInfo (ConstructorType sp _) = sp
+  getSpanInfo (ApplyType sp _ _)     = sp
+  getSpanInfo (VariableType sp _)    = sp
+  getSpanInfo (TupleType sp _)       = sp
+  getSpanInfo (ListType sp _)        = sp
+  getSpanInfo (ArrowType sp _ _)     = sp
+  getSpanInfo (ParenType sp _)       = sp
+  getSpanInfo (ForallType sp _ _)    = sp
+
+  setSpanInfo sp (ConstructorType _ qid) = ConstructorType sp qid
+  setSpanInfo sp (ApplyType _ ty1 ty2)   = ApplyType sp ty1 ty2
+  setSpanInfo sp (VariableType _ idt)    = VariableType sp idt
+  setSpanInfo sp (TupleType _ tys)       = TupleType sp tys
+  setSpanInfo sp (ListType _ ty)         = ListType sp ty
+  setSpanInfo sp (ArrowType _ ty1 ty2)   = ArrowType sp ty1 ty2
+  setSpanInfo sp (ParenType _ ty)        = ParenType sp ty
+  setSpanInfo sp (ForallType _ idt ty)   = ForallType sp idt ty
+
+  updateEndPos t@(ConstructorType _ qid) =
+    setEndPosition (incr (getPosition qid) (qIdentLength qid - 1)) t
+  updateEndPos t@(ApplyType _ _ t2) =
+    setEndPosition (getSrcSpanEnd t2) t
+  updateEndPos t@(VariableType _ idt) =
+    setEndPosition (incr (getPosition idt) (identLength idt - 1)) t
+  updateEndPos t@(ListType (SpanInfo _ (s:ss)) _) =
+    setEndPosition (end (last (s:ss))) t
+  updateEndPos t@(ListType _ _) = t
+  updateEndPos t@(TupleType _ tys) =
+    setEndPosition (getSrcSpanEnd (last tys)) t
+  updateEndPos t@(ArrowType _ _ t2) =
+    setEndPosition (getSrcSpanEnd t2) t
+  updateEndPos t@(ParenType (SpanInfo _ (s:ss)) _) =
+    setEndPosition (end (last (s:ss))) t
+  updateEndPos t@(ParenType _ _) = t
+  updateEndPos t@(ForallType _ _ _) = t -- not a parseable type
+
+instance HasSpanInfo QualTypeExpr where
+  getSpanInfo (QualTypeExpr sp _ _) = sp
+  setSpanInfo sp (QualTypeExpr _ cx ty) = QualTypeExpr sp cx ty
+  updateEndPos t@(QualTypeExpr _ _ ty) =
+    setEndPosition (getSrcSpanEnd ty) t
+
+instance HasSpanInfo Constraint where
+  getSpanInfo (Constraint sp _ _) = sp
+  setSpanInfo sp (Constraint _ qid ty) = Constraint sp qid ty
+  updateEndPos c@(Constraint (SpanInfo _ (s:ss)) _ _) =
+    setEndPosition (end (last (s:ss))) c
+  updateEndPos c@(Constraint _ _ ty) =
+    setEndPosition (getSrcSpanEnd ty) c
+
+instance HasSpanInfo (Lhs a) where
+  getSpanInfo (FunLhs sp _ _)   = sp
+  getSpanInfo (OpLhs  sp _ _ _) = sp
+  getSpanInfo (ApLhs  sp _ _)   = sp
+
+  setSpanInfo sp (FunLhs _ idt ps)    = FunLhs sp idt ps
+  setSpanInfo sp (OpLhs  _ p1 idt p2) = OpLhs sp p1 idt p2
+  setSpanInfo sp (ApLhs  _ lhs ps)    = ApLhs sp lhs ps
+
+  updateEndPos l@(FunLhs _ _ (p:ps)) =
+    setEndPosition (getSrcSpanEnd (last (p:ps))) l
+  updateEndPos l@(FunLhs _ idt _) =
+    setEndPosition (incr (getPosition idt) (identLength idt - 1)) l
+  updateEndPos l@(OpLhs _ _ _ p) =
+    setEndPosition (getSrcSpanEnd p) l
+  updateEndPos l@(ApLhs _ _ (p:ps)) =
+    setEndPosition (getSrcSpanEnd (last (p:ps))) l
+  updateEndPos l@(ApLhs (SpanInfo _ [_,s]) _ _) =
+    setEndPosition (end s) l
+  updateEndPos l@(ApLhs _ _ _) = l
+
+
+instance HasSpanInfo (Rhs a) where
+  getSpanInfo (SimpleRhs sp _ _ _)  = sp
+  getSpanInfo (GuardedRhs sp _ _ _) = sp
+
+  setSpanInfo sp (SimpleRhs _ li ex ds)  = SimpleRhs sp li ex ds
+  setSpanInfo sp (GuardedRhs _ li cs ds) = GuardedRhs sp li cs ds
+
+  updateEndPos r@(SimpleRhs (SpanInfo _ [_,_]) _ _ (d:ds)) =
+    setEndPosition (getSrcSpanEnd (last (d:ds))) r
+  updateEndPos r@(SimpleRhs (SpanInfo _ [_,s]) _ _ _) =
+    setEndPosition (end s) r
+  updateEndPos r@(SimpleRhs _ _ e _) =
+    setEndPosition (getSrcSpanEnd e) r
+  updateEndPos r@(GuardedRhs (SpanInfo _ [_,_]) _ _ (d:ds)) =
+    setEndPosition (getSrcSpanEnd (last (d:ds))) r
+  updateEndPos r@(GuardedRhs (SpanInfo _ [_,s]) _ _ _) =
+    setEndPosition (end s) r
+  updateEndPos r@(GuardedRhs _ _ cs _) =
+    setEndPosition (getSrcSpanEnd (last cs)) r
+
+  getLayoutInfo (SimpleRhs _ li _ _) = li
+  getLayoutInfo (GuardedRhs _ li _ _) = li
+
+instance HasSpanInfo (CondExpr a) where
+  getSpanInfo (CondExpr sp _ _) = sp
+  setSpanInfo sp (CondExpr _ e1 e2) = CondExpr sp e1 e2
+  updateEndPos ce@(CondExpr _ _ e) =
+    setEndPosition (getSrcSpanEnd e) ce
+
+instance HasSpanInfo (Pattern a) where
+  getSpanInfo (LiteralPattern  sp _ _)      = sp
+  getSpanInfo (NegativePattern sp _ _)      = sp
+  getSpanInfo (VariablePattern sp _ _)      = sp
+  getSpanInfo (ConstructorPattern sp _ _ _) = sp
+  getSpanInfo (InfixPattern sp _ _ _ _)     = sp
+  getSpanInfo (ParenPattern sp _)           = sp
+  getSpanInfo (RecordPattern sp _ _ _)      = sp
+  getSpanInfo (TuplePattern sp _)           = sp
+  getSpanInfo (ListPattern sp _ _)          = sp
+  getSpanInfo (AsPattern sp _ _)            = sp
+  getSpanInfo (LazyPattern sp _)            = sp
+  getSpanInfo (FunctionPattern sp _ _ _)    = sp
+  getSpanInfo (InfixFuncPattern sp _ _ _ _) = sp
+
+  setSpanInfo sp (LiteralPattern _ a l) = LiteralPattern sp a l
+  setSpanInfo sp (NegativePattern _ a l) = NegativePattern sp a l
+  setSpanInfo sp (VariablePattern _ a v) = VariablePattern sp a v
+  setSpanInfo sp (ConstructorPattern _ a c ts) = ConstructorPattern sp a c ts
+  setSpanInfo sp (InfixPattern _ a t1 op t2) = InfixPattern sp a t1 op t2
+  setSpanInfo sp (ParenPattern _ t) = ParenPattern sp t
+  setSpanInfo sp (RecordPattern _ a c fs) = RecordPattern sp a c fs
+  setSpanInfo sp (TuplePattern _ ts) = TuplePattern sp ts
+  setSpanInfo sp (ListPattern _ a ts) = ListPattern sp a ts
+  setSpanInfo sp (AsPattern _ v t) = AsPattern sp v t
+  setSpanInfo sp (LazyPattern _ t) = LazyPattern sp t
+  setSpanInfo sp (FunctionPattern _ a f' ts) = FunctionPattern sp a f' ts
+  setSpanInfo sp (InfixFuncPattern _ a t1 op t2) = InfixFuncPattern sp a t1 op t2
+
+  updateEndPos p@(LiteralPattern  _ _ _) = p
+  updateEndPos p@(NegativePattern _ _ _) = p
+  updateEndPos p@(VariablePattern _ _ v) =
+    setEndPosition (incr (getPosition v) (identLength v - 1)) p
+  updateEndPos p@(ConstructorPattern _ _ _ (t:ts)) =
+    setEndPosition (getSrcSpanEnd (last (t:ts))) p
+  updateEndPos p@(ConstructorPattern _ _ c _) =
+    setEndPosition (incr (getPosition c) (qIdentLength c - 1)) p
+  updateEndPos p@(InfixPattern _ _ _ _ t2) =
+    setEndPosition (getSrcSpanEnd t2) p
+  updateEndPos p@(ParenPattern (SpanInfo _ (s:ss)) _) =
+    setEndPosition (end (last (s:ss))) p
+  updateEndPos p@(ParenPattern _ _) = p
+  updateEndPos p@(RecordPattern (SpanInfo _ (s:ss)) _ _ _) =
+    setEndPosition (end (last (s:ss))) p
+  updateEndPos p@(RecordPattern _ _ _ _) = p
+  updateEndPos p@(TuplePattern (SpanInfo _ (s:ss)) _) =
+    setEndPosition (end (last (s:ss))) p
+  updateEndPos p@(TuplePattern _ _) = p
+  updateEndPos p@(ListPattern (SpanInfo _ (s:ss)) _ _) =
+    setEndPosition (end (last (s:ss))) p
+  updateEndPos p@(ListPattern _ _ _) = p
+  updateEndPos p@(AsPattern _ _ t) =
+    setEndPosition (getSrcSpanEnd t) p
+  updateEndPos p@(LazyPattern _ t) =
+    setEndPosition (getSrcSpanEnd t) p
+  updateEndPos p@(FunctionPattern _ _ _ _) = p
+  updateEndPos p@(InfixFuncPattern _ _ _ _ _) = p
+
+instance HasSpanInfo (Expression a) where
+  getSpanInfo (Literal sp _ _) = sp
+  getSpanInfo (Variable sp _ _) = sp
+  getSpanInfo (Constructor sp _ _) = sp
+  getSpanInfo (Paren sp _) = sp
+  getSpanInfo (Typed sp _ _) = sp
+  getSpanInfo (Record sp _ _ _) = sp
+  getSpanInfo (RecordUpdate sp _ _) = sp
+  getSpanInfo (Tuple sp _) = sp
+  getSpanInfo (List sp _ _) = sp
+  getSpanInfo (ListCompr sp _ _) = sp
+  getSpanInfo (EnumFrom sp _) = sp
+  getSpanInfo (EnumFromThen sp _ _) = sp
+  getSpanInfo (EnumFromTo sp _ _) = sp
+  getSpanInfo (EnumFromThenTo sp _ _ _) = sp
+  getSpanInfo (UnaryMinus sp _) = sp
+  getSpanInfo (Apply sp _ _) = sp
+  getSpanInfo (InfixApply sp _ _ _) = sp
+  getSpanInfo (LeftSection sp _ _) = sp
+  getSpanInfo (RightSection sp _ _) = sp
+  getSpanInfo (Lambda sp _ _) = sp
+  getSpanInfo (Let sp _ _ _) = sp
+  getSpanInfo (Do sp _ _ _) = sp
+  getSpanInfo (IfThenElse sp _ _ _) = sp
+  getSpanInfo (Case sp _ _ _ _) = sp
+
+  setSpanInfo sp (Literal _ a l) = Literal sp a l
+  setSpanInfo sp (Variable _ a v) = Variable sp a v
+  setSpanInfo sp (Constructor _ a c) = Constructor sp a c
+  setSpanInfo sp (Paren _ e) = Paren sp e
+  setSpanInfo sp (Typed _ e qty) = Typed sp e qty
+  setSpanInfo sp (Record _ a c fs) = Record sp a c fs
+  setSpanInfo sp (RecordUpdate _ e fs) = RecordUpdate sp e fs
+  setSpanInfo sp (Tuple _ es) = Tuple sp es
+  setSpanInfo sp (List _ a es) = List sp a es
+  setSpanInfo sp (ListCompr _ e stms) = ListCompr sp e stms
+  setSpanInfo sp (EnumFrom _ e) = EnumFrom sp e
+  setSpanInfo sp (EnumFromThen _ e1 e2) = EnumFromThen sp e1 e2
+  setSpanInfo sp (EnumFromTo _ e1 e2) = EnumFromTo sp e1 e2
+  setSpanInfo sp (EnumFromThenTo _ e1 e2 e3) = EnumFromThenTo sp e1 e2 e3
+  setSpanInfo sp (UnaryMinus _ e) = UnaryMinus sp e
+  setSpanInfo sp (Apply _ e1 e2) = Apply sp e1 e2
+  setSpanInfo sp (InfixApply _ e1 op e2) = InfixApply sp e1 op e2
+  setSpanInfo sp (LeftSection _ e op) = LeftSection sp e op
+  setSpanInfo sp (RightSection _ op e) = RightSection sp op e
+  setSpanInfo sp (Lambda _ ts e) = Lambda sp ts e
+  setSpanInfo sp (Let _ li ds e) = Let sp li ds e
+  setSpanInfo sp (Do _ li stms e) = Do sp li stms e
+  setSpanInfo sp (IfThenElse _ e1 e2 e3) = IfThenElse sp e1 e2 e3
+  setSpanInfo sp (Case _ li ct e as) = Case sp li ct e as
+
+  updateEndPos e@(Literal _ _ _) = e
+  updateEndPos e@(Variable _ _ v) =
+    setEndPosition (incr (getPosition v) (qIdentLength v - 1)) e
+  updateEndPos e@(Constructor _ _ c) =
+    setEndPosition (incr (getPosition c) (qIdentLength c - 1)) e
+  updateEndPos e@(Paren (SpanInfo _ [_,s]) _) =
+    setEndPosition (end s) e
+  updateEndPos e@(Paren _ _) = e
+  updateEndPos e@(Typed _ _ qty) =
+    setEndPosition (getSrcSpanEnd qty) e
+  updateEndPos e@(Record (SpanInfo _ (s:ss)) _ _ _) =
+    setEndPosition (end (last (s:ss))) e
+  updateEndPos e@(Record _ _ _ _) = e
+  updateEndPos e@(RecordUpdate (SpanInfo _ (s:ss)) _ _) =
+    setEndPosition (end (last (s:ss))) e
+  updateEndPos e@(RecordUpdate _ _ _) = e
+  updateEndPos e@(Tuple (SpanInfo _ [_,s]) _) =
+    setEndPosition (end s) e
+  updateEndPos e@(Tuple _ _) = e
+  updateEndPos e@(List (SpanInfo _ (s:ss)) _ _) =
+    setEndPosition (end (last (s:ss))) e
+  updateEndPos e@(List _ _ _) = e
+  updateEndPos e@(ListCompr (SpanInfo _ (s:ss)) _ _) =
+    setEndPosition (end (last (s:ss))) e
+  updateEndPos e@(ListCompr _ _ _) = e
+  updateEndPos e@(EnumFrom (SpanInfo _ [_,_,s]) _) =
+    setEndPosition (end s) e
+  updateEndPos e@(EnumFrom _ _) = e
+  updateEndPos e@(EnumFromTo (SpanInfo _ [_,_,s]) _ _) =
+    setEndPosition (end s) e
+  updateEndPos e@(EnumFromTo _ _ _) = e
+  updateEndPos e@(EnumFromThen (SpanInfo _ [_,_,_,s]) _ _) =
+    setEndPosition (end s) e
+  updateEndPos e@(EnumFromThen _ _ _) = e
+  updateEndPos e@(EnumFromThenTo (SpanInfo _ [_,_,_,s]) _ _ _) =
+    setEndPosition (end s) e
+  updateEndPos e@(EnumFromThenTo _ _ _ _) = e
+  updateEndPos e@(UnaryMinus _ e') =
+    setEndPosition (getSrcSpanEnd e') e
+  updateEndPos e@(Apply _ _ e') =
+    setEndPosition (getSrcSpanEnd e') e
+  updateEndPos e@(InfixApply _ _ _ e') =
+    setEndPosition (getSrcSpanEnd e') e
+  updateEndPos e@(LeftSection (SpanInfo _ [_,s]) _ _) =
+    setEndPosition (end s) e
+  updateEndPos e@(LeftSection _ _ _) = e
+  updateEndPos e@(RightSection (SpanInfo _ [_,s]) _ _) =
+    setEndPosition (end s) e
+  updateEndPos e@(RightSection _ _ _) = e
+  updateEndPos e@(Lambda _ _ e') =
+    setEndPosition (getSrcSpanEnd e') e
+  updateEndPos e@(Let _ _ _ e') =
+    setEndPosition (getSrcSpanEnd e') e
+  updateEndPos e@(Do _ _ _ e') =
+    setEndPosition (getSrcSpanEnd e') e
+  updateEndPos e@(IfThenElse _ _ _ e') =
+    setEndPosition (getSrcSpanEnd e') e
+  updateEndPos e@(Case _ _ _ _ (a:as)) =
+    setEndPosition (getSrcSpanEnd (last (a:as))) e
+  updateEndPos e@(Case (SpanInfo _ (s:ss)) _ _ _ _) =
+    setEndPosition (end (last (s:ss))) e
+  updateEndPos e@(Case _ _ _ _ _) = e
+
+  getLayoutInfo (Let _ li _ _) = li
+  getLayoutInfo (Do _ li _ _) = li
+  getLayoutInfo (Case _ li _ _ _) = li
+  getLayoutInfo _ = WhitespaceLayout
+
+instance HasSpanInfo (Statement a) where
+  getSpanInfo (StmtExpr sp _)   = sp
+  getSpanInfo (StmtDecl sp _ _) = sp
+  getSpanInfo (StmtBind sp _ _) = sp
+
+  setSpanInfo sp (StmtExpr _    ex) = StmtExpr sp ex
+  setSpanInfo sp (StmtDecl _ li ds) = StmtDecl sp li ds
+  setSpanInfo sp (StmtBind _ p  ex) = StmtBind sp p ex
+
+  updateEndPos s@(StmtExpr _ e) =
+    setEndPosition (getSrcSpanEnd e) s
+  updateEndPos s@(StmtBind _ _ e) =
+    setEndPosition (getSrcSpanEnd e) s
+  updateEndPos s@(StmtDecl _ _ (d:ds)) =
+    setEndPosition (getSrcSpanEnd (last (d:ds))) s
+  updateEndPos s@(StmtDecl (SpanInfo _ [s']) _ _) = -- empty let
+    setEndPosition (end s') s
+  updateEndPos s@(StmtDecl _ _ _) = s
+
+  getLayoutInfo (StmtDecl _ li _) = li
+  getLayoutInfo _ = WhitespaceLayout
+
+instance HasSpanInfo (Alt a) where
+  getSpanInfo (Alt sp _ _) = sp
+  setSpanInfo sp (Alt _ p rhs) = Alt sp p rhs
+  updateEndPos a@(Alt _ _ rhs) =
+    setEndPosition (getSrcSpanEnd rhs) a
+
+instance HasSpanInfo (Field a) where
+  getSpanInfo (Field sp _ _) = sp
+  setSpanInfo sp (Field _ qid a) = Field sp qid a
+  updateEndPos f@(Field (SpanInfo _ ss) _ _) =
+    setEndPosition (end (last ss)) f
+  updateEndPos f@ (Field _ _ _) = f
+
+instance HasSpanInfo (Goal a) where
+  getSpanInfo (Goal sp _ _ _) = sp
+  setSpanInfo sp (Goal _ li e ds) = Goal sp li e ds
+
+  updateEndPos g@(Goal (SpanInfo _ [_]) _ _ (d:ds)) =
+    setEndPosition (getSrcSpanEnd (last (d:ds))) g
+  updateEndPos g@(Goal (SpanInfo _ [s]) _ _ _) =
+    setEndPosition (end s) g
+  updateEndPos g@(Goal _ _ _ _) = g
+
+  getLayoutInfo (Goal _ li _ _) = li
+
+instance HasPosition (Module a) where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition (Decl a) where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition (Equation a) where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition ModulePragma where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition ExportSpec where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition ImportDecl where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition ImportSpec where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition Export where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition Import where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition ConstrDecl where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition TypeExpr where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition QualTypeExpr where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition NewConstrDecl where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition Constraint where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition FieldDecl where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition (Lhs a) where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition (Rhs a) where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition (CondExpr a) where
+  getPosition = getStartPosition
+
+instance HasPosition (Pattern a) where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition (Expression a) where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition (Alt a) where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition (Goal a) where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition (Field a) where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition (Statement a) where
+  getPosition = getStartPosition
+  setPosition = setStartPosition
+
+instance HasPosition (InfixOp a) where
+  getPosition (InfixOp     _ q) = getPosition q
+  getPosition (InfixConstr _ q) = getPosition q
+
+  setPosition p (InfixOp     a q) = InfixOp     a (setPosition p q)
+  setPosition p (InfixConstr a q) = InfixConstr a (setPosition p q)
+
+instance Binary a => Binary (Module a) where
+  put (Module spi li ps mid ex im ds) = put spi >> put li >> put ps >>
+                                        put mid >> put ex >> put im >> put ds
+  get = Module <$> get <*> get <*> get <*> get <*> get <*> get <*> get
+
+instance Binary ModulePragma where
+  put (LanguagePragma spi ex  ) = putWord8 0 >> put spi >> put ex
+  put (OptionsPragma  spi t  s) = putWord8 1 >> put spi >> put t >> put s
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 LanguagePragma get get
+      1 -> liftM3 OptionsPragma get get get
+      _ -> fail "Invalid encoding for ModulePragma"
+
+instance Binary ExportSpec where
+  put (Exporting spi es) = put spi >> put es
+  get = liftM2 Exporting get get
+
+instance Binary Export where
+  put (Export         spi qid   ) = putWord8 0 >> put spi >> put qid
+  put (ExportTypeWith spi qid is) = putWord8 1 >> put spi >> put qid >> put is
+  put (ExportTypeAll  spi qid   ) = putWord8 2 >> put spi >> put qid
+  put (ExportModule   spi mid   ) = putWord8 3 >> put spi >> put mid
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 Export get get
+      1 -> liftM3 ExportTypeWith get get get
+      2 -> liftM2 ExportTypeAll get get
+      3 -> liftM2 ExportModule get get
+      _ -> fail "Invalid encoding for Export"
+
+instance Binary ImportDecl where
+  put (ImportDecl spi mid q al im) = put spi >> put mid >> put q >>
+                                     put al >> put im
+  get = ImportDecl <$> get <*> get <*> get <*> get <*> get
+
+instance Binary ImportSpec where
+  put (Importing spi im) = putWord8 0 >> put spi >> put im
+  put (Hiding    spi im) = putWord8 1 >> put spi >> put im
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 Importing get get
+      1 -> liftM2 Hiding get get
+      _ -> fail "Invalid encoding for ImportSpec"
+
+instance Binary Import where
+  put (Import         spi idt   ) = putWord8 0 >> put spi >> put idt
+  put (ImportTypeWith spi idt is) = putWord8 1 >> put spi >> put idt >> put is
+  put (ImportTypeAll  spi idt   ) = putWord8 2 >> put spi >> put idt
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 Import get get
+      1 -> liftM3 ImportTypeWith get get get
+      2 -> liftM2 ImportTypeAll get get
+      _ -> fail "Invalid encoding for Import"
+
+instance Binary a => Binary (Decl a) where
+  put (InfixDecl spi i pr is) =
+    putWord8 0 >> put spi >> put i >> put pr >> put is
+  put (DataDecl spi idt vs cns cls) =
+    putWord8 1 >> put spi >> put idt >> put vs >> put cns >> put cls
+  put (ExternalDataDecl spi idt vs) =
+    putWord8 2 >> put spi >> put idt >> put vs
+  put (NewtypeDecl spi idt vs cn cls) =
+    putWord8 3 >> put spi >> put idt >> put vs  >> put cn >> put cls >> put cls
+  put (TypeDecl spi idt vs ty) =
+    putWord8 4 >> put spi >> put idt >> put vs  >> put ty
+  put (TypeSig spi fs ty) =
+    putWord8 5 >> put spi >> put fs >> put ty
+  put (FunctionDecl spi a f eqs) =
+    putWord8 6 >> put spi >> put a >> put f >> put eqs
+  put (ExternalDecl spi vs) =
+    putWord8 7 >> put spi >> put vs
+  put (PatternDecl spi p rhs) =
+    putWord8 8 >> put spi >> put p >> put rhs
+  put (FreeDecl spi vs) =
+    putWord8 9 >> put spi >> put vs
+  put (DefaultDecl spi tys) =
+    putWord8 10 >> put spi >> put tys
+  put (ClassDecl spi li cx cls v ds) =
+    putWord8 11 >> put spi >> put li >> put cx >> put cls >> put v >> put ds
+  put (InstanceDecl spi li cx cls ty ds) =
+    putWord8 12 >> put spi >> put li >> put cx >> put cls >> put ty >> put ds
+
+  get = do
+    x <- getWord8
+    case x of
+      0  -> InfixDecl <$> get <*> get <*> get <*> get
+      1  -> DataDecl <$> get <*> get <*> get <*> get <*> get
+      2  -> ExternalDataDecl <$> get <*> get <*> get
+      3  -> NewtypeDecl <$> get <*> get <*> get <*> get <*> get
+      4  -> TypeDecl <$> get <*> get <*> get <*> get
+      5  -> TypeSig <$> get <*> get <*> get
+      6  -> FunctionDecl <$> get <*> get <*> get <*> get
+      7  -> ExternalDecl <$> get <*> get
+      8  -> PatternDecl <$> get <*> get <*> get
+      9  -> FreeDecl <$> get <*> get
+      10 -> DefaultDecl <$> get <*> get
+      11 -> ClassDecl <$> get <*> get <*> get <*> get <*> get <*> get
+      12 -> InstanceDecl <$> get <*> get <*> get <*> get <*> get <*> get
+      _  -> fail "Invalid encoding for Decl"
+
+instance Binary Infix where
+  put InfixL = putWord8 0
+  put InfixR = putWord8 1
+  put Infix  = putWord8 2
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> return InfixL
+      1 -> return InfixR
+      2 -> return Infix
+      _ -> fail "Invalid encoding for Infix"
+
+instance Binary ConstrDecl where
+  put (ConstrDecl spi idt tys) =
+    putWord8 0 >> put spi >> put idt >> put tys
+  put (ConOpDecl spi ty1 idt ty2) =
+    putWord8 1 >> put spi >> put ty1 >> put idt >> put ty2
+  put (RecordDecl spi idt fs) =
+    putWord8 2 >> put spi >> put idt >> put fs
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM3 ConstrDecl get get get
+      1 -> ConOpDecl <$> get <*> get <*> get <*> get
+      2 -> liftM3 RecordDecl get get get
+      _ -> fail "Invalid encoding for ConstrDecl"
+
+instance Binary NewConstrDecl where
+  put (NewConstrDecl spi c ty) =
+    putWord8 0 >> put spi >> put c >> put ty
+  put (NewRecordDecl spi c fs) =
+    putWord8 1 >> put spi >> put c >> put fs
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM3 NewConstrDecl get get get
+      1 -> liftM3 NewRecordDecl get get get
+      _ -> fail "Invalid encoding for NewConstrDecl"
+
+instance Binary FieldDecl where
+  put (FieldDecl spi is ty) = put spi >> put is >> put ty
+  get = liftM3 FieldDecl get get get
+
+instance Binary QualTypeExpr where
+  put (QualTypeExpr spi ctx te) = put spi >> put ctx >> put te
+  get = liftM3 QualTypeExpr get get get
+
+instance Binary TypeExpr where
+  put (ConstructorType spi qid) =
+    putWord8 0 >> put spi >> put qid
+  put (ApplyType spi ty1 ty2) =
+    putWord8 1 >> put spi >> put ty1 >> put ty2
+  put (VariableType spi idt) =
+    putWord8 2 >> put spi >> put idt
+  put (TupleType spi tys) =
+    putWord8 3 >> put spi >> put tys
+  put (ListType spi ty) =
+    putWord8 4 >> put spi >> put ty
+  put (ArrowType spi ty1 ty2) =
+    putWord8 5 >> put spi >> put ty1 >> put ty2
+  put (ParenType spi ty) =
+    putWord8 6 >> put spi >> put ty
+  put (ForallType spi is ty) =
+    putWord8 7 >> put spi >> put is >> put ty
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 ConstructorType get get
+      1 -> liftM3 ApplyType get get get
+      2 -> liftM2 VariableType get get
+      3 -> liftM2 TupleType get get
+      4 -> liftM2 ListType get get
+      5 -> liftM3 ArrowType get get get
+      6 -> liftM2 ParenType get get
+      7 -> liftM3 ForallType get get get
+      _ -> fail "Invalid encoding for TypeExpr"
+
+instance Binary Constraint where
+  put (Constraint spi cls ty) = put spi >> put cls >> put ty
+  get = liftM3 Constraint get get get
+
+instance Binary a => Binary (Equation a) where
+  put (Equation spi lhs rhs) = put spi >> put lhs >> put rhs
+  get = liftM3 Equation get get get
+
+instance Binary a => Binary (Lhs a) where
+  put (FunLhs spi f ps) =
+    putWord8 0 >> put spi >> put f >> put ps
+  put (OpLhs spi p1 op p2) =
+    putWord8 1 >> put spi >> put p1 >> put op >> put p2
+  put (ApLhs spi lhs ps) =
+    putWord8 2 >> put spi >> put lhs >> put ps
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM3 FunLhs get get get
+      1 -> OpLhs <$> get <*> get <*> get <*> get
+      2 -> liftM3 ApLhs get get get
+      _ -> fail "Invalid encoding for Lhs"
+
+instance Binary a => Binary (Rhs a) where
+  put (SimpleRhs spi li e ds) =
+    putWord8 0 >> put spi >> put li >> put e >> put ds
+  put (GuardedRhs spi li gs ds) =
+    putWord8 1 >> put spi >> put li >> put gs >> put ds
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> SimpleRhs <$> get <*> get <*> get <*> get
+      1 -> GuardedRhs <$> get <*> get <*> get <*> get
+      _ -> fail "Invalid encoding for Rhs"
+
+instance Binary a => Binary (CondExpr a) where
+  put (CondExpr spi g e) = put spi >> put g >> put e
+  get = liftM3 CondExpr get get get
+
+instance Binary Literal where
+  put (Char   c) = putWord8 0 >> put c
+  put (Int    i) = putWord8 1 >> put i
+  put (Float  f) = putWord8 2 >> put (show f)
+  put (String s) = putWord8 3 >> put s
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> fmap Char get
+      1 -> fmap Int get
+      2 -> fmap (Float . read) get
+      3 -> fmap String get
+      _ -> fail "Invalid encoding for Literal"
+
+instance Binary a => Binary (Pattern a) where
+  put (LiteralPattern  spi a l) =
+    putWord8 0 >> put spi >> put a >> put l
+  put (NegativePattern spi a l) =
+    putWord8 1 >> put spi >> put a >> put l
+  put (VariablePattern spi a idt) =
+    putWord8 2 >> put spi >> put a >> put idt
+  put (ConstructorPattern spi a qid ps) =
+    putWord8 3 >> put spi >> put a >> put qid >> put ps
+  put (InfixPattern spi a p1 qid p2) =
+    putWord8 4 >> put spi >> put a >> put p1 >> put qid >> put p2
+  put (ParenPattern spi p) =
+    putWord8 5 >> put spi >> put p
+  put (RecordPattern spi a qid fs) =
+    putWord8 6 >> put spi >> put a >> put qid >> put fs
+  put (TuplePattern spi ps) =
+    putWord8 7 >> put spi >> put ps
+  put (ListPattern spi a ps) =
+    putWord8 8 >> put spi >> put a >> put ps
+  put (AsPattern spi idt p) =
+    putWord8 9 >> put spi >> put idt >> put p
+  put (LazyPattern spi p) =
+    putWord8 10 >> put spi >> put p
+  put (FunctionPattern spi a qid ps) =
+    putWord8 11 >> put spi >> put a >> put qid >> put ps
+  put (InfixFuncPattern spi a p1 qid p2) =
+    putWord8 12 >> put spi >> put a >> put p1 >> put qid >> put p2
+
+  get = do
+    x <- getWord8
+    case x of
+      0  -> liftM3 LiteralPattern get get get
+      1  -> liftM3 NegativePattern get get get
+      2  -> liftM3 VariablePattern get get get
+      3  -> ConstructorPattern <$> get <*> get <*> get <*> get
+      4  -> InfixPattern <$> get <*> get <*> get <*> get <*> get
+      5  -> liftM2 ParenPattern get get
+      6  -> RecordPattern <$> get <*> get <*> get <*> get
+      7  -> liftM2 TuplePattern get get
+      8  -> liftM3 ListPattern get get get
+      9  -> liftM3 AsPattern get get get
+      10 -> liftM2 LazyPattern get get
+      11 -> FunctionPattern <$> get <*> get <*> get <*> get
+      12 -> InfixFuncPattern <$> get <*> get <*> get <*> get <*> get
+      _  -> fail "Invalid encoding for Pattern"
+
+instance Binary a => Binary (Expression a) where
+  put (Literal spi a l) =
+    putWord8 0 >> put spi >> put a >> put l
+  put (Variable spi a qid) =
+    putWord8 1 >> put spi >> put a >> put qid
+  put (Constructor spi a qid) =
+    putWord8 2 >> put spi >> put a >> put qid
+  put (Paren spi e) =
+    putWord8 3 >> put spi >> put e
+  put (Typed spi e ty) =
+    putWord8 4 >> put spi >> put e >> put ty
+  put (Record spi a qid fs) =
+    putWord8 5 >> put spi >> put a >> put qid >> put fs
+  put (RecordUpdate spi e fs) =
+    putWord8 6 >> put spi >> put e >> put fs
+  put (Tuple spi es) =
+    putWord8 7 >> put spi >> put es
+  put (List spi a es) =
+    putWord8 8 >> put spi >> put a >> put es
+  put (ListCompr spi e stms) =
+    putWord8 9 >> put spi >> put e >> put stms
+  put (EnumFrom spi e1) =
+    putWord8 10 >> put spi >> put e1
+  put (EnumFromThen spi e1 e2) =
+    putWord8 11 >> put spi >> put e1 >> put e2
+  put (EnumFromTo spi e1 e2) =
+    putWord8 12 >> put spi >> put e1 >> put e2
+  put (EnumFromThenTo spi e1 e2 e3) =
+    putWord8 13 >> put spi >> put e1 >> put e2 >> put e3
+  put (UnaryMinus spi e) =
+    putWord8 14 >> put spi >> put e
+  put (Apply spi e1 e2) =
+    putWord8 15 >> put spi >> put e1 >> put e2
+  put (InfixApply spi e1 op e2) =
+    putWord8 16 >> put spi >> put e1 >> put op >> put e2
+  put (LeftSection spi e op) =
+    putWord8 17 >> put spi >> put e >> put op
+  put (RightSection spi op e) =
+    putWord8 18 >> put spi >> put op >> put e
+  put (Lambda spi ps e) =
+    putWord8 19 >> put spi >> put ps >> put e
+  put (Let spi li ds e) =
+    putWord8 20 >> put spi >> put li >> put ds >> put e
+  put (Do spi li stms e) =
+    putWord8 21 >> put spi >> put li >> put stms >> put e
+  put (IfThenElse spi e1 e2 e3) =
+    putWord8 22 >> put spi >> put e1 >> put e2 >> put e3
+  put (Case spi li cty e as) =
+    putWord8 23 >> put spi >> put li >> put cty >> put e >> put as
+
+  get = do
+    x <- getWord8
+    case x of
+      0  -> liftM3 Literal get get get
+      1  -> liftM3 Variable get get get
+      2  -> liftM3 Constructor get get get
+      3  -> liftM2 Paren get get
+      4  -> liftM3 Typed get get get
+      5  -> Record <$> get <*> get <*> get <*> get
+      6  -> RecordUpdate <$> get <*> get <*> get
+      7  -> liftM2 Tuple get get
+      8  -> liftM3 List get get get
+      9  -> liftM3 ListCompr get get get
+      10 -> liftM2 EnumFrom get get
+      11 -> liftM3 EnumFromThen get get get
+      12 -> liftM3 EnumFromTo get get get
+      13 -> EnumFromThenTo <$> get <*> get <*> get <*> get
+      14 -> liftM2 UnaryMinus get get
+      15 -> liftM3 Apply get get get
+      16 -> InfixApply <$> get <*> get <*> get <*> get
+      17 -> liftM3 LeftSection get get get
+      18 -> liftM3 RightSection get get get
+      19 -> liftM3 Lambda get get get
+      20 -> Let <$> get <*> get <*> get <*> get
+      21 -> Do <$> get <*> get <*> get <*> get
+      22 -> IfThenElse <$> get <*> get <*> get <*> get
+      23 -> Case <$> get <*> get <*> get <*> get <*> get
+      _  -> fail "Invalid encoding for Expression"
+
+instance Binary a => Binary (InfixOp a) where
+  put (InfixOp     a qid) = putWord8 0 >> put a >> put qid
+  put (InfixConstr a qid) = putWord8 1 >> put a >> put qid
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 InfixOp get get
+      1 -> liftM2 InfixConstr get get
+      _ -> fail "Invalid encoding for InfixOp"
+
+instance Binary a => Binary (Statement a) where
+  put (StmtExpr spi     e) = putWord8 0 >> put spi >> put e
+  put (StmtDecl spi li ds) = putWord8 1 >> put spi >> put li >> put ds
+  put (StmtBind spi p   e) = putWord8 2 >> put spi >> put p >> put e
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> liftM2 StmtExpr get get
+      1 -> liftM3 StmtDecl get get get
+      2 -> liftM3 StmtBind get get get
+      _ -> fail "Invalid encoding for Statement"
+
+instance Binary CaseType where
+  put Rigid = putWord8 0
+  put Flex  = putWord8 1
+
+  get = do
+    x <- getWord8
+    case x of
+      0 -> return Rigid
+      1 -> return Flex
+      _ -> fail "Invalid encoding for CaseType"
+
+instance Binary a => Binary (Alt a) where
+  put (Alt spi p rhs) = put spi >> put p >> put rhs
+  get = liftM3 Alt get get get
+
+instance Binary a => Binary (Field a) where
+  put (Field spi qid a) = put spi >> put qid >> put a
+  get = liftM3 Field get get get
+
+instance Binary a => Binary (Var a) where
+  put (Var a idt) = put a >> put idt
+  get = liftM2 Var get get
+
+{- HLINT ignore "Use record patterns"-}
diff --git a/src/Curry/Syntax/Type.lhs b/src/Curry/Syntax/Type.lhs
deleted file mode 100644
--- a/src/Curry/Syntax/Type.lhs
+++ /dev/null
@@ -1,315 +0,0 @@
-> {-# LANGUAGE DeriveDataTypeable #-}
-
-% $Id: CurrySyntax.lhs,v 1.43 2004/02/15 22:10:31 wlux Exp $
-%
-% Copyright (c) 1999-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{CurrySyntax.lhs}
-\section{The Parse Tree}
-This module provides the necessary data structures to maintain the
-parsed representation of a Curry program.
-
-\em{Note:} this modified version uses haskell type \texttt{Integer}
-instead of \texttt{Int} for representing integer values. This allows
-an unlimited range of integer constants in Curry programs.
-\begin{verbatim}
-
-> module Curry.Syntax.Type where
-
-> import Curry.Base.Ident
-> import Curry.Base.Position
-> import Data.Generics
-> import Control.Monad.State
-
-\end{verbatim}
-\paragraph{Modules}
-\begin{verbatim}
-
-> data Module = Module ModuleIdent (Maybe ExportSpec) [Decl] 
->  deriving (Eq,Show,Read,Typeable,Data)
-
-> data ExportSpec = Exporting Position [Export] deriving (Eq,Show,Read,Typeable,Data)
-> data Export =
->     Export         QualIdent                  -- f/T
->   | ExportTypeWith QualIdent [Ident]          -- T(C1,...,Cn)
->   | ExportTypeAll  QualIdent                  -- T(..)
->   | ExportModule   ModuleIdent
->   deriving (Eq,Show,Read,Typeable,Data)
-
-\end{verbatim}
-\paragraph{Module declarations}
-\begin{verbatim}
-
-> data ImportSpec =
->     Importing Position [Import]
->   | Hiding Position [Import]
->   deriving (Eq,Show,Read,Typeable,Data)
-> data Import =
->     Import         Ident            -- f/T
->   | ImportTypeWith Ident [Ident]    -- T(C1,...,Cn)
->   | ImportTypeAll  Ident            -- T(..)
->   deriving (Eq,Show,Read,Typeable,Data)
-
-> data Decl =
->     ImportDecl Position ModuleIdent Qualified (Maybe ModuleIdent)
->                (Maybe ImportSpec)
->   | InfixDecl Position Infix Integer [Ident]
->   | DataDecl Position Ident [Ident] [ConstrDecl]
->   | NewtypeDecl Position Ident [Ident] NewConstrDecl
->   | TypeDecl Position Ident [Ident] TypeExpr
->   | TypeSig Position [Ident] TypeExpr
->   | EvalAnnot Position [Ident] EvalAnnotation
->   | FunctionDecl Position Ident [Equation]
->   | ExternalDecl Position CallConv (Maybe String) Ident TypeExpr
->   | FlatExternalDecl Position [Ident]
->   | PatternDecl Position ConstrTerm Rhs
->   | ExtraVariables Position [Ident]
->   deriving (Eq,Show,Read,Typeable,Data)
-
-> data ConstrDecl =
->     ConstrDecl Position [Ident] Ident [TypeExpr]
->   | ConOpDecl Position [Ident] TypeExpr Ident TypeExpr
->   deriving (Eq,Show,Read,Typeable,Data)
-> data NewConstrDecl =
->   NewConstrDecl Position [Ident] Ident TypeExpr
->   deriving (Eq,Show,Read,Typeable,Data)
-
-> type Qualified = Bool
-> data Infix = InfixL | InfixR | Infix deriving (Eq,Show,Read,Typeable,Data)
-> data EvalAnnotation = EvalRigid | EvalChoice deriving (Eq,Show,Read,Typeable,Data)
-> data CallConv = CallConvPrimitive | CallConvCCall deriving (Eq,Show,Read,Typeable,Data)
-
-\end{verbatim}
-\paragraph{Module interfaces}
-Interface declarations are restricted to type declarations and signatures. 
-Note that an interface function declaration additionaly contains the 
-function arity (= number of parameters) in order to generate
-correct FlatCurry function applications.
-\begin{verbatim}
-
-> data Interface = Interface ModuleIdent [IDecl] deriving (Eq,Show,Read,Typeable,Data)
-
-> data IDecl =
->     IImportDecl Position ModuleIdent
->   | IInfixDecl Position Infix Integer QualIdent
->   | HidingDataDecl Position Ident [Ident] 
->   | IDataDecl Position QualIdent [Ident] [Maybe ConstrDecl]
->   | INewtypeDecl Position QualIdent [Ident] NewConstrDecl
->   | ITypeDecl Position QualIdent [Ident] TypeExpr
->   | IFunctionDecl Position QualIdent Int TypeExpr
->   deriving (Eq,Show,Read,Typeable,Data)
-
-\end{verbatim}
-\paragraph{Types}
-\begin{verbatim}
-
-> data TypeExpr =
->     ConstructorType QualIdent [TypeExpr]
->   | VariableType Ident
->   | TupleType [TypeExpr]
->   | ListType TypeExpr
->   | ArrowType TypeExpr TypeExpr
->   | RecordType [([Ident],TypeExpr)] (Maybe TypeExpr) 
->     -- {l1 :: t1,...,ln :: tn | r}
->   deriving (Eq,Show,Read,Typeable,Data)
-
-\end{verbatim}
-\paragraph{Functions}
-\begin{verbatim}
-
-> data Equation = Equation Position Lhs Rhs deriving (Eq,Show,Read,Typeable,Data)
-> data Lhs =
->     FunLhs Ident [ConstrTerm]
->   | OpLhs ConstrTerm Ident ConstrTerm
->   | ApLhs Lhs [ConstrTerm]
->   deriving (Eq,Show,Read,Typeable,Data)
-> data Rhs =
->     SimpleRhs Position Expression [Decl]
->   | GuardedRhs [CondExpr] [Decl]
->   deriving (Eq,Show,Read,Typeable,Data)
-> data CondExpr = CondExpr Position Expression Expression deriving (Eq,Show,Read,Typeable,Data)
-
-> flatLhs :: Lhs -> (Ident,[ConstrTerm])
-> flatLhs lhs = flat lhs []
->   where flat (FunLhs f ts) ts' = (f,ts ++ ts')
->         flat (OpLhs t1 op t2) ts = (op,t1:t2:ts)
->         flat (ApLhs lhs ts) ts' = flat lhs (ts ++ ts')
-
-\end{verbatim}
-\paragraph{Literals} The \texttt{Ident} argument of an \texttt{Int}
-literal is used for supporting ad-hoc polymorphism on integer
-numbers. An integer literal can be used either as an integer number or
-as a floating-point number depending on its context. The compiler uses
-the identifier of the \texttt{Int} literal for maintaining its type.
-\begin{verbatim}
-
-> data Literal =
->     Char SrcRef Char                         -- should be Int to handle Unicode
->   | Int Ident Integer
->   | Float SrcRef Double
->   | String SrcRef String                     -- should be [Int] to handle Unicode
->   deriving (Eq,Show,Read,Typeable,Data)
-
-> mk' :: ([SrcRef] -> a) -> a
-> mk' = ($[])
-
-> mk :: (SrcRef -> a) -> a
-> mk = ($noRef)
-
-> mkInt :: Integer -> Literal
-> mkInt i = mk (\r -> Int (addPositionIdent (AST  r) anonId) i) 
-
-\end{verbatim}
-\paragraph{Patterns}
-\begin{verbatim}
-
-> data ConstrTerm =
->     LiteralPattern Literal
->   | NegativePattern Ident Literal
->   | VariablePattern Ident
->   | ConstructorPattern QualIdent [ConstrTerm]
->   | InfixPattern ConstrTerm QualIdent ConstrTerm
->   | ParenPattern ConstrTerm
->   | TuplePattern SrcRef [ConstrTerm]
->   | ListPattern [SrcRef] [ConstrTerm]
->   | AsPattern Ident ConstrTerm
->   | LazyPattern SrcRef ConstrTerm
->   | FunctionPattern QualIdent [ConstrTerm]
->   | InfixFuncPattern ConstrTerm QualIdent ConstrTerm
->   | RecordPattern [Field ConstrTerm] (Maybe ConstrTerm)  
->         -- {l1 = p1, ..., ln = pn}  oder {l1 = p1, ..., ln = pn | p}
->   deriving (Eq,Show,Read,Typeable,Data)
-
-\end{verbatim}
-\paragraph{Expressions}
-\begin{verbatim}
-
-> data Expression =
->     Literal Literal
->   | Variable QualIdent
->   | Constructor QualIdent
->   | Paren Expression
->   | Typed Expression TypeExpr
->   | Tuple SrcRef [Expression]
->   | List [SrcRef] [Expression]
->   | ListCompr SrcRef Expression [Statement] -- the ref corresponds to the main list  
->   | EnumFrom Expression
->   | EnumFromThen Expression Expression
->   | EnumFromTo Expression Expression
->   | EnumFromThenTo Expression Expression Expression
->   | UnaryMinus Ident Expression
->   | Apply Expression Expression
->   | InfixApply Expression InfixOp Expression
->   | LeftSection Expression InfixOp
->   | RightSection InfixOp Expression
->   | Lambda SrcRef [ConstrTerm] Expression
->   | Let [Decl] Expression
->   | Do [Statement] Expression
->   | IfThenElse SrcRef Expression Expression Expression
->   | Case SrcRef Expression [Alt]
->   | RecordConstr [Field Expression]            -- {l1 = e1,...,ln = en}
->   | RecordSelection Expression Ident           -- e -> l
->   | RecordUpdate [Field Expression] Expression -- {l1 := e1,...,ln := en | e}
->   deriving (Eq,Show,Read,Typeable,Data)
-
-> data InfixOp = InfixOp QualIdent | InfixConstr QualIdent deriving (Eq,Show,Read,Typeable,Data)
-
-> data Statement =
->     StmtExpr SrcRef Expression
->   | StmtDecl [Decl]
->   | StmtBind SrcRef ConstrTerm Expression
->   deriving (Eq,Show,Read,Typeable,Data)
-
-> data Alt = Alt Position ConstrTerm Rhs deriving (Eq,Show,Read,Typeable,Data)
-
-> data Field a = Field Position Ident a deriving (Eq, Show,Read,Typeable,Data)
-
-> fieldLabel :: Field a -> Ident
-> fieldLabel (Field _ l _) = l
-
-> fieldTerm :: Field a -> a
-> fieldTerm (Field _ _ t) = t
-
-> field2Tuple :: Field a -> (Ident,a)
-> field2Tuple (Field _ l t) = (l,t)
-
-> opName :: InfixOp -> QualIdent
-> opName (InfixOp op) = op
-> opName (InfixConstr c) = c
-
-\end{verbatim}
-
-> instance SrcRefOf ConstrTerm where
->   srcRefOf (LiteralPattern l) = srcRefOf l
->   srcRefOf (NegativePattern i _) = srcRefOf i
->   srcRefOf (VariablePattern i) = srcRefOf i
->   srcRefOf (ConstructorPattern i _) = srcRefOf i
->   srcRefOf (InfixPattern _ i _) = srcRefOf i
->   srcRefOf (ParenPattern c) = srcRefOf c
->   srcRefOf (TuplePattern s _) = s
->   srcRefOf (ListPattern s _) = error "list pattern has several source refs"
->   srcRefOf (AsPattern i _) = srcRefOf i
->   srcRefOf (LazyPattern s _) = s
->   srcRefOf (FunctionPattern i _) = srcRefOf i
->   srcRefOf (InfixFuncPattern _ i _) = srcRefOf i
-
-> instance SrcRefOf Literal where
->   srcRefOf (Char s _)   = s
->   srcRefOf (Int i _)    = srcRefOf i
->   srcRefOf (Float s _)  = s
->   srcRefOf (String s _) = s
-
----------------------------
--- add source references
----------------------------
-
-> type M a = a -> State Int a
-> 
-> addSrcRefs :: Module -> Module
-> addSrcRefs x = evalState (addRef x) 0
->   where 
->     addRef :: Data a' => M a' 
->     addRef = down `extM` addRefPos   
->                   `extM` addRefSrc   
->                   `extM` addRefIdent
->                   `extM` addRefListPat
->                   `extM` addRefListExp
->       where
->         down :: Data a' => M a'
->         down = gmapM addRef
-> 
->         addRefPos :: M [SrcRef]
->         addRefPos _ = liftM (:[]) next
-> 
->         addRefSrc :: M SrcRef
->         addRefSrc _ = next
-> 
->         addRefIdent :: M Ident
->         addRefIdent ident = liftM (flip addRefId ident) next
->
->         addRefListPat :: M ConstrTerm
->         addRefListPat (ListPattern _ ts) = do
->           liftM (uncurry ListPattern) (addRefList ts)
->         addRefListPat ct = gmapM addRef ct
->   
->         addRefListExp :: M Expression
->         addRefListExp (List _ ts) = do
->           liftM (uncurry List) (addRefList ts)
->         addRefListExp ct = gmapM addRef ct
->   
->         addRefList :: Data a' => [a'] -> State Int ([SrcRef],[a'])
->         addRefList ts = do
->           i <- next
->           let add t = do t' <- addRef t;j <- next; return (j,t')
->           ists <- sequence (map add ts)
->           let (is,ts') = unzip ists
->           return (i:is,ts')
->         
->         next :: State Int SrcRef
->         next = do
->           i <- get
->           put $! i+1
->           return (SrcRef [i])
diff --git a/src/Curry/Syntax/Unlit.hs b/src/Curry/Syntax/Unlit.hs
deleted file mode 100644
--- a/src/Curry/Syntax/Unlit.hs
+++ /dev/null
@@ -1,61 +0,0 @@
-{-
-  Since version 0.7 of the language report, Curry accepts literate
-  source programs. In a literate source all program lines must begin
-  with a greater sign in the first column. All other lines are assumed
-  to be documentation. In order to avoid some common errors with
-  literate programs, Curry requires at least one program line to be
-  present in the file. In addition, every block of program code must be
-  preceded by a blank line and followed by a blank line.
-
-  This module has been rewritten by Holger Siegel in 2009.
-
-  (c) Holger Siegel, 2009.
--}
-
-
-module Curry.Syntax.Unlit(unlit) where
-
-import Control.Monad(when, zipWithM)
-import Data.Char
-
-import Curry.Base.Position
-import Curry.Base.MessageMonad
-
-
-data Line = Program !Int String
-          | Blank | Comment
-
-classify :: Int -> String -> Line
-classify l ('>':cs)  = Program l cs
-classify _ cs
-  | all isSpace cs = Blank
-  | otherwise      = Comment
-
-{-
-  Process a literate program into error messages (if any) and the
-  corresponding non-literate program.
--}
-
-unlit :: FilePath -> String -> MsgMonad String
-unlit fn lcy = do ls <- progLines fn (zipWith classify [1..] $ lines lcy)
-                  when (all null ls) $
-                       failWith (fn ++ ": no code in literate script")
-                  return (unlines ls)
-
-{-
-  Check that each program line is not adjacent to a comment line and
-  there is at least one program line.
--}
-progLines :: FilePath -> [Line] -> MsgMonad [String]
-progLines fn cs 
-   = zipWithM adjacent (Blank : cs) cs
-  where
-    adjacent :: Line -> Line -> MsgMonad String
-    adjacent (Program p _) Comment     = message fn p "followed"
-    adjacent Comment     (Program p _) = message fn p "preceded"
-    adjacent _ (Program _ s)           = return s
-    adjacent _ _                       = return ""
-
-message :: String -> Int -> String -> MsgMonad a
-message file p w = failWithAt (Position file p 1 noRef) msg
-    where msg = "When reading literate source: Program line is " ++ w ++ " by comment line."
diff --git a/src/Curry/Syntax/Utils.hs b/src/Curry/Syntax/Utils.hs
--- a/src/Curry/Syntax/Utils.hs
+++ b/src/Curry/Syntax/Utils.hs
@@ -1,257 +1,325 @@
-module Curry.Syntax.Utils(Expr, fv, qfv,
-                          QuantExpr, bv,
+{- |
+    Module      :  $Header$
+    Description :  Utility functions for Curry's abstract syntax
+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux
+                       2005        Martin Engelke
+                       2011 - 2014 Björn Peemöller
+                       2015        Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
 
-                          isEvalAnnot, isTypeSig,
-                          infixOp,
-                          isTypeDecl, isValueDecl,
-                          isInfixDecl,
-                          isRecordDecl, isImportDecl) where
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
 
-import qualified Data.Set as Set
+    This module provides some utility functions for working with the
+    abstract syntax tree of Curry.
+-}
 
+module Curry.Syntax.Utils
+  ( hasLanguageExtension, knownExtensions
+  , isTopDecl, isBlockDecl
+  , isTypeSig, infixOp, isTypeDecl, isValueDecl, isInfixDecl
+  , isDefaultDecl, isClassDecl, isTypeOrClassDecl, isInstanceDecl
+  , isFunctionDecl, isExternalDecl, patchModuleId
+  , isVariablePattern
+  , isVariableType, isSimpleType
+  , typeConstr, typeVariables, varIdent
+  , flatLhs, eqnArity, fieldLabel, fieldTerm, field2Tuple, opName
+  , funDecl, mkEquation, simpleRhs, patDecl, varDecl, constrPattern, caseAlt
+  , mkLet, mkVar, mkCase, mkLambda
+  , apply, unapply
+  , constrId, nconstrId
+  , nconstrType
+  , recordLabels, nrecordLabels
+  , methods, impls, imethod, imethodArity
+  , shortenModuleAST
+  ) where
 
-import Curry.Base.Ident 
+import Control.Monad.State
+
+import Curry.Base.Ident
+import Curry.Base.SpanInfo
+import Curry.Files.Filenames (takeBaseName)
+import Curry.Syntax.Extension
 import Curry.Syntax.Type
 
-{-
-  Free and bound variables
-  
-  The compiler needs to compute the sets of free and bound variables for
-  various different entities. We will devote three type classes to that
-  purpose. The \texttt{QualExpr} class is expected to take into account
-  that it is possible to use a qualified name to refer to a function
-  defined in the current module and therefore \emph{M.x} and $x$, where
-  $M$ is the current module name, should be considered the same name.
-  However note that this is correct only after renaming all local
-  definitions as \emph{M.x} always denotes an entity defined at the
-  top-level.
-  
-  The \texttt{Decl} instance of \texttt{QualExpr} returns all free
-  variables on the right hand side, regardless of whether they are bound
-  on the left hand side. This is more convenient as declarations are
-  usually processed in a declaration group where the set of free
-  variables cannot be computed independently for each declaration. Also
-  note that the operator in a unary minus expression is not a free
-  variable. This operator always refers to a global function from the
-  prelude.
--}
+-- |Check whether a 'Module' has a specific 'KnownExtension' enabled by a pragma
+hasLanguageExtension :: Module a -> KnownExtension -> Bool
+hasLanguageExtension mdl ext = ext `elem` knownExtensions mdl
 
-class Expr e where
-  fv :: e -> [Ident]
-class QualExpr e where
-  qfv :: ModuleIdent -> e -> [Ident]
-class QuantExpr e where
-  bv :: e -> [Ident]
+-- |Extract all known extensions from a 'Module'
+knownExtensions :: Module a -> [KnownExtension]
+knownExtensions (Module _ _ ps _ _ _ _) =
+  [ e | LanguagePragma _ exts <- ps, KnownExtension _ e <- exts]
 
-instance Expr e => Expr [e] where
-  fv = concat . map fv
-instance QualExpr e => QualExpr [e] where
-  qfv m = concat . map (qfv m)
-instance QuantExpr e => QuantExpr [e] where
-  bv = concat . map bv
+-- |Replace the generic module name @main@ with the module name derived
+-- from the 'FilePath' of the module.
+patchModuleId :: FilePath -> Module a -> Module a
+patchModuleId fn m@(Module spi li ps mid es is ds)
+  | mid == mainMIdent = Module spi li ps (mkMIdent [takeBaseName fn]) es is ds
+  | otherwise         = m
 
-instance QualExpr Decl where
-  qfv m (FunctionDecl _ _ eqs) = qfv m eqs
-  qfv m (PatternDecl _ _ rhs) = qfv m rhs
-  qfv _ _ = []
+-- |Is the declaration a top declaration?
+isTopDecl :: Decl a -> Bool
+isTopDecl = not . isBlockDecl
 
-instance QuantExpr Decl where
-  bv (TypeSig _ vs _) = vs
-  bv (EvalAnnot _ fs _) = fs
-  bv (FunctionDecl _ f _) = [f]
-  bv (ExternalDecl _ _ _ f _) = [f]
-  bv (FlatExternalDecl _ fs) = fs
-  bv (PatternDecl _ t _) = bv t
-  bv (ExtraVariables _ vs) = vs
-  bv _ = []
+-- |Is the declaration a block declaration?
+isBlockDecl :: Decl a -> Bool
+isBlockDecl = liftM3 ((.) (||) . (||)) isInfixDecl isTypeSig isValueDecl
 
-instance QualExpr Equation where
-  qfv m (Equation _ lhs rhs) = filterBv lhs (qfv m lhs ++ qfv m rhs)
+-- |Is the declaration an infix declaration?
+isInfixDecl :: Decl a -> Bool
+isInfixDecl (InfixDecl _ _ _ _) = True
+isInfixDecl _                   = False
 
-instance QuantExpr Lhs where
-  bv = bv . snd . flatLhs
+-- |Is the declaration a type declaration?
+isTypeDecl :: Decl a -> Bool
+isTypeDecl (DataDecl     _ _ _ _ _) = True
+isTypeDecl (ExternalDataDecl _ _ _) = True
+isTypeDecl (NewtypeDecl  _ _ _ _ _) = True
+isTypeDecl (TypeDecl       _ _ _ _) = True
+isTypeDecl _                        = False
 
-instance QualExpr Lhs where
-  qfv m lhs = qfv m (snd (flatLhs lhs))
+-- |Is the declaration a default declaration?
+isDefaultDecl :: Decl a -> Bool
+isDefaultDecl (DefaultDecl _ _) = True
+isDefaultDecl _                 = False
 
-instance QualExpr Rhs where
-  qfv m (SimpleRhs _ e ds) = filterBv ds (qfv m e ++ qfv m ds)
-  qfv m (GuardedRhs es ds) = filterBv ds (qfv m es ++ qfv m ds)
+-- |Is the declaration a class declaration?
+isClassDecl :: Decl a -> Bool
+isClassDecl (ClassDecl _ _ _ _ _ _) = True
+isClassDecl _                       = False
 
-instance QualExpr CondExpr where
-  qfv m (CondExpr _ g e) = qfv m g ++ qfv m e
+-- |Is the declaration a type or a class declaration?
+isTypeOrClassDecl :: Decl a -> Bool
+isTypeOrClassDecl = liftM2 (||) isTypeDecl isClassDecl
 
-instance QualExpr Expression where
-  qfv _ (Literal _) = []
-  qfv m (Variable v) = maybe [] return (localIdent m v)
-  qfv _ (Constructor _) = []
-  qfv m (Paren e) = qfv m e
-  qfv m (Typed e _) = qfv m e
-  qfv m (Tuple _ es) = qfv m es
-  qfv m (List _ es) = qfv m es
-  qfv m (ListCompr _ e qs) = foldr (qfvStmt m) (qfv m e) qs
-  qfv m (EnumFrom e) = qfv m e
-  qfv m (EnumFromThen e1 e2) = qfv m e1 ++ qfv m e2
-  qfv m (EnumFromTo e1 e2) = qfv m e1 ++ qfv m e2
-  qfv m (EnumFromThenTo e1 e2 e3) = qfv m e1 ++ qfv m e2 ++ qfv m e3
-  qfv m (UnaryMinus _ e) = qfv m e
-  qfv m (Apply e1 e2) = qfv m e1 ++ qfv m e2
-  qfv m (InfixApply e1 op e2) = qfv m op ++ qfv m e1 ++ qfv m e2
-  qfv m (LeftSection e op) = qfv m op ++ qfv m e
-  qfv m (RightSection op e) = qfv m op ++ qfv m e
-  qfv m (Lambda _ ts e) = filterBv ts (qfv m e)
-  qfv m (Let ds e) = filterBv ds (qfv m ds ++ qfv m e)
-  qfv m (Do sts e) = foldr (qfvStmt m) (qfv m e) sts
-  qfv m (IfThenElse _ e1 e2 e3) = qfv m e1 ++ qfv m e2 ++ qfv m e3
-  qfv m (Case _ e alts) = qfv m e ++ qfv m alts
-  qfv m (RecordConstr fs) = qfv m fs
-  qfv m (RecordSelection e _) = qfv m e
-  qfv m (RecordUpdate fs e) = qfv m e ++ qfv m fs
+-- |Is the declaration an instance declaration?
+isInstanceDecl :: Decl a -> Bool
+isInstanceDecl (InstanceDecl _ _ _ _ _ _) = True
+isInstanceDecl _                          = False
 
-qfvStmt :: ModuleIdent -> Statement -> [Ident] -> [Ident]
-qfvStmt m st fvs = qfv m st ++ filterBv st fvs
+-- |Is the declaration a type signature?
+isTypeSig :: Decl a -> Bool
+isTypeSig (TypeSig           _ _ _) = True
+isTypeSig _                         = False
 
-instance QualExpr Statement where
-  qfv m (StmtExpr _ e) = qfv m e
-  qfv m (StmtDecl ds) = filterBv ds (qfv m ds)
-  qfv m (StmtBind _ t e) = qfv m e
+-- |Is the declaration a value declaration?
+isValueDecl :: Decl a -> Bool
+isValueDecl (FunctionDecl    _ _ _ _) = True
+isValueDecl (ExternalDecl        _ _) = True
+isValueDecl (PatternDecl       _ _ _) = True
+isValueDecl (FreeDecl            _ _) = True
+isValueDecl _                         = False
 
-instance QualExpr Alt where
-  qfv m (Alt _ t rhs) = filterBv t (qfv m rhs)
+-- |Is the declaration a function declaration?
+isFunctionDecl :: Decl a -> Bool
+isFunctionDecl (FunctionDecl _ _ _ _) = True
+isFunctionDecl _                      = False
 
-instance QuantExpr a => QuantExpr (Field a) where
-  bv (Field _ _ t) = bv t
+-- |Is the declaration an external declaration?
+isExternalDecl :: Decl a -> Bool
+isExternalDecl (ExternalDecl _ _) = True
+isExternalDecl _                  = False
 
-instance QualExpr a => QualExpr (Field a) where
-  qfv m (Field _ _ t) = qfv m t
+-- |Is the pattern semantically equivalent to a variable pattern?
+isVariablePattern :: Pattern a -> Bool
+isVariablePattern (VariablePattern _ _ _) = True
+isVariablePattern (ParenPattern    _   t) = isVariablePattern t
+isVariablePattern (AsPattern       _ _ t) = isVariablePattern t
+isVariablePattern (LazyPattern     _   _) = True
+isVariablePattern _                       = False
 
-instance QuantExpr Statement where
-  bv (StmtExpr _ e) = []
-  bv (StmtBind _ t e) = bv t
-  bv (StmtDecl ds) = bv ds
+-- |Is a type expression a type variable?
+isVariableType :: TypeExpr -> Bool
+isVariableType (VariableType _ _) = True
+isVariableType _                  = False
 
-instance QualExpr InfixOp where
-  qfv m (InfixOp op) = qfv m (Variable op)
-  qfv _ (InfixConstr _) = []
+-- |Is a type expression simple, i.e., is it of the form T u_1 ... u_n,
+-- where T is a type constructor and u_1 ... u_n are type variables?
+isSimpleType :: TypeExpr -> Bool
+isSimpleType (ConstructorType _ _) = True
+isSimpleType (ApplyType _ ty1 ty2) = isSimpleType ty1 && isVariableType ty2
+isSimpleType (VariableType   _  _) = False
+isSimpleType (TupleType    _  tys) = all isVariableType tys
+isSimpleType (ListType      _  ty) = isVariableType ty
+isSimpleType (ArrowType _ ty1 ty2) = isVariableType ty1 && isVariableType ty2
+isSimpleType (ParenType     _  ty) = isSimpleType ty
+isSimpleType (ForallType    _ _ _) = False
 
-instance QuantExpr ConstrTerm where
-  bv (LiteralPattern _) = []
-  bv (NegativePattern _ _) = []
-  bv (VariablePattern v) = [v]
-  bv (ConstructorPattern c ts) = bv ts
-  bv (InfixPattern t1 op t2) = bv t1 ++ bv t2
-  bv (ParenPattern t) = bv t
-  bv (TuplePattern _ ts) = bv ts
-  bv (ListPattern _ ts) = bv ts
-  bv (AsPattern v t) = v : bv t
-  bv (LazyPattern _ t) = bv t
-  bv (FunctionPattern f ts) = bvFuncPatt (FunctionPattern f ts)
-  bv (InfixFuncPattern t1 op t2) = bvFuncPatt (InfixFuncPattern t1 op t2)
-  bv (RecordPattern fs r) = (maybe [] bv r) ++ bv fs
+-- |Return the qualified type constructor of a type expression.
+typeConstr :: TypeExpr -> QualIdent
+typeConstr (ConstructorType   _ tc) = tc
+typeConstr (ApplyType       _ ty _) = typeConstr ty
+typeConstr (TupleType        _ tys) = qTupleId (length tys)
+typeConstr (ListType           _ _) = qListId
+typeConstr (ArrowType        _ _ _) = qArrowId
+typeConstr (ParenType         _ ty) = typeConstr ty
+typeConstr (VariableType       _ _) =
+  error "Curry.Syntax.Utils.typeConstr: variable type"
+typeConstr (ForallType       _ _ _) =
+  error "Curry.Syntax.Utils.typeConstr: forall type"
 
-instance QualExpr ConstrTerm where
-  qfv _ (LiteralPattern _) = []
-  qfv _ (NegativePattern _ _) = []
-  qfv _ (VariablePattern _) = []
-  qfv m (ConstructorPattern _ ts) = qfv m ts
-  qfv m (InfixPattern t1 _ t2) = qfv m [t1,t2]
-  qfv m (ParenPattern t) = qfv m t
-  qfv m (TuplePattern _ ts) = qfv m ts
-  qfv m (ListPattern _ ts) = qfv m ts
-  qfv m (AsPattern _ ts) = qfv m ts
-  qfv m (LazyPattern _ t) = qfv m t
-  qfv m (FunctionPattern f ts) 
-    = (maybe [] return (localIdent m f)) ++ qfv m ts
-  qfv m (InfixFuncPattern t1 op t2) 
-    = (maybe [] return (localIdent m op)) ++ qfv m [t1,t2]
-  qfv m (RecordPattern fs r) = (maybe [] (qfv m) r) ++ qfv m fs
+-- |Return the list of variables occuring in a type expression.
+typeVariables :: TypeExpr -> [Ident]
+typeVariables (ConstructorType       _ _) = []
+typeVariables (ApplyType       _ ty1 ty2) = typeVariables ty1 ++ typeVariables ty2
+typeVariables (VariableType         _ tv) = [tv]
+typeVariables (TupleType           _ tys) = concatMap typeVariables tys
+typeVariables (ListType             _ ty) = typeVariables ty
+typeVariables (ArrowType       _ ty1 ty2) = typeVariables ty1 ++ typeVariables ty2
+typeVariables (ParenType            _ ty) = typeVariables ty
+typeVariables (ForallType        _ vs ty) = vs ++ typeVariables ty
 
-instance Expr TypeExpr where
-  fv (ConstructorType _ tys) = fv tys
-  fv (VariableType tv)
-    | tv == anonId = []
-    | otherwise = [tv]
-  fv (TupleType tys) = fv tys
-  fv (ListType ty) = fv ty
-  fv (ArrowType ty1 ty2) = fv ty1 ++ fv ty2
-  fv (RecordType fs rty) = (maybe [] fv rty) ++ fv (map snd fs)
+-- |Return the identifier of a variable.
+varIdent :: Var a -> Ident
+varIdent (Var _ v) = v
 
-filterBv :: QuantExpr e => e -> [Ident] -> [Ident]
-filterBv e = filter (`Set.notMember` Set.fromList (bv e))
+-- |Convert an infix operator into an expression
+infixOp :: InfixOp a -> Expression a
+infixOp (InfixOp     a op) = Variable NoSpanInfo a op
+infixOp (InfixConstr a op) = Constructor NoSpanInfo a op
 
-{-
-  Since multiple variable occurrences are allowed in function patterns,
-  it is necessary to compute the list of bound variables in a different way:
-  Each variable occuring in the function pattern will be unique in the result
-  list.
- -}
+-- |flatten the left-hand-side to the identifier and all constructor terms
+flatLhs :: Lhs a -> (Ident, [Pattern a])
+flatLhs lhs = flat lhs []
+  where flat (FunLhs    _ f ts) ts' = (f, ts ++ ts')
+        flat (OpLhs _ t1 op t2) ts' = (op, t1 : t2 : ts')
+        flat (ApLhs  _ lhs' ts) ts' = flat lhs' (ts ++ ts')
 
-bvFuncPatt :: ConstrTerm -> [Ident]
-bvFuncPatt = bvfp []
- where
- bvfp bvs (LiteralPattern _) = bvs
- bvfp bvs (NegativePattern _ _) = bvs
- bvfp bvs (VariablePattern v)
-    | elem v bvs = bvs
-    | otherwise  = v:bvs
- bvfp bvs (ConstructorPattern c ts) = foldl bvfp bvs ts
- bvfp bvs (InfixPattern t1 op t2) = foldl bvfp bvs [t1,t2]
- bvfp bvs (ParenPattern t) = bvfp bvs t
- bvfp bvs (TuplePattern _ ts) = foldl bvfp bvs ts
- bvfp bvs (ListPattern _ ts) = foldl bvfp bvs ts
- bvfp bvs (AsPattern v t)
-    | elem v bvs = bvfp bvs t
-    | otherwise  = bvfp (v:bvs) t
- bvfp bvs (LazyPattern _ t) = bvfp bvs t
- bvfp bvs (FunctionPattern f ts) = foldl bvfp bvs ts
- bvfp bvs (InfixFuncPattern t1 op t2) = foldl bvfp bvs [t1, t2]
- bvfp bvs (RecordPattern fs r)
-    = foldl bvfp (maybe bvs (bvfp bvs) r) (map fieldTerm fs)
+-- |Return the arity of an equation.
+eqnArity :: Equation a -> Int
+eqnArity (Equation _ lhs _) = length $ snd $ flatLhs lhs
 
+-- |Select the label of a field
+fieldLabel :: Field a -> QualIdent
+fieldLabel (Field _ l _) = l
 
+-- |Select the term of a field
+fieldTerm :: Field a -> a
+fieldTerm (Field _ _ t) = t
 
-{-
-  Here is a list of predicates identifying various kinds of
-  declarations.
--}
+-- |Select the label and term of a field
+field2Tuple :: Field a -> (QualIdent, a)
+field2Tuple (Field _ l t) = (l, t)
 
-isImportDecl, isInfixDecl, isTypeDecl :: Decl -> Bool
-isTypeSig, isEvalAnnot, isValueDecl :: Decl -> Bool
+-- |Get the operator name of an infix operator
+opName :: InfixOp a -> QualIdent
+opName (InfixOp     _ op) = op
+opName (InfixConstr _ c ) = c
 
-isImportDecl (ImportDecl _ _ _ _ _) = True
-isImportDecl _ = False
+-- | Get the identifier of a constructor declaration
+constrId :: ConstrDecl -> Ident
+constrId (ConstrDecl  _ c  _) = c
+constrId (ConOpDecl _ _ op _) = op
+constrId (RecordDecl  _ c  _) = c
 
-isInfixDecl (InfixDecl _ _ _ _) = True
-isInfixDecl _ = False
+-- | Get the identifier of a newtype constructor declaration
+nconstrId :: NewConstrDecl -> Ident
+nconstrId (NewConstrDecl _ c _) = c
+nconstrId (NewRecordDecl _ c _) = c
 
-isTypeDecl (DataDecl _ _ _ _) = True
-isTypeDecl (NewtypeDecl _ _ _ _) = True
-isTypeDecl (TypeDecl _ _ _ _) = True
-isTypeDecl _ = False
+-- | Get the type of a newtype constructor declaration
+nconstrType :: NewConstrDecl -> TypeExpr
+nconstrType (NewConstrDecl      _ _ ty) = ty
+nconstrType (NewRecordDecl _ _ (_, ty)) = ty
 
-isTypeSig (TypeSig _ _ _) = True
-isTypeSig (ExternalDecl _ _ _ _ _) = True
-isTypeSig _ = False
+-- | Get record label identifiers of a constructor declaration
+recordLabels :: ConstrDecl -> [Ident]
+recordLabels (ConstrDecl   _ _ _) = []
+recordLabels (ConOpDecl _ _ _  _) = []
+recordLabels (RecordDecl  _ _ fs) = [l | FieldDecl _ ls _ <- fs, l <- ls]
 
-isEvalAnnot (EvalAnnot _ _ _) = True
-isEvalAnnot _ = False
+-- | Get record label identifier of a newtype constructor declaration
+nrecordLabels :: NewConstrDecl -> [Ident]
+nrecordLabels (NewConstrDecl _ _ _     ) = []
+nrecordLabels (NewRecordDecl _ _ (l, _)) = [l]
 
-isValueDecl (FunctionDecl _ _ _) = True
-isValueDecl (ExternalDecl _ _ _ _ _) = True
-isValueDecl (FlatExternalDecl _ _) = True
-isValueDecl (PatternDecl _ _ _) = True
-isValueDecl (ExtraVariables _ _) = True
-isValueDecl _ = False
+-- | Get the declared method identifiers of a type class method declaration
+methods :: Decl a -> [Ident]
+methods (TypeSig _ fs _) = fs
+methods _                = []
 
-isRecordDecl (TypeDecl _ _ _ (RecordType _ _)) = True
-isRecordDecl _ = False
+-- | Get the method identifiers of a type class method implementations
+impls :: Decl a -> [Ident]
+impls (FunctionDecl _ _ f _) = [f]
+impls _                      = []
 
+-- | Get the declared method identifier of an interface method declaration
+imethod :: IMethodDecl -> Ident
+imethod (IMethodDecl _ f _ _) = f
 
-{-
-  The function \texttt{infixOp} converts an infix operator into an
-  expression.
--}
+-- | Get the arity of an interface method declaration
+imethodArity :: IMethodDecl -> Maybe Int
+imethodArity (IMethodDecl _ _ a _) = a
 
-infixOp :: InfixOp -> Expression
-infixOp (InfixOp op) = Variable op
-infixOp (InfixConstr op) = Constructor op
+--------------------------------------------------------
+-- constructing elements of the abstract syntax tree
+--------------------------------------------------------
+
+funDecl :: SpanInfo -> a -> Ident -> [Pattern a] -> Expression a -> Decl a
+funDecl spi a f ts e = FunctionDecl spi a f [mkEquation spi f ts e]
+
+mkEquation :: SpanInfo -> Ident -> [Pattern a] -> Expression a -> Equation a
+mkEquation spi f ts e = Equation spi (FunLhs NoSpanInfo f ts) (simpleRhs NoSpanInfo e)
+
+simpleRhs :: SpanInfo -> Expression a -> Rhs a
+simpleRhs spi e = SimpleRhs spi WhitespaceLayout e []
+
+patDecl :: SpanInfo -> Pattern a -> Expression a -> Decl a
+patDecl spi t e = PatternDecl spi t (SimpleRhs spi WhitespaceLayout e [])
+
+varDecl :: SpanInfo -> a -> Ident -> Expression a -> Decl a
+varDecl p ty = patDecl p . VariablePattern NoSpanInfo ty
+
+constrPattern :: a -> QualIdent -> [(a, Ident)] -> Pattern a
+constrPattern ty c = ConstructorPattern NoSpanInfo ty c
+                   . map (uncurry (VariablePattern NoSpanInfo))
+
+caseAlt :: SpanInfo -> Pattern a -> Expression a -> Alt a
+caseAlt spi t e = Alt spi t (SimpleRhs spi WhitespaceLayout e [])
+
+mkLet :: [Decl a] -> Expression a -> Expression a
+mkLet ds e = if null ds then e else Let NoSpanInfo WhitespaceLayout ds e
+
+mkVar :: a -> Ident -> Expression a
+mkVar ty = Variable NoSpanInfo ty . qualify
+
+mkCase :: CaseType -> Expression a -> [Alt a] -> Expression a
+mkCase = Case NoSpanInfo WhitespaceLayout
+
+mkLambda :: [Pattern a] -> Expression a -> Expression a
+mkLambda = Lambda NoSpanInfo
+
+apply :: Expression a -> [Expression a] -> Expression a
+apply = foldl (Apply NoSpanInfo)
+
+unapply :: Expression a -> [Expression a] -> (Expression a, [Expression a])
+unapply (Apply _ e1 e2) es = unapply e1 (e2 : es)
+unapply e               es = (e, es)
+
+
+--------------------------------------------------------
+-- Shorten Module
+-- Module Pragmas and Equations will be removed
+--------------------------------------------------------
+
+shortenModuleAST :: Module () -> Module ()
+shortenModuleAST = shortenAST
+
+class ShortenAST a where
+  shortenAST :: a -> a
+
+instance ShortenAST (Module a) where
+  shortenAST (Module spi li _ mid ex im ds) =
+    Module spi li [] mid ex im (map shortenAST ds)
+
+instance ShortenAST (Decl a) where
+  shortenAST (FunctionDecl spi a idt _) =
+    FunctionDecl spi a idt []
+  shortenAST (ClassDecl spi li cx cls tyv ds) =
+    ClassDecl spi li cx cls tyv (map shortenAST ds)
+  shortenAST (InstanceDecl spi li cx cls tyv ds) =
+    InstanceDecl spi li cx cls tyv (map shortenAST ds)
+  shortenAST d = d
diff --git a/src/CurryBuilder.hs b/src/CurryBuilder.hs
--- a/src/CurryBuilder.hs
+++ b/src/CurryBuilder.hs
@@ -1,202 +1,240 @@
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---
--- CurryBuilder - Generates Curry representations for a Curry source file
---                including all imported modules.
---
--- September 2005,
--- Martin Engelke (men@informatik.uni-kiel.de)
--- March 2007, extensions by Sebastian Fischer (sebf@informatik.uni-kiel.de)
---
-module CurryBuilder (buildCurry, smake) where
+{- |
+    Module      :  $Header$
+    Description :  Build tool for compiling multiple Curry modules
+    Copyright   :  (c) 2005        Martin Engelke
+                       2007        Sebastian Fischer
+                       2011 - 2015 Björn Peemöller
+                       2018        Kai-Oliver Prott
+    License     :  BSD-3-clause
 
-import System.Exit
-import System.Time
-import Control.Monad
-import qualified Data.Map as Map
-import Data.Maybe
-import Data.List 
-import System.IO
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
 
-import Curry.Base.Ident
+    This module contains functions to generate Curry representations for a
+    Curry source file including all imported modules.
+-}
+module CurryBuilder (buildCurry, findCurry) where
 
-import Modules (compileModule)
-import CurryCompilerOpts 
-import CurryDeps
+import Control.Monad   (foldM, liftM)
+import Data.Char       (isSpace)
+import Data.Maybe      (catMaybes, fromMaybe, mapMaybe)
+import System.FilePath ((</>), normalise)
+
+import Curry.Base.Ident
+import Curry.Base.Monad
+import Curry.Base.SpanInfo (SpanInfo)
+import Curry.Base.Pretty
 import Curry.Files.Filenames
 import Curry.Files.PathUtils
+import Curry.Syntax ( ModulePragma (..), Extension (KnownExtension)
+                    , KnownExtension (CPP), Tool (CYMAKE, FRONTEND) )
 
+import Base.Messages
 
-flatName' :: Options -> FilePath -> FilePath
-flatName' o
-    | extendedFlat o = extFlatName
-    | otherwise      = flatName
+import CompilerOpts ( Options (..), CppOpts (..), DebugOpts (..)
+                    , TargetType (..), defaultDebugOpts, updateOpts )
+import CurryDeps    (Source (..), flatDeps)
+import Modules      (compileModule)
 
--------------------------------------------------------------------------------
+-- |Compile the Curry module in the given source file including all imported
+-- modules w.r.t. the given 'Options'.
+buildCurry :: Options -> String -> CYIO ()
+buildCurry opts s = do
+  fn   <- findCurry opts s
+  deps <- flatDeps  opts fn
+  makeCurry opts' deps
+  where
+  opts' | null $ optTargetTypes opts = opts { optTargetTypes = [FlatCurry] }
+        | otherwise                  = opts
 
--- Compiles the Curry program 'file' including all imported modules, depending
--- on the options 'options'. The compilation was successful, if the returned
--- list is empty, otherwise it contains error messages.
-buildCurry :: Options -> FilePath -> IO ()
-buildCurry options file
-   = do let paths = importPaths options
-	file'          <- getCurryPath paths file
-	(cfile, errs1) <- return (maybe ("", [missingModule file])
-			                (\f -> (f,[]))
-				        file')
-	unless (null errs1) (abortWith errs1)
-	(deps, errs2) <- genDeps paths cfile
-	unless (null errs2) (abortWith errs2)
-	makeCurry options deps cfile
+-- |Search for a compilation target identified by the given 'String'.
+findCurry :: Options -> String -> CYIO FilePath
+findCurry opts s = do
+  mbTarget <- findFile `orIfNotFound` findModule
+  case mbTarget of
+    Nothing -> failMessages [complaint]
+    Just fn -> ok fn
+  where
+  canBeFile    = isCurryFilePath s
+  canBeModule  = isValidModuleName s
+  moduleFile   = moduleNameToFile $ fromModuleName s
+  paths        = "." : optImportPaths opts
+  findFile     = if canBeFile
+                    then liftIO $ lookupCurryFile paths s
+                    else return Nothing
+  findModule   = if canBeModule
+                    then liftIO $ lookupCurryFile paths moduleFile
+                    else return Nothing
+  complaint
+    | canBeFile && canBeModule = errMissing "target" s
+    | canBeFile                = errMissing "file"   s
+    | canBeModule              = errMissing "module" s
+    | otherwise                = errUnrecognized  s
+  first `orIfNotFound` second = do
+    mbFile <- first
+    case mbFile of
+      Nothing -> second
+      justFn  -> return justFn
 
+-- |Compiles the given source modules, which must be in topological order.
+makeCurry :: Options -> [(ModuleIdent, Source)] ->  CYIO ()
+makeCurry opts srcs = mapM_ process' (zip [1 ..] srcs)
+  where
+  total    = length srcs
+  tgtDir m = addOutDirModule (optUseOutDir opts) (optOutDir opts) m
 
--------------------------------------------------------------------------------
+  process' :: (Int, (ModuleIdent, Source)) -> CYIO ()
+  process' (n, (m, Source fn ps is)) = do
+    opts' <- processPragmas opts ps
+    process (adjustOptions (n == total) opts') (n, total) m fn deps
+    where
+    deps = fn : mapMaybe curryInterface is
 
-makeCurry :: Options -> [(ModuleIdent,Source)] -> FilePath -> IO ()
-makeCurry options deps file
-   = mapM compile (map snd deps) >> return ()
- where
- compile (Source file' mods)
-    | dropExtension file == dropExtension file'
-      = do 
-           flatIntfExists <- doesModuleExist (flatIntName file')
-	   if flatIntfExists && not (force options) && null (dump options)
-	    then smake (targetNames file')
-                       (file':(catMaybes (map flatInterface mods)))
-		       (generateFile file')
-		       (skipFile file')
-	    else generateFile file'
-    | otherwise
-      = do 
-           flatIntfExists <- doesModuleExist (flatIntName file')
-	   if flatIntfExists
-            then  smake [flatName' options file'] --[flatName file', flatIntName file']
-	                (file':(catMaybes (map flatInterface mods)))
-			(compileFile file')
-			(skipFile file')
-	    else compileFile file'
- compile _ = return ()
+    curryInterface i = case lookup i srcs of
+      Just (Source    fn' _ _) -> Just $ tgtDir i $ interfName fn'
+      Just (Interface fn'    ) -> Just $ tgtDir i $ interfName fn'
+      _                        -> Nothing
 
- compileFile file
-    = do unless (noVerb options) (putStrLn ("compiling " ++ file ++ " ..."))
-	 compileModule (compOpts True) file
-	 return ()
+  process' _ = return ()
 
- skipFile file
-    = do unless (noVerb options)
-		(putStrLn ("skipping " ++ file ++ " ..."))
+adjustOptions :: Bool -> Options -> Options
+adjustOptions final opts
+  | final      = opts { optForce         = optForce opts || isDump }
+  | otherwise  = opts { optForce         = False
+                      , optDebugOpts     = defaultDebugOpts
+                      }
+  where
+  isDump = not $ null $ dbDumpLevels $ optDebugOpts opts
 
- generateFile file
-    = do unless (noVerb options) 
-		(putStrLn ("generating "  
-			   ++ (head (targetNames file))               
-			   ++ " ..."))
-	 compileModule (compOpts False) file
-	 return ()
 
- targetNames fn         
-        | flat options            = [flatName' options fn] -- , flatIntName fn]
-		| flatXml options         = [xmlName fn]
-		| abstract options        = [acyName fn]
-		| untypedAbstract options = [uacyName fn]
-		| parseOnly options       = [maybe (sourceRepName fn) id (output options)]
-		| otherwise               = [flatName' options fn] -- , flatIntName fn]
-
- flatInterface mod 
-    = case (lookup mod deps) of
-        Just (Source file _)  -> Just (flatIntName (dropExtension file))
-	Just (Interface file) -> Just (flatIntName (dropExtension file))
-	_                     -> Nothing
-
- compOpts isImport
-    | isImport 
-      = options 
-	   { flat = True,
-	     flatXml = False,
-	     abstract = False,
-	     untypedAbstract = False,
-	     parseOnly = False,
-	     dump = []
-	   }
-    | otherwise = options
-
--------------------------------------------------------------------------------
-
--- Computes a dependency list for the Curry file 'file' (such a list
--- usualy starts with the prelude and ends with 'file'). The result 
--- is a tuple containing an association list (type [(ModuleIdent,Source)]; 
--- see module "CurryDeps") and a list of error messages.
-genDeps :: [FilePath] -> FilePath
-	   -> IO ([(ModuleIdent,Source)], [String])
-genDeps paths file
-   = fmap flattenDeps (deps paths [] Map.empty file)
+processPragmas :: Options -> [ModulePragma] -> CYIO Options
+processPragmas opts0 ps = do
+  let opts1 = foldl processLanguagePragma opts0
+                [ e | LanguagePragma _ es <- ps, KnownExtension _ e <- es ]
+  foldM processOptionPragma opts1 $
+    [ (p, s) | OptionsPragma p (Just FRONTEND) s <- ps ] ++
+      [ (p, s) | OptionsPragma p (Just CYMAKE) s <- ps ]
+  where
+  processLanguagePragma opts CPP
+    = opts { optCppOpts = (optCppOpts opts) { cppRun = True } }
+  processLanguagePragma opts _
+    = opts
+  processOptionPragma opts (p, s)
+    | not (null unknownFlags)
+    = failMessages [errUnknownOptions p unknownFlags]
+    | optMode         opts /= optMode         opts'
+    = failMessages [errIllegalOption p "Cannot change mode"]
+    | optLibraryPaths opts /= optLibraryPaths opts'
+    = failMessages [errIllegalOption p "Cannot change library path"]
+    | optImportPaths  opts /= optImportPaths  opts'
+    = failMessages [errIllegalOption p "Cannot change import path"]
+    | optTargetTypes  opts /= optTargetTypes  opts'
+    = failMessages [errIllegalOption p "Cannot change target type"]
+    | otherwise
+    = return opts'
+    where
+    (opts', files, errs) = updateOpts opts (quotedWords s)
+    unknownFlags = files ++ errs
 
+quotedWords :: String -> [String]
+quotedWords str = case dropWhile isSpace str of
+  []        -> []
+  s@('\'' : cs) -> case break (== '\'') cs of
+    (_     , []      ) -> def s
+    (quoted, (_:rest)) -> quoted : quotedWords rest
+  s@('"'  : cs) -> case break (== '"') cs of
+    (_     , []      ) -> def s
+    (quoted, (_:rest)) -> quoted : quotedWords rest
+  s         -> def s
+  where
+  def s = let (w, rest) = break isSpace s in  w : quotedWords rest
 
--------------------------------------------------------------------------------
--- A simple make function
+-- |Compile a single source module.
+process :: Options -> (Int, Int)
+        -> ModuleIdent -> FilePath -> [FilePath] -> CYIO ()
+process opts idx m fn deps
+  | optForce opts = compile
+  | otherwise     = smake (tgtDir (interfName fn) : destFiles) deps compile skip
+  where
+  skip    = status opts $ compMessage idx "Skipping" m (fn, head destFiles)
+  compile = do
+    status opts $ compMessage idx "Compiling" m (fn, head destFiles)
+    compileModule opts m fn
 
--- smake <destination files>
---       <dependencies> 
---       <io action, if dependencies are newer than destination files>
---       <io action, if destination files are newer than dependencies>
-smake :: [FilePath] -> [FilePath] -> IO a -> IO a -> IO a
-smake dests deps cmd alt
-   = do destTimes <- getDestTimes dests
-	depTimes  <- getDepTimes deps
-	make destTimes depTimes
- where
- make destTimes depTimes
-    | (length destTimes) < (length dests) 
-      = catch cmd (\err -> abortWith [show err]) 
-    | null depTimes 
-      = abortWith ["unknown dependencies"]
-    | outOfDate destTimes depTimes
-      = catch cmd (\err -> abortWith [show err])
-    | otherwise
-      = alt
+  tgtDir = addOutDirModule (optUseOutDir opts) (optOutDir opts) m
 
---
-getDestTimes :: [FilePath] -> IO [ClockTime]
-getDestTimes [] = return []
-getDestTimes (file:files)
-   = catch (do time  <- getModuleModTime file
-	       times <- getDestTimes files
-	       return (time:times))
-           (const (getDestTimes files))
+  destFiles = [ gen fn | (t, gen) <- nameGens, t `elem` optTargetTypes opts]
+  nameGens  =
+    [ (Tokens              , tgtDir . tokensName       )
+    , (Comments            , tgtDir . commentsName)
+    , (Parsed              , tgtDir . sourceRepName    )
+    , (FlatCurry           , tgtDir . flatName         )
+    , (TypedFlatCurry      , tgtDir . typedFlatName    )
+    , (AnnotatedFlatCurry  , tgtDir . annotatedFlatName)
+    , (AbstractCurry       , tgtDir . acyName          )
+    , (UntypedAbstractCurry, tgtDir . uacyName         )
+    , (AST                 , tgtDir . astName          )
+    , (ShortAST            , tgtDir . shortASTName     )
+    , (Html                , const (fromMaybe "." (optHtmlDir opts) </> htmlName m))
+    ]
 
---
-getDepTimes :: [String] -> IO [ClockTime]
-getDepTimes [] = return []
-getDepTimes (file:files)
-   = catch (do time  <- getModuleModTime file
-	       times <- getDepTimes files
-	       return (time:times))
-           (\err -> abortWith [show err])
+-- |Create a status message like
+-- @[m of n] Compiling Module          ( M.curry, .curry/M.fcy )@
+compMessage :: (Int, Int) -> String -> ModuleIdent
+            -> (FilePath, FilePath) -> String
+compMessage (curNum, maxNum) what m (src, dst)
+  =  '[' : lpad (length sMaxNum) (show curNum) ++ " of " ++ sMaxNum  ++ "]"
+  ++ ' ' : rpad 9 what ++ ' ' : rpad 16 (moduleName m)
+  ++ " ( " ++ normalise src ++ ", " ++ normalise dst ++ " )"
+  where
+  sMaxNum  = show maxNum
+  lpad n s = replicate (n - length s) ' ' ++ s
+  rpad n s = s ++ replicate (n - length s) ' '
 
---
-outOfDate :: [ClockTime] -> [ClockTime] -> Bool
-outOfDate tgtimes dptimes = or (map (\t -> or (map ((<) t) dptimes)) tgtimes)
+-- |A simple make function
+smake :: [FilePath] -- ^ destination files
+      -> [FilePath] -- ^ dependency files
+      -> CYIO a     -- ^ action to perform if depedency files are newer
+      -> CYIO a     -- ^ action to perform if destination files are newer
+      -> CYIO a
+smake dests deps actOutdated actUpToDate = do
+  destTimes <- catMaybes `liftM` mapM (liftIO . getModuleModTime) dests
+  depTimes  <- mapM (cancelMissing getModuleModTime) deps
+  make destTimes depTimes
+  where
+  make destTimes depTimes
+    | length destTimes < length dests = actOutdated
+    | outOfDate destTimes depTimes    = actOutdated
+    | otherwise                       = actUpToDate
 
--------------------------------------------------------------------------------
--- Error handling
+  outOfDate tgtimes dptimes = or [ tg < dp | tg <- tgtimes, dp <- dptimes]
 
--- Prints an error message on 'stderr'
-putErrLn :: String -> IO ()
-putErrLn = hPutStrLn stderr
+cancelMissing :: (FilePath -> IO (Maybe a)) -> FilePath -> CYIO a
+cancelMissing act f = liftIO (act f) >>= \res -> case res of
+  Nothing  -> failMessages [errModificationTime f]
+  Just val -> ok val
 
--- Prints a list of error messages on 'stderr'
-putErrsLn :: [String] -> IO ()
-putErrsLn = mapM_ putErrLn
+errUnknownOptions :: SpanInfo -> [String] -> Message
+errUnknownOptions spi errs = spanInfoMessage spi $
+  text "Unknown flag(s) in {-# OPTIONS_FRONTEND #-} pragma:"
+  <+> sep (punctuate comma $ map text errs)
 
--- Prints a list of error messages on 'stderr' and aborts the program
-abortWith :: [String] -> IO a
-abortWith errs = putErrsLn errs >> exitWith (ExitFailure 1)
+errIllegalOption :: SpanInfo -> String -> Message
+errIllegalOption spi err = spanInfoMessage spi $
+  text "Illegal option in {-# OPTIONS_FRONTEND #-} pragma:" <+> text err
 
+errMissing :: String -> String -> Message
+errMissing what which = message $ sep $ map text
+  [ "Missing", what, quote which ]
 
--- Error messages
+errUnrecognized :: String -> Message
+errUnrecognized f = message $ sep $ map text
+  [ "Unrecognized input", quote f ]
 
-missingModule :: FilePath -> String
-missingModule file = "Error: missing module \"" ++ file ++ "\""
+errModificationTime :: FilePath -> Message
+errModificationTime f = message $ sep $ map text
+  [ "Could not inspect modification time of file", quote f ]
 
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
+quote :: String -> String
+quote s = "\"" ++ s ++ "\""
diff --git a/src/CurryCompilerOpts.hs b/src/CurryCompilerOpts.hs
deleted file mode 100644
--- a/src/CurryCompilerOpts.hs
+++ /dev/null
@@ -1,166 +0,0 @@
--- -----------------------------------------------------------------------------
--- |
--- CurryCompilerOpts - Defines data structures containing options for
---                     compiling Curry programs (see module "CurryCompiler")
---
--- September 2005,
--- Martin Engelke (men@informatik.uni-kiel.de)
--- March 2007, extensions by Sebastian Fischer (sebf@informatik.uni-kiel.de)
---
--- -----------------------------------------------------------------------------
-
-module CurryCompilerOpts where
-
-import System.Console.GetOpt
-
-
--- | Data type for recording compiler options
-data Options
-  = Options
-  { force :: Bool             -- ^ force compilation
-  , html :: Bool              -- ^ generate Html code
-  , importPaths :: [FilePath] -- ^ directories for searching imports
-  , output :: Maybe FilePath  -- ^ name of output file
-  , noInterface :: Bool       -- ^ do not create an interface file
-  , noVerb :: Bool            -- ^ verbosity on/off
-  , noWarn :: Bool            -- ^ warnings on/off
-  , noOverlapWarn :: Bool     -- ^ "overlap" warnings on/off
-  , flat :: Bool              -- ^ generate FlatCurry code
-  , extendedFlat :: Bool      -- ^ generate FlatCurry code with extensions
-  , flatXml :: Bool           -- ^ generate flat XML code
-  , abstract :: Bool          -- ^ generate typed AbstracCurry code
-  , untypedAbstract :: Bool   -- ^ generate untyped AbstractCurry code
-  , parseOnly :: Bool         -- ^ generate source representation
-  , withExtensions :: Bool    -- ^ enable extended functionalities
-  , dump :: [Dump]            -- ^ dumps
-  , writeToSubdir :: Bool     -- ^ should the output be written to the subdir?
-  } deriving Show
-
-
--- | Default compiler options
-defaultOpts = Options
-  { force           = False
-  , html            = False
-  , importPaths     = []
-  , output          = Nothing
-  , noInterface     = False
-  , noVerb          = False
-  , noWarn          = False
-  , noOverlapWarn   = False
-  , extendedFlat    = False
-  , flat            = False
-  , flatXml         = False
-  , abstract        = False
-  , untypedAbstract = False
-  , parseOnly       = False
-  , withExtensions  = False
-  , dump            = []
-  , writeToSubdir   = True
-  }
-
-
--- | Data type for representing all available options (needed to read and parse
---   the options from the command line; see module 'GetOpt')
-data Option
-  = Help | Force | Html
-  | ImportPath FilePath | Output FilePath
-  | NoInterface | NoVerb | NoWarn | NoOverlapWarn
-  | FlatXML | Flat | ExtFlat | Abstract | UntypedAbstract | ParseOnly
-  | WithExtensions
-  | Dump [Dump]
-  | WriteToSubdir
-  deriving Eq
-
-
--- | All available compiler options
-options =
-  [ Option "f"  ["force"] (NoArg Force)
-              "force compilation of dependent files"
-  , Option ""   ["html"] (NoArg Html)
-              "generate html code"
-  , Option "i"  ["import-dir"] (ReqArg ImportPath "DIR")
-              "search for imports in DIR"
-  , Option "o"  ["output"] (ReqArg Output "FILE")
-              "write code to FILE"
-  , Option ""   ["no-intf"] (NoArg NoInterface)
-              "do not create an interface file"
-  , Option ""   ["no-verb"] (NoArg NoVerb)
-          "do not print compiler messages"
-  , Option ""   ["no-warn"] (NoArg NoWarn)
-          "do not print warnings"
-  , Option ""   ["no-overlap-warn"] (NoArg NoOverlapWarn)
-          "do not print warnings for overlapping rules"
-  , Option ""   ["flat"] (NoArg Flat)
-              "generate FlatCurry code"
-  , Option ""   ["extended-flat"] (NoArg ExtFlat)
-              "generate FlatCurry code with source references"
-  , Option ""   ["xml"] (NoArg FlatXML)
-              "generate flat xml code"
-  , Option ""   ["acy"] (NoArg Abstract)
-              "generate (type infered) AbstractCurry code"
-  , Option ""   ["uacy"] (NoArg UntypedAbstract)
-              "generate untyped AbstractCurry code"
-  , Option ""   ["parse-only"] (NoArg ParseOnly)
-              "generate source representation"
-  , Option "e"  ["extended"] (NoArg WithExtensions)
-              "enable extended Curry functionalities"
-  , Option ""   ["dump-all"] (NoArg (Dump [minBound..maxBound]))
-              "dump everything"
-  , Option ""   ["dump-renamed"] (NoArg (Dump [DumpRenamed]))
-              "dump source code after renaming"
-  , Option ""   ["dump-types"] (NoArg (Dump [DumpTypes]))
-              "dump types after type-checking"
-  , Option ""   ["dump-desugared"] (NoArg (Dump [DumpDesugared]))
-              "dump source code after desugaring"
-  , Option ""   ["dump-simplified"] (NoArg (Dump [DumpSimplified]))
-              "dump source code after simplification"
-  , Option ""   ["dump-lifted"] (NoArg (Dump [DumpLifted]))
-              "dump source code after lambda-lifting"
-  , Option ""   ["dump-il"] (NoArg (Dump [DumpIL]))
-              "dump intermediate language before lifting"
-  , Option ""   ["dump-case"] (NoArg (Dump [DumpCase]))
-              "dump intermediate language after case simplification"
-  , Option "?h" ["help"] (NoArg Help)
-              "display this help and exit"
-  , Option ""   ["no-hidden-subdir"] (NoArg WriteToSubdir)
-              "write all output to hidden .curry subdirectory"
-  ]
-
-
--- | Marks an 'Option' as selected in the 'Options' record
-selectOption :: Option -> Options -> Options
-selectOption Force opts           = opts { force = True }
-selectOption (ImportPath dir) opts
-   = opts { importPaths = dir:(importPaths opts) }
-selectOption (Output file) opts   = opts { output = Just file }
-selectOption NoInterface opts     = opts { noInterface = True }
-selectOption NoVerb opts          = opts { noVerb = True }
-selectOption NoWarn opts          = opts { noWarn = True }
-selectOption NoOverlapWarn opts   = opts { noOverlapWarn = True }
-selectOption Flat opts            = opts { flat = True }
-selectOption ExtFlat opts         = opts { extendedFlat = True }
-selectOption Html opts            = opts { html = True }
-selectOption FlatXML opts         = opts { flatXml = True }
-selectOption Abstract opts        = opts { abstract = True }
-selectOption UntypedAbstract opts = opts { untypedAbstract = True }
-selectOption ParseOnly opts       = opts { parseOnly = True }
-selectOption WithExtensions opts  = opts { withExtensions = True }
-selectOption (Dump ds) opts       = opts { dump = ds ++ dump opts }
-selectOption WriteToSubdir opts   = opts { writeToSubdir = False }
-
-
--- | Data type for representing code dumps
---   TODO: dump FlatCurry code, dump AbstractCurry code, dump after 'case'
---   expansion
-data Dump
-  = DumpRenamed      -- ^ dump source after renaming
-  | DumpTypes        -- ^ dump types after typechecking
-  | DumpDesugared    -- ^ dump source after desugaring
-  | DumpSimplified   -- ^ dump source after simplification
-  | DumpLifted       -- ^ dump source after lambda-lifting
-  | DumpIL           -- ^ dump IL code after translation
-  | DumpCase         -- ^ dump IL code after case elimination
-    deriving (Eq,Bounded,Enum,Show)
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
diff --git a/src/CurryDeps.hs b/src/CurryDeps.hs
new file mode 100644
--- /dev/null
+++ b/src/CurryDeps.hs
@@ -0,0 +1,191 @@
+{- |
+    Module      :  $Header$
+    Description :  Computation of module dependencies
+    Copyright   :  (c) 2002 - 2004 Wolfgang Lux
+                       2005        Martin Engelke
+                       2007        Sebastian Fischer
+                       2011 - 2013 Björn Peemöller
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module implements the functions to compute the dependency
+    information between Curry modules. This is used to create Makefile
+    dependencies and to update programs composed of multiple modules.
+-}
+{-# LANGUAGE CPP #-}
+module CurryDeps
+  ( Source (..), flatDeps, deps, flattenDeps, sourceDeps, moduleDeps ) where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+import           Control.Monad   (foldM)
+import           Data.List       (isSuffixOf, nub)
+import qualified Data.Map as Map (Map, empty, insert, lookup, toList)
+
+import Curry.Base.Ident
+import Curry.Base.Monad
+import Curry.Base.Pretty
+import Curry.Files.Filenames
+import Curry.Files.PathUtils
+import Curry.Syntax
+  ( Module (..), ModulePragma (..), ImportDecl (..), parseHeader, parsePragmas
+  , patchModuleId, hasLanguageExtension)
+
+import Base.Messages
+import Base.SCC (scc)
+import CompilerOpts (Options (..), CppOpts (..), KnownExtension (..))
+import CondCompile (condCompile)
+
+-- |Different types of source files
+data Source
+    -- | A source file with pragmas and module imports
+  = Source FilePath [ModulePragma] [ModuleIdent]
+    -- | An interface file
+  | Interface FilePath
+    -- | An unknown file
+  | Unknown
+    deriving (Eq, Show)
+
+type SourceEnv = Map.Map ModuleIdent Source
+
+-- |Retrieve the dependencies of a source file in topological order
+-- and possible errors during flattering
+flatDeps :: Options -> FilePath -> CYIO [(ModuleIdent, Source)]
+flatDeps opts fn = do
+  sEnv <- deps opts Map.empty fn
+  case flattenDeps sEnv of
+    (env, []  ) -> ok env
+    (_  , errs) -> failMessages errs
+
+-- |Retrieve the dependencies of a source file as a 'SourceEnv'
+deps :: Options -> SourceEnv -> FilePath -> CYIO SourceEnv
+deps opts sEnv fn
+  | ext   ==   icurryExt  = return sEnv
+  | ext `elem` sourceExts = sourceDeps opts sEnv fn
+  | otherwise             = targetDeps opts sEnv fn
+  where ext = takeExtension fn
+
+-- The following functions are used to lookup files related to a given
+-- module. Source files for targets are looked up in the current
+-- directory only. Two different search paths are used to look up
+-- imported modules, the first is used to find source modules, whereas
+-- the library path is used only for finding matching interface files. As
+-- the compiler does not distinguish these paths, we actually check for
+-- interface files in the source paths as well.
+
+-- In order to compute the dependency graph, source files for each module
+-- need to be looked up. When a source module is found, its header is
+-- parsed in order to determine the modules that it imports, and
+-- dependencies for these modules are computed recursively. The prelude
+-- is added implicitly to the list of imported modules except for the
+-- prelude itself.
+
+-- |Retrieve the dependencies of a given target file
+targetDeps :: Options -> SourceEnv -> FilePath -> CYIO SourceEnv
+targetDeps opts sEnv fn = do
+  mFile <- liftIO $ lookupFile [""] sourceExts fn
+  case mFile of
+    Nothing   -> return $ Map.insert (mkMIdent [fn]) Unknown sEnv
+    Just file -> sourceDeps opts sEnv file
+
+-- |Retrieve the dependencies of a given source file
+sourceDeps :: Options -> SourceEnv -> FilePath -> CYIO SourceEnv
+sourceDeps opts sEnv fn = readHeader opts fn >>= moduleDeps opts sEnv fn
+
+-- |Retrieve the dependencies of a given module
+moduleDeps :: Options -> SourceEnv -> FilePath -> Module a -> CYIO SourceEnv
+moduleDeps opts sEnv fn mdl@(Module _ _ ps m _ _ _) = case Map.lookup m sEnv of
+  Just  _ -> return sEnv
+  Nothing -> do
+    let imps  = imports opts mdl
+        sEnv' = Map.insert m (Source fn ps imps) sEnv
+    foldM (moduleIdentDeps opts) sEnv' imps
+
+-- |Retrieve the imported modules and add the import of the Prelude
+-- according to the compiler options.
+imports :: Options -> Module a -> [ModuleIdent]
+imports opts mdl@(Module _ _ _ m _ is _) = nub $
+     [preludeMIdent | m /= preludeMIdent && not noImplicitPrelude]
+  ++ [m' | ImportDecl _ m' _ _ _ <- is]
+  where noImplicitPrelude = NoImplicitPrelude `elem` optExtensions opts
+                              || mdl `hasLanguageExtension` NoImplicitPrelude
+
+-- |Retrieve the dependencies for a given 'ModuleIdent'
+moduleIdentDeps :: Options -> SourceEnv -> ModuleIdent -> CYIO SourceEnv
+moduleIdentDeps opts sEnv m = case Map.lookup m sEnv of
+  Just _  -> return sEnv
+  Nothing -> do
+    mFile <- liftIO $ lookupCurryModule ("." : optImportPaths opts)
+                                        (optLibraryPaths opts) m
+    case mFile of
+      Nothing -> return $ Map.insert m Unknown sEnv
+      Just fn
+        | icurryExt `isSuffixOf` fn ->
+            return $ Map.insert m (Interface fn) sEnv
+        | otherwise                 -> do
+            hdr@(Module _ _ _ m' _ _ _) <- readHeader opts fn
+            if m == m' then moduleDeps opts sEnv fn hdr
+                       else failMessages [errWrongModule m m']
+
+readHeader :: Options -> FilePath -> CYIO (Module ())
+readHeader opts fn = do
+  mbFile <- liftIO $ readModule fn
+  case mbFile of
+    Nothing  -> failMessages [errMissingFile fn]
+    Just src -> do
+      prgs <- liftCYM $ parsePragmas fn src
+      let cppOpts  = optCppOpts opts
+          cppOpts' =
+            cppOpts { cppRun = cppRun cppOpts || hasLanguageExtension prgs CPP }
+      condC <- condCompile cppOpts' fn src
+      hdr <- liftCYM $ parseHeader fn condC
+      return $ patchModuleId fn hdr
+
+-- If we want to compile the program instead of generating Makefile
+-- dependencies, the environment has to be sorted topologically. Note
+-- that the dependency graph should not contain any cycles.
+flattenDeps :: SourceEnv -> ([(ModuleIdent, Source)], [Message])
+flattenDeps = fdeps . sortDeps
+  where
+  sortDeps :: SourceEnv -> [[(ModuleIdent, Source)]]
+  sortDeps = scc idents imported . Map.toList
+
+  idents (m, _) = [m]
+
+  imported (_, Source _ _ ms) = ms
+  imported (_,             _) = []
+
+  fdeps :: [[(ModuleIdent, Source)]] -> ([(ModuleIdent, Source)], [Message])
+  fdeps = foldr checkdep ([], [])
+
+  checkdep []    (srcs, errs) = (srcs      , errs      )
+  checkdep [src] (srcs, errs) = (src : srcs, errs      )
+  checkdep dep   (srcs, errs) = (srcs      , err : errs)
+    where err = errCyclicImport $ map fst dep
+
+errMissingFile :: FilePath -> Message
+errMissingFile fn = message $ sep $ map text [ "Missing file:", fn ]
+
+errWrongModule :: ModuleIdent -> ModuleIdent -> Message
+errWrongModule m m' = message $ sep $
+  [ text "Expected module for", text (moduleName m) <> comma
+  , text "but found", text (moduleName m') ]
+
+errCyclicImport :: [ModuleIdent] -> Message
+errCyclicImport []  = internalError "CurryDeps.errCyclicImport: empty list"
+errCyclicImport [m] = message $ sep $ map text
+  [ "Recursive import for module", moduleName m ]
+errCyclicImport ms  = message $ sep $
+  text "Cyclic import dependency between modules" : punctuate comma inits
+  ++ [text "and", lastm]
+  where
+  (inits, lastm)     = splitLast $ map (text . moduleName) ms
+  splitLast []       = internalError "CurryDeps.splitLast: empty list"
+  splitLast (x : []) = ([]    , x)
+  splitLast (x : xs) = (x : ys, y) where (ys, y) = splitLast xs
diff --git a/src/CurryDeps.lhs b/src/CurryDeps.lhs
deleted file mode 100644
--- a/src/CurryDeps.lhs
+++ /dev/null
@@ -1,144 +0,0 @@
-
-% $Id: CurryDeps.lhs,v 1.14 2004/02/09 17:10:05 wlux Exp $
-%
-% Copyright (c) 2002-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-% Extended by Sebastian Fischer (sebf@informatik.uni-kiel.de)
-\nwfilename{CurryDeps.lhs}
-\section{Building Programs}
-This module implements the functions to compute the dependency
-information between Curry modules. This is used to create Makefile
-dependencies and to update programs composed of multiple modules.
-\begin{verbatim}
-
-> module CurryDeps(Source(..),
->                  deps, flattenDeps, sourceDeps, moduleDeps
->                 ) where
-
-> import Data.List
-> import qualified Data.Map as Map
-> import Data.Maybe
-> import Control.Monad
-
-> import Curry.Base.Ident
-> import Curry.Base.MessageMonad
-
-> import Curry.Files.Filenames
-> import Curry.Files.PathUtils
-
-> import Curry.Syntax hiding(Interface(..))
-
-> import SCC
-
-
-> data Source = Source FilePath [ModuleIdent]
->             | Interface FilePath
->             | Unknown
->             deriving (Eq,Ord,Show)
-> type SourceEnv = Map.Map ModuleIdent Source
-
-> deps :: [FilePath] -> [FilePath] -> SourceEnv -> FilePath -> IO SourceEnv
-> deps paths libraryPaths mEnv fn
->   | e `elem` sourceExts = sourceDeps paths libraryPaths (mkMIdent [r]) mEnv fn
->   | e == icurryExt = return Map.empty
->   | e `elem` objectExts = targetDeps paths libraryPaths mEnv r
->   | otherwise = targetDeps paths libraryPaths mEnv fn
->   where r = dropExtension fn
->         e = takeExtension fn
-
-> targetDeps :: [FilePath] -> [FilePath] -> SourceEnv -> FilePath
->            -> IO SourceEnv
-> targetDeps paths libraryPaths mEnv fn =
->   lookupFile [""] sourceExts fn >>=
->   maybe (return (Map.insert m Unknown mEnv)) (sourceDeps paths libraryPaths m mEnv)
->   where m = mkMIdent [fn]
-
-\end{verbatim}
-The following functions are used to lookup files related to a given
-module. Source files for targets are looked up in the current
-directory only. Two different search paths are used to look up
-imported modules, the first is used to find source modules, whereas
-the library path is used only for finding matching interface files. As
-the compiler does not distinguish these paths, we actually check for
-interface files in the source paths as well.
-
-Note that the functions \texttt{buildScript} and \texttt{makeDepend}
-already remove all directories that are included in the both search
-paths from the library paths in order to avoid scanning such
-directories more than twice.
-\begin{verbatim}
-
-\end{verbatim}
-In order to compute the dependency graph, source files for each module
-need to be looked up. When a source module is found, its header is
-parsed in order to determine the modules that it imports, and
-dependencies for these modules are computed recursively. The prelude
-is added implicitly to the list of imported modules except for the
-prelude itself. Any errors reported by the parser are ignored.
-\begin{verbatim}
-
-> moduleDeps :: [FilePath] -> [FilePath] -> SourceEnv -> ModuleIdent
->            -> IO SourceEnv
-> moduleDeps paths libraryPaths mEnv m =
->   case Map.lookup m mEnv of
->     Just _ -> return mEnv
->     Nothing ->
->       do
->         mbFn <- lookupModule paths libraryPaths m
->         case mbFn of
->           Just fn
->             | icurryExt `isSuffixOf` fn ->
->                 return (Map.insert m (Interface fn) mEnv)
->             | otherwise -> sourceDeps paths libraryPaths m mEnv fn
->           Nothing -> return (Map.insert m Unknown mEnv)
-
-> sourceDeps :: [FilePath] -> [FilePath] -> ModuleIdent -> SourceEnv
->            -> FilePath -> IO SourceEnv
-> sourceDeps paths libraryPaths m mEnv fn =
->   do
->     s <- readModule fn
->     case fst $ runMsg $ parseHeader fn s of
->       Right (Module m' _ ds) ->
->         let ms = imports m' ds in
->         foldM (moduleDeps paths libraryPaths) (Map.insert m (Source fn ms) mEnv) ms
->       Left _ -> return (Map.insert m (Source fn []) mEnv)
-
-> imports :: ModuleIdent -> [Decl] -> [ModuleIdent]
-> imports m ds = nub $
->   [preludeMIdent | m /= preludeMIdent] ++ [m | ImportDecl _ m _ _ _ <- ds]
-
-
-
-If we want to compile the program instead of generating Makefile
-dependencies the environment has to be sorted topologically. Note
-that the dependency graph should not contain any cycles.
-
-> flattenDeps :: SourceEnv -> ([(ModuleIdent,Source)],[String])
-> flattenDeps = fdeps . sortDeps
->     where
->     sortDeps :: SourceEnv -> [[(ModuleIdent,Source)]]
->     sortDeps = scc modules imports . Map.toList
->
->     modules (m, _) = [m]
->
->     imports (_,Source _ ms) = ms
->     imports (_,Interface _) = []
->     imports (_,Unknown) = []
->
->     fdeps :: [[(ModuleIdent,Source)]] -> ([(ModuleIdent,Source)],[String])
->     fdeps = foldr checkdep ([], [])
->     
->     checkdep [] (ms', es')  = (ms',es')
->     checkdep [m] (ms', es') = (m:ms',es')
->     checkdep dep (ms', es') = (ms',cyclicError (map fst dep) : es')
->
->     cyclicError :: [ModuleIdent] -> String
->     cyclicError (m:ms) =
->         "Cylic import dependency between modules " ++ show m ++ rest ms
->
->     rest [m] = " and " ++ show m
->     rest ms  = rest' ms
->     rest' [m] = ", and " ++ show m
->     rest' (m:ms) = ", " ++ show m ++ rest' ms
diff --git a/src/CurryEnv.hs b/src/CurryEnv.hs
deleted file mode 100644
--- a/src/CurryEnv.hs
+++ /dev/null
@@ -1,181 +0,0 @@
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---
--- CurryEnv - Generates a record containing extracted and prepared data
---            from a CurrySyntax module
---
--- November 2005,
--- Martin Engelke (men@informatik.uni-kiel.de)
---
-module CurryEnv (CurryEnv(..), curryEnv) where
-
-import Data.Maybe
-
-import Curry.Base.Position
-import Curry.Base.Ident
-
-import Curry.Syntax
-
-import Types
-import Base
-
-
-------------------------------------------------------------------------------
-
--- A record containing the following data for a module 'm':
---
---    moduleId    - the name of 'm'
---    exports     - the export list extracted from 'm'
---    interface   - all exported declarations in 'm' (including exported 
---                  imports)
---    infixDecls  - interfaces of all infix declarations in 'm'
---    typeSynonym - interfaces of all type synonyms in 'm'
---
-data CurryEnv = CurryEnv{ moduleId     :: ModuleIdent,
-			  exports      :: [Export],
-			  imports      :: [IDecl],
-			  interface    :: [IDecl],
-			  infixDecls   :: [IDecl],
-			  typeSynonyms :: [IDecl]
-			} deriving Show
-			  
-
--------------------------------------------------------------------------------
-
--- Returns a Curry environment for the module 'mod' and its corresponding
--- environments 'mEnv' (imported modules), 'tcEnv' (table of type
--- constructors) and 'intf' (the interface of 'mod')
-curryEnv :: ModuleEnv -> TCEnv -> Interface -> Module -> CurryEnv
-curryEnv mEnv tcEnv (Interface iid idecls) mod@(Module mid mExp decls)
-   | iid == mid
-     = CurryEnv{ moduleId     = mid,
-		 exports      = maybe [] (\ (Exporting _ exps) -> exps) mExp,
-		 imports      = genImportIntf decls,
-		 interface    = idecls,
-		 infixDecls   = genInfixDecls mod,
-		 typeSynonyms = genTypeSyns tcEnv mod
-	       }
-   | otherwise
-     = internalError ("CurryEnv: interface \"" ++ show iid 
-		      ++ "\" does not match module \"" ++ show mid ++ "\"")
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
--- Generate interfaces for import declarations
-genImportIntf :: [Decl] -> [IDecl]
-genImportIntf decls = reverse (map snd (foldl genImpIntf [] decls))
-
---
-genImpIntf imps (ImportDecl pos mid _ _ _)
-   = maybe ((mid, IImportDecl pos mid):imps) (const imps) (lookup mid imps)
-genImpIntf imps _ = imps
-
-
--------------------------------------------------------------------------------
-
--- Generate interface declaration for all infix declarations in the module
-genInfixDecls :: Module -> [IDecl]
-genInfixDecls (Module mident _ decls) = collectIInfixDecls mident decls
-
---
-collectIInfixDecls :: ModuleIdent -> [Decl] -> [IDecl]
-collectIInfixDecls mident [] = []
-collectIInfixDecls mident ((InfixDecl pos infixspec prec idents):decls)
-   = (map (\ident 
-	   -> IInfixDecl pos infixspec prec (qualifyWith mident ident)) 
-	   idents)
-     ++ (collectIInfixDecls mident decls)
-collectIInfixDecls mident (_:decls) = collectIInfixDecls mident decls
-
-
--------------------------------------------------------------------------------
-
--- Generate interface declarations for all type synonyms in the module.
-genTypeSyns :: TCEnv -> Module -> [IDecl]
-genTypeSyns tcEnv (Module mident _ decls)
-   = concatMap (genTypeSynDecl mident tcEnv) (filter isTypeSyn decls)
-
---
-genTypeSynDecl :: ModuleIdent -> TCEnv -> Decl -> [IDecl]
-genTypeSynDecl mid tcEnv (TypeDecl pos ident params texpr)
-   = [genTypeDecl pos mid ident params tcEnv texpr]
-genTypeSynDecl _ _ _ 
-   = []
-
---
-genTypeDecl :: Position -> ModuleIdent -> Ident -> [Ident] -> TCEnv
-	    -> TypeExpr -> IDecl
-genTypeDecl pos mid ident params tcEnv texpr
-   = ITypeDecl pos (qualifyWith mid ident) params
-               (modifyTypeExpr tcEnv texpr)
-
-
---
-modifyTypeExpr :: TCEnv -> TypeExpr -> TypeExpr
-modifyTypeExpr tcEnv (ConstructorType qident typeexprs)
-   = case (qualLookupTC qident tcEnv) of
-       [AliasType _ arity rhstype]
-          -> modifyTypeExpr tcEnv 
-	                    (genTypeSynDeref (zip [0 .. (arity-1)] typeexprs)
-			                     rhstype)
-       _  -> ConstructorType (fromMaybe qident (lookupTCId qident tcEnv))
-                             (map (modifyTypeExpr tcEnv) typeexprs)
-modifyTypeExpr _ (VariableType ident)
-   = VariableType ident
-modifyTypeExpr tcEnv (ArrowType type1 type2)
-   = ArrowType (modifyTypeExpr tcEnv type1) (modifyTypeExpr tcEnv type2)
-modifyTypeExpr tcEnv (TupleType typeexprs)
-   | null typeexprs 
-     = ConstructorType qUnitId []
-   | otherwise
-     = ConstructorType (qTupleId (length typeexprs)) 
-                       (map (modifyTypeExpr tcEnv) typeexprs)
-modifyTypeExpr tcEnv (ListType typeexpr)
-   = ConstructorType (qualify listId) [(modifyTypeExpr tcEnv typeexpr)]
-modifyTypeExpr tcEnv (RecordType fields rtype)
-   = RecordType (map (\ (labs, texpr) -> (labs, (modifyTypeExpr tcEnv texpr)))
-		     fields)
-                (maybe Nothing (Just . modifyTypeExpr tcEnv) rtype)
-
---
-genTypeSynDeref :: [(Int,TypeExpr)] -> Type -> TypeExpr
-genTypeSynDeref its (TypeConstructor qident typeexprs)
-   = ConstructorType qident (map (genTypeSynDeref its) typeexprs)
-genTypeSynDeref its (TypeVariable i)
-   = fromMaybe (internalError ("@CurryInfo.genTypeSynDeref: " ++
-			       "unkown type var index"))
-               (lookup i its)
-genTypeSynDeref its (TypeConstrained typeexprs i)
-   = internalError ("@CurryInfo.genTypeSynDeref: " ++
-		    "illegal constrained type occured")
-genTypeSynDeref its (TypeArrow type1 type2)
-   = ArrowType (genTypeSynDeref its type1) (genTypeSynDeref its type2)
-genTypeSynDeref its (TypeSkolem i)
-   = internalError ("@CurryInfo.genTypeSynDeref: " ++
-		    "illegal skolem type occured")
-genTypeSynDeref its (TypeRecord fields ri)
-   = RecordType (map (\ (lab, texpr) -> ([lab], genTypeSynDeref its texpr))
-		     fields)
-                (maybe Nothing 
-		       (\i -> Just (genTypeSynDeref its (TypeVariable i)))
-		       ri)
-
---
-lookupTCId :: QualIdent -> TCEnv -> Maybe QualIdent
-lookupTCId qident tcEnv
-   = case (qualLookupTC qident tcEnv) of
-       [DataType qident' _ _]     -> Just qident'
-       [RenamingType qident' _ _] -> Just qident'
-       [AliasType qident' _ _]    -> Just qident'
-       _                          -> Nothing
-
-
-
-isTypeSyn :: Decl -> Bool
-isTypeSyn (TypeDecl _ _ _ texpr)
-   = case texpr of
-       RecordType _ _ -> False
-       _              -> True
-isTypeSyn _ = False
diff --git a/src/CurryHtml.hs b/src/CurryHtml.hs
deleted file mode 100644
--- a/src/CurryHtml.hs
+++ /dev/null
@@ -1,190 +0,0 @@
-module CurryHtml(source2html) where
-
-import Data.Char hiding(Space)
-import Control.Exception
-
-import Curry.Base.Ident
-import Curry.Base.MessageMonad
-
-import Curry.Files.PathUtils (readModule, writeModule, getCurryPath)
-
-import SyntaxColoring
-import Curry.Syntax.Frontend as Frontend
-
-
-
---- translate source file into HTML file with syntaxcoloring
---- @param outputfilename
---- @param sourcefilename
-source2html :: [String] -> String -> String -> IO ()
-source2html imports outputfilename sourcefilename = do
-        let sourceprogname = removeExtension sourcefilename
-            output = if null outputfilename 
-                     then sourceprogname ++ "_curry.html"
-                     else outputfilename 
-            modulname = fileName sourceprogname
-        fullfname <- getCurryPath imports sourcefilename
-        program <- filename2program imports (maybe sourcefilename id fullfname)
-        (if null outputfilename then writeModule True output 
-                                else writeFile   output)
-           (program2html modulname program)
-             
---- @param importpaths
---- @param filename                  
---- @return program
-filename2program :: [String] -> String -> IO Program
-filename2program paths filename
-    = do cont <- readModule filename
-         typingParseResult <- (catchError (typingParse paths filename  cont))
-         fullParseResult <- (catchError (fullParse paths filename  cont))
-         parseResult <- (catchError (return (parse filename cont)))
-         lexResult <- (catchError (return (Frontend.lex filename cont)))
-         return (genProgram cont (typingParseResult : fullParseResult : [parseResult]) lexResult)
-
-
---- this function intercepts errors and converts it to Messages      
---- @param a show-function for (Result a)                    
---- @param a function that generates a (Result a)
---- @return (Result a) without runtimeerrors   
-
--- FIXME This is ugly. Avoid exceptions and report failure via MsgMonad instead! (hsi)
-catchError :: Show a =>IO (MsgMonad a) -> IO (MsgMonad a)
-catchError toDo = Control.Exception.catch (toDo >>= returnNF) handler 
-  where     
-    -- This refers to base3
-    handler (ErrorCall str) = return (failWith str)
-    handler  e = return (failWith (show e))  
-             
-    returnNF a = normalform a `seq` return a
-    normalform = length . show . runMsg
-                
-       
-
---- generates htmlcode with syntax highlighting            
---- @param modulname
---- @param a program
---- @return HTMLcode
-program2html :: String ->Program -> String
-program2html modulname codes =
-    "<html>\n<head>\n<title>Module "++ 
-    modulname++
-    "</title>\n" ++
-    "<link rel=\"stylesheet\" type=\"text/css\" href=\"currydoc.css\">"++
-    "</link>\n</head>\n<body style=\"font-family:'Courier New', Arial;\">\n<pre>\n" ++
-    concat (map (code2html True . (\(_,_,c) -> c)) codes) ++
-    "<pre>\n</body>\n</html>"            
-            
-            
---- which code has which color 
---- @param code
---- @return color of the code  
-code2class :: Code -> String                          
-code2class (Keyword _) = "keyword"
-code2class (Space _)= ""
-code2class NewLine = ""
-code2class (ConstructorName ConstrPattern _) = "constructorname_constrpattern"
-code2class (ConstructorName ConstrCall _) = "constructorname_constrcall"
-code2class (ConstructorName ConstrDecla _) = "constructorname_constrdecla"
-code2class (ConstructorName OtherConstrKind _) = "constructorname_otherconstrkind"
-code2class (Function InfixFunction _) = "function_infixfunction"
-code2class (Function TypSig _) = "function_typsig"
-code2class (Function FunDecl _) = "function_fundecl"
-code2class (Function FunctionCall _) = "function_functioncall"
-code2class (Function OtherFunctionKind _) = "function_otherfunctionkind"
-code2class (ModuleName _) = "modulename"
-code2class (Commentary _) = "commentary"
-code2class (NumberCode _) = "numbercode"
-code2class (StringCode _) = "stringcode"
-code2class (CharCode _) = "charcode"
-code2class (Symbol _) = "symbol"
-code2class (Identifier IdDecl _) = "identifier_iddecl"
-code2class (Identifier IdOccur _) = "identifier_idoccur"
-code2class (Identifier UnknownId _) = "identifier_unknownid"
-code2class (TypeConstructor TypeDecla _) = "typeconstructor_typedecla"
-code2class (TypeConstructor TypeUse _) = "typeconstructor_typeuse"
-code2class (TypeConstructor TypeExport _) = "typeconstructor_typeexport"
-code2class (CodeWarning _ _) = "codewarning"
-code2class (NotParsed _) = "notparsed"
-
-
-code2html :: Bool -> Code -> String    
-code2html ownClass code@(CodeWarning _ c) =
-     (if ownClass then spanTag (code2class code) else id)
-              (code2html False c)       
-code2html ownClass code@(Commentary _) =
-    (if ownClass then spanTag (code2class code) else id)
-      (replace '<' "<span>&lt</span>" (code2string code))                
-code2html ownClass c
-      | isCall c && ownClass = maybe tag (addHtmlLink tag) (getQualIdent c) 
-      | isDecl c && ownClass= maybe tag (addHtmlAnchor tag) (getQualIdent c)
-      | otherwise = tag
-    where tag = (if ownClass then spanTag (code2class c) else id)
-                      (htmlQuote (code2string c)) 
-                                        
-spanTag :: String -> String -> String
-spanTag [] str = str
-spanTag cl str = "<span class=\""++ cl ++ "\">" ++ str ++ "</span>"
-
-replace :: Char -> String -> String -> String
-replace old new = foldr (\ x -> if x == old then (new ++) else ([x]++)) ""
-
-addHtmlAnchor :: String -> QualIdent -> String
-addHtmlAnchor html qualIdent = "<a name=\""++ string2urlencoded (show (unqualify qualIdent)) ++"\"></a>" ++ html
-
-addHtmlLink :: String -> QualIdent -> String
-addHtmlLink html qualIdent =
-   let (maybeModuleIdent,ident) = (qualidMod qualIdent, qualidId qualIdent) in
-   "<a href=\"" ++ 
-   (maybe "" (\x -> show x ++ "_curry.html") maybeModuleIdent) ++ 
-   "#"++ 
-   string2urlencoded (show ident) ++
-   "\">"++ 
-   html ++
-   "</a>"
-
-isCall :: Code -> Bool
-isCall (TypeConstructor TypeExport _) = True
-isCall (TypeConstructor _ _) = False
-isCall (Identifier _ _) = False
-isCall code = not (isDecl code) &&
-                maybe False (const True) (getQualIdent code)
-
-     
-isDecl :: Code -> Bool
-isDecl (ConstructorName ConstrDecla _) = True
-isDecl (Function FunDecl _) = True
-isDecl (TypeConstructor TypeDecla _) = True
-isDecl _ = False 
-
-
-fileName = reverse . takeWhile (/='/') . reverse 
-
-removeExtension = reverse . drop 1 . dropWhile (/='.') . reverse 
-
-
---- Translates arbitrary strings into equivalent urlencoded string.
-string2urlencoded :: String -> String
-string2urlencoded = id
-{-
-string2urlencoded [] = []
-string2urlencoded (c:cs)
-  | isAlphaNum c = c : string2urlencoded cs
-  | c == ' '     = '+' : string2urlencoded cs
-  | otherwise = show (ord c) ++ (if null cs then "" else ".") ++ string2urlencoded cs
--}
-
-htmlQuote :: String -> String
-htmlQuote [] = []
-htmlQuote (c:cs) | c=='<' = "&lt;"   ++ htmlQuote cs
-                 | c=='>' = "&gt;"   ++ htmlQuote cs
-                 | c=='&' = "&amp;"  ++ htmlQuote cs
-                 | c=='"' = "&quot;" ++ htmlQuote cs
-                 | c=='\228' = "&auml;" ++ htmlQuote cs
-                 | c=='\246' = "&ouml;" ++ htmlQuote cs
-                 | c=='\252' = "&uuml;" ++ htmlQuote cs
-                 | c=='\196' = "&Auml;" ++ htmlQuote cs
-                 | c=='\214' = "&Ouml;" ++ htmlQuote cs
-                 | c=='\220' = "&Uuml;" ++ htmlQuote cs
-                 | c=='\223' = "&szlig;"++ htmlQuote cs
-                 | otherwise = c : htmlQuote cs
-  
diff --git a/src/Desugar.lhs b/src/Desugar.lhs
deleted file mode 100644
--- a/src/Desugar.lhs
+++ /dev/null
@@ -1,843 +0,0 @@
-% $Id: Desugar.lhs,v 1.42 2004/02/15 22:10:32 wlux Exp $
-%
-% Copyright (c) 2001-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{Desugar.lhs}
-\section{Desugaring Curry Expressions}
-The desugaring pass removes all syntactic sugar from the module. In
-particular, the output of the desugarer will have the following
-properties.
-\begin{itemize}
-\item All function definitions are $\eta$-expanded.\\
-  {\em Note:} Since this version is used as a frontend for PAKCS, the 
-  $\eta$-expansion had been disabled.
-\item No guarded right hand sides occur in equations, pattern
-  declarations, and case alternatives. In addition, the declaration
-  lists of the right hand sides are empty; local declarations are
-  transformed into let expressions.
-\item Patterns in equations and case alternatives are composed only of
-  \begin{itemize}
-  \item literals,
-  \item variables,
-  \item constructor applications, and
-  \item as patterns.
-  \end{itemize}
-\item Expressions are composed only of
-  \begin{itemize}
-  \item literals,
-  \item variables,
-  \item constructors,
-  \item (binary) applications,
-  \item let expressions, and
-  \item case expressions.
-  \end{itemize}
-\item Applications $N\:x$ in patterns and expressions, where $N$ is a
-  newtype constructor, are replaced by a $x$. Note that neither the
-  newtype declaration itself nor partial applications of newtype
-  constructors are changed.\footnote{It were possible to replace
-  partial applications of newtype constructor by \texttt{prelude.id}.
-  However, our solution yields a more accurate output when the result
-  of a computation includes partial applications.}
-\item Function patterns are replaced by variables and are integrated
-  in a guarded right hand side using the \texttt{=:<=} operator
-\item Records, which currently must be declared using the keyword
-  \texttt{type}, are transformed into data types with one constructor.
-  Record construction and pattern matching are represented using the
-  record constructor. Selection and update are represented using selector
-  and update functions which are generated for each record declaration.
-  The record constructor must be entered into the type environment as well
-  as the selector functions and the update functions. 
-\end{itemize}
-
-\ToDo{Use a different representation for the restricted code instead
-of using the syntax tree from \texttt{CurrySyntax}.}
-
-\textbf{As we are going to insert references to real prelude entities,
-all names must be properly qualified before calling this module.}
-\begin{verbatim}
-
-> module Desugar(desugar) where
-
-> import Data.Maybe
-> import Control.Arrow(second)
-> import Control.Monad.State as S
-> import Data.List
-
-> import Curry.Base.Position
-> import Curry.Base.Ident
-> import Curry.Syntax.Utils
-> import Curry.Syntax
-
-> import Types
-> import Base
-> import Typing
-> import Utils
-
-
-
-posE = undefined
-
-\end{verbatim}
-New identifiers may be introduced while desugaring pattern
-declarations, case and $\lambda$-expressions, and list comprehensions.
-As usual, we use a state monad transformer for generating unique
-names. In addition, the state is also used for passing through the
-type environment, which must be augmented with the types of these new
-variables.
-\begin{verbatim}
-
-> type DesugarState a = S.StateT ValueEnv (S.State Int) a
-
-> run :: DesugarState a -> ValueEnv -> a
-> run m tyEnv = S.evalState (S.evalStateT m tyEnv) 1
-
-\end{verbatim}
-The desugaring phase keeps only the type, function, and value
-declarations of the module. In the current version record declarations
-are transformed into data types. The remaining type declarations are
-not desugared and cannot occur in local declaration groups.
-They are filtered out separately.
-
-In order to use records within other modules, the export specification
-of the module has to be extended with the selector and update functions of
-all exported labels.
-
-Actually, the transformation is slightly more general than necessary
-as it allows value declarations at the top-level of a module.
-\begin{verbatim}
-
-> desugar :: ValueEnv -> TCEnv -> Module -> (Module,ValueEnv)
-> desugar tyEnv tcEnv (Module m es ds) = (Module m es ds',tyEnv')
->   where (ds',tyEnv') = run (desugarModule m tcEnv ds) tyEnv
-
-> desugarModule :: ModuleIdent -> TCEnv -> [Decl] 
->	        -> DesugarState ([Decl],ValueEnv)
-> desugarModule m tcEnv ds = 
->   do
->     dss <- mapM (desugarRecordDecl m tcEnv) ds
->     let ds' = concat dss
->     ds'' <- desugarDeclGroup m tcEnv ds'
->     tyEnv' <- S.get
->     return (filter isTypeDecl ds' ++ ds'', tyEnv')
-
-\end{verbatim}
-
-
-Within a declaration group, all type signatures and evaluation
-annotations are discarded. First, the patterns occurring in the left
-hand sides are desugared. Due to lazy patterns this may add further
-declarations to the group that must be desugared as well.
-\begin{verbatim}
-
-> desugarDeclGroup :: ModuleIdent -> TCEnv -> [Decl] -> DesugarState [Decl]
-> desugarDeclGroup m tcEnv ds =
->   do
->     dss' <- mapM (desugarDeclLhs m tcEnv) (filter isValueDecl ds)
->     mapM (desugarDeclRhs m tcEnv) (concat dss')
-
-> desugarDeclLhs :: ModuleIdent -> TCEnv -> Decl -> DesugarState [Decl]
-> desugarDeclLhs m tcEnv (PatternDecl p t rhs) =
->   do
->     (ds',t') <- desugarTerm m tcEnv p [] t
->     dss' <- mapM (desugarDeclLhs m tcEnv) ds'
->     return (PatternDecl p t' rhs : concat dss')
-> desugarDeclLhs m tcEnv (FlatExternalDecl p fs) =
->   do
->     tyEnv <- S.get
->     return (map (externalDecl tyEnv p) fs)
->   where externalDecl tyEnv p f =
->           ExternalDecl p CallConvPrimitive (Just (name f)) f
->                        (fromType (typeOf tyEnv (Variable (qual f))))
->         qual f
->           | unRenameIdent f == f = qualifyWith m f
->           | otherwise = qualify f
-> desugarDeclLhs _ _ d = return [d]
-
-\end{verbatim}
-After desugaring its right hand side, each equation is $\eta$-expanded
-by adding as many variables as necessary to the argument list and
-applying the right hand side to those variables ({\em Note:} $\eta$-expansion
-is disabled in the version for PAKCS).
-Furthermore every occurrence of a record type within the type of a function
-is simplified to the corresponding type constructor from the record
-declaration. This is possible because currently records must not be empty
-and a record label belongs to only one record declaration.
-\begin{verbatim}
-
-> desugarDeclRhs :: ModuleIdent -> TCEnv -> Decl -> DesugarState Decl
-> desugarDeclRhs m tcEnv (FunctionDecl p f eqs) =
->   do
->     tyEnv <- S.get
->     let ty =  (flip typeOf (Variable (qual f))) tyEnv
->     liftM (FunctionDecl p f) 
->	    (mapM (desugarEquation m tcEnv (arrowArgs ty)) eqs)
->   where qual f
->           | unRenameIdent f == f = qualifyWith m f
->           | otherwise = qualify f
-> desugarDeclRhs _ tcEnv (ExternalDecl p cc ie f ty) =
->   return (ExternalDecl p cc (ie `mplus` Just (name f)) f ty)
-> desugarDeclRhs m tcEnv (PatternDecl p t rhs) =
->   liftM (PatternDecl p t) (desugarRhs m tcEnv p rhs)
-> desugarDeclRhs _ tcEnv (ExtraVariables p vs) = return (ExtraVariables p vs)
-
-> desugarEquation :: ModuleIdent -> TCEnv -> [Type] -> Equation 
->	          -> DesugarState Equation
-> desugarEquation m tcEnv tys (Equation p lhs rhs) =
->   do
->     (ds',ts') <- mapAccumM (desugarTerm m tcEnv p) [] ts
->     rhs' <- desugarRhs m tcEnv p (addDecls ds' rhs)
->     (ts'', rhs'') <- desugarFunctionPatterns m p ts' rhs'
->     return (Equation p (FunLhs f ts'') rhs'')
->   where (f,ts) = flatLhs lhs
-
-
-\end{verbatim}
-The transformation of patterns is straight forward except for lazy
-patterns. A lazy pattern \texttt{\~}$t$ is replaced by a fresh
-variable $v$ and a new local declaration $t$~\texttt{=}~$v$ in the
-scope of the pattern. In addition, as-patterns $v$\texttt{@}$t$ where
-$t$ is a variable or an as-pattern are replaced by $t$ in combination
-with a local declaration for $v$.
-\begin{verbatim}
-
-> desugarLiteral :: Literal -> DesugarState (Either Literal ([SrcRef],[Literal]))
-> desugarLiteral (Char p c) = return (Left (Char p c))
-> desugarLiteral (Int v i)  = liftM (Left . fixType) S.get
->   where 
->    fixType tyEnv
->      | typeOf tyEnv v == floatType 
->          = Float (srcRefOf $ positionOfIdent v) (fromIntegral i)
->      | otherwise = Int v i
-> desugarLiteral (Float p f) = return (Left (Float p f))
-> desugarLiteral (String (SrcRef [i]) cs) 
->   = return (Right (consRefs i cs,zipWith (Char . SrcRef . (:[])) [i,i+2..] cs))
->   where consRefs r []     = [SrcRef [r]]
->         consRefs r (_:xs) = let r'=r+2 in r' `seq` (SrcRef [r']:consRefs r' xs)
-> desugarLiteral (String is _) = error $ "internal error desugarLiteral; "++
->                                        "wrong source ref for string: "  ++ show is
-
-> desugarList :: [SrcRef] -> (SrcRef -> b -> b -> b) -> (SrcRef -> b) -> [b] -> b
-> desugarList pos cons nil xs = snd (foldr cons' nil' xs)
->   where rNil:rCs = reverse pos 
->         nil'                = (rCs,nil rNil)
->         cons' t (rC:rCs,ts) = (rCs,cons rC t ts)
-
-> desugarTerm :: ModuleIdent -> TCEnv -> Position -> [Decl] -> ConstrTerm
->             -> DesugarState ([Decl],ConstrTerm)
-> desugarTerm m tcEnv p ds (LiteralPattern l) =
->   desugarLiteral l >>=
->   either (return . (,) ds . LiteralPattern)
->          (\ (pos,ls) -> desugarTerm m tcEnv p ds $ ListPattern pos $ map LiteralPattern ls)
-> desugarTerm m tcEnv p ds (NegativePattern _ l) =
->   desugarTerm m tcEnv p ds (LiteralPattern (negateLiteral l))
->   where negateLiteral (Int v i) = Int v (-i)
->         negateLiteral (Float p f) = Float p (-f)
->         negateLiteral _ = internalError "negateLiteral"
-> desugarTerm _ _ _ ds (VariablePattern v) = return (ds,VariablePattern v)
-> desugarTerm m tcEnv p ds (ConstructorPattern c [t]) =
->   do
->     tyEnv <- S.get
->     liftM (if isNewtypeConstr tyEnv c then id else second (constrPat c))
->           (desugarTerm m tcEnv p ds t)
->   where constrPat c t = ConstructorPattern c [t]
-> desugarTerm m tcEnv p ds (ConstructorPattern c ts) =
->   liftM (second (ConstructorPattern c)) (mapAccumM (desugarTerm m tcEnv p) ds ts)
-> desugarTerm m tcEnv p ds (InfixPattern t1 op t2) =
->   desugarTerm m tcEnv p ds (ConstructorPattern op [t1,t2])
-> desugarTerm m tcEnv p ds (ParenPattern t) = desugarTerm m tcEnv p ds t
-> desugarTerm m tcEnv p ds (TuplePattern pos ts) =
->   desugarTerm m tcEnv p ds (ConstructorPattern (tupleConstr ts) ts)
->   where tupleConstr ts = addRef pos $ 
->                          if null ts then qUnitId else qTupleId (length ts)
-> desugarTerm m tcEnv p ds (ListPattern pos ts) =
->   liftM (second (desugarList pos cons nil)) (mapAccumM (desugarTerm m tcEnv p) ds ts)
->   where nil  p' = ConstructorPattern (addRef p' qNilId) []
->         cons p' t ts = ConstructorPattern (addRef p' qConsId) [t,ts]
-
-> desugarTerm m tcEnv p ds (AsPattern v t) =
->   liftM (desugarAs p v) (desugarTerm m tcEnv p ds t)
-> desugarTerm m tcEnv p ds (LazyPattern pos t) = desugarLazy pos m p ds t
-> desugarTerm m tcEnv p ds (FunctionPattern f ts) =
->   liftM (second (FunctionPattern f)) (mapAccumM (desugarTerm m tcEnv p) ds ts)
-> desugarTerm m tcEnv p ds (InfixFuncPattern t1 f t2) =
->   desugarTerm m tcEnv p ds (FunctionPattern f [t1,t2])
-> desugarTerm m tcEnv p ds (RecordPattern fs _)
->   | null fs = internalError "desugarTerm: empty record"
->   | otherwise =
->     do tyEnv <- S.get 
->	 case (lookupValue (fieldLabel (head fs)) tyEnv) of
->          [Label _ r _] -> 
->            desugarRecordPattern m tcEnv p ds (map field2Tuple fs) r
->          _ -> internalError "desugarTerm: no label"
-
-> desugarAs :: Position -> Ident -> ([Decl],ConstrTerm) -> ([Decl],ConstrTerm)
-> desugarAs p v (ds,t) =
->  case t of
->    VariablePattern v' -> (varDecl p v (mkVar v') : ds,t)
->    AsPattern v' _ -> (varDecl p v (mkVar v') : ds,t)
->    _ -> (ds,AsPattern v t)
-
-> desugarLazy :: SrcRef -> ModuleIdent -> Position -> [Decl] -> ConstrTerm
->             -> DesugarState ([Decl],ConstrTerm)
-> desugarLazy pos m p ds t =
->   case t of
->     VariablePattern _ -> return (ds,t)
->     ParenPattern t' -> desugarLazy pos m p ds t'
->     AsPattern v t' -> liftM (desugarAs p v) (desugarLazy pos m p ds t')
->     LazyPattern pos t' -> desugarLazy pos m p ds t'
->     _ ->
->       do
->         v0 <- S.get >>= freshIdent m "_#lazy" . monoType . flip typeOf t
->         let v' = addPositionIdent (AST pos) v0
->         return (patDecl p{astRef=pos} t (mkVar v') : ds,VariablePattern v')
-
-
-\end{verbatim}
-A list of boolean guards is expanded into a nested if-then-else
-expression, whereas a constraint guard is replaced by a case
-expression. Note that if the guard type is \texttt{Success} only a
-single guard is allowed for each equation.\footnote{This change was
-introduced in version 0.8 of the Curry report.} We check for the
-type \texttt{Bool} of the guard because the guard's type defaults to
-\texttt{Success} if it is not restricted by the guard expression.
-\begin{verbatim}
-
-> desugarRhs :: ModuleIdent -> TCEnv -> Position -> Rhs -> DesugarState Rhs
-> desugarRhs m tcEnv p rhs =
->   do
->     tyEnv <- S.get
->     e' <- desugarExpr m tcEnv p (expandRhs tyEnv prelFailed rhs)
->     return (SimpleRhs p e' [])
-
-> expandRhs :: ValueEnv -> Expression -> Rhs -> Expression
-> expandRhs tyEnv _ (SimpleRhs _ e ds) = Let ds e
-> expandRhs tyEnv e0 (GuardedRhs es ds) = Let ds (expandGuards tyEnv e0 es)
-
-> expandGuards :: ValueEnv -> Expression -> [CondExpr] -> Expression
-> expandGuards tyEnv e0 es
->   | booleanGuards tyEnv es = foldr mkIfThenElse e0 es
->   | otherwise = mkCond es
->   where mkIfThenElse (CondExpr p g e) = IfThenElse (srcRefOf p) g e
->         mkCond [CondExpr p g e] = Apply (Apply prelCond g) e
-
-> booleanGuards :: ValueEnv -> [CondExpr] -> Bool
-> booleanGuards _ [] = False
-> booleanGuards tyEnv (CondExpr _ g _ : es) =
->   not (null es) || typeOf tyEnv g == boolType
-
-> desugarExpr :: ModuleIdent -> TCEnv -> Position -> Expression
->             -> DesugarState Expression
-> desugarExpr m tcEnv p (Literal l) =
->   desugarLiteral l >>=
->   either (return . Literal) (\ (pos,ls) -> desugarExpr m tcEnv p $ List pos $ map Literal ls)
-> desugarExpr _ _ _ (Variable v) = return (Variable v)
-> desugarExpr _ _ _ (Constructor c) = return (Constructor c)
-> desugarExpr m tcEnv p (Paren e) = desugarExpr m tcEnv p e
-> desugarExpr m tcEnv p (Typed e _) = desugarExpr m tcEnv p e
-> desugarExpr m tcEnv p (Tuple pos es) =
->   liftM (apply (Constructor (tupleConstr es))) 
->         (mapM (desugarExpr m tcEnv p) es)
->   where tupleConstr es = addRef pos $ if null es then qUnitId else qTupleId (length es)
-> desugarExpr m tcEnv p (List pos es) =
->   liftM (desugarList pos cons nil) (mapM (desugarExpr m tcEnv p) es)
->   where nil p'  = Constructor (addRef p' qNilId)
->         cons p' = Apply . Apply (Constructor $ addRef p' qConsId)
-> desugarExpr m tcEnv p (ListCompr pos e []) = desugarExpr m tcEnv p (List [pos,pos] [e])
-> desugarExpr m tcEnv p (ListCompr r e (q:qs)) = 
->   desugarQual m tcEnv p q (ListCompr r e qs)
-> desugarExpr m tcEnv p (EnumFrom e) = 
->   liftM (Apply prelEnumFrom) (desugarExpr m tcEnv p e)
-> desugarExpr m tcEnv p (EnumFromThen e1 e2) =
->   liftM (apply prelEnumFromThen) (mapM (desugarExpr m tcEnv p) [e1,e2])
-> desugarExpr m tcEnv p (EnumFromTo e1 e2) =
->   liftM (apply prelEnumFromTo) (mapM (desugarExpr m tcEnv p) [e1,e2])
-> desugarExpr m tcEnv p (EnumFromThenTo e1 e2 e3) =
->   liftM (apply prelEnumFromThenTo) (mapM (desugarExpr m tcEnv p) [e1,e2,e3])
-> desugarExpr m tcEnv p (UnaryMinus op e) =
->   do
->     tyEnv <- S.get
->     liftM (Apply (unaryMinus op (typeOf tyEnv e))) (desugarExpr m tcEnv p e)
->   where unaryMinus op ty
->           | op == minusId =
->               if ty == floatType then prelNegateFloat else prelNegate
->           | op == fminusId = prelNegateFloat
->           | otherwise = internalError "unaryMinus"
-> desugarExpr m tcEnv p (Apply (Constructor c) e) =
->   do
->     tyEnv <- S.get
->     liftM (if isNewtypeConstr tyEnv c then id else (Apply (Constructor c)))
->           (desugarExpr m tcEnv p e)
-> desugarExpr m tcEnv p (Apply e1 e2) =
->   do
->     e1' <- desugarExpr m tcEnv p e1
->     e2' <- desugarExpr m tcEnv p e2
->     return (Apply e1' e2')
-> desugarExpr m tcEnv p (InfixApply e1 op e2) =
->   do
->     op' <- desugarExpr m tcEnv p (infixOp op)
->     e1' <- desugarExpr m tcEnv p e1
->     e2' <- desugarExpr m tcEnv p e2
->     return (Apply (Apply op' e1') e2')
-> desugarExpr m tcEnv p (LeftSection e op) =
->   do
->     op' <- desugarExpr m tcEnv p (infixOp op)
->     e' <- desugarExpr m tcEnv p e
->     return (Apply op' e')
-> desugarExpr m tcEnv p (RightSection op e) =
->   do
->     op' <- desugarExpr m tcEnv p (infixOp op)
->     e' <- desugarExpr m tcEnv p e
->     return (Apply (Apply prelFlip op') e')
-> desugarExpr m tcEnv p exp@(Lambda r ts e) =
->   do
->     f <- S.get >>=
->          freshIdent m "_#lambda" . polyType . flip typeOf exp
->     desugarExpr m tcEnv p (Let [funDecl (AST r) f ts e] (mkVar f))
-> desugarExpr m tcEnv p (Let ds e) =
->   do
->     ds' <- desugarDeclGroup m tcEnv ds
->     e' <- desugarExpr m tcEnv p e
->     return (if null ds' then e' else Let ds' e')
-> desugarExpr m tcEnv p (Do sts e) = 
->   desugarExpr m tcEnv p (foldr desugarStmt e sts)
->   where desugarStmt (StmtExpr r e) e' = apply (prelBind_ r) [e,e']
->         desugarStmt (StmtBind r t e) e' = apply (prelBind r) [e,Lambda r [t] e']
->         desugarStmt (StmtDecl ds) e' = Let ds e'
-> desugarExpr m tcEnv p (IfThenElse r e1 e2 e3) =
->   do
->     e1' <- desugarExpr m tcEnv p e1
->     e2' <- desugarExpr m tcEnv p e2
->     e3' <- desugarExpr m tcEnv p e3
->     return (Case r e1' [caseAlt p truePattern e2',caseAlt p falsePattern e3'])
-> desugarExpr m tcEnv p (Case r e alts)
->   | null alts = return prelFailed
->   | otherwise =
->       do
->         e' <- desugarExpr m tcEnv p e
->         v <- S.get >>= freshIdent m "_#case" . monoType . flip typeOf e
->         alts' <- mapM (desugarAltLhs m tcEnv) alts
->         tyEnv <- S.get
->         alts'' <- mapM (desugarAltRhs m tcEnv)
->                        (map (expandAlt tyEnv v) (init (tails alts')))
->         return (mkCase m v e' alts'')
->   where mkCase m v e alts
->           | v `elem` qfv m alts = Let [varDecl p v e] (Case r (mkVar v) alts)
->           | otherwise = Case r e alts
-> desugarExpr m tcEnv p (RecordConstr fs)
->   | null fs = internalError "desugarExpr: empty record construction"
->   | otherwise =
->       do let l = fieldLabel (head fs)
->	       fs' = map field2Tuple fs
->          tyEnv <- S.get
->	   case (lookupValue l tyEnv) of
->            [Label l' r _] -> desugarRecordConstr m tcEnv p r fs'
->            _  -> internalError "desugarExpr: illegal record construction"
-> desugarExpr m tcEnv p (RecordSelection e l) =
->   do tyEnv <- S.get
->      case (lookupValue l tyEnv) of
->        [Label _ r _] -> desugarRecordSelection m tcEnv p r l e
->        _ -> internalError "desugarExpr: illegal record selection"
-> desugarExpr m tcEnv p (RecordUpdate fs rexpr)
->   | null fs = internalError "desugarExpr: empty record update"
->   | otherwise =
->       do let l = fieldLabel (head fs)
->	       fs' = map field2Tuple fs
->          tyEnv <- S.get
->	   case (lookupValue l tyEnv) of
->            [Label _ r _] -> desugarRecordUpdate m tcEnv p r rexpr fs'
->            _  -> internalError "desugarExpr: illegal record update"
-
-desugarExpr _ _ _ x = internalError $ "desugarExpr: unexpected expression " ++ show x
-
-\end{verbatim}
-If an alternative in a case expression has boolean guards and all of
-these guards return \texttt{False}, the enclosing case expression does
-not fail but continues to match the remaining alternatives against the
-selector expression. In order to implement this semantics, which is
-compatible with Haskell, we expand an alternative with boolean guards
-such that it evaluates a case expression with the remaining cases that
-are compatible with the matched pattern when the guards fail.
-\begin{verbatim}
-
-> desugarAltLhs :: ModuleIdent -> TCEnv -> Alt -> DesugarState Alt
-> desugarAltLhs m tcEnv (Alt p t rhs) =
->   do
->     (ds',t') <- desugarTerm m tcEnv p [] t
->     return (Alt p t' (addDecls ds' rhs))
-
-> desugarAltRhs :: ModuleIdent -> TCEnv -> Alt -> DesugarState Alt
-> desugarAltRhs m tcEnv (Alt p t rhs) = 
->   liftM (Alt p t) (desugarRhs m tcEnv p rhs)
-
-> expandAlt :: ValueEnv -> Ident -> [Alt] -> Alt
-> expandAlt tyEnv v (Alt p t rhs : alts) = caseAlt p t (expandRhs tyEnv e0 rhs)
->   where e0 = Case (srcRefOf p) (mkVar v) 
->                   (filter (isCompatible t . altPattern) alts)
->         altPattern (Alt _ t _) = t
-
-> isCompatible :: ConstrTerm -> ConstrTerm -> Bool
-> isCompatible (VariablePattern _) _ = True
-> isCompatible _ (VariablePattern _) = True
-> isCompatible (AsPattern _ t1) t2 = isCompatible t1 t2
-> isCompatible t1 (AsPattern _ t2) = isCompatible t1 t2
-> isCompatible (ConstructorPattern c1 ts1) (ConstructorPattern c2 ts2) =
->   and ((c1 == c2) : zipWith isCompatible ts1 ts2)
-> isCompatible (LiteralPattern l1) (LiteralPattern l2) = canon l1 == canon l2
->   where canon (Int _ i) = Int anonId i
->         canon l = l
-
-\end{verbatim}
-The frontend provides several extensions of the Curry functionality, which
-have to be desugared as well. This part transforms the following extensions:
-\begin{itemize}
-\item runction patterns
-\item records
-\end{itemize}
-\begin{verbatim}
-
-> desugarFunctionPatterns :: ModuleIdent -> Position -> [ConstrTerm] -> Rhs
->	                     -> DesugarState ([ConstrTerm], Rhs)
-> desugarFunctionPatterns m p ts rhs = 
->   do (ts', its) <- elimFunctionPattern m p ts
->      rhs' <- genFunctionPatternExpr m p its rhs
->      return (ts', rhs')
-
-> desugarRecordDecl :: ModuleIdent -> TCEnv -> Decl -> DesugarState [Decl]
-> desugarRecordDecl m tcEnv (TypeDecl p r vs (RecordType fss _)) =
->   case (qualLookupTC r' tcEnv) of
->     [AliasType _ n (TypeRecord fs' _)] ->
->       do tyEnv <- S.get
->	   let tys = concatMap (\ (ls,ty) -> replicate (length ls) ty) fss
->	       --tys' = map (elimRecordTypes tyEnv) tys
->	       rdecl = DataDecl p r vs [ConstrDecl p [] r tys]
->	       rty' = TypeConstructor r' (map TypeVariable [0 .. n-1])
->              rcts' = ForAllExist 0 n (foldr TypeArrow rty' (map snd fs'))
->	   rfuncs <- mapM (genRecordFuncs m tcEnv p r' rty' (map fst fs')) fs'
->	   S.modify (bindGlobalInfo DataConstructor m r rcts')
->          return (rdecl:(concat rfuncs))
->     _ -> internalError "desugarRecordDecl: no record"
->   where r' = qualifyWith m r
-> desugarRecordDecl _ _ decl = return [decl]
-
-> desugarRecordPattern :: ModuleIdent -> TCEnv -> Position -> [Decl]
->		       -> [(Ident,ConstrTerm)] -> QualIdent
->		       -> DesugarState ([Decl],ConstrTerm)
-> desugarRecordPattern m tcEnv p ds fs r =
->   case (qualLookupTC r tcEnv) of
->     [AliasType _ _ (TypeRecord fs' _)] ->
->       do let ts = map (\ (l,_) 
->		         -> fromMaybe (VariablePattern anonId)
->		                      (lookup l fs))
->		        fs'
->	   desugarTerm m tcEnv p ds (ConstructorPattern r ts)
-
-> desugarRecordConstr :: ModuleIdent -> TCEnv -> Position -> QualIdent 
->	              -> [(Ident,Expression)] -> DesugarState Expression
-> desugarRecordConstr m tcEnv p r fs =
->   case (qualLookupTC r tcEnv) of
->     [AliasType _ _ (TypeRecord fs' _)] ->
->       do let cts = map (\ (l,_) -> 
->	                  fromMaybe (internalError "desugarRecordConstr")
->		                    (lookup l fs)) fs'
->	   desugarExpr m tcEnv p (foldl Apply (Constructor r) cts)
->     _ -> internalError "desugarRecordConstr: wrong type"
-
-> desugarRecordSelection :: ModuleIdent -> TCEnv -> Position -> QualIdent 
->		         -> Ident -> Expression -> DesugarState Expression
-> desugarRecordSelection m tcEnv p r l e =
->   desugarExpr m tcEnv p (Apply (Variable (qualRecSelectorId m r l)) e)
-
-> desugarRecordUpdate :: ModuleIdent -> TCEnv -> Position -> QualIdent
->	              -> Expression -> [(Ident,Expression)] 
->	              -> DesugarState Expression
-> desugarRecordUpdate m tcEnv p r rexpr fs =
->   desugarExpr m tcEnv p (foldl (genRecordUpdate m r) rexpr fs)
->   where
->   genRecordUpdate m r rexpr (l,e) =
->     Apply (Apply (Variable (qualRecUpdateId m r l)) rexpr) e
-
-> elimFunctionPattern :: ModuleIdent -> Position -> [ConstrTerm]
->		         -> DesugarState ([ConstrTerm], [(Ident,ConstrTerm)])
-> elimFunctionPattern m p [] = return ([],[])
-> elimFunctionPattern m p (t:ts)
->    | containsFunctionPattern t
->      = do tyEnv <- S.get
->	    ident <- freshIdent m "_#funpatt" (monoType (typeOf tyEnv t))
->	    (ts',its') <- elimFunctionPattern m p ts
->           return ((VariablePattern ident):ts', (ident,t):its')
->    | otherwise
->      = do (ts', its') <- elimFunctionPattern m p ts
->	    return (t:ts', its')
-
-> containsFunctionPattern :: ConstrTerm -> Bool
-> containsFunctionPattern (ConstructorPattern _ ts)
->    = any containsFunctionPattern ts
-> containsFunctionPattern (InfixPattern t1 _ t2)
->    = any containsFunctionPattern [t1,t2]
-> containsFunctionPattern (ParenPattern t)
->    = containsFunctionPattern t
-> containsFunctionPattern (TuplePattern _ ts)
->    = any containsFunctionPattern ts
-> containsFunctionPattern (ListPattern _ ts)
->    = any containsFunctionPattern ts
-> containsFunctionPattern (AsPattern _ t)
->    = containsFunctionPattern t
-> containsFunctionPattern (LazyPattern _ t)
->    = containsFunctionPattern t
-> containsFunctionPattern (FunctionPattern _ _) = True
-> containsFunctionPattern (InfixFuncPattern _ _ _) = True
-> containsFunctionPattern _ = False
-
-> genFunctionPatternExpr :: ModuleIdent -> Position -> [(Ident, ConstrTerm)]
->		            -> Rhs -> DesugarState Rhs
-> genFunctionPatternExpr m _ its rhs@(SimpleRhs p expr decls)
->    | null its = return rhs
->    | otherwise
->      = let ies = map (\ (i,t) -> (i, constrTerm2Expr t)) its
->	     fpexprs = map (\ (ident, expr) 
->		            -> Apply (Apply prelFuncPattEqu expr) 
->		                     (Variable (qualify ident)))
->	                   ies
->	     fpexpr =  foldl (\e1 e2 -> Apply (Apply prelConstrConj e1) e2)
->	                     (head fpexprs) 
->		             (tail fpexprs)
->	     freevars = foldl getConstrTermVars [] (map snd its)
->            rhsexpr = Let [ExtraVariables p freevars]
->		           (Apply (Apply prelCond fpexpr) expr)
->        in  return (SimpleRhs p rhsexpr decls)  
-> genFunctionPatternExpr _ _ _ rhs
->    = internalError "genFunctionPatternExpr: unexpected right-hand-side"
-
-> constrTerm2Expr :: ConstrTerm -> Expression
-> constrTerm2Expr (LiteralPattern lit)
->    = Literal lit
-> constrTerm2Expr (VariablePattern ident)
->    = Variable (qualify ident)
-> constrTerm2Expr (ConstructorPattern qident cts)
->    = foldl (\e1 e2 -> Apply e1 e2) 
->            (Constructor qident) 
->            (map constrTerm2Expr cts)
-> constrTerm2Expr (FunctionPattern qident cts)
->    = foldl (\e1 e2 -> Apply e1 e2) 
->            (Variable qident) 
->            (map constrTerm2Expr cts)
-> constrTerm2Expr _
->    = internalError "constrTerm2Expr: unexpected constructor term"
-
-> getConstrTermVars :: [Ident] -> ConstrTerm -> [Ident]
-> getConstrTermVars ids (VariablePattern ident)
->    | elem ident ids = ids
->    | otherwise      = ident:ids
-> getConstrTermVars ids (ConstructorPattern _ cts)
->    = foldl getConstrTermVars ids cts
-> getConstrTermVars ids (InfixPattern c1 qid c2)
->    = getConstrTermVars ids (ConstructorPattern qid [c1,c2])
-> getConstrTermVars ids (ParenPattern c)
->    = getConstrTermVars ids c
-> getConstrTermVars ids (TuplePattern _ cts)
->    = foldl getConstrTermVars ids cts
-> getConstrTermVars ids (ListPattern _ cts)
->    = foldl getConstrTermVars ids cts
-> getConstrTermVars ids (AsPattern _ c)
->    = getConstrTermVars ids c
-> getConstrTermVars ids (LazyPattern _ c)
->    = getConstrTermVars ids c
-> getConstrTermVars ids (FunctionPattern _ cts)
->    = foldl getConstrTermVars ids cts
-> getConstrTermVars ids (InfixFuncPattern c1 qid c2)
->    = getConstrTermVars ids (FunctionPattern qid [c1,c2])
-> getConstrTermVars ids _
->    = ids
-
-> genRecordFuncs :: ModuleIdent -> TCEnv -> Position -> QualIdent -> Type 
->	         -> [Ident] -> (Ident, Type) -> DesugarState [Decl]
-> genRecordFuncs m tcEnv p r rty ls (l,ty) =
->   case (qualLookupTC r tcEnv) of
->     [AliasType _ n (TypeRecord fs _)] ->
->       do let (selId, selFunc) = genSelectorFunc m p r ls l
->              (updId, updFunc) = genUpdateFunc m p r ls l
->	       selType = polyType (TypeArrow rty ty)
->	       updType = polyType (TypeArrow rty (TypeArrow ty rty))
->	   S.modify (bindFun m selId selType . bindFun m updId updType)
->	   return [selFunc,updFunc]
->     _ -> internalError "genRecordFuncs: wrong type"
-
-> genSelectorFunc :: ModuleIdent -> Position -> QualIdent -> [Ident] -> Ident
->	          -> (Ident, Decl)
-> genSelectorFunc m p r ls l =
->   let selId = recSelectorId r l
->       cpatt = ConstructorPattern r (map VariablePattern ls)
->	selLhs = FunLhs selId [cpatt]
->	selRhs = SimpleRhs p (Variable (qualify l)) []
->   in  (selId, FunctionDecl p selId [Equation p selLhs selRhs])
-
-> genUpdateFunc :: ModuleIdent -> Position -> QualIdent -> [Ident] -> Ident
->	        -> (Ident, Decl)
-> genUpdateFunc m p r ls l =
->   let updId = recUpdateId r l
->	ls' = replaceIdent l anonId ls
->	cpatt1 = ConstructorPattern r (map VariablePattern ls')
->       cpatt2 = VariablePattern l
->	cexpr = foldl Apply 
->	              (Constructor r)
->	              (map (Variable . qualify) ls) 
->	updLhs = FunLhs updId [cpatt1, cpatt2]
->	updRhs = SimpleRhs p cexpr []
->   in  (updId, FunctionDecl p updId [Equation p updLhs updRhs])
-
-> replaceIdent :: Ident -> Ident -> [Ident] -> [Ident]
-> replaceIdent _ _ [] = []
-> replaceIdent what with (id:ids)
->   | what == id = with:ids
->   | otherwise  = id:(replaceIdent what with ids)
-
-\end{verbatim}
-In general, a list comprehension of the form
-\texttt{[}$e$~\texttt{|}~$t$~\texttt{<-}~$l$\texttt{,}~\emph{qs}\texttt{]}
-is transformed into an expression \texttt{foldr}~$f$~\texttt{[]}~$l$ where $f$
-is a new function defined as
-\begin{quote}
-  \begin{tabbing}
-    $f$ $x$ \emph{xs} \texttt{=} \\
-    \quad \= \texttt{case} $x$ \texttt{of} \\
-          \> \quad \= $t$ \texttt{->} \texttt{[}$e$ \texttt{|} \emph{qs}\texttt{]} \texttt{++} \emph{xs} \\
-          \>       \> \texttt{\_} \texttt{->} \emph{xs}
-  \end{tabbing}
-\end{quote}
-Note that this translation evaluates the elements of $l$ rigidly,
-whereas the translation given in the Curry report is flexible.
-However, it does not seem very useful to have the comprehension
-generate instances of $t$ which do not contribute to the list.
-
-Actually, we generate slightly better code in a few special cases.
-When $t$ is a plain variable, the \texttt{case} expression degenerates
-into a let-binding and the auxiliary function thus becomes an alias
-for \texttt{(++)}. Instead of \texttt{foldr~(++)} we use the
-equivalent prelude function \texttt{concatMap}. In addition, if the
-remaining list comprehension in the body of the auxiliary function has
-no qualifiers -- i.e., if it is equivalent to \texttt{[$e$]} -- we
-avoid the construction of the singleton list by calling \texttt{(:)}
-instead of \texttt{(++)} and \texttt{map} in place of
-\texttt{concatMap}, respectively. -}
-\begin{verbatim}
-
-> desugarQual :: ModuleIdent -> TCEnv -> Position -> Statement -> Expression
->      -> DesugarState Expression
-> desugarQual m tcEnv p (StmtExpr pos b) e = 
->   desugarExpr m tcEnv p (IfThenElse pos b e (List [pos] []))
-> desugarQual m tcEnv p (StmtBind refBind t l) e
->   | isVarPattern t = desugarExpr m tcEnv p (qualExpr t e l)
->   | otherwise =
->       do
->         tyEnv <- S.get
->         v0 <- freshIdent m "_#var" (monoType (typeOf tyEnv t))
->         l0 <- freshIdent m "_#var" (monoType (typeOf tyEnv e))
->         let v  = addRefId refBind v0
->             l' = addRefId refBind l0
->         desugarExpr m tcEnv p (apply (prelFoldr refBind) 
->                                      [foldFunct v l' e,List [refBind] [],l])
->   where 
->     qualExpr v (ListCompr _ e []) l 
->       = apply (prelMap refBind) [Lambda refBind [v] e,l]
->     qualExpr v e l = apply (prelConcatMap refBind) [Lambda refBind [v] e,l]
-
->     foldFunct v l e =
->           Lambda refBind (map VariablePattern [v,l])
->             (Case refBind (mkVar v)
->                   [caseAlt {-refBind-} p t (append e (mkVar l)),
->                    caseAlt {-refBind-} p (VariablePattern v) (mkVar l)])
->
->     append (ListCompr _ e []) l = apply (Constructor $ addRef refBind $ qConsId) [e,l]
->     append e l = apply (prelAppend refBind) [e,l]
->
-> desugarQual m tcEnv p (StmtDecl ds) e = desugarExpr m tcEnv p (Let ds e)
-
-\end{verbatim}
-Generation of fresh names
-\begin{verbatim}
-
-> freshIdent :: ModuleIdent -> String -> TypeScheme -> DesugarState Ident
-> freshIdent m prefix ty =
->   do
->     x <- liftM (mkName prefix) (S.lift (S.modify succ >> S.get))
->     S.modify (bindFun m x ty)
->     return x
->   where mkName pre n = mkIdent (pre ++ show n)
-
-\end{verbatim}
-Prelude entities
-\begin{verbatim}
-
-> prelBind = prel ">>="
-> prelBind_ = prel ">>"
-> prelFlip = Variable $ preludeIdent "flip"
-> prelEnumFrom = Variable $ preludeIdent "enumFrom"
-> prelEnumFromTo = Variable $ preludeIdent "enumFromTo"
-> prelEnumFromThen = Variable $ preludeIdent "enumFromThen"
-> prelEnumFromThenTo = Variable $ preludeIdent "enumFromThenTo"
-> prelFailed = Variable $ preludeIdent "failed"
-> prelMap r = Variable $ addRef r $ preludeIdent "map"
-> prelFoldr = prel "foldr"
-> prelAppend = prel "++"
-> prelConcatMap = prel "concatMap"
-> prelNegate = Variable $ preludeIdent "negate"
-> prelNegateFloat = Variable $ preludeIdent "negateFloat"
-> prelCond = Variable $ preludeIdent "cond"
-> prelFuncPattEqu = Variable $ preludeIdent "=:<="
-> prelConstrConj = Variable $ preludeIdent "&"
-
-> prel s r = Variable (addRef r (preludeIdent s))
-
-> truePattern = ConstructorPattern qTrueId []
-> falsePattern = ConstructorPattern qFalseId []
-
-
-> preludeIdent :: String -> QualIdent
-> preludeIdent = qualifyWith preludeMIdent . mkIdent
-
-\end{verbatim}
-Auxiliary definitions
-\begin{verbatim}
-
-> isNewtypeConstr :: ValueEnv -> QualIdent -> Bool
-> isNewtypeConstr tyEnv c =
->   case qualLookupValue c tyEnv of
->     [DataConstructor _ _] -> False
->     [NewtypeConstructor _ _] -> True
->     _ -> internalError ("isNewtypeConstr " ++ show c) --internalError "isNewtypeConstr"
-
-> isVarPattern :: ConstrTerm -> Bool
-> isVarPattern (VariablePattern _) = True
-> isVarPattern (ParenPattern t) = isVarPattern t
-> isVarPattern (AsPattern _ t) = isVarPattern t
-> isVarPattern (LazyPattern _ _) = True
-> isVarPattern _ = False
-
-> funDecl :: Position -> Ident -> [ConstrTerm] -> Expression -> Decl
-> funDecl p f ts e =
->   FunctionDecl p f [Equation p (FunLhs f ts) (SimpleRhs p e [])]
-
-> patDecl :: Position -> ConstrTerm -> Expression -> Decl
-> patDecl p t e = PatternDecl p t (SimpleRhs p e [])
-
-> varDecl :: Position -> Ident -> Expression -> Decl
-> varDecl p = patDecl p . VariablePattern
-
-> addDecls :: [Decl] -> Rhs -> Rhs
-> addDecls ds (SimpleRhs p e ds') = SimpleRhs p e (ds ++ ds')
-> addDecls ds (GuardedRhs es ds') = GuardedRhs es (ds ++ ds')
-
-> caseAlt :: Position -> ConstrTerm -> Expression -> Alt
-> caseAlt p t e = Alt p t (SimpleRhs p e [])
-
-> apply :: Expression -> [Expression] -> Expression
-> apply = foldl Apply
-
-> mkVar :: Ident -> Expression
-> mkVar = Variable . qualify
-
-
-\end{verbatim}
diff --git a/src/Env/Class.hs b/src/Env/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Env/Class.hs
@@ -0,0 +1,75 @@
+{- |
+    Module      :  $Header$
+    Description :  Environment of classes
+    Copyright   :  (c) 2016 - 2020 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    The compiler maintains information about all type classes in an
+    environment that maps type classes to a sorted list of their direct
+    superclasses and all their associated class methods with an additional
+    flag stating whether an default implementation has been provided or not.
+    For both the type class identifier and the list of super classes original
+    names are used. Thus, the use of a flat environment is sufficient.
+-}
+
+module Env.Class
+  ( ClassEnv, initClassEnv
+  , ClassInfo, bindClassInfo, mergeClassInfo, lookupClassInfo
+  , superClasses, allSuperClasses, classMethods, hasDefaultImpl
+  ) where
+
+import           Data.List       (nub, sort)
+import qualified Data.Map as Map (Map, empty, insertWith, lookup)
+
+import Curry.Base.Ident
+
+import Base.Messages (internalError)
+
+type ClassInfo = ([QualIdent], [(Ident, Bool)])
+
+type ClassEnv = Map.Map QualIdent ClassInfo
+
+initClassEnv :: ClassEnv
+initClassEnv = Map.empty
+
+bindClassInfo :: QualIdent -> ClassInfo -> ClassEnv -> ClassEnv
+bindClassInfo cls (sclss, ms) =
+  Map.insertWith mergeClassInfo cls (sort sclss, ms)
+
+-- We have to be careful when merging two class infos into one as hidden class
+-- declarations in interfaces provide no information about class methods. If
+-- one of the method lists is empty, we simply take the other one. This way,
+-- we do overwrite the list of class methods that may have been entered into
+-- the class environment before with an empty list.
+
+mergeClassInfo :: ClassInfo -> ClassInfo -> ClassInfo
+mergeClassInfo (sclss1, ms1) (_, ms2) = (sclss1, if null ms1 then ms2 else ms1)
+
+lookupClassInfo :: QualIdent -> ClassEnv -> Maybe ClassInfo
+lookupClassInfo = Map.lookup
+
+superClasses :: QualIdent -> ClassEnv -> [QualIdent]
+superClasses cls clsEnv = case lookupClassInfo cls clsEnv of
+  Just (sclss, _) -> sclss
+  _ -> internalError $ "Env.Classes.superClasses: " ++ show cls
+
+allSuperClasses :: QualIdent -> ClassEnv -> [QualIdent]
+allSuperClasses cls clsEnv = nub $ classes cls
+  where
+    classes cls' = cls' : concatMap classes (superClasses cls' clsEnv)
+
+classMethods :: QualIdent -> ClassEnv -> [Ident]
+classMethods cls clsEnv = case lookupClassInfo cls clsEnv of
+  Just (_, ms) -> map fst ms
+  _ -> internalError $ "Env.Classes.classMethods: " ++ show cls
+
+hasDefaultImpl :: QualIdent -> Ident -> ClassEnv -> Bool
+hasDefaultImpl cls f clsEnv = case lookupClassInfo cls clsEnv of
+  Just (_, ms) -> case lookup f ms of
+    Just dflt -> dflt
+    Nothing -> internalError $ "Env.Classes.hasDefaultImpl: " ++ show f
+  _ -> internalError $ "Env.Classes.hasDefaultImpl: " ++ show cls
diff --git a/src/Env/Instance.hs b/src/Env/Instance.hs
new file mode 100644
--- /dev/null
+++ b/src/Env/Instance.hs
@@ -0,0 +1,54 @@
+{- |
+    Module      :  $Header$
+    Description :  Environment of instances
+    Copyright   :  (c) 2016 - 2020 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    The compiler maintains information about defined instances in an
+    environment that maps pairs of type classes and type constructors
+    to the name of the module where the instance is declared, the context
+    as given in the instance declaration, and a list of the class methods
+    implemented in the specific instance along with their arity. A flat
+    environment is sufficient because instances are visible globally and
+    cannot be hidden. Instances are recorded only with the original names
+    of the type class and type constructor involved. The context also uses
+    original names and is already minimized.
+-}
+
+module Env.Instance
+  ( InstIdent, ppInstIdent, InstInfo
+  , InstEnv, initInstEnv, bindInstInfo, removeInstInfo, lookupInstInfo
+  ) where
+
+import qualified Data.Map as Map (Map, empty, insert, delete, lookup)
+
+import Curry.Base.Ident
+import Curry.Base.Pretty
+import Curry.Syntax.Pretty
+
+import Base.Types
+
+type InstIdent = (QualIdent, QualIdent)
+
+ppInstIdent :: InstIdent -> Doc
+ppInstIdent (qcls, qtc) = ppQIdent qcls <+> ppQIdent qtc
+
+type InstInfo = (ModuleIdent, PredSet, [(Ident, Int)])
+
+type InstEnv = Map.Map InstIdent InstInfo
+
+initInstEnv :: InstEnv
+initInstEnv = Map.empty
+
+bindInstInfo :: InstIdent -> InstInfo -> InstEnv -> InstEnv
+bindInstInfo = Map.insert
+
+removeInstInfo  :: InstIdent -> InstEnv -> InstEnv
+removeInstInfo = Map.delete
+
+lookupInstInfo :: InstIdent -> InstEnv -> Maybe InstInfo
+lookupInstInfo = Map.lookup
diff --git a/src/Env/Interface.hs b/src/Env/Interface.hs
new file mode 100644
--- /dev/null
+++ b/src/Env/Interface.hs
@@ -0,0 +1,31 @@
+{- |
+    Module      :  $Header$
+    Description :  Environment of imported interfaces
+    Copyright   :  (c) 2002 - 2004 Wolfgang Lux
+                       2011 - 2013 Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module provides an environment for imported interfaces.
+-}
+module Env.Interface where
+
+import qualified Data.Map as Map (Map, empty, lookup)
+
+import Curry.Base.Ident (ModuleIdent)
+import Curry.Syntax     (Interface)
+
+-- |Environment which maps the 'ModuleIdent' of an imported module
+-- to the corresponding 'Interface'.
+type InterfaceEnv = Map.Map ModuleIdent Interface
+
+-- |Initial 'InterfaceEnv'.
+initInterfaceEnv :: InterfaceEnv
+initInterfaceEnv = Map.empty
+
+-- |Lookup the 'Interface' for an imported module.
+lookupInterface :: ModuleIdent -> InterfaceEnv -> Maybe Interface
+lookupInterface = Map.lookup
diff --git a/src/Env/ModuleAlias.hs b/src/Env/ModuleAlias.hs
new file mode 100644
--- /dev/null
+++ b/src/Env/ModuleAlias.hs
@@ -0,0 +1,41 @@
+{- |
+    Module      :  $Header$
+    Description :  Environment of module aliases
+    Copyright   :  (c) 2002 - 2004, Wolfgang Lux
+                       2011 - 2013, Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module provides an environment for resolving module aliases.
+
+    For example, if module @FiniteMap@ is imported via
+
+    @import FiniteMap as FM@
+
+    then @FM@ is an alias for @FiniteMap@, and @FiniteMap@ is aliased by @FM@.
+-}
+module Env.ModuleAlias ( AliasEnv, initAliasEnv, importAliases ) where
+
+import qualified Data.Map   as Map (Map, empty, insert)
+import           Data.Maybe        (fromMaybe)
+
+import Curry.Base.Ident (ModuleIdent)
+import Curry.Syntax     (ImportDecl (..))
+
+-- |Mapping from the original name of an imported module to its alias.
+type AliasEnv = Map.Map ModuleIdent ModuleIdent
+
+-- |Initial alias environment
+initAliasEnv :: AliasEnv
+initAliasEnv = Map.empty
+
+-- |Create an alias environment from a list of import declarations
+importAliases :: [ImportDecl] -> AliasEnv
+importAliases = foldr bindAlias initAliasEnv
+
+-- |Bind an alias for a module from a single import declaration
+bindAlias :: ImportDecl -> AliasEnv -> AliasEnv
+bindAlias (ImportDecl _ mid _ alias _) = Map.insert mid $ fromMaybe mid alias
diff --git a/src/Env/OpPrec.hs b/src/Env/OpPrec.hs
new file mode 100644
--- /dev/null
+++ b/src/Env/OpPrec.hs
@@ -0,0 +1,111 @@
+{- |
+    Module      :  $Header$
+    Description :  Environment of operator precedences
+    Copyright   :  (c) 2002 - 2004, Wolfgang Lux
+                       2011 - 2013, Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    In order to parse infix expressions correctly, the compiler must know
+    the precedence and fixity of each operator. Operator precedences are
+    associated with entities and will be checked after renaming was
+    applied. Nevertheless, we need to save precedences for ambiguous names
+    in order to handle them correctly while computing the exported
+    interface of a module.
+
+    If no fixity is assigned to an operator, it will be given the default
+    precedence 9 and assumed to be a left-associative operator.
+
+    /Note:/ this modified version uses Haskell type 'Integer'
+    for representing the precedence. This change had to be done due to the
+    introduction of unlimited integer constants in the parser / lexer.
+-}
+module Env.OpPrec
+  ( OpPrec (..), defaultP, defaultAssoc, defaultPrecedence, mkPrec
+  , OpPrecEnv,  PrecInfo (..), bindP, lookupP, qualLookupP, initOpPrecEnv
+  ) where
+
+import Curry.Base.Ident
+import Curry.Base.Pretty (Pretty(..))
+import Curry.Syntax      (Infix (..))
+
+import Base.TopEnv
+
+import Data.Maybe        (fromMaybe)
+
+import Text.PrettyPrint
+
+-- |Operator precedence.
+data OpPrec = OpPrec Infix Precedence deriving Eq
+
+type Precedence = Integer
+
+-- TODO: Change to real show instance and provide Pretty instance
+-- if used anywhere.
+instance Show OpPrec where
+  showsPrec _ (OpPrec fix p) = showString (assoc fix) . shows p
+    where
+    assoc InfixL = "left "
+    assoc InfixR = "right "
+    assoc Infix  = "non-assoc "
+
+instance Pretty OpPrec where
+  pPrint (OpPrec fix p) = pPrint fix <+> integer p
+
+-- |Default operator declaration (associativity and precedence).
+defaultP :: OpPrec
+defaultP = OpPrec defaultAssoc defaultPrecedence
+
+-- |Default operator associativity.
+defaultAssoc :: Infix
+defaultAssoc = InfixL
+
+-- |Default operator precedence.
+defaultPrecedence :: Precedence
+defaultPrecedence = 9
+
+mkPrec :: Maybe Precedence -> Precedence
+mkPrec mprec = fromMaybe defaultPrecedence mprec
+
+-- |Precedence information for an identifier.
+data PrecInfo = PrecInfo QualIdent OpPrec deriving (Eq, Show)
+
+instance Entity PrecInfo where
+  origName (PrecInfo op _) = op
+
+instance Pretty PrecInfo where
+  pPrint (PrecInfo qid prec) = pPrint qid <+> pPrint prec
+
+-- |Environment mapping identifiers to their operator precedence.
+type OpPrecEnv = TopEnv PrecInfo
+
+-- |Initial 'OpPrecEnv'.
+initOpPrecEnv :: OpPrecEnv
+initOpPrecEnv = predefTopEnv qConsId consPrec emptyTopEnv
+
+-- |Precedence of list constructor.
+consPrec :: PrecInfo
+consPrec = PrecInfo qConsId (OpPrec InfixR 5)
+
+-- |Bind an operator precedence.
+bindP :: ModuleIdent -> Ident -> OpPrec -> OpPrecEnv -> OpPrecEnv
+bindP m op p
+  | hasGlobalScope op = bindTopEnv op info . qualBindTopEnv qop info
+  | otherwise         = bindTopEnv op info
+  where qop  = qualifyWith m op
+        info = PrecInfo qop p
+
+-- The lookup functions for the environment which maintains the operator
+-- precedences are simpler than for the type and value environments
+-- because they do not need to handle tuple constructors.
+
+-- |Lookup the operator precedence for an 'Ident'.
+lookupP :: Ident -> OpPrecEnv -> [PrecInfo]
+lookupP = lookupTopEnv
+
+-- |Lookup the operator precedence for an 'QualIdent'.
+qualLookupP :: QualIdent -> OpPrecEnv -> [PrecInfo]
+qualLookupP = qualLookupTopEnv
diff --git a/src/Env/Type.hs b/src/Env/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/Env/Type.hs
@@ -0,0 +1,70 @@
+{- |
+    Module      :  $Header$
+    Description :  Environment of type identifiers
+    Copyright   :  (c) 2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    At the type level, we distinguish data and renaming types, synonym
+    types, and type classes. Type variables are not recorded. Type
+    synonyms use a kind of their own so that the compiler can verify that
+    no type synonyms are used in type expressions in interface files.
+-}
+
+module Env.Type
+  ( TypeKind (..), toTypeKind,
+    TypeEnv, bindTypeKind, lookupTypeKind, qualLookupTypeKind
+  ) where
+
+import Curry.Base.Ident
+
+import Base.Messages (internalError)
+import Base.TopEnv
+import Base.Types (constrIdent, methodName)
+
+import Env.TypeConstructor (TypeInfo (..))
+
+import Data.List (union)
+
+data TypeKind
+  = Data  QualIdent [Ident]
+  | Alias QualIdent
+  | Class QualIdent [Ident]
+  deriving (Eq, Show)
+
+instance Entity TypeKind where
+  origName (Data  tc  _) = tc
+  origName (Alias tc   ) = tc
+  origName (Class cls _) = cls
+
+  merge (Data tc cs) (Data tc' cs')
+    | tc == tc' = Just $ Data tc $ cs `union` cs'
+  merge (Alias tc) (Alias tc')
+    | tc == tc' = Just $ Alias tc
+  merge (Class cls ms) (Class cls' ms')
+    | cls == cls' = Just $Class cls $ ms `union` ms'
+  merge _ _ = Nothing
+
+toTypeKind :: TypeInfo -> TypeKind
+toTypeKind (DataType     tc    _ cs) = Data tc (map constrIdent cs)
+toTypeKind (RenamingType tc    _ nc) = Data tc [constrIdent nc]
+toTypeKind (AliasType    tc  _ _  _) = Alias tc
+toTypeKind (TypeClass    cls   _ ms) = Class cls (map methodName ms)
+toTypeKind (TypeVar               _) =
+  internalError "Env.Type.toTypeKind: type variable"
+
+type TypeEnv = TopEnv TypeKind
+
+bindTypeKind :: ModuleIdent -> Ident -> TypeKind -> TypeEnv -> TypeEnv
+bindTypeKind m ident tk = bindTopEnv ident tk . qualBindTopEnv qident tk
+  where
+    qident = qualifyWith m ident
+
+lookupTypeKind :: Ident -> TypeEnv -> [TypeKind]
+lookupTypeKind = lookupTopEnv
+
+qualLookupTypeKind :: QualIdent -> TypeEnv -> [TypeKind]
+qualLookupTypeKind = qualLookupTopEnv
diff --git a/src/Env/TypeConstructor.hs b/src/Env/TypeConstructor.hs
new file mode 100644
--- /dev/null
+++ b/src/Env/TypeConstructor.hs
@@ -0,0 +1,221 @@
+{- |
+    Module      :  $Header$
+    Description :  Environment of type constructors
+    Copyright   :  (c) 2002 - 2004 Wolfgang Lux
+                       2011        Björn Peemöller
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    For all defined types the compiler must maintain kind information.
+    For algebraic data types and renaming types the compiler also records
+    all data constructors belonging to that type, for alias types the
+    type expression to be expanded is saved. Futhermore, recording the
+    arity is necessary for alias types because the right hand side, i.e.,
+    the type expression, can have arbitrary kind and therefore the type
+    alias' arity cannot be determined from its own kind. For instance,
+    the type alias type List = [] has the kind * -> *, but its arity is 0.
+    In order to manage the import and export of types, the names of the
+    original definitions are also recorded. On import two types are
+    considered equal if their original names match.
+
+    The information for a data constructor comprises the number of
+    existentially quantified type variables, the context and the list
+    of the argument types. Note that renaming type constructors have only
+    one type argument.
+
+    For type classes the all their methods are saved. Type classes are
+    recorded in the type constructor environment because type constructors
+    and type classes share a common name space.
+
+    For type variables only their kind is recorded in the environment.
+
+    Importing and exporting algebraic data types and renaming types is
+    complicated by the fact that the constructors of the type may be
+    (partially) hidden in the interface. This facilitates the definition
+    of abstract data types. An abstract type is always represented as a
+    data type without constructors in the interface regardless of whether
+    it is defined as a data type or as a renaming type. When only some
+    constructors of a data type are hidden, those constructors are
+    replaced by underscores in the interface. Furthermore, if the
+    right-most constructors of a data type are hidden, they are not
+    exported at all in order to make the interface more stable against
+    changes which are private to the module.
+-}
+{-# LANGUAGE CPP #-}
+module Env.TypeConstructor
+  ( TypeInfo (..), tcKind, clsKind, varKind, clsMethods
+  , TCEnv, initTCEnv, bindTypeInfo, rebindTypeInfo
+  , lookupTypeInfo, qualLookupTypeInfo, qualLookupTypeInfoUnique
+  , getOrigName, reverseLookupByOrigName
+  ) where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+import Curry.Base.Ident
+import Curry.Base.Pretty (Pretty(..), blankLine)
+
+import Base.Kinds
+import Base.Messages (internalError)
+import Base.PrettyKinds ()
+import Base.PrettyTypes ()
+import Base.TopEnv
+import Base.Types
+import Base.Utils         ((++!))
+
+import Text.PrettyPrint
+
+data TypeInfo
+  = DataType     QualIdent Kind [DataConstr]
+  | RenamingType QualIdent Kind DataConstr
+  | AliasType    QualIdent Kind Int Type
+  | TypeClass    QualIdent Kind [ClassMethod]
+  | TypeVar      Kind
+    deriving Show
+
+instance Entity TypeInfo where
+  origName (DataType     tc    _ _) = tc
+  origName (RenamingType tc    _ _) = tc
+  origName (AliasType    tc  _ _ _) = tc
+  origName (TypeClass    cls   _ _) = cls
+  origName (TypeVar              _) =
+    internalError "Env.TypeConstructor.origName: type variable"
+
+  merge (DataType tc k cs) (DataType tc' k' cs')
+    | tc == tc' && k == k' && (null cs || null cs' || cs == cs') =
+    Just $ DataType tc k $ if null cs then cs' else cs
+  merge (DataType tc k _) (RenamingType tc' k' nc)
+    | tc == tc' && k == k' = Just (RenamingType tc k nc)
+  merge l@(RenamingType tc k _) (DataType tc' k' _)
+    | tc == tc' && k == k' = Just l
+  merge l@(RenamingType tc k _) (RenamingType tc' k' _)
+    | tc == tc' && k == k' = Just l
+  merge l@(AliasType tc k _ _) (AliasType tc' k' _ _)
+    | tc == tc' && k == k' = Just l
+  merge (TypeClass cls k ms) (TypeClass cls' k' ms')
+    | cls == cls' && k == k' && (null ms || null ms' || ms == ms') =
+    Just $ TypeClass cls k $ if null ms then ms' else ms
+  merge _ _ = Nothing
+
+instance Pretty TypeInfo where
+  pPrint (DataType qid k cs)    =      text "data" <+> pPrint qid
+                                   <>  text "/" <> pPrint k
+                                   <+> equals
+                                   <+> hsep (punctuate (text "|") (map pPrint cs))
+  pPrint (RenamingType qid k c) =      text "newtype" <+> pPrint qid
+                                   <>  text "/" <> pPrint k
+                                   <+> equals <+> pPrint c
+  pPrint (AliasType qid k ar ty)=      text "type" <+> pPrint qid
+                                   <>  text "/" <> pPrint k <> text "/" <> int ar
+                                   <+> equals <+> pPrint ty
+  pPrint (TypeClass qid k ms)   =      text "class" <+> pPrint qid
+                                   <>  text "/" <> pPrint k
+                                   <+> equals
+                                   <+> vcat (blankLine : map pPrint ms)
+  pPrint (TypeVar _)            =
+    internalError $ "Env.TypeConstructor.Pretty.TypeInfo.pPrint: type variable"
+
+tcKind :: ModuleIdent -> QualIdent -> TCEnv -> Kind
+tcKind m tc tcEnv = case qualLookupTypeInfo tc tcEnv of
+  [DataType     _ k   _] -> k
+  [RenamingType _ k   _] -> k
+  [AliasType    _ k _ _] -> k
+  _ -> case qualLookupTypeInfo (qualQualify m tc) tcEnv of
+    [DataType     _ k   _] -> k
+    [RenamingType _ k   _] -> k
+    [AliasType    _ k _ _] -> k
+    _ -> internalError $
+           "Env.TypeConstructor.tcKind: no type constructor: " ++ show tc
+
+clsKind :: ModuleIdent -> QualIdent -> TCEnv -> Kind
+clsKind m cls tcEnv = case qualLookupTypeInfo cls tcEnv of
+  [TypeClass _ k _] -> k
+  _ -> case qualLookupTypeInfo (qualQualify m cls) tcEnv of
+    [TypeClass _ k _] -> k
+    _ -> internalError $
+           "Env.TypeConstructor.clsKind: no type class: " ++ show cls
+
+varKind :: Ident -> TCEnv -> Kind
+varKind tv tcEnv
+  | isAnonId tv = KindStar
+  | otherwise = case lookupTypeInfo tv tcEnv of
+    [TypeVar k] -> k
+    _ -> internalError "Env.TypeConstructor.varKind: no type variable"
+
+clsMethods :: ModuleIdent -> QualIdent -> TCEnv -> [Ident]
+clsMethods m cls tcEnv = case qualLookupTypeInfo cls tcEnv of
+  [TypeClass _ _ ms] -> map methodName ms
+  _ -> case qualLookupTypeInfo (qualQualify m cls) tcEnv of
+    [TypeClass _ _ ms] -> map methodName ms
+    _ -> internalError $ "Env.TypeConstructor.clsMethods: " ++ show cls
+
+-- Types can only be defined on the top-level; no nested environments are
+-- needed for them. Tuple types must be handled as a special case because
+-- there is an infinite number of potential tuple types making it
+-- impossible to insert them into the environment in advance.
+
+type TCEnv = TopEnv TypeInfo
+
+initTCEnv :: TCEnv
+initTCEnv = foldr (uncurry $ predefTC . unapplyType False) emptyTopEnv predefTypes
+  where
+    predefTC (TypeConstructor tc, tys) =
+      predefTopEnv tc . DataType tc (simpleKind $ length tys)
+    predefTC _                        =
+      internalError "Env.TypeConstructor.initTCEnv.predefTC: no type constructor"
+
+bindTypeInfo :: ModuleIdent -> Ident -> TypeInfo -> TCEnv -> TCEnv
+bindTypeInfo m ident ti = bindTopEnv ident ti . qualBindTopEnv qident ti
+  where
+    qident = qualifyWith m ident
+
+rebindTypeInfo :: ModuleIdent -> Ident -> TypeInfo -> TCEnv -> TCEnv
+rebindTypeInfo m ident ti = rebindTopEnv ident ti . qualRebindTopEnv qident ti
+  where
+    qident = qualifyWith m ident
+
+lookupTypeInfo :: Ident -> TCEnv -> [TypeInfo]
+lookupTypeInfo ident tcEnv = lookupTopEnv ident tcEnv ++! lookupTupleTC ident
+
+qualLookupTypeInfo :: QualIdent -> TCEnv -> [TypeInfo]
+qualLookupTypeInfo ident tcEnv =
+  qualLookupTopEnv ident tcEnv ++! lookupTupleTC (unqualify ident)
+
+qualLookupTypeInfoUnique :: ModuleIdent -> QualIdent -> TCEnv -> [TypeInfo]
+qualLookupTypeInfoUnique m qident tcEnv =
+  case qualLookupTypeInfo qident tcEnv of
+    []   -> []
+    [ti] -> [ti]
+    tis  -> case qualLookupTypeInfo (qualQualify m qident) tcEnv of
+      []  -> tis
+      [ti] -> [ti]
+      tis' -> tis'
+
+getOrigName :: ModuleIdent -> QualIdent -> TCEnv -> QualIdent
+getOrigName m tc tcEnv = case qualLookupTypeInfo tc tcEnv of
+  [y] -> origName y
+  _ -> case qualLookupTypeInfo (qualQualify m tc) tcEnv of
+    [y] -> origName y
+    _ -> internalError $ "Env.TypeConstructor.getOrigName: " ++ show tc
+
+reverseLookupByOrigName :: QualIdent -> TCEnv -> [QualIdent]
+reverseLookupByOrigName on
+  | isQTupleId on = const [on]
+  | otherwise     = map fst . filter ((== on) . origName . snd) . allBindings
+
+lookupTupleTC :: Ident -> [TypeInfo]
+lookupTupleTC tc | isTupleId tc = [tupleTCs !! (tupleArity tc - 2)]
+                 | otherwise    = []
+
+tupleTCs :: [TypeInfo]
+tupleTCs = map typeInfo tupleData
+  where
+    typeInfo dc@(DataConstr _ tys) =
+      let n = length tys in DataType (qTupleId n) (simpleKind n) [dc]
+    typeInfo (RecordConstr  _ _ _) =
+      internalError "Env.TypeConstructor.tupleTCs: record constructor"
diff --git a/src/Env/Value.hs b/src/Env/Value.hs
new file mode 100644
--- /dev/null
+++ b/src/Env/Value.hs
@@ -0,0 +1,207 @@
+{- |
+    Module      :  $Header$
+    Description :  Environment for functions, constructors and labels
+    Copyright   :  (c) 2001 - 2004 Wolfgang Lux
+                       2011        Björn Peemöller
+                       2015        Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    In order to test the type correctness of a module, the compiler needs
+    to determine the type of every data constructor, function and
+    variable in the module.
+    For the purpose of type checking there is no
+    need for distinguishing between variables and functions. For all objects
+    their original names and their types are saved. In addition, the compiler
+    also saves the (optional) list of field labels for data and newtype
+    constructors. Data constructors and functions also contain arity
+    information. On import two values are considered equal if their original
+    names match.
+-}
+{-# LANGUAGE CPP #-}
+module Env.Value
+  ( ValueEnv, ValueInfo (..)
+  , bindGlobalInfo, bindFun, qualBindFun, rebindFun, unbindFun
+  , lookupValue, qualLookupValue, qualLookupValueUnique
+  , initDCEnv
+  , ValueType (..), bindLocalVars, bindLocalVar
+  ) where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+import Curry.Base.Ident
+import Curry.Base.Pretty (Pretty(..))
+
+import Base.Messages (internalError)
+import Base.PrettyTypes ()
+import Base.TopEnv
+import Base.Types
+import Base.Utils ((++!))
+
+import Text.PrettyPrint
+
+data ValueInfo
+  -- |Data constructor with original name, arity, list of record labels and type
+  = DataConstructor    QualIdent                   Int [Ident] TypeScheme
+  -- |Newtype constructor with original name, record label and type
+  -- (arity is always 1)
+  | NewtypeConstructor QualIdent                       Ident   TypeScheme
+  -- |Value with original name, class method name, arity and type
+  | Value              QualIdent (Maybe QualIdent) Int         TypeScheme
+  -- |Record label with original name, list of constructors for which label
+  -- is a valid field and type (arity is always 1)
+  | Label              QualIdent [QualIdent]                   TypeScheme
+    deriving Show
+
+instance Entity ValueInfo where
+  origName (DataConstructor    orgName _ _ _) = orgName
+  origName (NewtypeConstructor orgName   _ _) = orgName
+  origName (Value              orgName _ _ _) = orgName
+  origName (Label              orgName   _ _) = orgName
+
+  merge (DataConstructor c1 ar1 ls1 ty1) (DataConstructor c2 ar2 ls2 ty2)
+    | c1 == c2 && ar1 == ar2 && ty1 == ty2 = do
+      ls' <- sequence (zipWith mergeLabel ls1 ls2)
+      Just (DataConstructor c1 ar1 ls' ty1)
+  merge (NewtypeConstructor c1 l1 ty1) (NewtypeConstructor c2 l2 ty2)
+    | c1 == c2 && ty1 == ty2 = do
+      l' <- mergeLabel l1 l2
+      Just (NewtypeConstructor c1 l' ty1)
+  merge (Value x1 ar1 cm1 ty1) (Value x2 ar2 cm2 ty2)
+    | x1 == x2 && ar1 == ar2 && cm1 == cm2 && ty1 == ty2 =
+      Just (Value x1 ar1 cm1 ty1)
+  merge (Label l1 cs1 ty1) (Label l2 cs2 ty2)
+    | l1 == l2 && cs1 == cs2 && ty1 == ty2 = Just (Label l1 cs1 ty1)
+  merge _ _ = Nothing
+
+instance Pretty ValueInfo where
+  pPrint (DataConstructor qid ar _ tySc) =     text "data" <+> pPrint qid
+                                           <>  text "/" <> int ar
+                                           <+> equals <+> pPrint tySc
+  pPrint (NewtypeConstructor qid _ tySc) =     text "newtype" <+> pPrint qid
+                                           <+> equals <+> pPrint tySc
+  pPrint (Value qid _ ar tySc)           =     pPrint qid
+                                           <>  text "/" <> int ar
+                                           <+> equals <+> pPrint tySc
+  pPrint (Label qid _ tySc)              =     text "label" <+> pPrint qid
+                                           <+> equals <+> pPrint tySc
+
+mergeLabel :: Ident -> Ident -> Maybe Ident
+mergeLabel l1 l2
+  | l1 == anonId = Just l2
+  | l2 == anonId = Just l1
+  | l1 == l2     = Just l1
+  | otherwise    = Nothing
+
+-- Even though value declarations may be nested, the compiler uses only
+-- flat environments for saving type information. This is possible
+-- because all identifiers are renamed by the compiler. Here we need
+-- special cases for handling tuple constructors.
+--
+-- Note: the function 'qualLookupValue' has been extended to
+-- allow the usage of the qualified list constructor (Prelude.:).
+
+type ValueEnv = TopEnv ValueInfo
+
+bindGlobalInfo :: (QualIdent -> a -> ValueInfo) -> ModuleIdent -> Ident -> a
+               -> ValueEnv -> ValueEnv
+bindGlobalInfo f m c ty = bindTopEnv c v . qualBindTopEnv qc v
+  where qc = qualifyWith m c
+        v  = f qc ty
+
+bindFun :: ModuleIdent -> Ident -> Maybe QualIdent -> Int -> TypeScheme
+        -> ValueEnv -> ValueEnv
+bindFun m f cm a ty
+  | hasGlobalScope f = bindTopEnv f v . qualBindTopEnv qf v
+  | otherwise        = bindTopEnv f v
+  where qf = qualifyWith m f
+        v  = Value qf cm a ty
+
+qualBindFun :: ModuleIdent -> Ident -> Maybe QualIdent -> Int -> TypeScheme
+            -> ValueEnv -> ValueEnv
+qualBindFun m f cm a ty = qualBindTopEnv qf $ Value qf cm a ty
+  where qf = qualifyWith m f
+
+rebindFun :: ModuleIdent -> Ident -> Maybe QualIdent -> Int -> TypeScheme
+          -> ValueEnv -> ValueEnv
+rebindFun m f cm a ty
+  | hasGlobalScope f = rebindTopEnv f v . qualRebindTopEnv qf v
+  | otherwise        = rebindTopEnv f v
+  where qf = qualifyWith m f
+        v  = Value qf cm a ty
+
+unbindFun :: Ident -> ValueEnv -> ValueEnv
+unbindFun = unbindTopEnv
+
+lookupValue :: Ident -> ValueEnv -> [ValueInfo]
+lookupValue x tyEnv = lookupTopEnv x tyEnv ++! lookupTuple x
+
+qualLookupValue :: QualIdent -> ValueEnv -> [ValueInfo]
+qualLookupValue x tyEnv = qualLookupTopEnv x tyEnv
+                      ++! lookupTuple (unqualify x)
+
+qualLookupValueUnique :: ModuleIdent -> QualIdent -> ValueEnv -> [ValueInfo]
+qualLookupValueUnique m x tyEnv = case qualLookupValue x tyEnv of
+  []  -> []
+  [v] -> [v]
+  vs  -> case qualLookupValue (qualQualify m x) tyEnv of
+    []  -> vs
+    [v] -> [v]
+    qvs -> qvs
+
+lookupTuple :: Ident -> [ValueInfo]
+lookupTuple c | isTupleId c = [tupleDCs !! (tupleArity c - 2)]
+              | otherwise   = []
+
+tupleDCs :: [ValueInfo]
+tupleDCs = map dataInfo tupleData
+  where dataInfo (DataConstr _ tys) =
+          let n = length tys
+          in  DataConstructor (qTupleId n) n (replicate n anonId) $
+                ForAll n $ predType $ foldr TypeArrow (tupleType tys) tys
+        dataInfo (RecordConstr _ _ _) =
+          internalError $ "Env.Value.tupleDCs: " ++ show tupleDCs
+
+-- Since all predefined types are free of existentially quantified type
+-- variables and have an empty predicate set, we can ignore both of them
+-- when entering the types into the value environment.
+
+initDCEnv :: ValueEnv
+initDCEnv = foldr predefDC emptyTopEnv
+  [ (c, length tys, constrType (polyType ty) tys)
+  | (ty, cs) <- predefTypes, DataConstr c tys <- cs ]
+  where predefDC (c, a, ty) = predefTopEnv c' (DataConstructor c' a ls ty)
+          where ls = replicate a anonId
+                c' = qualify c
+        constrType (ForAll n (PredType ps ty)) =
+          ForAll n . PredType ps . foldr TypeArrow ty
+
+-- The functions 'bindLocalVar' and 'bindLocalVars' add the type of one or
+-- many local variables or functions to the value environment. In contrast
+-- to global functions, we do not care about the name of the module containing
+-- the variable or function's definition.
+
+class ValueType t where
+  toValueType :: Type -> t
+  fromValueType :: t -> PredType
+
+instance ValueType Type where
+  toValueType = id
+  fromValueType = predType
+
+instance ValueType PredType where
+  toValueType = predType
+  fromValueType = id
+
+bindLocalVars :: ValueType t => [(Ident, Int, t)] -> ValueEnv -> ValueEnv
+bindLocalVars = flip $ foldr bindLocalVar
+
+bindLocalVar :: ValueType t => (Ident, Int, t) -> ValueEnv -> ValueEnv
+bindLocalVar (v, a, ty) =
+  bindTopEnv v $ Value (qualify v) Nothing a $ typeScheme $ fromValueType ty
diff --git a/src/Eval.lhs b/src/Eval.lhs
deleted file mode 100644
--- a/src/Eval.lhs
+++ /dev/null
@@ -1,96 +0,0 @@
-
-% $Id: Eval.lhs,v 1.12 2004/02/08 15:35:12 wlux Exp $
-%
-% Copyright (c) 2001-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-\nwfilename{Eval.lhs}
-\section{Collecting Evaluation Annotations}
-The module \texttt{Eval} computes the evaluation annotation
-environment. There is no need to check the annotations because this
-happens already while checking the definitions of the module.
-\begin{verbatim}
-
-> module Eval(evalEnv) where
-
-> import qualified Data.Map as Map
-
-> import Curry.Syntax
-> import Base
-
-
-\end{verbatim}
-The function \texttt{evalEnv} collects all evaluation annotations of
-the module by traversing the syntax tree.
-\begin{verbatim}
-
-> evalEnv :: [Decl] -> EvalEnv
-> evalEnv = foldr collectAnnotsDecl Map.empty
-
-> collectAnnotsDecl :: Decl -> EvalEnv -> EvalEnv
-> collectAnnotsDecl (EvalAnnot _ fs ev) env = foldr (flip Map.insert ev) env fs
-> collectAnnotsDecl (FunctionDecl _ _ eqs) env = foldr collectAnnotsEqn env eqs
-> collectAnnotsDecl (PatternDecl _ _ rhs) env = collectAnnotsRhs rhs env
-> collectAnnotsDecl _ env = env
-
-> collectAnnotsEqn :: Equation -> EvalEnv -> EvalEnv
-> collectAnnotsEqn (Equation _ _ rhs) env = collectAnnotsRhs rhs env
-
-> collectAnnotsRhs :: Rhs -> EvalEnv -> EvalEnv
-> collectAnnotsRhs (SimpleRhs _ e ds) env =
->   collectAnnotsExpr e (foldr collectAnnotsDecl env ds)
-> collectAnnotsRhs (GuardedRhs es ds) env =
->   foldr collectAnnotsCondExpr (foldr collectAnnotsDecl env ds) es
-
-> collectAnnotsCondExpr :: CondExpr -> EvalEnv -> EvalEnv
-> collectAnnotsCondExpr (CondExpr _ g e) env =
->   collectAnnotsExpr g (collectAnnotsExpr e env)
-
-> collectAnnotsExpr :: Expression -> EvalEnv -> EvalEnv
-> collectAnnotsExpr (Literal _) env = env
-> collectAnnotsExpr (Variable _) env = env
-> collectAnnotsExpr (Constructor _) env = env
-> collectAnnotsExpr (Paren e) env = collectAnnotsExpr e env
-> collectAnnotsExpr (Typed e _) env = collectAnnotsExpr e env
-> collectAnnotsExpr (Tuple _ es) env = foldr collectAnnotsExpr env es
-> collectAnnotsExpr (List _ es) env = foldr collectAnnotsExpr env es
-> collectAnnotsExpr (ListCompr _ e qs) env =
->   collectAnnotsExpr e (foldr collectAnnotsStmt env qs)
-> collectAnnotsExpr (EnumFrom e) env = collectAnnotsExpr e env
-> collectAnnotsExpr (EnumFromThen e1 e2) env =
->   collectAnnotsExpr e1 (collectAnnotsExpr e2 env)
-> collectAnnotsExpr (EnumFromTo e1 e2) env =
->   collectAnnotsExpr e1 (collectAnnotsExpr e2 env)
-> collectAnnotsExpr (EnumFromThenTo e1 e2 e3) env =
->   collectAnnotsExpr e1 (collectAnnotsExpr e2 (collectAnnotsExpr e3 env))
-> collectAnnotsExpr (UnaryMinus _ e) env = collectAnnotsExpr e env
-> collectAnnotsExpr (Apply e1 e2) env =
->   collectAnnotsExpr e1 (collectAnnotsExpr e2 env)
-> collectAnnotsExpr (InfixApply e1 _ e2) env =
->   collectAnnotsExpr e1 (collectAnnotsExpr e2 env)
-> collectAnnotsExpr (LeftSection e _) env = collectAnnotsExpr e env
-> collectAnnotsExpr (RightSection _ e) env = collectAnnotsExpr e env
-> collectAnnotsExpr (Lambda _ _ e) env = collectAnnotsExpr e env
-> collectAnnotsExpr (Let ds e) env =
->   foldr collectAnnotsDecl (collectAnnotsExpr e env) ds
-> collectAnnotsExpr (Do sts e) env =
->   foldr collectAnnotsStmt (collectAnnotsExpr e env) sts
-> collectAnnotsExpr (IfThenElse _ e1 e2 e3) env =
->   collectAnnotsExpr e1 (collectAnnotsExpr e2 (collectAnnotsExpr e3 env))
-> collectAnnotsExpr (Case _ e alts) env =
->   collectAnnotsExpr e (foldr collectAnnotsAlt env alts)
-> collectAnnotsExpr (RecordConstr fs) env =
->   foldr collectAnnotsExpr env (map fieldTerm fs)
-> collectAnnotsExpr (RecordSelection e _) env = collectAnnotsExpr e env
-> collectAnnotsExpr (RecordUpdate fs e) env =
->   foldr collectAnnotsExpr (collectAnnotsExpr e env) (map fieldTerm fs)
-
-> collectAnnotsStmt :: Statement -> EvalEnv -> EvalEnv
-> collectAnnotsStmt (StmtExpr _ e) env = collectAnnotsExpr e env
-> collectAnnotsStmt (StmtDecl ds) env = foldr collectAnnotsDecl env ds
-> collectAnnotsStmt (StmtBind _ _ e) env = collectAnnotsExpr e env
-
-> collectAnnotsAlt :: Alt -> EvalEnv -> EvalEnv
-> collectAnnotsAlt (Alt _ _ rhs) env = collectAnnotsRhs rhs env
-
-\end{verbatim}
diff --git a/src/Exports.hs b/src/Exports.hs
new file mode 100644
--- /dev/null
+++ b/src/Exports.hs
@@ -0,0 +1,425 @@
+{- |
+    Module      :  $Header$
+    Description :  Computation of export interface
+    Copyright   :  (c) 2000 - 2004 Wolfgang Lux
+                       2005        Martin Engelke
+                       2011 - 2016 Björn Peemöller
+                       2015        Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module provides the computation of the exported interface of a
+    compiled module. The function 'exportInterface' uses the expanded export
+    specifications and the corresponding environments in order to compute
+    the interface of the module.
+-}
+module Exports (exportInterface) where
+
+import           Data.List         (nub)
+import qualified Data.Map   as Map (foldrWithKey, toList)
+import           Data.Maybe        (mapMaybe)
+import qualified Data.Set   as Set ( Set, empty, insert, deleteMin, fromList
+                                   , member, toList )
+
+import Curry.Base.Position
+import Curry.Base.SpanInfo
+import Curry.Base.Ident
+import Curry.Syntax
+
+import Base.CurryKinds (fromKind')
+import Base.CurryTypes (fromQualType, fromQualPredType)
+import Base.Messages
+import Base.Types
+
+import Env.Class
+import Env.OpPrec          (OpPrecEnv, PrecInfo (..), OpPrec (..), qualLookupP)
+import Env.Instance
+import Env.TypeConstructor ( TCEnv, TypeInfo (..), tcKind, clsKind
+                           , qualLookupTypeInfo )
+import Env.Value           (ValueEnv, ValueInfo (..), qualLookupValue)
+
+import CompilerEnv
+
+import Base.Kinds
+
+-- ---------------------------------------------------------------------------
+-- Computation of the interface
+-- ---------------------------------------------------------------------------
+
+-- After checking that the interface is not ambiguous, the compiler
+-- generates the interface's declarations from the list of exported
+-- functions and values. In order to make the interface more stable
+-- against private changes in the module, we remove the hidden data
+-- constructors of a data type in the interface when they occur
+-- right-most in the declaration. In addition, newtypes whose constructor
+-- is not exported are transformed into (abstract) data types.
+--
+-- If a type is imported from another module, its name is qualified with
+-- the name of the module where it is defined. The same applies to an
+-- exported function.
+
+exportInterface :: CompilerEnv -> Module a -> Interface
+exportInterface env (Module _ _ _ m (Just (Exporting _ es)) _ _) =
+  exportInterface' m es (opPrecEnv env) (tyConsEnv env) (valueEnv env)
+    (classEnv env) (instEnv env)
+exportInterface _   (Module _ _ _ _ Nothing                 _ _) =
+  internalError "Exports.exportInterface: no export specification"
+
+exportInterface' :: ModuleIdent -> [Export] -> OpPrecEnv -> TCEnv -> ValueEnv
+                 -> ClassEnv -> InstEnv -> Interface
+exportInterface' m es pEnv tcEnv vEnv clsEnv inEnv = Interface m imports decls'
+  where
+  tvs     = filter (`notElem` tcs) identSupply
+  tcs     = mapMaybe (localIdent m) $ definedTypes decls'
+  imports = map (IImportDecl NoPos) $ usedModules decls'
+  precs   = foldr (infixDecl m pEnv) [] es
+  types   = foldr (typeDecl m tcEnv clsEnv tvs) [] es
+  values  = foldr (valueDecl m vEnv tvs) [] es
+  insts   = Map.foldrWithKey (instDecl m tcEnv tvs) [] inEnv
+  decls   = precs ++ types ++ values ++ insts
+  decls'  = closeInterface m tcEnv clsEnv inEnv tvs Set.empty decls
+
+infixDecl :: ModuleIdent -> OpPrecEnv -> Export -> [IDecl] -> [IDecl]
+infixDecl m pEnv (Export             _ f) ds = iInfixDecl m pEnv f ds
+infixDecl m pEnv (ExportTypeWith _ tc cs) ds =
+  foldr (iInfixDecl m pEnv . qualifyLike tc) ds cs
+infixDecl _ _ _ _ = internalError "Exports.infixDecl: no pattern match"
+
+iInfixDecl :: ModuleIdent -> OpPrecEnv -> QualIdent -> [IDecl] -> [IDecl]
+iInfixDecl m pEnv op ds = case qualLookupP op pEnv of
+  []                        -> ds
+  [PrecInfo _ (OpPrec f p)] -> IInfixDecl NoPos f p (qualUnqualify m op) : ds
+  _                         -> internalError "Exports.infixDecl"
+
+-- Data types and renaming types whose constructors and field labels are
+-- not exported are exported as abstract types, i.e., their constructors
+-- do not appear in the interface. If only some constructors or field
+-- labels of a type are not exported all constructors appear in the
+-- interface, but a pragma marks the constructors and field labels which
+-- are not exported as hidden to prevent their use in user code.
+
+typeDecl :: ModuleIdent -> TCEnv -> ClassEnv -> [Ident] -> Export -> [IDecl]
+         -> [IDecl]
+typeDecl _ _     _      _   (Export             _ _) ds = ds
+typeDecl m tcEnv clsEnv tvs (ExportTypeWith _ tc xs) ds =
+  case qualLookupTypeInfo tc tcEnv of
+    [DataType tc' k cs]
+      | null xs   -> iTypeDecl IDataDecl m tvs tc' k []  [] : ds
+      | otherwise -> iTypeDecl IDataDecl m tvs tc' k cs' hs : ds
+      where hs    = filter (`notElem` xs) (csIds ++ ls)
+            cs'   = map (constrDecl m n tvs) cs
+            ls    = nub (concatMap recordLabels cs')
+            csIds = map constrIdent cs
+            n = kindArity k
+    [RenamingType tc' k c]
+      | null xs   -> iTypeDecl IDataDecl    m tvs tc' k [] [] : ds
+      | otherwise -> iTypeDecl INewtypeDecl m tvs tc' k nc hs : ds
+      where hs  = filter (`notElem` xs) (cId : ls)
+            nc  = newConstrDecl m tvs c
+            ls  = nrecordLabels nc
+            cId = constrIdent c
+    [AliasType tc' k n ty] -> ITypeDecl NoPos tc'' k' tvs' ty' : ds
+      where tc'' = qualUnqualify m tc'
+            k'   = fromKind' k n
+            tvs' = take n tvs
+            ty'  = fromQualType m tvs' ty
+    [TypeClass qcls k ms] -> IClassDecl NoPos cx qcls' k' tv ms' hs : ds
+      where qcls' = qualUnqualify m qcls
+            cx    = [ Constraint NoSpanInfo (qualUnqualify m scls)
+                        (VariableType NoSpanInfo tv)
+                    | scls <- superClasses qcls clsEnv ]
+            k'    = fromKind' k 0
+            tv    = head tvs
+            ms'   = map (methodDecl m tvs) ms
+            hs    = filter (`notElem` xs) (map methodName ms)
+    _ -> internalError "Exports.typeDecl"
+typeDecl _ _ _ _ _ _ = internalError "Exports.typeDecl: no pattern match"
+
+iTypeDecl
+  :: (Position -> QualIdent -> Maybe KindExpr -> [Ident] -> a -> [Ident] -> IDecl)
+  -> ModuleIdent -> [Ident] -> QualIdent -> Kind -> a -> [Ident] -> IDecl
+iTypeDecl f m tvs tc k x hs = f NoPos (qualUnqualify m tc) k' (take n tvs) x hs
+  where n  = kindArity k
+        k' = fromKind' k n
+
+constrDecl :: ModuleIdent -> Int -> [Ident] -> DataConstr -> ConstrDecl
+constrDecl m _ tvs (DataConstr c [ty1, ty2])
+  | isInfixOp c = ConOpDecl NoSpanInfo ty1' c ty2'
+  where [ty1', ty2'] = map (fromQualType m tvs) [ty1, ty2]
+constrDecl m _ tvs (DataConstr c tys) =
+  ConstrDecl NoSpanInfo c tys'
+  where tys' = map (fromQualType m tvs) tys
+constrDecl m _ tvs (RecordConstr c ls tys) =
+  RecordDecl NoSpanInfo c fs
+  where
+    tys' = map (fromQualType m tvs) tys
+    fs   = zipWith (FieldDecl NoSpanInfo . return) ls tys'
+
+newConstrDecl :: ModuleIdent -> [Ident] -> DataConstr -> NewConstrDecl
+newConstrDecl m tvs (DataConstr c tys)
+  = NewConstrDecl NoSpanInfo c (fromQualType m tvs (head tys))
+newConstrDecl m tvs (RecordConstr c ls tys)
+  = NewRecordDecl NoSpanInfo c (head ls, fromQualType m tvs (head tys))
+
+-- When exporting a class method, we have to remove the implicit class context.
+-- Due to the sorting of the predicate set, this is fortunatly very easy. The
+-- implicit class context is always the minimum element as the class variable
+-- is assigned the index 0 and no other constraints on it are allowed.
+
+methodDecl :: ModuleIdent -> [Ident] -> ClassMethod -> IMethodDecl
+methodDecl m tvs (ClassMethod f a (PredType ps ty)) = IMethodDecl NoPos f a $
+  fromQualPredType m tvs $ PredType (Set.deleteMin ps) ty
+
+valueDecl :: ModuleIdent -> ValueEnv -> [Ident] -> Export -> [IDecl] -> [IDecl]
+valueDecl m vEnv tvs (Export     _ f) ds = case qualLookupValue f vEnv of
+  [Value _ cm a (ForAll _ pty)] ->
+    IFunctionDecl NoPos (qualUnqualify m f)
+      (fmap (const (head tvs)) cm) a (fromQualPredType m tvs pty) : ds
+  [Label _ _ _ ] -> ds -- Record labels are collected somewhere else.
+  _ -> internalError $ "Exports.valueDecl: " ++ show f
+valueDecl _ _ _ (ExportTypeWith _ _ _) ds = ds
+valueDecl _ _ _ _ _ = internalError "Exports.valueDecl: no pattern match"
+
+instDecl :: ModuleIdent -> TCEnv -> [Ident] -> InstIdent -> InstInfo -> [IDecl]
+         -> [IDecl]
+instDecl m tcEnv tvs ident@(cls, tc) info@(m', _, _) ds
+  | qidModule cls /= Just m' && qidModule tc /= Just m' =
+    iInstDecl m tcEnv tvs ident info : ds
+  | otherwise = ds
+
+iInstDecl :: ModuleIdent -> TCEnv -> [Ident] -> InstIdent -> InstInfo -> IDecl
+iInstDecl m tcEnv tvs (cls, tc) (m', ps, is) =
+  IInstanceDecl NoPos cx (qualUnqualify m cls) ty is mm
+  where pty = PredType ps $ applyType (TypeConstructor tc) $
+                map TypeVariable [0 .. n-1]
+        QualTypeExpr _ cx ty = fromQualPredType m tvs pty
+        n = kindArity (tcKind m tc tcEnv) - kindArity (clsKind m cls tcEnv)
+        mm = if m == m' then Nothing else Just m'
+
+-- The compiler determines the list of imported modules from the set of
+-- module qualifiers that are used in the interface. Careful readers
+-- probably will have noticed that the functions above carefully strip
+-- the module prefix from all entities that are defined in the current
+-- module. Note that the list of modules returned from
+-- 'usedModules' is not necessarily a subset of the modules that
+-- were imported into the current module. This will happen when an
+-- imported module re-exports entities from another module. E.g., given
+-- the three modules
+--
+-- @
+-- module A where { data A = A; }
+-- module B(A(..)) where { import A; }
+-- module C where { import B; x = A; }
+-- @
+--
+-- the interface for module @C@ will import module @A@ but not module @B@.
+
+usedModules :: [IDecl] -> [ModuleIdent]
+usedModules ds = nub' (modules ds [])
+  where nub' = Set.toList . Set.fromList
+
+class HasModule a where
+  modules :: a -> [ModuleIdent] -> [ModuleIdent]
+
+instance HasModule a => HasModule (Maybe a) where
+  modules = maybe id modules
+
+instance HasModule a => HasModule [a] where
+  modules xs ms = foldr modules ms xs
+
+instance HasModule IDecl where
+  modules (IInfixDecl            _ _ _ op) = modules op
+  modules (HidingDataDecl        _ tc _ _) = modules tc
+  modules (IDataDecl        _ tc _ _ cs _) = modules tc . modules cs
+  modules (INewtypeDecl     _ tc _ _ nc _) = modules tc . modules nc
+  modules (ITypeDecl          _ tc _ _ ty) = modules tc . modules ty
+  modules (IFunctionDecl      _ f _ _ qty) = modules f . modules qty
+  modules (HidingClassDecl   _ cx cls _ _) = modules cx . modules cls
+  modules (IClassDecl   _ cx cls _ _ ms _) =
+    modules cx . modules cls . modules ms
+  modules (IInstanceDecl _ cx cls ty _ mm) =
+    modules cx . modules cls . modules ty . modules mm
+
+instance HasModule ConstrDecl where
+  modules (ConstrDecl    _ _ tys) = modules tys
+  modules (ConOpDecl _ ty1 _ ty2) = modules ty1 . modules ty2
+  modules (RecordDecl     _ _ fs) = modules fs
+
+instance HasModule FieldDecl where
+  modules (FieldDecl _ _ ty) = modules ty
+
+instance HasModule NewConstrDecl where
+  modules (NewConstrDecl _ _      ty) = modules ty
+  modules (NewRecordDecl _ _ (_, ty)) = modules ty
+
+instance HasModule IMethodDecl where
+  modules (IMethodDecl _ _ _ qty) = modules qty
+
+instance HasModule Constraint where
+  modules (Constraint _ cls ty) = modules cls . modules ty
+
+instance HasModule TypeExpr where
+  modules (ConstructorType _ tc) = modules tc
+  modules (ApplyType  _ ty1 ty2) = modules ty1 . modules ty2
+  modules (VariableType     _ _) = id
+  modules (TupleType      _ tys) = modules tys
+  modules (ListType        _ ty) = modules ty
+  modules (ArrowType  _ ty1 ty2) = modules ty1 . modules ty2
+  modules (ParenType       _ ty) = modules ty
+  modules (ForallType    _ _ ty) = modules ty
+
+instance HasModule QualTypeExpr where
+  modules (QualTypeExpr _ cx ty) = modules cx . modules ty
+
+instance HasModule QualIdent where
+  modules = modules . qidModule
+
+instance HasModule ModuleIdent where
+  modules = (:)
+
+-- After the interface declarations have been computed, the compiler
+-- eventually must add hidden (data) type and class declarations to the
+-- interface for all those types and classs which were used in the interface
+-- but not exported from the current module, so that these type constructors
+-- can always be distinguished from type variables. Besides hidden type and
+-- class declarations, the compiler also adds instance declarations to the
+-- interface. Since class and instance declarations added to an interface can
+-- require the inclusion of further classes by their respective contexts,
+-- closing an interface is implemented as a fix-point computation which
+-- starts from the initial interface.
+
+data IInfo = IOther | IType QualIdent | IClass QualIdent | IInst InstIdent
+  deriving (Eq, Ord)
+
+iInfo :: IDecl -> IInfo
+iInfo (IInfixDecl           _ _ _ _) = IOther
+iInfo (HidingDataDecl      _ tc _ _) = IType tc
+iInfo (IDataDecl       _ tc _ _ _ _) = IType tc
+iInfo (INewtypeDecl    _ tc _ _ _ _) = IType tc
+iInfo (ITypeDecl          _ _ _ _ _) = IOther
+iInfo (HidingClassDecl  _ _ cls _ _) = IClass cls
+iInfo (IClassDecl   _ _ cls _ _ _ _) = IClass cls
+iInfo (IInstanceDecl _ _ cls ty _ _) = IInst (cls, typeConstr ty)
+iInfo (IFunctionDecl      _ _ _ _ _) = IOther
+
+closeInterface :: ModuleIdent -> TCEnv -> ClassEnv -> InstEnv -> [Ident]
+               -> Set.Set IInfo -> [IDecl] -> [IDecl]
+closeInterface _ _ _ _ _ _ [] = []
+closeInterface m tcEnv clsEnv inEnv tvs is (d:ds)
+  | i == IOther       =
+    d : closeInterface m tcEnv clsEnv inEnv tvs is (ds ++ ds')
+  | i `Set.member` is = closeInterface m tcEnv clsEnv inEnv tvs is ds
+  | otherwise         =
+    d : closeInterface m tcEnv clsEnv inEnv tvs (Set.insert i is) (ds ++ ds')
+  where i   = iInfo d
+        ds' = hiddenTypes m tcEnv clsEnv tvs d ++
+                instances m tcEnv inEnv tvs is i
+
+hiddenTypes :: ModuleIdent -> TCEnv -> ClassEnv -> [Ident] -> IDecl -> [IDecl]
+hiddenTypes m tcEnv clsEnv tvs d =
+  map hiddenTypeDecl $ filter (not . isPrimTypeId) (usedTypes d [])
+  where hiddenTypeDecl tc = case qualLookupTypeInfo (qualQualify m tc) tcEnv of
+          [DataType       _ k _] -> hidingDataDecl k
+          [RenamingType   _ k _] -> hidingDataDecl k
+          [TypeClass    cls k _] -> hidingClassDecl k $ superClasses cls clsEnv
+          _                      ->
+            internalError $ "Exports.hiddenTypeDecl: " ++ show tc
+          where hidingDataDecl k =
+                  let n = kindArity k
+                      k' = fromKind' k n
+                  in  HidingDataDecl NoPos tc k' $ take n tvs
+                hidingClassDecl k sclss =
+                  let cx = [ Constraint NoSpanInfo (qualUnqualify m scls)
+                               (VariableType NoSpanInfo tv)
+                           | scls <- sclss ]
+                      tv = head tvs
+                      k' = fromKind' k 0
+                  in  HidingClassDecl NoPos cx tc k' tv
+
+instances :: ModuleIdent -> TCEnv -> InstEnv -> [Ident] -> Set.Set IInfo
+          -> IInfo -> [IDecl]
+instances _ _ _ _ _ IOther = []
+instances m tcEnv inEnv tvs is (IType tc) =
+  [ iInstDecl m tcEnv tvs ident info
+  | (ident@(cls, tc'), info@(m', _, _)) <- Map.toList inEnv,
+    qualQualify m tc == tc',
+    if qidModule cls == Just m' then Set.member (IClass (qualUnqualify m cls)) is
+                                else qidModule tc' == Just m' ]
+instances m tcEnv inEnv tvs is (IClass cls) =
+  [ iInstDecl m tcEnv tvs ident info
+  | (ident@(cls', tc), info@(m', _, _)) <- Map.toList inEnv,
+    qualQualify m cls == cls',
+    qidModule cls' == Just m',
+    m /= m' || isPrimTypeId tc
+            || qidModule tc /= Just m
+            || Set.member (IType (qualUnqualify m tc)) is ]
+instances _ _ _ _ _ (IInst _) = []
+
+definedTypes :: [IDecl] -> [QualIdent]
+definedTypes ds = foldr definedType [] ds
+  where
+  definedType :: IDecl -> [QualIdent] -> [QualIdent]
+  definedType (HidingDataDecl     _ tc _ _) tcs = tc : tcs
+  definedType (IDataDecl      _ tc _ _ _ _) tcs = tc : tcs
+  definedType (INewtypeDecl   _ tc _ _ _ _) tcs = tc : tcs
+  definedType (ITypeDecl      _ tc _ _ _  ) tcs = tc : tcs
+  definedType (HidingClassDecl _ _ cls _ _) tcs = cls : tcs
+  definedType (IClassDecl  _ _ cls _ _ _ _) tcs = cls : tcs
+  definedType _                             tcs = tcs
+
+class HasType a where
+  usedTypes :: a -> [QualIdent] -> [QualIdent]
+
+instance HasType a => HasType (Maybe a) where
+  usedTypes = maybe id usedTypes
+
+instance HasType a => HasType [a] where
+  usedTypes xs tcs = foldr usedTypes tcs xs
+
+instance HasType IDecl where
+  usedTypes (IInfixDecl            _ _ _ _) = id
+  usedTypes (HidingDataDecl        _ _ _ _) = id
+  usedTypes (IDataDecl        _ _ _ _ cs _) = usedTypes cs
+  usedTypes (INewtypeDecl     _ _ _ _ nc _) = usedTypes nc
+  usedTypes (ITypeDecl          _ _ _ _ ty) = usedTypes ty
+  usedTypes (IFunctionDecl     _ _ _ _ qty) = usedTypes qty
+  usedTypes (HidingClassDecl    _ cx _ _ _) = usedTypes cx
+  usedTypes (IClassDecl    _ cx _ _ _ ms _) = usedTypes cx . usedTypes ms
+  usedTypes (IInstanceDecl _ cx cls ty _ _) =
+    usedTypes cx . (cls :) . usedTypes ty
+
+instance HasType ConstrDecl where
+  usedTypes (ConstrDecl    _ _ tys) = usedTypes tys
+  usedTypes (ConOpDecl _ ty1 _ ty2) =
+    usedTypes ty1 . usedTypes ty2
+  usedTypes (RecordDecl     _ _ fs) = usedTypes fs
+
+instance HasType FieldDecl where
+  usedTypes (FieldDecl _ _ ty) = usedTypes ty
+
+instance HasType NewConstrDecl where
+  usedTypes (NewConstrDecl      _ _ ty) = usedTypes ty
+  usedTypes (NewRecordDecl _ _ (_, ty)) = usedTypes ty
+
+instance HasType IMethodDecl where
+  usedTypes (IMethodDecl _ _ _ qty) = usedTypes qty
+
+instance HasType Constraint where
+  usedTypes (Constraint _ cls ty) = (cls :) . usedTypes ty
+
+instance HasType TypeExpr where
+  usedTypes (ConstructorType _ tc) = (tc :)
+  usedTypes (ApplyType _ ty1 ty2) = usedTypes ty1 . usedTypes ty2
+  usedTypes (VariableType     _ _) = id
+  usedTypes (TupleType      _ tys) = usedTypes tys
+  usedTypes (ListType        _ ty) = usedTypes ty
+  usedTypes (ArrowType  _ ty1 ty2) = usedTypes ty1 . usedTypes ty2
+  usedTypes (ParenType       _ ty) = usedTypes ty
+  usedTypes (ForallType    _ _ ty) = usedTypes ty
+
+instance HasType QualTypeExpr where
+  usedTypes (QualTypeExpr _ cx ty) = usedTypes cx . usedTypes ty
diff --git a/src/Exports.lhs b/src/Exports.lhs
deleted file mode 100644
--- a/src/Exports.lhs
+++ /dev/null
@@ -1,463 +0,0 @@
-
-% $Id: Exports.lhs,v 1.32 2004/02/13 19:23:57 wlux Exp $
-%
-% Copyright (c) 2000-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{Exports.lhs}
-\section{Creating Interfaces}
-This section describes how the exported interface of a compiled module
-is computed.
-\begin{verbatim}
-
-> module Exports(expandInterface,exportInterface) where
-
-> import Data.List
-> import Data.Maybe
-> import qualified Data.Set as Set
-> import qualified Data.Map as Map
-
-> import Curry.Syntax
-> import Types
-> import Curry.Base.Position
-> import Curry.Base.Ident
-> import Base
-> import TopEnv
-
-\end{verbatim}
-The interface of a module is computed in two steps. The function
-\texttt{expandInterface} checks the export specifications of the
-module and expands them into a list containing all exported types and
-functions, combining multiple exports for the same entity. The
-expanded export specifications refer to the original names of all
-entities. The function \texttt{exportInterface} uses the expanded
-specifications and the corresponding environments in order to compute
-to the interface of the module.
-\begin{verbatim}
-
-> expandInterface :: Module -> TCEnv -> ValueEnv -> Module
-> expandInterface (Module m es ds) tcEnv tyEnv =
->     --error (show es')
->   case findDouble [unqualify tc | ExportTypeWith tc _ <- es'] of
->     Nothing ->
->       case findDouble ([c | ExportTypeWith _ cs <- es', c <- cs] ++
->                    [unqualify f | Export f <- es']) of
->         Nothing -> Module m (Just (Exporting NoPos es')) ds
->         Just v -> errorAt' (ambiguousExportValue v)
->     Just tc -> errorAt' (ambiguousExportType tc) 
->   where ms = Set.fromList [fromMaybe m asM | ImportDecl _ m _ asM _ <- ds]
->         es' = joinExports $
->               maybe (expandLocalModule tcEnv tyEnv)
->                     (expandSpecs ms m tcEnv tyEnv)
->                     es
-
-\end{verbatim}
-While checking all export specifications, the compiler expands
-specifications of the form \verb|T(..)| into
-\texttt{T($C_1,\dots,C_n$)}, where $C_1,\dots,C_n$ are the data
-constructors or the record labels of type \texttt{T}, and replaces 
-an export specification
-\verb|module M| by specifications for all entities which are defined
-in module \texttt{M} and imported into the current module with their
-unqualified name. In order to distinguish exported type constructors
-from exported functions, the former are translated into the equivalent
-form \verb|T()|. Note that the export specification \texttt{x} may
-export a type constructor \texttt{x} \emph{and} a global function
-\texttt{x} at the same time.
-
-\em{Note:} This frontend allows redeclaration and export of imported
-identifiers.
-\begin{verbatim}
-
-> expandSpecs :: Set.Set ModuleIdent -> ModuleIdent -> TCEnv -> ValueEnv
->             -> ExportSpec -> [Export]
-> expandSpecs ms m tcEnv tyEnv (Exporting _ es) =
->   concat (map (expandExport ms m tcEnv tyEnv) es)
-
-> expandExport :: Set.Set ModuleIdent -> ModuleIdent -> TCEnv
->              -> ValueEnv -> Export -> [Export]
-> expandExport _ m tcEnv tyEnv (Export x) = expandThing m tcEnv tyEnv x
-> expandExport _ m tcEnv _ (ExportTypeWith tc cs) =
->   expandTypeWith m tcEnv tc cs
-> expandExport _ m tcEnv tyEnv (ExportTypeAll tc) = 
->   expandTypeAll m tyEnv tcEnv tc
-> expandExport ms m tcEnv tyEnv (ExportModule m')
->   | m == m' = (if m `Set.member` ms then expandModule tcEnv tyEnv m else [])
->               ++ expandLocalModule tcEnv tyEnv
->   | m' `Set.member` ms = expandModule tcEnv tyEnv m'
->   | otherwise = errorAt' (moduleNotImported m')
-
-> expandThing :: ModuleIdent -> TCEnv -> ValueEnv -> QualIdent
->                -> [Export]
-> expandThing m tcEnv tyEnv tc =
->   case qualLookupTC tc tcEnv of
->     [] -> expandThing' m tyEnv tc Nothing
->     [t] -> expandThing' m tyEnv tc (Just [ExportTypeWith (origName t) []])
->     _ -> errorAt' (ambiguousType tc)
-
-> expandThing' :: ModuleIdent -> ValueEnv -> QualIdent
->              -> Maybe [Export] -> [Export]
-> expandThing' m tyEnv f tcExport =
->   case (qualLookupValue f tyEnv) of
->     [] -> fromMaybe (errorAt' (undefinedEntity f)) tcExport
->     [Value f' _] -> Export f' : fromMaybe [] tcExport
->     [_] -> fromMaybe (errorAt' (exportDataConstr f)) tcExport
->     vs -> case (qualLookupValue (qualQualify m f) tyEnv) of
->             [] -> fromMaybe (errorAt' (undefinedEntity f)) tcExport
->             [Value f'' _] -> Export f'' : fromMaybe [] tcExport
->             [_] -> fromMaybe (errorAt' (exportDataConstr f)) tcExport
->             _   -> errorAt' (ambiguousName f)
-
-> expandTypeWith :: ModuleIdent -> TCEnv -> QualIdent -> [Ident] 
->	 -> [Export]
-> expandTypeWith m tcEnv tc cs =
->   case qualLookupTC tc tcEnv of
->     [] -> errorAt' (undefinedType tc)
->     [t]
->       | isDataType t -> [ExportTypeWith (origName t)
->                            (map (checkConstr (constrs t)) (nub cs))]
->       | isRecordType t -> [ExportTypeWith (origName t)
->                            (map (checkLabel (labels t)) (nub cs))]
->       | otherwise -> errorAt' (nonDataType tc)
->     _ -> errorAt' (ambiguousType tc)
->   where checkConstr cs c
->           | c `elem` cs = c
->           | otherwise = errorAt' (undefinedDataConstr tc c)
->         checkLabel ls l
->	    | l' `elem` ls = l'
->           | otherwise = errorAt' (undefinedLabel tc l)
->	   where l' = renameLabel l
-
-> expandTypeAll :: ModuleIdent -> ValueEnv -> TCEnv -> QualIdent 
->	-> [Export]
-> expandTypeAll m tyEnv tcEnv tc =
->   case qualLookupTC tc tcEnv of
->     [] -> errorAt' (undefinedType tc)
->     [t]
->       | isDataType t -> [exportType tyEnv t]
->       | isRecordType t -> exportRecord m t
->       | otherwise -> errorAt' (nonDataType tc)
->     _ -> errorAt' (ambiguousType tc)
-
-> expandLocalModule :: TCEnv -> ValueEnv -> [Export]
-> expandLocalModule tcEnv tyEnv =
->   [exportType tyEnv t | (_,t) <- localBindings tcEnv] ++
->   [Export f' | (f,Value f' _) <- localBindings tyEnv, f == unRenameIdent f]
-
-> expandModule :: TCEnv -> ValueEnv -> ModuleIdent -> [Export]
-> expandModule tcEnv tyEnv m =
->   [exportType tyEnv t | (_,t) <- moduleImports m tcEnv] ++
->   [Export f | (_,Value f _) <- moduleImports m tyEnv]
-
-> exportType :: ValueEnv -> TypeInfo -> Export
-> exportType tyEnv t 
->   | isRecordType t -- = ExportTypeWith (origName t) (labels t)
->     = let ls = labels t
->           r  = origName t
->       in  case (lookupValue (head ls) tyEnv) of
->             [Label _ r' _] -> if r == r' then ExportTypeWith r ls
->		                   else ExportTypeWith r []
->             _ -> internalError "exportType"
->   | otherwise = ExportTypeWith (origName t) (constrs t)
-
-> exportRecord :: ModuleIdent -> TypeInfo -> [Export]
-> exportRecord m t = [ExportTypeWith (origName t) (labels t)]
-
-\end{verbatim}
-The expanded list of exported entities may contain duplicates. These
-are removed by the function \texttt{joinExports}.
-\begin{verbatim}
-
-> joinExports :: [Export] -> [Export]
-> joinExports es =
->   [ExportTypeWith tc cs | (tc,cs) <- Map.toList (foldr joinType Map.empty es)] ++
->   [Export f | f <- Set.toList (foldr joinFun Set.empty es)]
-
-> joinType :: Export -> Map.Map QualIdent [Ident] -> Map.Map QualIdent [Ident]
-> joinType (Export _) tcs = tcs
-> joinType (ExportTypeWith tc cs) tcs =
->   Map.insertWith union tc cs tcs
-
-> joinFun :: Export -> Set.Set QualIdent -> Set.Set QualIdent
-> joinFun (Export f) fs = f `Set.insert` fs
-> joinFun (ExportTypeWith _ _) fs = fs
-
-\end{verbatim}
-After checking that the interface is not ambiguous, the compiler
-generates the interface's declarations from the list of exported
-functions and values. In order to make the interface more stable
-against private changes in the module, we remove the hidden data
-constructors of a data type in the interface when they occur
-right-most in the declaration. In addition, newtypes whose constructor
-is not exported are transformed into (abstract) data types.
-
-If a type is imported from another module, its name is qualified with
-the name of the module where it is defined. The same applies to an
-exported function.
-\begin{verbatim}
-
-> exportInterface :: Module -> PEnv -> TCEnv -> ValueEnv -> Interface
-> exportInterface (Module m (Just (Exporting _ es)) _) pEnv tcEnv tyEnv =
->   Interface m (imports ++ precs ++ hidden ++ ds)
->   where imports = map (IImportDecl NoPos) (usedModules ds)
->         precs = foldr (infixDecl m pEnv) [] es
->         hidden = map (hiddenTypeDecl m tcEnv) (hiddenTypes ds)
->         ds = foldr (typeDecl m tcEnv) (foldr (funDecl m tyEnv) [] es) es
-> exportInterface (Module _ Nothing _) _ _ _ = internalError "exportInterface"
-
-> infixDecl :: ModuleIdent -> PEnv -> Export -> [IDecl] -> [IDecl]
-> infixDecl m pEnv (Export f) ds = iInfixDecl m pEnv f ds
-> infixDecl m pEnv (ExportTypeWith tc cs) ds =
->   foldr (iInfixDecl m pEnv . qualifyLike (qualidMod tc)) ds cs
->   where qualifyLike = maybe qualify qualifyWith
-
-> iInfixDecl :: ModuleIdent -> PEnv -> QualIdent -> [IDecl] -> [IDecl]
-> iInfixDecl m pEnv op ds =
->   case qualLookupP op pEnv of
->     [] -> ds
->     [PrecInfo _ (OpPrec fix pr)] ->
->       IInfixDecl NoPos fix pr (qualUnqualify m op) : ds
->     _ -> internalError "infixDecl"
-
-> typeDecl :: ModuleIdent -> TCEnv -> Export -> [IDecl] -> [IDecl]
-> typeDecl _ _ (Export _) ds = ds
-> typeDecl m tcEnv (ExportTypeWith tc cs) ds =
->   case qualLookupTC tc tcEnv of
->     [DataType tc n cs'] ->
->       iTypeDecl IDataDecl m tc n
->          (constrDecls m (drop n nameSupply) cs cs') : ds
->     [RenamingType tc n (Data c n' ty)]
->       | c `elem` cs ->
->           iTypeDecl INewtypeDecl m tc n (NewConstrDecl NoPos tvs c ty') : ds
->       | otherwise -> iTypeDecl IDataDecl m tc n [] : ds
->       where tvs = take n' (drop n nameSupply)
->             ty' = fromQualType m ty
->     [AliasType tc n ty] ->
->       case ty of 
->	  TypeRecord fs _ ->
->           let ty' = TypeRecord (filter (\ (l,_) -> elem l cs) fs) Nothing
->           in  iTypeDecl ITypeDecl m tc n (fromQualType m ty') : ds
->         _ -> iTypeDecl ITypeDecl m tc n (fromQualType m ty) : ds
->     _ -> internalError "typeDecl"
-
-> iTypeDecl :: (Position -> QualIdent -> [Ident] -> a -> IDecl)
->            -> ModuleIdent -> QualIdent -> Int -> a -> IDecl
-> iTypeDecl f m tc n = f NoPos (qualUnqualify m tc) (take n nameSupply)
-
-> constrDecls :: ModuleIdent -> [Ident] -> [Ident] -> [Maybe (Data [Type])]
->             -> [Maybe ConstrDecl]
-> constrDecls m tvs cs = clean . map (>>= constrDecl m tvs)
->   where clean = reverse . dropWhile isNothing . reverse
->         constrDecl m tvs (Data c n tys)
->           | c `elem` cs =
->               Just (iConstrDecl (take n tvs) c (map (fromQualType m) tys))
->           | otherwise = Nothing
-
-> iConstrDecl :: [Ident] -> Ident -> [TypeExpr] -> ConstrDecl
-> iConstrDecl tvs op [ty1,ty2]
->   | isInfixOp op = ConOpDecl NoPos tvs ty1 op ty2
-> iConstrDecl tvs c tys = ConstrDecl NoPos tvs c tys
-
-> funDecl :: ModuleIdent -> ValueEnv -> Export -> [IDecl] -> [IDecl]
-> funDecl m tyEnv (Export f) ds =
->   case qualLookupValue f tyEnv of
->     [Value _ (ForAll _ ty)] ->
->       IFunctionDecl NoPos (qualUnqualify m f) (arrowArity ty) 
->		  (fromQualType m ty) : ds
->     _ -> internalError ("funDecl: " ++ show f)
-> funDecl _ _ (ExportTypeWith _ _) ds = ds
-
-
-\end{verbatim}
-The compiler determines the list of imported modules from the set of
-module qualifiers that are used in the interface. Careful readers
-probably will have noticed that the functions above carefully strip
-the module prefix from all entities that are defined in the current
-module. Note that the list of modules returned from
-\texttt{usedModules} is not necessarily a subset of the modules that
-were imported into the current module. This will happen when an
-imported module re-exports entities from another module. E.g., given
-the three modules
-\begin{verbatim}
-module A where { data A = A; }
-module B(A(..)) where { import A; }
-module C where { import B; x = A; }
-\end{verbatim}
-the interface for module \texttt{C} will import module \texttt{A} but
-not module \texttt{B}.
-\begin{verbatim}
-
-> usedModules :: [IDecl] -> [ModuleIdent]
-> usedModules ds = nub (catMaybes (map qualidMod (foldr identsDecl [] ds)))
->   where nub = Set.toList . Set.fromList
-
-> identsDecl :: IDecl -> [QualIdent] -> [QualIdent]
-> identsDecl (IDataDecl _ tc _ cs) xs =
->   tc : foldr identsConstrDecl xs (catMaybes cs)
-> identsDecl (INewtypeDecl _ tc _ nc) xs = tc : identsNewConstrDecl nc xs
-> identsDecl (ITypeDecl _ tc _ ty) xs = tc : identsType ty xs
-> identsDecl (IFunctionDecl _ f _ ty) xs = f : identsType ty xs
-
-> identsConstrDecl :: ConstrDecl -> [QualIdent] -> [QualIdent]
-> identsConstrDecl (ConstrDecl _ _ _ tys) xs = foldr identsType xs tys
-> identsConstrDecl (ConOpDecl _ _ ty1 _ ty2) xs =
->   identsType ty1 (identsType ty2 xs)
-
-> identsNewConstrDecl :: NewConstrDecl -> [QualIdent] -> [QualIdent]
-> identsNewConstrDecl (NewConstrDecl _ _ _ ty) xs = identsType ty xs
-
-> identsType :: TypeExpr -> [QualIdent] -> [QualIdent]
-> identsType (ConstructorType tc tys) xs = tc : foldr identsType xs tys
-> identsType (VariableType _) xs = xs
-> identsType (TupleType tys) xs = foldr identsType xs tys
-> identsType (ListType ty) xs = identsType ty xs
-> identsType (ArrowType ty1 ty2) xs = identsType ty1 (identsType ty2 xs)
-> identsType (RecordType fs rty) xs =
->   foldr identsType (maybe xs (\ty -> identsType ty xs) rty) (map snd fs)
-
-\end{verbatim}
-After the interface declarations have been computed, the compiler
-eventually must add hidden (data) type declarations to the interface
-for all those types which were used in the interface but not exported
-from the current module, so that these type constructors can always be
-distinguished from type variables.
-\begin{verbatim}
-
-> hiddenTypeDecl :: ModuleIdent -> TCEnv -> QualIdent -> IDecl
-> hiddenTypeDecl m tcEnv tc =
->   case qualLookupTC (qualQualify m tc) tcEnv of
->     [DataType _ n _] -> hidingDataDecl tc n
->     [RenamingType _ n _] -> hidingDataDecl tc n
->     _ ->  internalError "hiddenTypeDecl"
->   where hidingDataDecl tc n =
->           HidingDataDecl NoPos (unqualify tc) (take n nameSupply)
-
-> hiddenTypes :: [IDecl] -> [QualIdent]
-> hiddenTypes ds = [tc | tc <- Set.toList tcs, not (isQualified tc)]
->   where tcs = foldr Set.delete (Set.fromList (usedTypes ds))
->                     (definedTypes ds)
-
-> usedTypes :: [IDecl] -> [QualIdent]
-> usedTypes ds = foldr usedTypesDecl [] ds
-
-> usedTypesDecl :: IDecl -> [QualIdent] -> [QualIdent]
-> usedTypesDecl (IDataDecl _ _ _ cs) tcs =
->   foldr usedTypesConstrDecl tcs (catMaybes cs)
-> usedTypesDecl (INewtypeDecl _ _ _ nc) tcs = usedTypesNewConstrDecl nc tcs
-> usedTypesDecl (ITypeDecl _ _ _ ty) tcs = usedTypesType ty tcs
-> usedTypesDecl (IFunctionDecl _ _ _ ty) tcs = usedTypesType ty tcs
-
-> usedTypesConstrDecl :: ConstrDecl -> [QualIdent] -> [QualIdent]
-> usedTypesConstrDecl (ConstrDecl _ _ _ tys) tcs = foldr usedTypesType tcs tys
-> usedTypesConstrDecl (ConOpDecl _ _ ty1 _ ty2) tcs =
->   usedTypesType ty1 (usedTypesType ty2 tcs)
-
-> usedTypesNewConstrDecl :: NewConstrDecl -> [QualIdent] -> [QualIdent]
-> usedTypesNewConstrDecl (NewConstrDecl _ _ _ ty) tcs = usedTypesType ty tcs
-
-> usedTypesType :: TypeExpr -> [QualIdent] -> [QualIdent]
-> usedTypesType (ConstructorType tc tys) tcs = tc : foldr usedTypesType tcs tys
-> usedTypesType (VariableType _) tcs = tcs
-> usedTypesType (TupleType tys) tcs = foldr usedTypesType tcs tys
-> usedTypesType (ListType ty) tcs = usedTypesType ty tcs
-> usedTypesType (ArrowType ty1 ty2) tcs =
->   usedTypesType ty1 (usedTypesType ty2 tcs)
-> usedTypesType (RecordType fs rty) tcs =
->   foldr usedTypesType 
->         (maybe tcs (\ty -> usedTypesType ty tcs) rty) 
->         (map snd fs)
-
-> definedTypes :: [IDecl] -> [QualIdent]
-> definedTypes ds = foldr definedType [] ds
-
-> definedType :: IDecl -> [QualIdent] -> [QualIdent]
-> definedType (IDataDecl _ tc _ _) tcs = tc : tcs
-> definedType (INewtypeDecl _ tc _ _) tcs = tc : tcs
-> definedType (ITypeDecl _ tc _ _) tcs = tc : tcs
-> definedType (IFunctionDecl _ _ _ _)  tcs = tcs
-
-\end{verbatim}
-Auxiliary definitions
-\begin{verbatim}
-
-
-> isDataType :: TypeInfo -> Bool
-> isDataType (DataType _ _ _) = True
-> isDataType (RenamingType _ _ _) = True
-> isDataType (AliasType _ _ _) = False
-
-> isRecordType :: TypeInfo -> Bool
-> isRecordType (AliasType _ _ (TypeRecord _ _)) = True
-> isRecordType _ = False
-
-> constrs :: TypeInfo -> [Ident]
-> constrs (DataType _ _ cs) = [c | Just (Data c _ _) <- cs]
-> constrs (RenamingType _ _ (Data c _ _)) = [c]
-> constrs (AliasType _ _ _) = []
-
-> labels :: TypeInfo -> [Ident]
-> labels (AliasType _ _ (TypeRecord fs _)) = map fst fs
-> labels _ = []
-
-\end{verbatim}
-Error messages
-\begin{verbatim}
-
-> undefinedEntity :: QualIdent -> (Position,String)
-> undefinedEntity x =
->   (positionOfQualIdent x,
->    "Entity " ++ qualName x ++ " in export list is not defined")
-
-> undefinedType :: QualIdent -> (Position,String)
-> undefinedType tc = 
->   (positionOfQualIdent tc,
->    "Type " ++ qualName tc ++ " in export list is not defined")
-
-> moduleNotImported :: ModuleIdent -> (Position,String)
-> moduleNotImported m = 
->   (positionOfModuleIdent m,
->    "Module " ++ moduleName m ++ " not imported")
-
-> ambiguousExportType :: Ident -> (Position,String)
-> ambiguousExportType x = 
->   (positionOfIdent x,
->    "Ambiguous export of type " ++ name x)
-
-> ambiguousExportValue :: Ident -> (Position,String)
-> ambiguousExportValue x = 
->   (positionOfIdent x,
->    "Ambiguous export of " ++ name x)
-
-> ambiguousType :: QualIdent -> (Position,String)
-> ambiguousType tc = 
->   (positionOfQualIdent tc,
->    "Ambiguous type " ++ qualName tc)
-
-> ambiguousName :: QualIdent -> (Position,String)
-> ambiguousName x = 
->   (positionOfQualIdent x,
->    "Ambiguous name " ++ qualName x)
-
-> exportDataConstr :: QualIdent -> (Position,String)
-> exportDataConstr c = 
->   (positionOfQualIdent c,
->    "Data constructor " ++ qualName c ++ " in export list")
-
-> nonDataType :: QualIdent -> (Position,String)
-> nonDataType tc = 
->   (positionOfQualIdent tc,
->    qualName tc ++ " is not a data type")
-
-> undefinedDataConstr :: QualIdent -> Ident -> (Position,String)
-> undefinedDataConstr tc c =
->   (positionOfIdent c,    
->    name c ++ " is not a data constructor of type " ++ qualName tc)
-
-> undefinedLabel :: QualIdent -> Ident -> (Position,String)
-> undefinedLabel r l =
->   (positionOfIdent l,    
->    name l ++ " is not a label of the record " ++ qualName r)
-
-\end{verbatim}
diff --git a/src/Files/CymakePath.hs b/src/Files/CymakePath.hs
new file mode 100644
--- /dev/null
+++ b/src/Files/CymakePath.hs
@@ -0,0 +1,32 @@
+{- |
+    Module      :  $Header$
+    Description :  File pathes
+    Copyright   :  (c) 2011, Björn Peemöller (bjp@informatik.uni-kiel.de)
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module contains functions to obtain the version number and path
+    of the front end binary.
+-}
+module Files.CymakePath (getCymake, cymakeGreeting, cymakeVersion) where
+
+import Data.Version (showVersion)
+import System.FilePath ((</>))
+import Paths_curry_frontend
+
+-- | Show a greeting of the current front end
+cymakeGreeting :: String
+cymakeGreeting = "This is the Curry front end, version " ++ cymakeVersion
+
+-- | Retrieve the version number of cymake
+cymakeVersion :: String
+cymakeVersion = showVersion version
+
+-- | Retrieve the location of the front end executable
+getCymake :: IO String
+getCymake = do
+  cymakeDir <- getBinDir
+  return $ cymakeDir </> "curry-frontend"
diff --git a/src/GenAbstractCurry.hs b/src/GenAbstractCurry.hs
deleted file mode 100644
--- a/src/GenAbstractCurry.hs
+++ /dev/null
@@ -1,1041 +0,0 @@
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---
--- GenAbstractCurry - Generates an AbstractCurry program term
---                    (type 'CurryProg')
---
--- July 2005,
--- Martin Engelke (men@informatik.uni-kiel.de)
---
-module GenAbstractCurry (genTypedAbstract, 
-			 genUntypedAbstract) where
-
-import qualified Data.Map as Map
-import qualified Data.Set as Set
-import Data.Maybe
-import Data.List
-import Data.Char
-
-import Curry.Syntax
-import Curry.Syntax.Utils
-import Curry.AbstractCurry
-
-import Base
-import Types
-import Curry.Base.Ident
-import Curry.Base.Position
-import TopEnv
-
-
--------------------------------------------------------------------------------
-
--- Generates standard (type infered) AbstractCurry code from a CurrySyntax
--- module. The function needs the type environment 'tyEnv' to determin the
--- infered function types.
-genTypedAbstract :: ValueEnv -> TCEnv -> Module -> CurryProg
-genTypedAbstract tyEnv tcEnv mod
-   = genAbstract (genAbstractEnv TypedAcy tyEnv tcEnv mod) mod
-
-
--- Generates untyped AbstractCurry code from a CurrySyntax module. The type
--- signature takes place in every function type annotation, if it exists, 
--- otherwise the dummy type "Prelude.untyped" is used.
-genUntypedAbstract :: ValueEnv -> TCEnv -> Module -> CurryProg
-genUntypedAbstract tyEnv tcEnv mod
-   = genAbstract (genAbstractEnv UntypedAcy tyEnv tcEnv mod) mod
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--- Private...
-
--- Generates an AbstractCurry program term from the syntax tree
-genAbstract :: AbstractEnv -> Module -> CurryProg
-genAbstract env (Module mid exp decls)
-   = let partitions = foldl partitionDecl emptyPartitions decls
-         modname    = moduleName mid 
-	 (imps, _)  
-	     = mapfoldl genImportDecl env (reverse (importDecls partitions))
-	 (types, _) 
-	     = mapfoldl genTypeDecl env (reverse (typeDecls partitions))
-	 (_, funcs) 
-	     = Map.mapAccumWithKey (genFuncDecl False) 
-	                env 
-			(funcDecls partitions)
-	 (ops, _)   
-	     = mapfoldl genOpDecl env (reverse (opDecls partitions))
-     in  CurryProg modname imps types (Map.elems funcs) ops
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--- The following types and functions can be used to spread a list of
--- CurrySyntax declarations into four parts: a list of imports, a list of
--- type declarations (data types and type synonyms), a table of function
--- declarations and a list of fixity declarations.
-
-
--- Inserts a CurrySyntax top level declaration into a partition.
--- Note: declarations are collected in reverse order.
-partitionDecl :: Partitions -> Decl -> Partitions
-partitionDecl partitions (TypeSig pos ids typeexpr)
-   = partitionFuncDecls (\id -> TypeSig pos [id] typeexpr) partitions ids
-partitionDecl partitions (EvalAnnot pos ids annot)
-   = partitionFuncDecls (\id -> EvalAnnot pos [id] annot) partitions ids
-partitionDecl partitions (FunctionDecl pos id equs)
-   = partitionFuncDecls (const (FunctionDecl pos id equs)) partitions [id]
-partitionDecl partitions (ExternalDecl pos conv name id typeexpr)
-   = partitionFuncDecls (const (ExternalDecl pos conv name id typeexpr))
-                     partitions
-		     [id]
-partitionDecl partitions (FlatExternalDecl pos ids)
-   = partitionFuncDecls (\id -> FlatExternalDecl pos [id]) partitions ids
-partitionDecl partitions (InfixDecl pos fix prec idents)
-   = partitions {opDecls = map (\id -> (InfixDecl pos fix prec [id])) idents
-		           ++ opDecls partitions }
-partitionDecl partitions decl
-   = case decl of
-       ImportDecl _ _ _ _ _ 
-         -> partitions {importDecls = decl: importDecls partitions }
-       DataDecl _ _ _ _     
-         -> partitions {typeDecls = decl : typeDecls partitions }
-       TypeDecl _ _ _ _     
-         -> partitions {typeDecls = decl : typeDecls partitions }
-       _ -> partitions
-
-
---
-partitionFuncDecls :: (Ident -> Decl) -> Partitions -> [Ident] -> Partitions
-partitionFuncDecls genDecl partitions ids
-   = partitions {funcDecls = foldl partitionFuncDecl (funcDecls partitions) ids}
- where
-   partitionFuncDecl funcs' id
-      = Map.insert id (genDecl id : fromMaybe [] (Map.lookup id funcs')) funcs'
-
-
--- Data type for representing partitions of CurrySyntax declarations
--- (according to the definition of the AbstractCurry program
--- representation; type 'CurryProg').
--- Since a complete function declaration usually consist of more than one
--- declaration (e.g. rules, type signature etc.), it is necessary 
--- to collect them within an association list
-data Partitions = Partitions {importDecls :: [Decl],
-			      typeDecls   :: [Decl],
-			      funcDecls   :: Map.Map Ident [Decl],
-			      opDecls     :: [Decl]
-			     } deriving Show
-
--- Generates initial partitions.
-emptyPartitions = Partitions {importDecls = [],
-			      typeDecls   = [],
-			      funcDecls   = Map.empty,
-			      opDecls     = []
-			     } 
-
-
--------------------------------------------------------------------------------
--- The following functions convert CurrySyntax terms to AbstractCurry
--- terms.
-
---
-genImportDecl :: AbstractEnv -> Decl -> (String, AbstractEnv)
-genImportDecl env (ImportDecl _ mid _ _ _) = (moduleName mid, env)
-
-
---
-genTypeDecl :: AbstractEnv -> Decl -> (CTypeDecl, AbstractEnv)
-genTypeDecl env (DataDecl _ ident params cdecls)
-   = let (idxs, env1)    = mapfoldl genTVarIndex env params
-	 (cdecls', env2) = mapfoldl genConsDecl env1 cdecls
-     in  (CType (genQName True env2 (qualifyWith (moduleId env) ident))
-	        (genVisibility env2 ident)
-	        (zip idxs (map name params))
-	        cdecls',
-	  resetScope env2)
-genTypeDecl env (TypeDecl _ ident params typeexpr)
-   = let (idxs, env1)      = mapfoldl genTVarIndex env params
-	 (typeexpr', env2) = genTypeExpr env1 typeexpr
-     in  (CTypeSyn (genQName True env2 (qualifyWith (moduleId env) ident))
-	           (genVisibility env2 ident)
-	           (zip idxs (map name params))
-	           typeexpr',
-	  resetScope env2)
-genTypeDecl env (NewtypeDecl pos ident _ _)
-   = errorAt pos "'newtype' declarations are not supported in AbstractCurry"
-genTypeDecl env _
-   = internalError "unexpected declaration"
-
-
---
-genConsDecl :: AbstractEnv -> ConstrDecl -> (CConsDecl, AbstractEnv)
-genConsDecl env (ConstrDecl _ _ ident params)
-   = let (params', env') = mapfoldl genTypeExpr env params
-     in  (CCons (genQName False env' (qualifyWith (moduleId env) ident))
-	        (length params)
-	        (genVisibility env' ident)
-	        params',
-	  env')
-genConsDecl env (ConOpDecl pos ids ltype ident rtype)
-   = genConsDecl env (ConstrDecl pos ids ident [ltype, rtype])
-
-
---
-genTypeExpr :: AbstractEnv -> TypeExpr -> (CTypeExpr, AbstractEnv)
-genTypeExpr env (ConstructorType qident targs)
-   = let (targs', env') = mapfoldl genTypeExpr env targs
-     in  (CTCons (genQName True env' qident) targs', env')
-genTypeExpr env (VariableType ident)
-   | isJust midx = (CTVar (fromJust midx, name ident), env)
-   | otherwise   = (CTVar (idx, name ident), env')
- where
-   midx        = getTVarIndex env ident
-   (idx, env') = genTVarIndex env ident
-genTypeExpr env (TupleType targs)
-   | len > 1   = genTypeExpr env (ConstructorType (qTupleId len) targs)
-   | len == 0  = genTypeExpr env (ConstructorType qUnitId targs)
-   | len == 1  = genTypeExpr env (head targs)
- where len = length targs
-genTypeExpr env (ListType typeexpr)
-   = genTypeExpr env (ConstructorType qListId [typeexpr])
-genTypeExpr env (ArrowType texpr1 texpr2)
-   = let (texpr1', env1) = genTypeExpr env texpr1
-	 (texpr2', env2) = genTypeExpr env1 texpr2
-     in  (CFuncType texpr1' texpr2', env2)
-genTypeExpr env (RecordType fss mr)
-   = let fs = concatMap (\ (ls,typeexpr) -> map (\l -> (l,typeexpr)) ls) fss
-         (ls,ts) = unzip fs
-         (ts',env1) = mapfoldl genTypeExpr env ts
-         ls' = map name ls
-     in case mr of
-           Nothing
-             -> (CRecordType (zip ls' ts') Nothing, env1)
-           Just tvar@(VariableType _)
-             -> let (CTVar iname, env2) = genTypeExpr env1 tvar
-                in  (CRecordType (zip ls' ts') (Just iname), env2)
-           (Just r@(RecordType _ _))
-             -> let (CRecordType fields rbase, env2) = genTypeExpr env1 r
-		    fields' = foldr (uncurry insertEntry) 
-				    fields
-			            (zip ls' ts')
-		in  (CRecordType fields' rbase, env2)
-           _ -> internalError "illegal record base"
-
-
--- NOTE: every infix declaration must declare exactly one operator.
-genOpDecl :: AbstractEnv -> Decl -> (COpDecl, AbstractEnv)
-genOpDecl env (InfixDecl _ fix prec [ident])
-   = (COp (genQName False env (qualifyWith (moduleId env) ident))
-          (genFixity fix)
-          (fromInteger prec),
-      env)
-
-
---
-genFixity :: Infix -> CFixity
-genFixity InfixL = CInfixlOp
-genFixity InfixR = CInfixrOp
-genFixity Infix  = CInfixOp
-
-
--- Generate an AbstractCurry function declaration from a list of CurrySyntax
--- function declarations.
--- NOTES: 
---   - every declaration in 'decls' must declare exactly one function.
---   - since infered types are internally represented in flat style,
---     all type variables are renamed with generated symbols when
---     generating typed AbstractCurry.
-genFuncDecl :: Bool -> AbstractEnv -> Ident -> [Decl] -> (AbstractEnv, CFuncDecl)
-genFuncDecl isLocal env ident decls
-   | not (null decls)
-     = let name          = genQName False env (qualify ident)
-	   visibility    = genVisibility env ident
-           evalannot     = maybe CFlex 
-	                         (\ (EvalAnnot _ _ ea) -> genEvalAnnot ea)
-				 (find isEvalAnnot decls)
-           (mtype, env1) = maybe (Nothing, env) 
-                                 (\ (t, env') -> (Just t, env'))
-				 (genFuncType env decls)
-	   (rules, env2) = maybe ([], env1)
-			         (\ (FunctionDecl _ _ equs)
-				  -> mapfoldl genRule env1 equs)
-				 (find isFunctionDecl decls)
-           mexternal     = fmap genExternal (find isExternal decls)
-	   arity         = compArity mtype rules
-           typeexpr      = fromMaybe (CTCons ("Prelude","untyped") []) mtype
-           rule          = compRule evalannot rules mexternal
-           env3          = if isLocal then env1 else resetScope env2
-       in  (env3, CFunc name arity visibility typeexpr rule)
-   | otherwise
-     = internalError ("missing declaration for function \""
-		      ++ show ident ++ "\"")
- where
-   genFuncType env decls
-      | acytype == UntypedAcy
-	= fmap (genTypeSig env) (find isTypeSig decls)
-      | acytype == TypedAcy
-	= fmap (genTypeExpr env) mftype
-      | otherwise 
-	= Nothing
-    where 
-    acytype = acyType env
-    mftype  | isLocal   
-	      = lookupType ident (typeEnv env)
-	    | otherwise 
-	      = qualLookupType (qualifyWith (moduleId env) ident)
-	                       (typeEnv env)
-
-   genTypeSig env (TypeSig _ _ ts)          = genTypeExpr env ts
-   genTypeSig env (ExternalDecl _ _ _ _ ts) = genTypeExpr env ts
-
-   genExternal (ExternalDecl _ _ mname ident _)
-      = CExternal (fromMaybe (name ident) mname)
-   genExternal (FlatExternalDecl _ [ident])
-      = CExternal (name ident)
-   genExternal _
-      = internalError "illegal external declaration occured"
-
-   compArity mtypeexpr rules
-      | not (null rules)
-        = let (CRule patts _ _) = head rules in length patts
-      | otherwise
-        = maybe (internalError ("unable to compute arity for function \""
-				++ show ident ++ "\""))
-	        compArityFromType
-		mtypeexpr
-
-   compArityFromType (CTVar _)        = 0
-   compArityFromType (CFuncType _ t2) = 1 + compArityFromType t2
-   compArityFromType (CTCons _ _)     = 0
-
-   compRule evalannot rules mexternal
-      | not (null rules) = CRules evalannot rules
-      | otherwise
-	= fromMaybe (internalError ("missing rule for function \""
-				    ++ show ident ++ "\""))
-	            mexternal
-
-
---
-genRule :: AbstractEnv -> Equation -> (CRule, AbstractEnv)
-genRule env (Equation pos lhs rhs)
-   = let (patts, env1)  = mapfoldl (genPattern pos)
-			           (beginScope env) 
-				   (simplifyLhs lhs)
-	 (locals, env2) = genLocalDecls env1 (simplifyRhsLocals rhs)
-	 (crhss, env3)  = mapfoldl (genCrhs pos) env2 (simplifyRhsExpr rhs)
-     in  (CRule patts crhss locals, endScope env3)
-
-
---
-genCrhs :: Position -> AbstractEnv -> (Expression, Expression) 
-           -> ((CExpr, CExpr), AbstractEnv)
-genCrhs pos env (cond, expr)
-   = let (cond', env1) = genExpr pos env cond
-	 (expr', env2) = genExpr pos env1 expr
-     in  ((cond', expr'), env2)
-
-
--- NOTE: guarded expressions and 'where' declarations in local pattern
--- declarations are not supported in PAKCS
-genLocalDecls :: AbstractEnv -> [Decl] -> ([CLocalDecl], AbstractEnv)
-genLocalDecls env decls
-   = genLocals (foldl genLocalIndex env decls)
-               (funcDecls (foldl partitionDecl emptyPartitions decls))
-	       decls
- where
-   genLocalIndex env (PatternDecl _ constr _)
-      = genLocalPatternIndex env constr
-   genLocalIndex env (ExtraVariables _ idents)
-      = let (_, env') = mapfoldl genVarIndex env idents
-	in  env'
-   genLocalIndex env _
-       = env
-
-   genLocalPatternIndex env (VariablePattern ident)
-      = snd (genVarIndex env ident)
-   genLocalPatternIndex env (ConstructorPattern _ args)
-      = foldl genLocalPatternIndex env args
-   genLocalPatternIndex env (InfixPattern c1 _ c2)
-      = foldl genLocalPatternIndex env [c1,c2]
-   genLocalPatternIndex env (ParenPattern c)
-      = genLocalPatternIndex env c
-   genLocalPatternIndex env (TuplePattern _ args)
-      = foldl genLocalPatternIndex env args
-   genLocalPatternIndex env (ListPattern _ args)
-      = foldl genLocalPatternIndex env args
-   genLocalPatternIndex env (AsPattern ident c)
-      = genLocalPatternIndex (snd (genVarIndex env ident)) c
-   genLocalPatternIndex env (LazyPattern _ c)
-      = genLocalPatternIndex env c
-   genLocalPatternIndex env (RecordPattern fields mc)
-      = let env' = foldl genLocalPatternIndex env (map fieldTerm fields)
-        in  maybe env' (genLocalPatternIndex env') mc
-   genLocalPatternIndex env _
-      = env
-
-   -- The association list 'fdecls' is necessary because function
-   -- rules may not be together in the declaration list
-   genLocals :: AbstractEnv -> Map.Map Ident [Decl] -> [Decl] 
-	        -> ([CLocalDecl], AbstractEnv)
-   genLocals env _ [] = ([], env)
-   genLocals env fdecls ((FunctionDecl _ ident _):decls)
-      = let (funcdecl, env1) = genLocalFuncDecl (beginScope env) fdecls ident
-	    (locals, env2)   = genLocals (endScope env1) fdecls decls
-        in  (funcdecl:locals, env2)
-   genLocals env fdecls ((ExternalDecl _ _ _ ident _):decls)
-      = let (funcdecl, env1) = genLocalFuncDecl (beginScope env) fdecls ident
-	    (locals, env2)   = genLocals (endScope env1) fdecls decls
-        in  (funcdecl:locals, env2)
-   genLocals env fdecls ((FlatExternalDecl pos idents):decls)
-      | null idents = genLocals env fdecls decls
-      | otherwise 
-        = let (funcdecl, env1) 
-		= genLocalFuncDecl (beginScope env) fdecls (head idents)
-	      (locals, env2) 
-		= genLocals (endScope env1)
-		            fdecls 
-			    (FlatExternalDecl pos (tail idents):decls)
-          in  (funcdecl:locals, env2)
-   genLocals env fdecls (PatternDecl pos constr rhs : decls)
-      = let (patt, env1)    = genLocalPattern pos env constr
-	    (plocals, env2) = genLocalDecls (beginScope env1) 
-			                    (simplifyRhsLocals rhs)
-	    (expr, env3)    = genLocalPattRhs pos env2 (simplifyRhsExpr rhs)
-	    (locals, env4)  = genLocals (endScope env3) fdecls decls
-	in  (CLocalPat patt expr plocals:locals, env4)
-   genLocals env fdecls ((ExtraVariables pos idents):decls)
-      | null idents  = genLocals env fdecls decls
-      | otherwise
-        = let ident  = head idents
-	      idx    = fromMaybe 
-		         (internalError ("cannot find index"
-					 ++ " for free variable \""
-					 ++ show ident ++ "\""))
-		         (getVarIndex env ident)
-	      decls' = ExtraVariables pos (tail idents) : decls
-	      (locals, env') = genLocals env fdecls decls'
-          in (CLocalVar (idx, name ident) : locals, env')
-   genLocals env fdecls ((TypeSig _ _ _):decls)
-      = genLocals env fdecls decls
-   genLocals _ _ decl = internalError ("unexpected local declaration: \n"
-				       ++ show (head decl))
-
-   genLocalFuncDecl :: AbstractEnv -> Map.Map Ident [Decl] -> Ident 
-		       -> (CLocalDecl, AbstractEnv)
-   genLocalFuncDecl env fdecls ident
-      = let fdecl = fromMaybe 
-		      (internalError ("missing declaration" 
-				      ++ " for local function \""
-				      ++ show ident ++ "\""))
-		      (Map.lookup ident fdecls)
-	    (_, funcdecl) = genFuncDecl True env ident fdecl
-        in  (CLocalFunc funcdecl, env)
-
-   genLocalPattern pos env (LiteralPattern lit)
-      = case lit of
-       String _ cs 
-         -> genLocalPattern pos env 
-                 (ListPattern [] (map (LiteralPattern . Char noRef) cs))
-       _ -> (CPLit (genLiteral lit), env)
-   genLocalPattern pos env (VariablePattern ident)
-      = let idx = fromMaybe 
-		     (internalError ("cannot find index"
-				    ++ " for pattern variable \""
-				    ++ show ident ++ "\""))
-		     (getVarIndex env ident)   
-        in  (CPVar (idx, name ident), env)
-   genLocalPattern pos env (ConstructorPattern qident args)
-      = let (args', env') = mapfoldl (genLocalPattern pos) env args
-	in (CPComb (genQName False env qident) args', env')
-   genLocalPattern pos env (InfixPattern larg qident rarg)
-      = genLocalPattern pos env (ConstructorPattern qident [larg, rarg])
-   genLocalPattern pos env (ParenPattern patt)
-      = genLocalPattern pos env patt
-   genLocalPattern pos env (TuplePattern _ args)
-      | len > 1  
-        = genLocalPattern pos env (ConstructorPattern (qTupleId len) args)
-      | len == 1
-	= genLocalPattern pos env (head args)
-      | len == 0
-	= genLocalPattern pos env (ConstructorPattern qUnitId [])
-    where len = length args
-   genLocalPattern pos env (ListPattern _ args)
-      = genLocalPattern pos env 
-	  (foldr (\p1 p2 -> ConstructorPattern qConsId [p1,p2])
-	   (ConstructorPattern qNilId [])
-	   args)
-   genLocalPattern pos _ (NegativePattern _ _)
-      = errorAt pos "negative patterns are not supported in AbstractCurry"
-   genLocalPattern pos env (AsPattern ident cterm)
-      = let (patt, env1) = genLocalPattern pos env cterm
-	    idx          = fromMaybe 
-			      (internalError ("cannot find index"
-					      ++ " for alias variable \""
-					      ++ show ident ++ "\""))
-			      (getVarIndex env1 ident)
-        in  (CPAs (idx, name ident) patt, env1)
-   genLocalPattern pos env (LazyPattern _ cterm)
-      = let (patt, env') = genLocalPattern pos env cterm
-        in  (CPLazy patt, env')
-   genLocalPattern pos env (RecordPattern fields mr)
-      = let (fields', env1) = mapfoldl (genField genLocalPattern) env fields
-	    (mr', env2)
-		= maybe (Nothing, env1)
-		        (applyFst Just . genLocalPattern pos env1)
-			mr
-	in  (CPRecord fields' mr', env2)
-
-   genLocalPattRhs pos env [(Variable qSuccessFunId, expr)]
-      = genExpr pos env expr
-   genLocalPattRhs pos _ _
-      = errorAt pos ("guarded expressions in pattern declarations"
-		     ++ " are not supported in AbstractCurry")
-
-
---
-genExpr :: Position -> AbstractEnv -> Expression -> (CExpr, AbstractEnv)
-genExpr pos env (Literal lit)
-   = case lit of
-       String _ cs -> genExpr pos env (List [] (map (Literal . Char noRef) cs))
-       _           -> (CLit (genLiteral lit), env)
-genExpr _ env (Variable qident)
-   | isJust midx          = (CVar (fromJust midx, name ident), env)
-   | qident == qSuccessId = (CSymbol (genQName False env qSuccessFunId), env)
-   | otherwise            = (CSymbol (genQName False env qident), env)
- where
-   ident = unqualify qident
-   midx  = getVarIndex env ident
-genExpr _ env (Constructor qident)
-   = (CSymbol (genQName False env qident), env)
-genExpr pos env (Paren expr)
-   = genExpr pos env expr
-genExpr pos env (Typed expr _)
-   = genExpr pos env expr
-genExpr pos env (Tuple _ args)
-   | len > 1
-     = genExpr pos env (foldl Apply (Variable (qTupleId (length args))) args)
-   | len == 1
-     = genExpr pos env (head args)
-   | len == 0
-     = genExpr pos env (Variable qUnitId)
- where len = length args
-genExpr pos env (List _ args)
-   = let cons = Constructor qConsId
-	 nil  = Constructor qNilId
-     in  genExpr pos env (foldr (Apply . Apply cons) nil args)
-genExpr pos env (ListCompr _ expr stmts)
-   = let (stmts', env1) = mapfoldl (genStatement pos) (beginScope env) stmts
-	 (expr', env2)  = genExpr pos env1 expr
-     in  (CListComp expr' stmts', endScope env2)
-genExpr pos env (EnumFrom expr)
-   = genExpr pos env (Apply (Variable qEnumFromId) expr)
-genExpr pos env (EnumFromThen expr1 expr2)
-   = genExpr pos env (Apply (Apply (Variable qEnumFromThenId) expr1) expr2)
-genExpr pos env (EnumFromTo expr1 expr2)
-   = genExpr pos env (Apply (Apply (Variable qEnumFromToId) expr1) expr2)
-genExpr pos env (EnumFromThenTo expr1 expr2 expr3)
-   = genExpr pos env (Apply (Apply (Apply (Variable qEnumFromThenToId) 
-				    expr1) expr2) expr3)
-genExpr pos env (UnaryMinus _ expr)
-   = genExpr pos env (Apply (Variable qNegateId) expr)
-genExpr pos env (Apply expr1 expr2)
-   = let (expr1', env1) = genExpr pos env expr1
-	 (expr2', env2) = genExpr pos env1 expr2
-     in  (CApply expr1' expr2', env2)
-genExpr pos env (InfixApply expr1 op expr2)
-   = genExpr pos env (Apply (Apply (opToExpr op) expr1) expr2)
-genExpr pos env (LeftSection expr op)
-   = let ident  = freshVar env "x"
-	 patt   = VariablePattern ident
-	 var    = Variable (qualify ident)
-	 applic = Apply (Apply (opToExpr op) expr) var 
-     in  genExpr pos env (Lambda noRef [patt] applic)
-genExpr pos env (RightSection op expr)
-   = let ident  = freshVar env "x"
-	 patt   = VariablePattern ident
-	 var    = Variable (qualify ident)
-	 applic = Apply (Apply (opToExpr op) var) expr 
-     in  genExpr pos env (Lambda noRef [patt] applic)
-genExpr pos env (Lambda _ params expr)
-   = let (params', env1) = mapfoldl (genPattern pos) (beginScope env) params
-	 (expr', env2)   = genExpr pos env1 expr
-     in  (CLambda params' expr', endScope env2)
-genExpr pos env (Let decls expr)
-   = let (decls', env1) = genLocalDecls (beginScope env) decls
-	 (expr', env2)  = genExpr pos env1 expr
-     in  (CLetDecl decls' expr', endScope env2)
-genExpr pos env (Do stmts expr)
-   = let (stmts', env1) = mapfoldl (genStatement pos) (beginScope env) stmts
-	 (expr', env2)  = genExpr pos env1 expr
-     in  (CDoExpr (stmts' ++ [CSExpr expr']), endScope env2)
-genExpr pos env (IfThenElse _ expr1 expr2 expr3)
-   = genExpr pos env (Apply (Apply (Apply (Variable qIfThenElseId)
-				    expr1) expr2) expr3)
-genExpr pos env (Case _ expr alts)
-   = let (expr', env1) = genExpr pos env expr
-	 (alts', env2) = mapfoldl genBranchExpr env1 alts
-     in  (CCase expr' alts', env2)
-genExpr pos env (RecordConstr fields)
-   = let (fields', env1) = mapfoldl (genField genExpr) env fields
-     in  (CRecConstr fields', env1)
-genExpr pos env (RecordSelection expr label)
-   = let (expr', env1) = genExpr pos env expr
-     in  (CRecSelect expr' (name label), env1)
-genExpr pos env (RecordUpdate fields expr)
-   = let (fields', env1) = mapfoldl (genField genExpr) env fields
-         (expr', env2)   = genExpr pos env1 expr
-     in  (CRecUpdate fields' expr', env2)
-
-
---
-genStatement :: Position -> AbstractEnv -> Statement 
-	        -> (CStatement, AbstractEnv)
-genStatement pos env (StmtExpr _ expr)
-   = let (expr', env') = genExpr pos env expr
-     in  (CSExpr expr', env')
-genStatement _ env (StmtDecl decls)
-   = let (decls', env') = genLocalDecls env decls
-     in  (CSLet decls', env')
-genStatement pos env (StmtBind _ patt expr)
-   = let (expr', env1) = genExpr pos env expr
-	 (patt', env2) = genPattern pos env1 patt
-     in  (CSPat patt' expr', env2)
-
-
--- NOTE: guarded expressions and local declarations in case branches
--- are not supported in PAKCS
-genBranchExpr :: AbstractEnv -> Alt -> (CBranchExpr, AbstractEnv)
-genBranchExpr env (Alt pos patt rhs)
-   = let (patt', env1) = genPattern pos (beginScope env) patt
-	 (expr', env2) = genBranchRhs pos env1 (simplifyRhsExpr rhs)
-     in  (CBranch patt' expr', endScope env2)
- where
-   genBranchRhs pos env [(Variable qSuccessFunId, expr)]
-      = genExpr pos env expr
-   genBranchRhs pos _ _
-      = errorAt pos ("guarded expressions in case alternatives"
-		     ++ " are not supported in AbstractCurry")
-
-
---
-genPattern :: Position -> AbstractEnv -> ConstrTerm -> (CPattern, AbstractEnv)
-genPattern pos env (LiteralPattern lit)
-   = case lit of
-       String _ cs 
-         -> genPattern pos env (ListPattern [] (map (LiteralPattern . Char noRef) cs))
-       _ -> (CPLit (genLiteral lit), env)
-genPattern _ env (VariablePattern ident)
-   = let (idx, env') = genVarIndex env ident
-     in  (CPVar (idx, name ident), env')
-genPattern pos env (ConstructorPattern qident args)
-   = let (args', env') = mapfoldl (genPattern pos) env args
-     in  (CPComb (genQName False env qident) args', env')
-genPattern pos env (InfixPattern larg qident rarg)
-   = genPattern pos env (ConstructorPattern qident [larg, rarg])
-genPattern pos env (ParenPattern patt)
-   = genPattern pos env patt
-genPattern pos env (TuplePattern _ args)
-   | len > 1
-     = genPattern pos env (ConstructorPattern (qTupleId len) args)
-   | len == 1
-     = genPattern pos env (head args)
-   | len == 0
-     = genPattern pos env (ConstructorPattern qUnitId [])
- where len = length args
-genPattern pos env (ListPattern _ args)
-   = genPattern pos env (foldr (\x1 x2 -> ConstructorPattern qConsId [x1, x2]) 
-		         (ConstructorPattern qNilId []) 
-		         args)
-genPattern pos _ (NegativePattern _ _)
-   = errorAt pos "negative patterns are not supported in AbstractCurry"
-genPattern pos env (AsPattern ident cterm)
-   = let (patt, env1) = genPattern pos env cterm
-	 (idx, env2) = genVarIndex env1 ident
-     in  (CPAs (idx, name ident) patt, env2)
-genPattern pos env (LazyPattern _ cterm)
-   = let (patt, env') = genPattern pos env cterm
-     in  (CPLazy patt, env')
-genPattern pos env (FunctionPattern qident cterms)
-   = let (patts, env') = mapfoldl (genPattern pos) env cterms
-     in  (CPFuncComb (genQName False env qident) patts, env')
-genPattern pos env (InfixFuncPattern cterm1 qident cterm2)
-   = genPattern pos env (FunctionPattern qident [cterm1, cterm2])
-genPattern pos env (RecordPattern fields mr)
-   = let (fields', env1) = mapfoldl (genField genPattern) env fields
-         (mr', env2)     = maybe (Nothing, env1)
-                                 (applyFst Just . genPattern pos env1)
-				 mr
-     in  (CPRecord fields' mr', env2)
-
-
---
-genField :: (Position -> AbstractEnv -> a -> (b, AbstractEnv))
-	 -> AbstractEnv -> Field a -> (CField b, AbstractEnv)
-genField genTerm env (Field pos label term)
-   = let (term',env1) = genTerm pos env term
-     in  ((name label, term'), env1)
-
---
-genLiteral :: Literal -> CLiteral
-genLiteral (Char _ c)  = CCharc c
-genLiteral (Int _ i)   = CIntc i
-genLiteral (Float _ f) = CFloatc f
-genLiteral _           = internalError "unsupported literal"
-
-
--- Notes: 
--- - Some prelude identifiers are not quialified. The first check ensures
---   that they get a correct qualifier.
--- - The test for unqualified identifiers is necessary to qualify
---   them correctly in the untyped AbstractCurry representation.
-genQName :: Bool -> AbstractEnv -> QualIdent -> QName
-genQName isTypeCons env qident
-   | isPreludeSymbol qident
-     = genQualName (qualQualify preludeMIdent qident)
-   | not (isQualified qident)
-     = genQualName (getQualIdent (unqualify qident))
-   | otherwise
-     = genQualName qident
- where
-  genQualName qid
-     = let (mmid, id) = (qualidMod qid, qualidId qid)
-	   mid = maybe (moduleId env)
-		       (\mid' -> fromMaybe mid' (Map.lookup mid' (imports env)))
-		       mmid
-       in  (moduleName mid, name id)
-
-  getQualIdent id
-     | isTypeCons = case (lookupTC id (tconsEnv env)) of
-		      --[DataType qid _ _] -> qid
-		      --[RenamingType qid _ _] -> qid
-		      --[AliasType qid _ _] -> qid
-		      [info] -> origName info
-		      _ ->  qualifyWith (moduleId env) id
-     | otherwise  = case (lookupValue id (typeEnv env)) of
-		      --[DataConstructor qid _] -> qid
-		      --[NewtypeConstructor qid _] -> qid
-		      --[Value qid _] -> qid
-		      [info] -> origName info
-		      _ -> qualifyWith (moduleId env) id
-		      
-
-
---
-genVisibility :: AbstractEnv -> Ident -> CVisibility
-genVisibility env ident
-   | isExported env ident = Public
-   | otherwise            = Private
-
-
---
-genEvalAnnot :: EvalAnnotation -> CEvalAnnot
-genEvalAnnot EvalRigid  = CRigid
-genEvalAnnot EvalChoice = CChoice
-
-
--------------------------------------------------------------------------------
--- This part defines an environment containing all necessary information
--- for generating the AbstractCurry representation of a CurrySyntax term.
-
--- Data type for representing an AbstractCurry generator environment.
---
---    moduleName  - name of the module
---    typeEnv     - table of all known types
---    exports     - table of all exported symbols from the module
---    imports     - table of import aliases
---    varIndex    - index counter for generating variable indices
---    tvarIndex   - index counter for generating type variable indices
---    varScope    - stack of variable tables
---    tvarScope   - stack of type variable tables
---    acyType     - type of AbstractCurry code to be generated
-data AbstractEnv = AbstractEnv {moduleId   :: ModuleIdent,
-				typeEnv    :: ValueEnv,
-				tconsEnv   :: TCEnv,
-				exports    :: Set.Set Ident,
-				imports    :: Map.Map ModuleIdent ModuleIdent,
-				varIndex   :: Int,
-				tvarIndex  :: Int,
-				varScope   :: [Map.Map Ident Int],
-				tvarScope  :: [Map.Map Ident Int],
-                                acyType    :: AbstractType
-			       } deriving Show
-
--- Data type representing the type of AbstractCurry code to be generated
--- (typed infered or untyped (i.e. type signated))
-data AbstractType = TypedAcy | UntypedAcy deriving (Eq, Show)
-
-
--- Initializes the AbstractCurry generator environment.
-genAbstractEnv :: AbstractType -> ValueEnv -> TCEnv -> Module -> AbstractEnv
-genAbstractEnv absType tyEnv tcEnv (Module mid exps decls)
-   = AbstractEnv 
-       {moduleId     = mid,
-	typeEnv      = tyEnv,
-	tconsEnv     = tcEnv,
-	exports      = foldl (buildExportTable mid decls) Set.empty exps',
-	imports      = foldl buildImportTable Map.empty decls,
-	varIndex     = 0,
-	tvarIndex    = 0,
-	varScope     = [Map.empty],
-	tvarScope    = [Map.empty],
-        acyType      = absType
-       }
- where
-   exps' = maybe (buildExports mid decls) (\ (Exporting _ es) -> es) exps
-
-
--- Generates a list of exports for all specified top level declarations
-buildExports :: ModuleIdent -> [Decl] -> [Export]
-buildExports _ [] = []
-buildExports mid (DataDecl _ ident _ _:ds) 
-   = ExportTypeAll (qualifyWith mid ident) : buildExports mid ds
-buildExports mid ((NewtypeDecl _ ident _ _):ds)
-   = ExportTypeAll (qualifyWith mid ident) : buildExports mid ds
-buildExports mid ((TypeDecl _ ident _ _):ds)
-   = Export (qualifyWith mid ident) : buildExports mid ds
-buildExports mid ((FunctionDecl _ ident _):ds)
-   = Export (qualifyWith mid ident) : buildExports mid ds
-buildExports mid (ExternalDecl _ _ _ ident _ : ds)
-   = Export (qualifyWith mid ident) : buildExports mid ds
-buildExports mid (FlatExternalDecl _ idents : ds)
-   = map (Export . qualifyWith mid) idents ++ buildExports mid ds
-buildExports mid (_:ds) = buildExports mid ds
-
-
--- Builds a table containing all exported (i.e. public) identifiers
--- from a module.
-buildExportTable :: ModuleIdent -> [Decl] -> Set.Set Ident -> Export 
-                 -> Set.Set Ident
-buildExportTable mid _ exptab (Export qident)
-   | isJust (localIdent mid qident)
-     = insertExportedIdent exptab (unqualify qident)
-   | otherwise = exptab
-buildExportTable mid _ exptab (ExportTypeWith qident ids)
-   | isJust (localIdent mid qident)
-     = foldl insertExportedIdent 
-             (insertExportedIdent exptab (unqualify qident))
-             ids
-   | otherwise  = exptab
-buildExportTable mid decls exptab (ExportTypeAll qident)
-   | isJust ident'
-     = foldl insertExportedIdent
-             (insertExportedIdent exptab ident)
-             (maybe [] getConstrIdents (find (isDataDeclOf ident) decls))
-   | otherwise = exptab
- where 
-   ident' = localIdent mid qident
-   ident  = fromJust ident'
-buildExportTable _ _ exptab (ExportModule _) = exptab
-
---
-insertExportedIdent :: Set.Set Ident -> Ident -> Set.Set Ident
-insertExportedIdent env ident = Set.insert ident env
-
---
-getConstrIdents :: Decl -> [Ident]
-getConstrIdents (DataDecl _ _ _ constrs)
-   = map getConstrIdent constrs
- where
-   getConstrIdent (ConstrDecl _ _ ident _)  = ident
-   getConstrIdent (ConOpDecl _ _ _ ident _) = ident
-
-
--- Builds a table for dereferencing import aliases
-buildImportTable :: Map.Map ModuleIdent ModuleIdent -> Decl
-		    -> Map.Map ModuleIdent ModuleIdent
-buildImportTable env (ImportDecl _ mid _ malias _)
-   = Map.insert (fromMaybe mid malias) mid env
-buildImportTable env _ = env
-
-
--- Checks whether an identifier is exported or not.
-isExported :: AbstractEnv -> Ident -> Bool
-isExported env ident = Set.member ident (exports env)
-
-
--- Generates an unique index for the  variable 'ident' and inserts it
--- into the  variable table of the current scope.
-genVarIndex :: AbstractEnv -> Ident -> (Int, AbstractEnv)
-genVarIndex env ident 
-   = let idx   = varIndex env
-         vtabs = varScope env
-	 vtab  = head vtabs --if null vtabs then Map.empty else head vtabs
-     in  (idx, env {varIndex = idx + 1,
-		    varScope = Map.insert ident idx vtab : sureTail vtabs})
-
--- Generates an unique index for the type variable 'ident' and inserts it
--- into the type variable table of the current scope.
-genTVarIndex :: AbstractEnv -> Ident -> (Int, AbstractEnv)
-genTVarIndex env ident
-   = let idx   = tvarIndex env
-         vtabs = tvarScope env
-	 vtab  = head vtabs --if null vtabs then Map.empty else head vtabs
-     in  (idx, env {tvarIndex = idx + 1,
-		    tvarScope = Map.insert ident idx vtab : sureTail vtabs })
-
-
--- Looks up the unique index for the variable 'ident' in the
--- variable table of the current scope.
-getVarIndex :: AbstractEnv -> Ident -> Maybe Int
-getVarIndex env ident = Map.lookup ident (head (varScope env))
-
--- Looks up the unique index for the type variable 'ident' in the type
--- variable table of the current scope.
-getTVarIndex :: AbstractEnv -> Ident -> Maybe Int
-getTVarIndex env ident = Map.lookup ident (head (tvarScope env))
-
-
--- Generates an indentifier which doesn't occur in the variable table
--- of the current scope.
-freshVar :: AbstractEnv -> String -> Ident
-freshVar env name = genFreshVar env name 0
- where
-   genFreshVar env name idx
-      | isJust (getVarIndex env ident)
-         = genFreshVar env name (idx + 1)
-      | otherwise 
-         = ident
-    where ident = mkIdent (name ++ show idx)
-
--- Sets the index counter back to zero and deletes all stack entries.
-resetScope :: AbstractEnv -> AbstractEnv
-resetScope env = env {varIndex  = 0,
-		      tvarIndex = 0,
-		      varScope  = [Map.empty],
-		      tvarScope = [Map.empty]}
-
--- Starts a new scope, i.e. copies and pushes the variable table of the current 
--- scope onto the top of the stack
-beginScope :: AbstractEnv -> AbstractEnv
-beginScope env = env {varScope  = head vs :vs,
-		      tvarScope = head tvs :tvs }
- where
- vs  = varScope env
- tvs = tvarScope env
-
--- End the current scope, i.e. pops and deletes the variable table of the
--- current scope from the top of the stack.
-endScope :: AbstractEnv -> AbstractEnv
-endScope env = env {varScope  = if oneElement vs then vs else tail vs,
-		    tvarScope = if oneElement tvs then tvs else tail tvs}
- where
- vs  = varScope env
- tvs = tvarScope env
-
-
--------------------------------------------------------------------------------
--- Miscellaneous...
-
--- Some identifiers...
-qEnumFromId       = qualifyWith preludeMIdent (mkIdent "enumFrom")
-qEnumFromThenId   = qualifyWith preludeMIdent (mkIdent "enumFromThen")
-qEnumFromToId     = qualifyWith preludeMIdent (mkIdent "enumFromTo")
-qEnumFromThenToId = qualifyWith preludeMIdent (mkIdent "enumFromThenTo")
-qNegateId         = qualifyWith preludeMIdent (mkIdent "negate")
-qIfThenElseId     = qualifyWith preludeMIdent (mkIdent "if_then_else")
-qSuccessFunId     = qualifyWith preludeMIdent (mkIdent "success")
-
-
--- The following functions check whether a declaration is of a certain kind
-isFunctionDecl :: Decl -> Bool
-isFunctionDecl (FunctionDecl _ _ _) = True
-isFunctionDecl _                    = False
-
-isExternal :: Decl -> Bool
-isExternal (ExternalDecl _ _ _ _ _) = True
-isExternal (FlatExternalDecl _ _)   = True
-isExternal _                        = False
-
-
--- Checks, whether a declaration is the data declaration of 'ident'.
-isDataDeclOf :: Ident -> Decl -> Bool
-isDataDeclOf ident (DataDecl _ ident' _ _) 
-   = ident == ident'
-isDataDeclOf _ _  
-   = False
-
-
--- Checks, whether a symbol is defined in the Prelude.
-isPreludeSymbol :: QualIdent -> Bool
-isPreludeSymbol qident
-   = let (mmid, ident) = (qualidMod qident, qualidId qident)
-     in  (isJust mmid && preludeMIdent == fromJust mmid)
-         || elem ident [unitId, listId, nilId, consId]
-	 || isTupleId ident
-
-
--- Converts an infix operator to an expression
-opToExpr :: InfixOp -> Expression
-opToExpr (InfixOp qident)     = Variable qident
-opToExpr (InfixConstr qident) = Constructor qident
-
-
--- Looks up the type of a qualified symbol in the type environment and
--- converts it to a CurrySyntax type term.
-qualLookupType :: QualIdent -> ValueEnv -> Maybe TypeExpr
-qualLookupType qident tyEnv
-   = case (qualLookupValue qident tyEnv) of
-       [Value _ ts] -> (\ (ForAll _ ty) -> Just (fromType ty)) ts
-       _            -> Nothing
-
--- Looks up the type of a symbol in the type environment and
--- converts it to a CurrySyntax type term.
-lookupType :: Ident -> ValueEnv -> Maybe TypeExpr
-lookupType ident tyEnv
-   = case (lookupValue ident tyEnv) of
-       [Value _ ts] -> (\ (ForAll _ ty) -> Just (fromType ty)) ts
-       _            -> Nothing
-
-
--- The following functions transform left-hand-side and right-hand-side terms
--- for a better handling
-simplifyLhs :: Lhs -> [ConstrTerm]
-simplifyLhs = snd . flatLhs
-
-simplifyRhsExpr :: Rhs -> [(Expression, Expression)]
-simplifyRhsExpr (SimpleRhs _ expr _) 
-   = [(Variable qSuccessId, expr)]
-simplifyRhsExpr (GuardedRhs crhs _)  
-   = map (\ (CondExpr _ cond expr) -> (cond, expr)) crhs
-
-simplifyRhsLocals :: Rhs -> [Decl]
-simplifyRhsLocals (SimpleRhs _ _ locals) = locals
-simplifyRhsLocals (GuardedRhs _ locals)  = locals
-
-
--- FIXME This mapfold is a twisted mapAccumL
--- A combination of 'map' and 'foldl'. It maps a function to a list
--- from left to right while updating the argument 'e' continously.
-mapfoldl :: (a -> b -> (c,a)) -> a -> [b] -> ([c], a)
-mapfoldl _ e []     = ([], e)
-mapfoldl f e (x:xs) = let (x', e')   = f e x
-                          (xs', e'') = mapfoldl f e' xs
-                      in  (x':xs', e'')
-
--- Inserts an element under a key into an association list
-insertEntry :: Eq a => a -> b -> [(a,b)] -> [(a,b)]
-insertEntry k e [] = [(k,e)]
-insertEntry k e ((x,y):xys)
-   | k == x    = (k,e):xys
-   | otherwise = (x,y) : insertEntry k e xys
-
-
--- Returns the list without the first element. If the list is empty, an
--- empty list will be returned.
-sureTail :: [a] -> [a]
-sureTail []     = []
-sureTail (_:xs) = xs
-
-
--- Returns 'True', if a list contains exactly one element
-oneElement :: [a] -> Bool
-oneElement [_] = True
-oneElement _   = False
-
-
--- Applies 'f' on the first value in a tuple
-applyFst :: (a -> c) -> (a,b) -> (c,b)
-applyFst f (x,y) = (f x, y)
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
diff --git a/src/GenFlatCurry.hs b/src/GenFlatCurry.hs
deleted file mode 100644
--- a/src/GenFlatCurry.hs
+++ /dev/null
@@ -1,1153 +0,0 @@
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---
--- GenFlatCurry - Generates FlatCurry program terms and FlatCurry interfaces
---                (type 'FlatCurry.Prog')
---
--- November 2005,
--- Martin Engelke (men@informatik.uni-kiel.de)
---
-module GenFlatCurry (genFlatCurry,
-		     genFlatInterface) where
-
-
-import Control.Monad.State
-import Control.Monad
-import Data.Maybe
-import Data.List
-import qualified Data.Map as Map
-
-
-import Curry.Base.MessageMonad
-import Curry.Base.Ident as Id
-
-import qualified Curry.Syntax as CS
-
-import Curry.ExtendedFlat.Type
-import Curry.ExtendedFlat.TypeInference
-
-import Curry.ExtendedFlat.EraseTypes
-
-import Base
-
-import qualified IL.Type as IL
-import qualified IL.CurryToIL as IL
-
-import TopEnv(topEnvMap)
-import CurryEnv (CurryEnv)
-import qualified CurryEnv
-import ScopeEnv (ScopeEnv)
-import qualified ScopeEnv
-import Types
-import CurryCompilerOpts
-import PatchPrelude
-
-
-import Debug.Trace
-trace' _ x = x
-
--------------------------------------------------------------------------------
-
--- transforms intermediate language code (IL) to FlatCurry code
-genFlatCurry :: Options -> CurryEnv -> ModuleEnv -> ValueEnv -> TCEnv 
-		-> ArityEnv -> IL.Module -> (Prog, [WarnMsg])
-genFlatCurry opts cEnv mEnv tyEnv tcEnv aEnv mod
-   = (prog', messages)
- where (prog, messages) 
-           = run opts cEnv mEnv tyEnv tcEnv aEnv False (visitModule mod)
-       prog' = -- eraseTypes $ 
-               adjustTypeInfo $ adjustTypeInfo $ patchPreludeFCY prog
-
-
--- transforms intermediate language code (IL) to FlatCurry interfaces
-genFlatInterface :: Options -> CurryEnv -> ModuleEnv -> ValueEnv -> TCEnv
-		 -> ArityEnv -> IL.Module -> (Prog, [WarnMsg])
-genFlatInterface opts cEnv mEnv tyEnv tcEnv aEnv mod
-   = (patchPreludeFCY intf, messages)
- where (intf, messages) 
-	   = run opts cEnv mEnv tyEnv tcEnv aEnv True (visitModule mod)
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
-
--- The environment 'FlatEnv' is embedded in the monadic representation
--- 'FlatState' which allows the usage of 'do' expressions.
-
-type FlatState a = State FlatEnv a
-
--- Data type for representing an environment which contains information needed
--- for generating FlatCurry code.
-data FlatEnv = FlatEnv{ moduleIdE     :: ModuleIdent,
-			  functionIdE   :: (QualIdent, [(Ident, IL.Type)]),
-			  compilerOptsE :: Options,
-			  moduleEnvE    :: ModuleEnv,
-			  arityEnvE     :: ArityEnv,
-			  typeEnvE      :: ValueEnv,     -- types of defined values
-			  tConsEnvE     :: TCEnv,
-			  publicEnvE    :: Map.Map Ident IdentExport,
-			  fixitiesE     :: [CS.IDecl],
-			  typeSynonymsE :: [CS.IDecl],
-			  importsE      :: [CS.IDecl],
-			  exportsE      :: [CS.Export],
-			  interfaceE    :: [CS.IDecl],
-			  varIndexE     :: Int,
-			  varIdsE       :: ScopeEnv Ident VarIndex,
-			  tvarIndexE    :: Int,
-			  messagesE     :: [WarnMsg],
-			  genInterfaceE :: Bool,
-                          localTypes    :: Map.Map QualIdent IL.Type,
-                          constrTypes   :: Map.Map QualIdent IL.Type
-			}
-
-data IdentExport = NotConstr       -- function, type-constructor
-                 | OnlyConstr      -- constructor
-                 | NotOnlyConstr   -- constructor, function, type-constructor
-
-
-
-
--- Runs a 'FlatState' action and returns the result
-run :: Options -> CurryEnv -> ModuleEnv -> ValueEnv -> TCEnv -> ArityEnv 
-    -> Bool -> FlatState a -> (a, [WarnMsg])
-run opts cEnv mEnv tyEnv tcEnv aEnv genIntf f
-   = (result, messagesE env)
- where
- (result, env) = runState f env0
- env0 = FlatEnv{ moduleIdE     = CurryEnv.moduleId cEnv,
-		 functionIdE   = (qualify (mkIdent ""), []),
-		 compilerOptsE = opts,
-		 moduleEnvE    = mEnv,
-		 arityEnvE     = aEnv,
-		 typeEnvE      = tyEnv,
-		 tConsEnvE     = tcEnv,
-		 publicEnvE    = genPubEnv (CurryEnv.moduleId cEnv)
-		                 (CurryEnv.interface cEnv),
-		 fixitiesE     = CurryEnv.infixDecls cEnv,
-		 typeSynonymsE = CurryEnv.typeSynonyms cEnv,
-		 importsE      = CurryEnv.imports cEnv,
-		 exportsE      = CurryEnv.exports cEnv,
-		 interfaceE    = CurryEnv.interface cEnv,
-		 varIndexE     = 0,
-		 varIdsE       = ScopeEnv.new,
-		 tvarIndexE    =0,
-		 messagesE      = [],
-		 genInterfaceE = genIntf,
-                 localTypes    = Map.empty,
-                 constrTypes   = Map.fromList (getConstrTypes tcEnv)
-	       }
-
-getConstrTypes :: TCEnv -> [(QualIdent, IL.Type)]
-getConstrTypes tcEnv = trace' (show tinfos) tinfos
-    where tcList = Map.toList $ topEnvMap tcEnv
-          tinfos = [ foo tqid conid argtypes targnum
-                   | (_, (_, DataType tqid targnum dts):_) <- tcList
-                   , Just (Data conid _ argtypes) <- dts]
-          foo tqid conid argtypes targnum
-              = let conname = QualIdent (qualidMod tqid) conid
-                    resulttype = IL.TypeConstructor tqid (map IL.TypeVariable [0..targnum-1])
-                    contype = foldr IL.TypeArrow resulttype (map ttrans argtypes)
-                in (conname, contype)
-              
-
---
-visitModule :: IL.Module -> FlatState Prog
-visitModule (IL.Module mid imps decls) = do
-  -- insert local decls into localDecls
-  let ts = [ (qn, t) | IL.FunctionDecl qn _ t _ <- decls ]
-  modify (\ s -> s {localTypes = Map.fromList ts})
-  whenFlatCurry
-       (do ops     <- genOpDecls
-           datas   <- mapM visitDataDecl (filter isDataDecl decls)
-	   types   <- genTypeSynonyms
-	   records <- genRecordTypes
-	   funcs   <- mapM visitFuncDecl (filter isFuncDecl decls)
-	   mod     <- visitModuleIdent mid
-	   imps'   <- imports
-	   is      <- mapM visitModuleIdent 
-	                   (nub (imps ++ (map (\ (CS.IImportDecl _ mid) 
-					       -> mid) imps')))
-           return (Prog mod is (records ++ types ++ datas) funcs ops))
-       (do ops     <- genOpDecls
-	   ds      <- filterM isPublicDataDecl decls
-	   datas   <- mapM visitDataDecl ds
-	   types   <- genTypeSynonyms
-	   records <- genRecordTypes
-	   fs      <- filterM isPublicFuncDecl decls
-	   funcs   <- mapM visitFuncDecl fs
-	   expimps <- getExportedImports
-	   itypes  <- mapM visitTypeIDecl (filter isTypeIDecl expimps)
-	   ifuncs  <- mapM visitFuncIDecl (filter isFuncIDecl expimps)
-	   iops    <- mapM visitOpIDecl (filter isOpIDecl expimps)
-	   mod     <- visitModuleIdent mid
-	   imps'   <- imports
-	   is      <- mapM visitModuleIdent 
-	                   (nub (imps ++ (map (\ (CS.IImportDecl _ mid) 
-					       -> mid) imps')))
-	   return (Prog mod 
-		        is 
-		        (itypes ++ records ++ types ++ datas)
-		        (ifuncs ++ funcs)
-		        (iops ++ ops)))
-
---
-visitDataDecl :: IL.Decl -> FlatState TypeDecl
-visitDataDecl (IL.DataDecl qident arity constrs)
-   = do cdecls <- mapM visitConstrDecl constrs
-	qname  <- visitQualTypeIdent qident
-	vis    <- getVisibility False qident
-	return (Type qname vis [0 .. (arity - 1)] (concat cdecls))
-visitDataDecl _ = internalError "GenFlatCurry: no data declaration"
-
---
-visitConstrDecl :: IL.ConstrDecl [IL.Type] -> FlatState [ConsDecl]
-visitConstrDecl (IL.ConstrDecl qident types)
-   = do texprs <- mapM visitType types
-	qname  <- visitQualIdent qident
-	vis    <- getVisibility True qident
-        genFint <- genInterface
-        if genFint && vis == Private 
-          then return []
-          else return [Cons qname (length types) vis texprs]
-
---
-visitType :: IL.Type -> FlatState TypeExpr
-visitType (IL.TypeConstructor qident types)
-   = do texprs <- mapM visitType types
-	qname  <- visitQualTypeIdent qident
-	if (qualName qident) == "Identity"
-	   then return (head texprs)
-	   else return (TCons qname texprs)
-visitType (IL.TypeVariable index)
-   = return (TVar (abs index))
-visitType (IL.TypeArrow type1 type2)
-   = do texpr1 <- visitType type1
-	texpr2 <- visitType type2
-	return (FuncType texpr1 texpr2)
-
---
-visitFuncDecl :: IL.Decl -> FlatState FuncDecl
-visitFuncDecl (IL.FunctionDecl qident params typeexpr expression)
-   = let argtypes = splitoffArgTypes typeexpr params 
-     in do setFunctionId (qident, argtypes)
-           qname <- visitQualIdent qident
-           whenFlatCurry (do is    <- mapM newVarIndex params
-	                     texpr <- visitType typeexpr
-	                     expr  <- visitExpression expression
-	                     vis   <- getVisibility False qident
-	                     clearVarIndices
-	                     return (Func qname (length params) vis texpr (Rule is expr)))
-                         (do texpr <- visitType typeexpr
-	                     clearVarIndices
-	                     return (Func qname (length params) Public texpr (Rule [] (Var $ mkIdx 0))))
-visitFuncDecl (IL.ExternalDecl qident _ name typeexpr)
-   = do setFunctionId (qident, [])
-	texpr <- visitType typeexpr
-	qname <- visitQualIdent qident
-	vis   <- getVisibility False qident
-	xname <- visitExternalName name
-	return (Func qname (typeArity typeexpr) vis texpr (External xname))
-visitFuncDecl (IL.NewtypeDecl _ _ _)
-   = do mid <- moduleId 
-	error ("\"" ++ Id.moduleName mid 
-	       ++ "\": newtype declarations are not supported")
-visitFuncDecl _ = internalError "GenFlatCurry: no function declaration"
-
---
-visitExpression :: IL.Expression -> FlatState Expr
-visitExpression (IL.Literal literal)
-   = liftM Lit (visitLiteral literal)
-visitExpression (IL.Variable ident)
-   = liftM Var (lookupVarIndex ident)
-visitExpression (IL.Function qident _)
-   = do arity_ <- lookupIdArity qident
-        qname <- visitQualIdent qident
-	maybe (internalError (funcArity qname))
-	      (\arity -> genFuncCall qname arity [])
-	      arity_
-visitExpression (IL.Constructor qident arity)
-   = do arity_ <- lookupIdArity qident
-        qname <- visitQualIdent qident
-	maybe (internalError (consArity qident))
-	      (\arity -> genConsCall qname arity [])
-	      arity_
-visitExpression (IL.Apply e1 e2)
-   = genFlatApplication e1 e2
-visitExpression (IL.Case r evalannot expression alts)
-   = do ea       <- visitEval evalannot
-	expr     <- visitExpression expression
-	branches <- mapM visitAlt alts
-	return (Case r ea expr branches)
-visitExpression (IL.Or expression1 expression2)
-   = do expr1 <- visitExpression expression1
-	expr2 <- visitExpression expression2
-	checkOverlapping expr1 expr2
-	return (Or expr1 expr2)
-visitExpression (IL.Exist ident expression)
-   = do index <- newVarIndex ident
-	expr  <- visitExpression expression
-	case expr of
-	  Free is expr' -> return (Free (index:is) expr')
-	  _             -> return (Free [index] expr)
-visitExpression (IL.Let binding expression)
-   = do beginScope
-	newVarIndex (bindingIdent binding)
-        bind <- visitBinding binding
-	expr <- visitExpression expression
-        -- is it correct that there is no endScope? (hsi)
-        return (Let [bind] expr)
-visitExpression (IL.Letrec bindings expression)
-   = do beginScope
-	mapM_ (newVarIndex . bindingIdent) bindings
-	binds <- mapM visitBinding bindings
-	expr  <- visitExpression expression
-	endScope
-	return (Let binds expr)
-
-
---
-visitLiteral :: IL.Literal -> FlatState Literal
-visitLiteral (IL.Char rs c)  = return (Charc rs c)
-visitLiteral (IL.Int rs i)   = return (Intc rs i)
-visitLiteral (IL.Float rs f) = return (Floatc rs f)
-
---
-visitAlt :: IL.Alt -> FlatState BranchExpr
-visitAlt (IL.Alt cterm expression)
-   = do patt <- visitConstrTerm cterm
-	expr <- visitExpression expression
-	return (Branch patt expr)
-
---
-visitConstrTerm :: IL.ConstrTerm -> FlatState Pattern
-visitConstrTerm (IL.LiteralPattern literal)
-   = do lit <- visitLiteral literal
-	return (LPattern lit)
-visitConstrTerm (IL.ConstructorPattern qident args)
-   = do is    <- mapM newVarIndex args
-	qname <- visitQualIdent qident
-	return (Pattern qname is)
-visitConstrTerm (IL.VariablePattern ident)
-   = do mid <- moduleId
-	error ("\"" ++ Id.moduleName mid 
-	       ++ "\": variable patterns are not supported")
-
---
-visitEval :: IL.Eval -> FlatState CaseType
-visitEval IL.Rigid = return Rigid
-visitEval IL.Flex  = return Flex
-
---
-visitBinding :: IL.Binding -> FlatState (VarIndex, Expr)
-visitBinding (IL.Binding ident expression)
-   = do index <- lookupVarIndex ident
-	expr  <- visitExpression expression
-	return (index, expr)
-
-
--------------------------------------------------------------------------------
-
---
-visitFuncIDecl :: CS.IDecl -> FlatState FuncDecl
-visitFuncIDecl (CS.IFunctionDecl _ qident arity typeexpr)
-   = do texpr <- visitType (fst (cs2ilType [] typeexpr))
-	qname <- visitQualIdent qident
-	return (Func qname arity Public texpr (Rule [] (Var $ mkIdx 0)))
-visitFuncIDecl _ = internalError "GenFlatCurry: no function interface"
-
---
-visitTypeIDecl :: CS.IDecl -> FlatState TypeDecl
-visitTypeIDecl (CS.IDataDecl _ qident params constrs_)
-   = do let mid = fromMaybe (internalError "GenFlatCurry: no module name")
-		            (qualidMod qident)
-	    is  = [0 .. length params - 1]
-	cdecls <- mapM (visitConstrIDecl mid (zip params is)) 
-		       (catMaybes constrs_)
-	qname  <- visitQualTypeIdent qident
-	return (Type qname Public is cdecls)
-visitTypeIDecl (CS.ITypeDecl _ qident params typeexpr)
-   = do let is = [0 .. (length params) - 1]
-	texpr <- visitType (fst (cs2ilType (zip params is) typeexpr))
-	qname <- visitQualTypeIdent qident
-	return (TypeSyn qname Public is texpr)
-visitTypeIDecl _ = internalError "GenFlatCurry: no type interface"
-
---
-visitConstrIDecl :: ModuleIdent -> [(Ident, Int)] -> CS.ConstrDecl 
-		    -> FlatState ConsDecl
-visitConstrIDecl mid tis (CS.ConstrDecl _ _ ident typeexprs)
-   = do texprs <- mapM (visitType . (fst . cs2ilType tis)) typeexprs
-	qname  <- visitQualIdent (qualifyWith mid ident)
-	return (Cons qname (length typeexprs) Public texprs)
-visitConstrIDecl mid tis (CS.ConOpDecl pos ids type1 ident type2)
-   = visitConstrIDecl mid tis (CS.ConstrDecl pos ids ident [type1,type2])
-
---
-visitOpIDecl :: CS.IDecl -> FlatState OpDecl
-visitOpIDecl (CS.IInfixDecl _ fixity prec qident)
-   = do let fix = case fixity of
-	            CS.InfixL -> InfixlOp
-		    CS.InfixR -> InfixrOp
-		    _         -> InfixOp
-        qname <- visitQualIdent qident
-	return (Op qname fix prec)
-
-
--------------------------------------------------------------------------------
-
---
-visitModuleIdent :: ModuleIdent -> FlatState String
-visitModuleIdent = return . Id.moduleName
-
---
-visitQualIdent :: QualIdent -> FlatState QName
-visitQualIdent qident
-   = do mid <- moduleId
-	let (mmod, ident) = (qualidMod qident, qualidId qident)
-	    mod | elem ident [listId, consId, nilId, unitId] || isTupleId ident
-		  = Id.moduleName preludeMIdent
-		| otherwise
-		  = maybe (Id.moduleName mid) Id.moduleName mmod
-        ftype <- lookupIdType qident
-	return (QName Nothing ftype mod $ name ident)
-
--- This variant of visitQualIdent does not look up the type of the identifier,
--- which is wise when the identifier is bound to a type, because looking up
--- the type of a type via lookupIdType will get stuck in an endless loop. (hsi)
-visitQualTypeIdent :: QualIdent -> FlatState QName
-visitQualTypeIdent qident
-   = do mid <- moduleId
-	let (mmod, ident) = (qualidMod qident, qualidId qident)
-	    mod | elem ident [listId, consId, nilId, unitId] || isTupleId ident
-		  = Id.moduleName preludeMIdent
-		| otherwise
-		  = maybe (Id.moduleName mid) Id.moduleName mmod
-	return (QName Nothing Nothing mod $ name ident)
-
---
-visitExternalName :: String -> FlatState String
-visitExternalName name 
-   = moduleId >>= \mid -> return (Id.moduleName mid ++ "." ++ name)
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
---
-getVisibility :: Bool -> QualIdent -> FlatState Visibility
-getVisibility isConstr qident
-   = do public <- isPublic isConstr qident
-	if public then return Public else return Private
-
-
---
-getExportedImports :: FlatState [CS.IDecl]
-getExportedImports
-   = do mid  <- moduleId
-	exps <- exports
-	genExportedIDecls (Map.toList (getExpImports mid Map.empty exps))
-
---
-getExpImports :: ModuleIdent -> Map.Map ModuleIdent [CS.Export] -> [CS.Export]
-		 -> Map.Map ModuleIdent [CS.Export]
-getExpImports mident expenv [] = expenv
-getExpImports mident expenv ((CS.Export qident):exps)
-   = getExpImports mident 
-	           (bindExpImport mident qident (CS.Export qident) expenv) 
-		   exps
-getExpImports mident expenv ((CS.ExportTypeWith qident idents):exps)
-   = getExpImports mident 
-		   (bindExpImport mident 
-		                  qident 
-		                  (CS.ExportTypeWith qident idents) 
-		                  expenv)
-		   exps
-getExpImports mident expenv ((CS.ExportTypeAll qident):exps)
-   = getExpImports mident 
-	 	   (bindExpImport mident qident (CS.ExportTypeAll qident) expenv) 
-		   exps
-getExpImports mident expenv ((CS.ExportModule mident'):exps)
-   = getExpImports mident (Map.insert mident' [] expenv) exps
-
---
-bindExpImport :: ModuleIdent -> QualIdent -> CS.Export 
-	         -> Map.Map ModuleIdent [CS.Export] -> Map.Map ModuleIdent [CS.Export]
-bindExpImport mident qident export expenv
-   | isJust (localIdent mident qident)
-     = expenv
-   | otherwise
-     = let (Just mod) = qualidMod qident
-       in  maybe (Map.insert mod [export] expenv)
-	         (\es -> Map.insert mod (export:es) expenv) 
-		 (Map.lookup mod expenv)
-
---
-genExportedIDecls :: [(ModuleIdent,[CS.Export])] -> FlatState [CS.IDecl]
-genExportedIDecls mes = genExpIDecls [] mes
-
---
-genExpIDecls :: [CS.IDecl] -> [(ModuleIdent,[CS.Export])] -> FlatState [CS.IDecl]
-genExpIDecls idecls [] = return idecls
-genExpIDecls idecls ((mid,exps):mes)
-   = do intf_ <- lookupModuleIntf mid
-	let idecls' = maybe idecls (p_genExpIDecls mid idecls exps) intf_
-	genExpIDecls idecls' mes
- where
-   p_genExpIDecls mid idecls exps intf
-      | null exps = (map (qualifyIDecl mid) intf) ++ idecls
-      | otherwise = (filter (isExportedIDecl exps) 
-		            (map (qualifyIDecl mid) intf))
-		    ++ idecls
-
--- 
-isExportedIDecl :: [CS.Export] -> CS.IDecl -> Bool
-isExportedIDecl exports (CS.IInfixDecl _ _ _ qident)
-   = isExportedQualIdent qident exports
-isExportedIDecl exports (CS.IDataDecl _ qident _ _)
-   = isExportedQualIdent qident exports
-isExportedIDecl exports (CS.ITypeDecl _ qident _ _)
-   = isExportedQualIdent qident exports
-isExportedIDecl exports (CS.IFunctionDecl _ qident _ _)
-   = isExportedQualIdent qident exports
-isExportedIDecl exports _
-   = False
-
---
-isExportedQualIdent :: QualIdent -> [CS.Export] -> Bool
-isExportedQualIdent qident [] = False
-isExportedQualIdent qident ((CS.Export qident'):exps)
-   = qident == qident' || isExportedQualIdent qident exps
-isExportedQualIdent qident ((CS.ExportTypeWith qident' idents):exps)
-   = qident == qident' || isExportedQualIdent qident exps
-isExportedQualIdent qident ((CS.ExportTypeAll qident'):exps)
-   = qident == qident' || isExportedQualIdent qident exps
-isExportedQualIdent qident ((CS.ExportModule _):exps)
-   = isExportedQualIdent qident exps
-
---
-qualifyIDecl :: ModuleIdent -> CS.IDecl -> CS.IDecl
-qualifyIDecl mident (CS.IInfixDecl pos fix prec qident)
-   = (CS.IInfixDecl pos fix prec (qualQualify mident qident))
-qualifyIDecl mident (CS.IDataDecl pos qident idents cdecls)
-   = (CS.IDataDecl pos (qualQualify mident qident) idents cdecls)
-qualifyIDecl mident (CS.INewtypeDecl pos qident idents ncdecl)
-   = (CS.INewtypeDecl pos (qualQualify mident qident) idents ncdecl)
-qualifyIDecl mident (CS.ITypeDecl pos qident idents texpr)
-   = (CS.ITypeDecl pos (qualQualify mident qident) idents texpr)
-qualifyIDecl mident (CS.IFunctionDecl pos qident arity texpr)
-   = (CS.IFunctionDecl pos (qualQualify mident qident) arity texpr)
-qualifyIDecl _ idecl = idecl
-
-
---
-typeArity :: IL.Type -> Int
-typeArity (IL.TypeArrow _ t)       = 1 + (typeArity t)
-typeArity (IL.TypeConstructor _ _) = 0
-typeArity (IL.TypeVariable _)      = 0
-
-
--------------------------------------------------------------------------------
-
---
-genFlatApplication :: IL.Expression -> IL.Expression -> FlatState Expr
-genFlatApplication e1 e2
-   = genFlatApplic [e2] e1
- where
-   genFlatApplic args expression 
-      = case expression of
-	  (IL.Apply expr1 expr2)    
-	      -> genFlatApplic (expr2:args) expr1
-	  (IL.Function qident _)
-	      -> do arity_ <- lookupIdArity qident
-                    qname <- visitQualIdent qident
-		    maybe (internalError (funcArity qident))
-			  (\arity -> genFuncCall qname arity args)
-			  arity_
-	  (IL.Constructor qident _)
-	      -> do arity_ <- lookupIdArity qident
-                    qname <- visitQualIdent qident
-		    maybe (internalError (consArity qident))
-			  (\arity -> genConsCall qname arity args)
-			  arity_
-	  _   -> do expr <- visitExpression expression
-		    genApplicComb expr args
-
---
-genFuncCall :: QName -> Int -> [IL.Expression] -> FlatState Expr
-genFuncCall qname arity args
-   | arity > cnt 
-     = genComb qname args (FuncPartCall (arity - cnt))
-   | arity < cnt 
-     = do let (funcargs, applicargs) = splitAt arity args
-	  funccall <- genComb qname funcargs FuncCall
-	  genApplicComb funccall applicargs
-   | otherwise   
-     = genComb qname args FuncCall
- where cnt = length args
-
---
-genConsCall :: QName -> Int -> [IL.Expression] -> FlatState Expr
-genConsCall qname arity args
-   | arity > cnt 
-     = genComb qname args (ConsPartCall (arity - cnt))
-   | arity < cnt
-     = do let (funcargs, applicargs) = splitAt arity args
-	  conscall <- genComb qname funcargs ConsCall
-	  genApplicComb conscall applicargs
-   | otherwise 
-     = genComb qname args ConsCall 
- where cnt = length args
-
---
-genComb :: QName -> [IL.Expression] -> CombType -> FlatState Expr
-genComb qname args combtype
-   = do exprs <- mapM visitExpression args
-	return (Comb combtype qname exprs)
-	 
---
-genApplicComb :: Expr -> [IL.Expression] -> FlatState Expr
-genApplicComb expr [] = return expr
-genApplicComb expr (e1:es)
-   = do expr1 <- visitExpression e1
-	qname <- visitQualIdent qidApply
-	genApplicComb (Comb FuncCall qname [expr, expr1]) es
- where
- qidApply = qualifyWith preludeMIdent (mkIdent "apply")
-
-
---
-genOpDecls :: FlatState [OpDecl]
-genOpDecls = fixities >>= mapM genOpDecl
-
---
-genOpDecl :: CS.IDecl -> FlatState OpDecl
-genOpDecl (CS.IInfixDecl _ fixity prec qident)
-   = do qname <- visitQualIdent qident
-	return (Op qname (p_genOpFixity fixity) prec)
- where
-   p_genOpFixity CS.InfixL = InfixlOp
-   p_genOpFixity CS.InfixR = InfixrOp
-   p_genOpFixity CS.Infix  = InfixOp
-genOpDecl _ = internalError "GenFlatCurry: no infix interface"
-
-
--- The intermediate language (IL) does not represent type synonyms
--- (and also no record declarations). For this reason an interface
--- representation of all type synonyms is generated (see "CurryEnv")
--- from the abstract syntax representation of the Curry program.
--- The function 'typeSynonyms' returns this list of type synonyms.
-genTypeSynonyms ::  FlatState [TypeDecl]
-genTypeSynonyms = typeSynonyms >>= mapM genTypeSynonym
-
---
-genTypeSynonym :: CS.IDecl -> FlatState TypeDecl
-genTypeSynonym (CS.ITypeDecl _ qident params typeexpr)
-   = do let is = [0 .. (length params) - 1]
-        tyEnv <- gets typeEnvE
-        tcEnv <- gets tConsEnvE
-	let typeexpr' = elimRecordTypes tyEnv tcEnv typeexpr
-	texpr <- visitType (fst (cs2ilType (zip params is) typeexpr'))
-	qname <- visitQualTypeIdent qident
-	vis   <- getVisibility False qident
-	return (TypeSyn qname vis is texpr)
-genTypeSynonym _ = internalError "GenFlatCurry: no type synonym interface"
-
-
--- In order to provide an interface for record declarations, 'genRecordTypes'
--- generates dummy data declarations representing records together
--- with their typed labels. For the record declaration
---
---      type Rec = {l_1 :: t_1,..., l_n :: t_n}
---
--- the following data declaration will be generated:
---
---      data Rec' = l_1' t_1 | ... | l_n' :: t_n
---
--- Rec' and l_i' are unique idenfifiers which encode the original names
--- Rec and l_i.
--- When reading an interface file containing such declarations, it is
--- now possible to reconstruct the original record declaration. Since
--- usual FlatCurry code is used, these declaration should not have any
--- effects on the behaviour of the Curry program. But to ensure correctness,
--- these dummies should be generated for the interface file as well as for
--- the corresponding FlatCurry file.
-genRecordTypes :: FlatState [TypeDecl]
-genRecordTypes = records >>= mapM genRecordType
-
---
-genRecordType :: CS.IDecl -> FlatState TypeDecl
-genRecordType (CS.ITypeDecl _ qident params (CS.RecordType fields _))
-   = do let is = [0 .. (length params) - 1]
-	    (mod,ident) = (qualidMod qident, qualidId qident)
-	qname <- visitQualIdent ((maybe qualify qualifyWith mod) 
-				 (recordExtId ident))
-	labels <- mapM (genRecordLabel mod (zip params is)) fields
-	return (Type qname Public is labels)
-
---
-genRecordLabel :: Maybe ModuleIdent -> [(Ident,Int)] -> ([Ident],CS.TypeExpr) 
-	       -> FlatState ConsDecl
-genRecordLabel mod vis ([ident],typeexpr)
-   = do tyEnv <- gets typeEnvE
-        tcEnv <- gets tConsEnvE
-	let typeexpr' = elimRecordTypes tyEnv tcEnv typeexpr
-        texpr <- visitType (fst (cs2ilType vis typeexpr'))
-	qname <- visitQualIdent ((maybe qualify qualifyWith mod) 
-				 (labelExtId ident))
-	return (Cons qname 1 Public [texpr])
-
-
--------------------------------------------------------------------------------
-
--- FlatCurry provides no possibility of representing record types like
--- {l_1::t_1, l_2::t_2, ..., l_n::t_n}. So they have to be transformed to
--- to the corresponding type constructors which are defined in the record 
--- declarations. 
--- Unlike data declarations or function type annotations, type synonyms and
--- record declarations are not generated from the intermediate language.
--- So the transformation has only to be performed in these cases.
-elimRecordTypes :: ValueEnv -> TCEnv -> CS.TypeExpr -> CS.TypeExpr
-elimRecordTypes tyEnv tcEnv (CS.ConstructorType qid typeexprs)
-   = CS.ConstructorType qid (map (elimRecordTypes tyEnv tcEnv) typeexprs)
-elimRecordTypes tyEnv tcEnv (CS.VariableType id)
-   = CS.VariableType id
-elimRecordTypes tyEnv tcEnv (CS.TupleType typeexprs)
-   = CS.TupleType (map (elimRecordTypes tyEnv tcEnv) typeexprs)
-elimRecordTypes tyEnv tcEnv (CS.ListType typeexpr)
-   = CS.ListType (elimRecordTypes tyEnv tcEnv typeexpr)
-elimRecordTypes tyEnv tcEnv (CS.ArrowType typeexpr1 typeexpr2)
-   = CS.ArrowType (elimRecordTypes tyEnv tcEnv typeexpr1)
-                  (elimRecordTypes tyEnv tcEnv typeexpr2)
-elimRecordTypes tyEnv tcEnv (CS.RecordType fss _)
-   = let fs = flattenRecordTypeFields fss
-     in  case (lookupValue (fst (head fs)) tyEnv) of
-  	   [Label _ record _] ->
-	     case (qualLookupTC record tcEnv) of
-	       [AliasType _ n (TypeRecord fs' _)] ->
-	         let ms = foldl (matchTypeVars fs) Map.empty fs'
-		     types = map (\i -> maybe 
-			 	          (CS.VariableType 
-					     (mkIdent ("#tvar" ++ show i)))
-				          (elimRecordTypes tyEnv tcEnv)
-				          (Map.lookup i ms))
-			         [0 .. n-1]
-	         in  CS.ConstructorType record types
-	       _ -> internalError ("GenFlatCurry.elimRecordTypes: "
-		 		   ++ "no record type")
-	   _ -> internalError ("GenFlatCurry.elimRecordTypes: "
-			       ++ "no label")
-
-matchTypeVars :: [(Ident,CS.TypeExpr)] -> Map.Map Int CS.TypeExpr
-	      -> (Ident, Type) -> Map.Map Int CS.TypeExpr
-matchTypeVars fs ms (l,ty)
-   = maybe ms (match ms ty) (lookup l fs)
-  where
-  match ms (TypeVariable i) typeexpr = Map.insert i typeexpr ms
-  match ms (TypeConstructor _ tys) (CS.ConstructorType _ typeexprs)
-     = matchList ms tys typeexprs
-  match ms (TypeConstructor _ tys) (CS.ListType typeexpr)
-     = matchList ms tys [typeexpr]
-  match ms (TypeConstructor _ tys) (CS.TupleType typeexprs)
-     = matchList ms tys typeexprs
-  match ms (TypeArrow ty1 ty2) (CS.ArrowType typeexpr1 typeexpr2)
-     = matchList ms [ty1,ty2] [typeexpr1,typeexpr2]
-  match ms (TypeRecord fs' _) (CS.RecordType fss _)
-     = foldl (matchTypeVars (flattenRecordTypeFields fss)) ms fs'
-  match ms ty typeexpr
-     = internalError ("GenFlatCurry.matchTypeVars: "
-		      ++ show ty ++ "\n" ++ show typeexpr)
-
-  matchList ms tys
-     = foldl (\ms' (ty,typeexpr) -> match ms' ty typeexpr) ms . zip tys
-
-
-flattenRecordTypeFields :: [([Ident],CS.TypeExpr)] -> [(Ident,CS.TypeExpr)]
-flattenRecordTypeFields
-   = concatMap (\ (labels, typeexpr)
-		-> map (\label -> (label,typeexpr)) labels)
-
--------------------------------------------------------------------------------
-
---
-checkOverlapping :: Expr -> Expr -> FlatState ()
-checkOverlapping expr1 expr2
-   = do opts <- compilerOpts
-	unless (noOverlapWarn opts)
-	       (checkOverlap expr1 expr2)
- where
- checkOverlap (Case _ _ _ _) _ 
-    = do qid <- functionId
-	 genWarning (overlappingRules qid)
- checkOverlap _ (Case _ _ _ _)
-    = do qid <- functionId
-	 genWarning (overlappingRules qid)
- checkOverlap _ _ = return ()
-
-
--------------------------------------------------------------------------------
-
--- 
-cs2ilType :: [(Ident,Int)] -> CS.TypeExpr -> (IL.Type, [(Ident,Int)])
-cs2ilType ids (CS.ConstructorType qident typeexprs)
-   = let (ilTypeexprs, ids') = emap cs2ilType ids typeexprs
-     in  (IL.TypeConstructor qident ilTypeexprs, ids')
-cs2ilType ids (CS.VariableType ident)
-   = let mid        = lookup ident ids
-	 nid        | null ids  = 0
-		    | otherwise = 1 + snd (head ids)
-	 (id, ids') | isJust mid = (fromJust mid, ids)
-		    | otherwise  = (nid, (ident, nid):ids)
-     in  (IL.TypeVariable id, ids')
-cs2ilType ids (CS.ArrowType type1 type2)
-   = let (ilType1, ids')  = cs2ilType ids type1
-	 (ilType2, ids'') = cs2ilType ids' type2
-     in  (IL.TypeArrow ilType1 ilType2, ids'')
-cs2ilType ids (CS.ListType typeexpr)
-   = let (ilTypeexpr, ids') = cs2ilType ids typeexpr
-     in  (IL.TypeConstructor (qualify listId) [ilTypeexpr], ids')
-cs2ilType ids (CS.TupleType typeexprs)
-   = case typeexprs of
-       []  -> (IL.TypeConstructor qUnitId [], ids)
-       [t] -> cs2ilType ids t
-       _   -> let (ilTypeexprs, ids') = emap cs2ilType ids typeexprs
-		  tuplen = length ilTypeexprs
-	      in  (IL.TypeConstructor (qTupleId tuplen) ilTypeexprs,
-		   ids')
-cs2ilType _ typeexpr = internalError ("cs2ilType: " ++ show typeexpr)
-
-
--------------------------------------------------------------------------------
--- Messages for internal errors and warnings
-
-funcArity qid = "GenFlatCurry: missing arity for function \"" 
-		++ show qid ++ "\""
-
-consArity qid = "GenFlatCurry: missing arity for constructor \""
-		++ show qid ++ "\""
-
-missingVarIndex id = "GenFlatCurry: missing index for \"" ++ show id ++ "\""
-
-
-overlappingRules qid =  "function \""
-		        ++ qualName qid 
-		        ++ "\" is non-deterministic due to non-trivial "
-		        ++ "overlapping rules"
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
---
-isDataDecl :: IL.Decl -> Bool
-isDataDecl (IL.DataDecl _ _ _) = True
-isDataDecl _                = False
-
---
-isFuncDecl :: IL.Decl -> Bool
-isFuncDecl (IL.FunctionDecl _ _ _ _) = True
-isFuncDecl (IL.ExternalDecl _ _ _ _) = True
-isFuncDecl _                         = False
-
---
-isPublicDataDecl :: IL.Decl -> FlatState Bool
-isPublicDataDecl (IL.DataDecl qident _ _ ) = isPublic False qident
-isPublicDataDecl _                         = return False
-
---
-isPublicFuncDecl :: IL.Decl -> FlatState Bool
-isPublicFuncDecl (IL.FunctionDecl qident _ _ _) = isPublic False qident
-isPublicFuncDecl (IL.ExternalDecl qident _ _ _) = isPublic False qident
-isPublicFuncDecl _                              = return False
-
---
-isTypeIDecl :: CS.IDecl -> Bool
-isTypeIDecl (CS.IDataDecl _ _ _ _) = True
-isTypeIDecl (CS.ITypeDecl _ _ _ _) = True
-isTypeIDecl _                      = False
-
---
-isRecordIDecl :: CS.IDecl -> Bool
-isRecordIDecl (CS.ITypeDecl _ _ _ (CS.RecordType (_:_) _)) = True
-isRecordIDecl _                                            = False
-
---
-isFuncIDecl :: CS.IDecl -> Bool
-isFuncIDecl (CS.IFunctionDecl _ _ _ _) = True
-isFuncIDecl _                          = False
-
---
-isOpIDecl :: CS.IDecl -> Bool
-isOpIDecl (CS.IInfixDecl _ _ _ _) = True
-isOpIDecl _                       = False 
-
-
---
-bindingIdent :: IL.Binding -> Ident
-bindingIdent (IL.Binding ident _) = ident
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
-emap :: (e -> a -> (b,e)) -> e -> [a] -> ([b], e)
-emap _ env []     = ([], env)
-emap f env (x:xs) = let (x',env')    = f env x
-			(xs', env'') = emap f env' xs
-		    in  ((x':xs'), env'')
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
---
-moduleId :: FlatState ModuleIdent
-moduleId = gets moduleIdE
-
---
-functionId :: FlatState QualIdent
-functionId = gets (fst . functionIdE)
-
---
-setFunctionId :: (QualIdent, [(Ident, IL.Type)]) -> FlatState ()
-setFunctionId qid = modify (\env -> env{ functionIdE = qid })
-
---
-compilerOpts :: FlatState Options
-compilerOpts = gets compilerOptsE
-
---
-exports :: FlatState [CS.Export]
-exports = gets exportsE
-
---
-imports :: FlatState [CS.IDecl]
-imports = gets importsE
-
---
-records :: FlatState [CS.IDecl]
-records = gets (filter isRecordIDecl . interfaceE)
-
---
-fixities :: FlatState [CS.IDecl]
-fixities = gets fixitiesE
-
---
-typeSynonyms :: FlatState [CS.IDecl]
-typeSynonyms = gets typeSynonymsE
-
---
-isPublic :: Bool -> QualIdent -> FlatState Bool
-isPublic isConstr qid = gets (\env -> maybe False isP
-                                      (Map.lookup (unqualify qid) 
-                                       (publicEnvE env)))
-  where
-    isP NotConstr = not isConstr
-    isP OnlyConstr = isConstr
-    isP NotOnlyConstr = True
-
---
-lookupModuleIntf :: ModuleIdent -> FlatState (Maybe [CS.IDecl])
-lookupModuleIntf mid
-   = gets (Map.lookup mid . moduleEnvE)
-
---
-lookupIdArity :: QualIdent -> FlatState (Maybe Int)
-lookupIdArity qid
-   = gets (lookupA qid . arityEnvE)
- where
- lookupA qid aEnv = case (qualLookupArity qid aEnv) of
-		      [ArityInfo _ a]
-		         -> Just a
-		      [] -> case (lookupArity (unqualify qid) aEnv) of
-			      [ArityInfo _ a] -> Just a
-			      _               -> Nothing
-		      _  -> Nothing
-
-
-
-getTypeOf :: Ident -> FlatState (Maybe TypeExpr)
-getTypeOf ident = do
-    valEnv <- gets typeEnvE 
-    case lookupValue ident valEnv of 
-      Value _ (ForAll _ t) : _ 
-          -> do t <- visitType (ttrans t)
-                trace' ("getTypeOf(" ++ show ident ++ ") = " ++ show t)$
-                       return (Just t)
-      DataConstructor _ (ForAllExist _ _ t):_ 
-          -> do t <- visitType (ttrans t)
-                trace' ("getTypeOfDataCon(" ++ show ident ++ ") = " ++ show t)$
-                       return (Just t)
-      _   -> do (_,ats) <- gets functionIdE
-                case lookup ident ats of
-                  Just t -> liftM Just (visitType t)
-                  Nothing -> trace' ("lookupValue did not return a value for index " ++ show ident)
-                             (return Nothing)
-ttrans :: Type -> IL.Type 
-ttrans (TypeConstructor i ts)
-    = IL.TypeConstructor i (map ttrans ts)
-ttrans (TypeVariable v)
-    = IL.TypeVariable v
-ttrans (TypeConstrained [] v)
-    = IL.TypeVariable v
-ttrans (TypeConstrained (v:_) i)
-    = ttrans v
-ttrans (TypeArrow f x) = IL.TypeArrow (ttrans f) (ttrans x)
-ttrans s@(TypeSkolem _) = error $ "in ttrans: " ++ show s
-ttrans s@(TypeRecord _ _) = error $ "in ttrans: " ++ show s
-
-
-
--- Constructor (:) receives special treatment throughout the
--- whole implementation. We won't depart from that for mere
--- aesthetic reasons. (hsi)
-lookupIdType :: QualIdent -> FlatState (Maybe TypeExpr)
-lookupIdType (QualIdent Nothing (Ident _ "[]" _))
-    = return (Just l0)
-      where l0 = TCons (mkQName ("Prelude", "[]")) [TVar 0]
-lookupIdType (QualIdent Nothing (Ident _ ":" _))
-    = return (Just (FuncType (TVar 0) (FuncType (l0) (l0))))
-      where l0 = TCons (mkQName ("Prelude", "[]")) [TVar 0]
-lookupIdType (QualIdent Nothing (Ident _ "()" _))
-    = return (Just l0)
-      where l0 = TCons (mkQName ("Prelude", "()")) []
-lookupIdType (QualIdent Nothing (Ident _ t@('(':',':r) _))
-    = return (Just funtype)
-      where tupleArity = length r + 1
-            argTypes   = map TVar [1..tupleArity]
-            contype    = TCons (mkQName ("Prelude", t)) argTypes
-            funtype    = foldr FuncType contype argTypes
-lookupIdType qid
-   = do aEnv <- gets typeEnvE
-        lt <- gets localTypes
-        ct <- gets constrTypes
-        case Map.lookup qid lt `mplus` Map.lookup qid ct of
-          Just t -> trace' ("lookupIdType local " ++ show (qid, t)) $ liftM Just (visitType t)  -- local name or constructor
-          Nothing -> case [ t | Value _ (ForAll _ t) <- qualLookupValue qid aEnv ] of 
-                       t : _ -> liftM Just (visitType (IL.translType t))  -- imported name
-                       []    -> case qualidMod qid of
-                                  Nothing -> trace' ("no type for "  ++ show qid) $ return Nothing  -- no known type
-                                  Just _ -> lookupIdType qid {qualidMod = Nothing}
--- 
-
--- Generates a new index for a variable
-newVarIndex :: Ident -> FlatState VarIndex
-newVarIndex ident
-   = do idx0 <- gets varIndexE
-        ty <- getTypeOf ident
-        let idx = idx0 + 1
-            vid = VarIndex ty idx
-        vids <- gets varIdsE
-        modify (\env -> env{ varIndexE = idx,
-			     varIdsE   = ScopeEnv.insert ident vid vids
-			   })
-        return vid
-
---
-lookupVarIndex :: Ident -> FlatState VarIndex
-lookupVarIndex id
-   = do index_ <- gets (ScopeEnv.lookup id . varIdsE)
-        maybe (internalError (missingVarIndex id)) return index_
-
---
-clearVarIndices :: FlatState ()
-clearVarIndices = modify (\env -> env { varIndexE = 0,
-				        varIdsE = ScopeEnv.new 
-				      })
-
---
-genWarning :: String -> FlatState ()
-genWarning msg
-   = modify (\env -> env{ messagesE = warnMsg:(messagesE env) })
-    where warnMsg = WarnMsg Nothing msg
-
---
-genInterface :: FlatState Bool
-genInterface = gets genInterfaceE
-
---
-beginScope :: FlatState ()
-beginScope = modify
-	       (\env -> env { varIdsE  = ScopeEnv.beginScope (varIdsE env)
-			    })
-
---
-endScope :: FlatState ()
-endScope = modify
-	     (\env -> env { varIdsE  = ScopeEnv.endScope (varIdsE env)
-			  })
-
---
-whenFlatCurry :: FlatState a -> FlatState a -> FlatState a
-whenFlatCurry genFlat genIntf 
-   = genInterface >>= (\intf -> if intf then genIntf else genFlat)
-
-
--------------------------------------------------------------------------------
-
--- Generates an evironment containing all public identifiers from the module
--- Note: Currently the record functions (selection and update) for all public 
--- record labels are inserted into the environment, though they are not
--- explicitly declared in the export specifications.
-genPubEnv :: ModuleIdent -> [CS.IDecl] -> Map.Map Ident IdentExport
-genPubEnv mid idecls = foldl (bindEnvIDecl mid) Map.empty idecls
-
-bindIdentExport :: Ident -> Bool -> Map.Map Ident IdentExport -> Map.Map Ident IdentExport
-bindIdentExport id isConstr env =
-    maybe (Map.insert id (if isConstr then OnlyConstr else NotConstr) env)
-          (\ ie -> Map.insert id (updateIdentExport ie isConstr) env)
-          (Map.lookup id env)
-  where
-    updateIdentExport OnlyConstr True  = OnlyConstr
-    updateIdentExport OnlyConstr False = NotOnlyConstr
-    updateIdentExport NotConstr True   = NotOnlyConstr
-    updateIdentExport NotConstr False  = NotConstr
-    updateIdentExport NotOnlyConstr _  = NotOnlyConstr
-
-
---
-bindEnvIDecl :: ModuleIdent -> Map.Map Ident IdentExport -> CS.IDecl -> Map.Map Ident IdentExport
-bindEnvIDecl mid env (CS.IDataDecl _ qid _ mcdecls)
-   = maybe env 
-           (\id -> foldl bindEnvConstrDecl
-	                 (bindIdentExport id False env)
-	                 (catMaybes mcdecls))
-	   (localIdent mid qid)
-bindEnvIDecl mid env (CS.INewtypeDecl _ qid _ ncdecl)
-   = maybe env 
-           (\id -> bindEnvNewConstrDecl (bindIdentExport id False env) ncdecl)
-	   (localIdent mid qid)
-bindEnvIDecl mid env (CS.ITypeDecl _ qid _ texpr)
-   = maybe env (\id -> bindEnvITypeDecl env id texpr) (localIdent mid qid)
-bindEnvIDecl mid env (CS.IFunctionDecl _ qid _ _)
-   = maybe env (\id -> bindIdentExport id False env) (localIdent mid qid)
-bindEnvIDecl _ env _ = env
-
---
-bindEnvITypeDecl :: Map.Map Ident IdentExport -> Ident -> CS.TypeExpr
-		    -> Map.Map Ident IdentExport
-bindEnvITypeDecl env id (CS.RecordType fs _)
-   = bindIdentExport id False (foldl (bindEnvRecordLabel id) env fs)
-bindEnvITypeDecl env id texpr
-   = bindIdentExport id False env
-
---
-bindEnvConstrDecl :: Map.Map Ident IdentExport -> CS.ConstrDecl -> Map.Map Ident IdentExport
-bindEnvConstrDecl env (CS.ConstrDecl _ _ id _)  = bindIdentExport id True env
-bindEnvConstrDecl env (CS.ConOpDecl _ _ _ id _) = bindIdentExport id True env
-
---
-bindEnvNewConstrDecl :: Map.Map Ident IdentExport -> CS.NewConstrDecl -> Map.Map Ident IdentExport
-bindEnvNewConstrDecl env (CS.NewConstrDecl _ _ id _) = bindIdentExport id False env
-
---
-bindEnvRecordLabel :: Ident -> Map.Map Ident IdentExport -> ([Ident],CS.TypeExpr) -> Map.Map Ident IdentExport
-bindEnvRecordLabel r env ([lab], _) = bindIdentExport (recSelectorId (qualify r) lab) False expo
-    where 
-      expo = (bindIdentExport (recUpdateId (qualify r) lab) False env)
-
-
-splitoffArgTypes :: IL.Type -> [Ident] -> [(Ident, IL.Type)]
-splitoffArgTypes (IL.TypeArrow l r) (i:is) = (i, l):splitoffArgTypes r is
-splitoffArgTypes _ [] = []
-splitoffArgTypes _ _  = error "internal error in splitoffArgTypes"
-
-
diff --git a/src/Generators.hs b/src/Generators.hs
new file mode 100644
--- /dev/null
+++ b/src/Generators.hs
@@ -0,0 +1,59 @@
+{- |
+    Module      :  $Header$
+    Description :  Code generators
+    Copyright   :  (c) 2011        Björn Peemöller
+                       2017        Finn Teegen
+                       2018        Kai-Oliver Prott
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module subsumes the different code generators.
+-}
+module Generators where
+
+import qualified Curry.AbstractCurry            as AC   (CurryProg)
+import qualified Curry.FlatCurry.Type           as FC   (Prog, TypeExpr)
+import qualified Curry.FlatCurry.Annotated.Type as AFC  (AProg)
+import qualified Curry.FlatCurry.Typed.Type     as TFC  (TProg)
+import qualified Curry.Syntax                   as CS   (Module)
+
+import qualified Generators.GenAbstractCurry    as GAC  (genAbstractCurry)
+import qualified Generators.GenFlatCurry        as GFC  ( genFlatCurry
+                                                        , genFlatInterface
+                                                        )
+import qualified Generators.GenAnnotatedFlatCurry
+                                                as GAFC (genAnnotatedFlatCurry)
+import qualified Generators.GenTypedFlatCurry   as GTFC (genTypedFlatCurry)
+
+import           Base.Types                             (Type, PredType)
+
+import           CompilerEnv                            (CompilerEnv (..))
+import qualified IL                                     (Module)
+
+-- |Generate typed AbstractCurry
+genTypedAbstractCurry :: CompilerEnv -> CS.Module PredType -> AC.CurryProg
+genTypedAbstractCurry = GAC.genAbstractCurry False
+
+-- |Generate untyped AbstractCurry
+genUntypedAbstractCurry :: CompilerEnv -> CS.Module PredType -> AC.CurryProg
+genUntypedAbstractCurry = GAC.genAbstractCurry True
+
+-- |Generate typed FlatCurry
+genTypedFlatCurry :: AFC.AProg FC.TypeExpr -> TFC.TProg
+genTypedFlatCurry = GTFC.genTypedFlatCurry
+
+-- |Generate type-annotated FlatCurry
+genAnnotatedFlatCurry :: CompilerEnv -> CS.Module Type -> IL.Module
+                      -> AFC.AProg FC.TypeExpr
+genAnnotatedFlatCurry = GAFC.genAnnotatedFlatCurry
+
+-- |Generate FlatCurry
+genFlatCurry :: AFC.AProg FC.TypeExpr -> FC.Prog
+genFlatCurry = GFC.genFlatCurry
+
+-- |Generate a FlatCurry interface
+genFlatInterface :: FC.Prog -> FC.Prog
+genFlatInterface = GFC.genFlatInterface
diff --git a/src/Generators/GenAbstractCurry.hs b/src/Generators/GenAbstractCurry.hs
new file mode 100644
--- /dev/null
+++ b/src/Generators/GenAbstractCurry.hs
@@ -0,0 +1,541 @@
+{- |
+    Module      :  $Header$
+    Description :  Generation of AbstractCurry program terms
+    Copyright   :  (c) 2005        Martin Engelke
+                       2011 - 2015 Björn Peemöller
+                       2015        Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module contains the generation of an 'AbstractCurry' program term
+    for a given 'Curry' module.
+-}
+{-# LANGUAGE CPP #-}
+module Generators.GenAbstractCurry (genAbstractCurry) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative          ((<$>), (<*>), pure)
+#endif
+import           Control.Monad.Extra
+import qualified Control.Monad.State as S     (State, evalState, get, gets
+                                              , modify, put, when)
+import qualified Data.Map            as Map   (Map, empty, fromList, lookup
+                                              , union)
+import qualified Data.Maybe          as Maybe (fromJust, fromMaybe, listToMaybe)
+import qualified Data.Set            as Set   (Set, empty, insert, member)
+import qualified Data.Traversable    as T     (forM)
+
+import Curry.AbstractCurry
+import Curry.Base.Ident
+import Curry.Base.SpanInfo
+import Curry.Syntax
+
+import Base.CurryTypes (fromPredType, toType, toPredType)
+import Base.Expr       (bv)
+import Base.Messages   (internalError)
+import Base.NestEnv
+import Base.Types      (arrowArity, PredType, unpredType, TypeScheme (..))
+import Base.TypeSubst
+
+import Env.Value       (ValueEnv, ValueInfo (..), qualLookupValue)
+import Env.OpPrec      (mkPrec)
+
+import CompilerEnv
+
+type GAC a = S.State AbstractEnv a
+
+-- ---------------------------------------------------------------------------
+-- Interface
+-- ---------------------------------------------------------------------------
+
+-- |Generate an AbstractCurry program term from the syntax tree
+--  when uacy flag is set untype AbstractCurry is generated
+genAbstractCurry :: Bool -> CompilerEnv -> Module PredType -> CurryProg
+genAbstractCurry uacy env mdl
+  = S.evalState (trModule mdl) (abstractEnv uacy env mdl)
+
+-- ---------------------------------------------------------------------------
+-- Conversion from Curry to AbstractCurry
+-- ---------------------------------------------------------------------------
+
+trModule :: Module PredType -> GAC CurryProg
+trModule (Module _ _ _ mid _ is ds) =
+  CurryProg mid' is' <$> dflt' <*> cds' <*> ids' <*> ts' <*> fs' <*> os'
+  where
+  mid'  = moduleName mid
+  is'   = map cvImportDecl is
+  dflt' = Maybe.listToMaybe <$> concatMapM (withLocalEnv . trDefaultDecl) ds
+  cds'  = concatMapM (withLocalEnv . trClassDecl) ds
+  ids'  = concatMapM (withLocalEnv . trInstanceDecl) ds
+  ts'   = concatMapM (withLocalEnv . trTypeDecl) ds
+  fs'   = concatMapM (withLocalEnv . trFuncDecl True) ds
+  os'   = concatMapM (withLocalEnv . trInfixDecl) ds
+
+cvImportDecl :: ImportDecl -> String
+cvImportDecl (ImportDecl _ mid _ _ _) = moduleName mid
+
+trDefaultDecl :: Decl a -> GAC [CDefaultDecl]
+trDefaultDecl (DefaultDecl _ tys) = (\tys' -> [CDefaultDecl tys'])
+  <$> mapM trTypeExpr tys
+trDefaultDecl _                   = return []
+
+trClassDecl :: Decl PredType -> GAC [CClassDecl]
+trClassDecl (ClassDecl _ _ cx cls tv ds) =
+  (\cls' v' cx' tv' ds' -> [CClass cls' v' cx' tv' ds'])
+    <$> trGlobalIdent cls <*> getTypeVisibility cls <*> trContext cx
+    <*> getTVarIndex tv <*> concatMapM (trClassMethodDecl sigs fs) ds
+  where fs = [f | FunctionDecl _ _ f _ <- ds]
+        sigs = signatures ds
+trClassDecl _ = return []
+
+-- We ignore type signatures for class methods with a given default
+-- implementation as declarations for those are generated anyway.
+-- For function declarations we use the equation's arity instead of
+-- the one from the value environment or 0.
+trClassMethodDecl :: [(Ident, QualTypeExpr)] -> [Ident] -> Decl PredType
+                  -> GAC [CFuncDecl]
+trClassMethodDecl sigs fs (TypeSig p [f] _) | f `notElem` fs =
+  trClassMethodDecl sigs fs $ FunctionDecl p undefined f []
+trClassMethodDecl sigs fs (TypeSig p (f:f':fs') qty) =
+  liftM2 (++) (trClassMethodDecl sigs fs $ TypeSig p [f] qty)
+              (trClassMethodDecl sigs fs $ TypeSig p (f':fs') qty)
+trClassMethodDecl sigs _ (FunctionDecl _ _ f eqs) =
+  (\f' a v ty rs -> [CFunc f' a v ty rs]) <$> trGlobalIdent f
+  <*> pure (maybe 0 eqnArity $ Maybe.listToMaybe eqs)
+  <*> getVisibility (unRenameIdent f)
+  <*> trQualTypeExpr (Maybe.fromJust $ lookup f sigs) <*> mapM trEquation eqs
+trClassMethodDecl _ _ _ = return []
+
+trInstanceDecl :: Decl PredType -> GAC [CInstanceDecl]
+trInstanceDecl (InstanceDecl _ _ cx qcls ty ds) =
+  (\qcls' cx' ty' ds' -> [CInstance qcls' cx' ty' ds']) <$> trQual qcls
+  <*> trContext cx <*> trTypeExpr ty <*> mapM (trInstanceMethodDecl qcls ty) ds
+trInstanceDecl _ = return []
+
+-- Again, we use the equation's arity for function declarations instead of
+-- the one from the value.
+trInstanceMethodDecl :: QualIdent -> TypeExpr -> Decl PredType -> GAC CFuncDecl
+trInstanceMethodDecl qcls ty (FunctionDecl _ _ f eqs) = do
+  uacy <- S.gets untypedAcy
+  qty <- if uacy
+           then return $ QualTypeExpr NoSpanInfo [] $
+                           ConstructorType NoSpanInfo prelUntyped
+           else getQualType' (qualifyLike qcls $ unRenameIdent f)
+  CFunc <$> trLocalIdent f <*> pure (eqnArity $ head eqs) <*> pure Public
+        <*> trInstanceMethodType ty qty <*> mapM trEquation eqs
+trInstanceMethodDecl _ _ _ = internalError "GenAbstractCurry.trInstanceMethodDecl"
+
+-- Transforms a class method type into an instance method's type by replacing
+-- the class variable with the given instance type. The implicit class context
+-- is dropped in doing so.
+trInstanceMethodType :: TypeExpr -> QualTypeExpr -> GAC CQualTypeExpr
+trInstanceMethodType ity (QualTypeExpr _ cx ty) =
+  trQualTypeExpr $ fromPredType identSupply $
+    subst (bindSubst 0 (toType [] ity) idSubst) $
+      toPredType (take 1 identSupply) $ QualTypeExpr NoSpanInfo (drop 1 cx) ty
+
+trTypeDecl :: Decl a -> GAC [CTypeDecl]
+trTypeDecl (DataDecl    _ t vs cs clss) =
+  (\t' v vs' cs' clss' -> [CType t' v vs' cs' clss'])
+  <$> trGlobalIdent t <*> getTypeVisibility t
+  <*> mapM genTVarIndex vs <*> mapM trConsDecl cs
+  <*> mapM trQual clss
+trTypeDecl (TypeDecl    _ t vs ty) = (\t' v vs' ty' -> [CTypeSyn t' v vs' ty'])
+  <$> trGlobalIdent t <*> getTypeVisibility t
+  <*> mapM genTVarIndex vs <*> trTypeExpr ty
+trTypeDecl (NewtypeDecl _ t vs nc clss) =
+  (\t' v vs' nc' clss' -> [CNewType t' v vs' nc' clss'])
+  <$> trGlobalIdent t <*> getTypeVisibility t
+  <*> mapM genTVarIndex vs <*> trNewConsDecl nc
+  <*> mapM trQual clss
+trTypeDecl (ExternalDataDecl _ t vs) =
+  (\t' v vs' -> [CType t' v vs' [] []])
+  <$> trGlobalIdent t <*> getTypeVisibility t <*> mapM genTVarIndex vs
+trTypeDecl _                       = return []
+
+trConsDecl :: ConstrDecl -> GAC CConsDecl
+trConsDecl (ConstrDecl  _ c tys) = inNestedTScope $ CCons
+  <$> trGlobalIdent c <*> getVisibility c <*> mapM trTypeExpr tys
+trConsDecl (ConOpDecl p ty1 op ty2) = inNestedTScope $ trConsDecl $
+  ConstrDecl p op [ty1, ty2]
+trConsDecl (RecordDecl   _ c fs) = inNestedTScope $ CRecord
+  <$> trGlobalIdent c <*> getVisibility c <*> concatMapM trFieldDecl fs
+
+trFieldDecl :: FieldDecl -> GAC [CFieldDecl]
+trFieldDecl (FieldDecl _ ls ty) = T.forM ls $ \l ->
+  CField <$> trGlobalIdent l <*> getVisibility l <*> trTypeExpr ty
+
+trNewConsDecl :: NewConstrDecl -> GAC CConsDecl
+trNewConsDecl (NewConstrDecl _ nc      ty) = CCons
+  <$> trGlobalIdent nc <*> getVisibility nc <*> ((:[]) <$> trTypeExpr ty)
+trNewConsDecl (NewRecordDecl p nc (l, ty)) = CRecord
+  <$> trGlobalIdent nc <*> getVisibility nc <*> trFieldDecl (FieldDecl p [l] ty)
+
+trTypeExpr :: TypeExpr -> GAC CTypeExpr
+trTypeExpr (ConstructorType _ q) = CTCons <$> trQual q
+trTypeExpr (ApplyType _ ty1 ty2) = CTApply <$> trTypeExpr ty1 <*> trTypeExpr ty2
+trTypeExpr (VariableType    _ v) = CTVar  <$> getTVarIndex v
+trTypeExpr (TupleType     _ tys) =
+  trTypeExpr $ foldl (ApplyType NoSpanInfo)
+                     (ConstructorType NoSpanInfo $ qTupleId $ length tys) tys
+trTypeExpr (ListType       _ ty) =
+  trTypeExpr $ ApplyType NoSpanInfo (ConstructorType NoSpanInfo qListId) ty
+trTypeExpr (ArrowType _ ty1 ty2) = CFuncType <$> trTypeExpr ty1 <*> trTypeExpr ty2
+trTypeExpr (ParenType      _ ty) = trTypeExpr ty
+trTypeExpr (ForallType    _ _ _) = internalError "GenAbstractCurry.trTypeExpr"
+
+trConstraint :: Constraint -> GAC CConstraint
+trConstraint (Constraint _ q ty) = (,) <$> trQual q <*> trTypeExpr ty
+
+trContext :: Context -> GAC CContext
+trContext cx = CContext <$> mapM trConstraint cx
+
+trQualTypeExpr :: QualTypeExpr -> GAC CQualTypeExpr
+trQualTypeExpr (QualTypeExpr _ cx ty) =
+  CQualType <$> trContext cx <*> trTypeExpr ty
+
+trInfixDecl :: Decl a -> GAC [COpDecl]
+trInfixDecl (InfixDecl _ fix mprec ops) = mapM trInfix (reverse ops)
+  where
+  trInfix op = COp <$> trGlobalIdent op <*> return (cvFixity fix)
+                   <*> return (fromInteger (mkPrec mprec))
+  cvFixity InfixL = CInfixlOp
+  cvFixity InfixR = CInfixrOp
+  cvFixity Infix  = CInfixOp
+trInfixDecl _ = return []
+
+trFuncDecl :: Bool -> Decl PredType -> GAC [CFuncDecl]
+trFuncDecl global (FunctionDecl  _ pty f eqs)
+  =   (\f' a v ty rs -> [CFunc f' a v ty rs])
+  <$> trFuncName global f <*> pure (eqnArity $ head eqs) <*> getVisibility f
+  <*> getQualType f pty <*> mapM trEquation eqs
+trFuncDecl global (ExternalDecl         _ vs)
+  =   T.forM vs $ \(Var pty f) -> CFunc
+  <$> trFuncName global f <*> pure (arrowArity $ unpredType pty)
+  <*> getVisibility f <*> getQualType f pty <*> return []
+trFuncDecl _      _                           = return []
+
+trFuncName :: Bool -> Ident -> GAC QName
+trFuncName global = if global then trGlobalIdent else trLocalIdent
+
+trEquation :: Equation PredType -> GAC CRule
+trEquation (Equation _ lhs rhs) = inNestedScope
+                                $ CRule <$> trLhs lhs <*> trRhs rhs
+
+trLhs :: Lhs a -> GAC [CPattern]
+trLhs = mapM trPat . snd . flatLhs
+
+trRhs :: Rhs PredType -> GAC CRhs
+trRhs (SimpleRhs _ _ e ds) = inNestedScope $ do
+  mapM_ insertDeclLhs ds
+  CSimpleRhs <$> trExpr e <*> concatMapM trLocalDecl ds
+trRhs (GuardedRhs _ _ gs ds) = inNestedScope $ do
+  mapM_ insertDeclLhs ds
+  CGuardedRhs <$> mapM trCondExpr gs <*> concatMapM trLocalDecl ds
+
+trCondExpr :: CondExpr PredType -> GAC (CExpr, CExpr)
+trCondExpr (CondExpr _ g e) = (,) <$> trExpr g <*> trExpr e
+
+trLocalDecls :: [Decl PredType] -> GAC [CLocalDecl]
+trLocalDecls ds = do
+  mapM_ insertDeclLhs ds
+  concatMapM trLocalDecl ds
+
+-- Insert all variables declared in local declarations
+insertDeclLhs :: Decl a -> GAC ()
+insertDeclLhs   (PatternDecl      _ p _) = mapM_ genVarIndex (bv p)
+insertDeclLhs   (FreeDecl          _ vs) = mapM_ genVarIndex (map varIdent vs)
+insertDeclLhs s@(TypeSig          _ _ _) = do
+  uacy <- S.gets untypedAcy
+  S.when uacy (insertSig s)
+insertDeclLhs _                          = return ()
+
+trLocalDecl :: Decl PredType -> GAC [CLocalDecl]
+trLocalDecl f@(FunctionDecl    _ _ _ _) = map CLocalFunc <$> trFuncDecl False f
+trLocalDecl f@(ExternalDecl        _ _) = map CLocalFunc <$> trFuncDecl False f
+trLocalDecl (PatternDecl       _ p rhs) = (\p' rhs' -> [CLocalPat p' rhs'])
+                                          <$> trPat p <*> trRhs rhs
+trLocalDecl (FreeDecl             _ vs) = (\vs' -> [CLocalVars vs'])
+                                          <$> mapM getVarIndex (map varIdent vs)
+trLocalDecl _                           = return [] -- can not occur (types etc.)
+
+insertSig :: Decl a -> GAC ()
+insertSig (TypeSig _ fs qty) = do
+  sigs <- S.gets typeSigs
+  let lsigs = Map.fromList [(f, qty) | f <- fs]
+  S.modify $ \env -> env { typeSigs = sigs `Map.union` lsigs }
+insertSig _                 = return ()
+
+trExpr :: Expression PredType -> GAC CExpr
+trExpr (Literal       _ _ l) = return (CLit $ cvLiteral l)
+trExpr (Variable      _ _ v)
+  | isQualified v = CSymbol <$> trQual v
+  | otherwise     = lookupVarIndex (unqualify v) >>= \mvi -> case mvi of
+    Just vi -> return (CVar vi)
+    _       -> CSymbol <$> trQual v
+trExpr (Constructor   _ _ c) = CSymbol <$> trQual c
+trExpr (Paren           _ e) = trExpr e
+trExpr (Typed       _ e qty) = CTyped <$> trExpr e <*> trQualTypeExpr qty
+trExpr (Record     _ _ c fs) = CRecConstr <$> trQual c
+                                          <*> mapM (trField trExpr) fs
+trExpr (RecordUpdate _ e fs) = CRecUpdate <$> trExpr e
+                                          <*> mapM (trField trExpr) fs
+trExpr (Tuple          _ es) =
+  trExpr $ apply (Variable NoSpanInfo undefined $ qTupleId $ length es) es
+trExpr (List         _ _ es) =
+  trExpr $ foldr (Apply NoSpanInfo . Apply NoSpanInfo
+                   (Constructor NoSpanInfo undefined qConsId))
+                 (Constructor NoSpanInfo undefined qNilId)
+                 es
+trExpr (ListCompr    _ e ds) = inNestedScope $ flip CListComp
+                               <$> mapM trStatement ds <*> trExpr e
+trExpr (EnumFrom              _ e) =
+  trExpr $ apply (Variable NoSpanInfo undefined qEnumFromId) [e]
+trExpr (EnumFromThen      _ e1 e2) =
+  trExpr $ apply (Variable NoSpanInfo undefined qEnumFromThenId) [e1, e2]
+trExpr (EnumFromTo        _ e1 e2) =
+  trExpr $ apply (Variable NoSpanInfo undefined qEnumFromToId) [e1, e2]
+trExpr (EnumFromThenTo _ e1 e2 e3) =
+  trExpr $ apply (Variable NoSpanInfo undefined qEnumFromThenToId) [e1, e2, e3]
+trExpr (UnaryMinus            _ e) =
+  trExpr $ apply (Variable NoSpanInfo undefined qNegateId) [e]
+trExpr (Apply             _ e1 e2) = CApply <$> trExpr e1 <*> trExpr e2
+trExpr (InfixApply     _ e1 op e2) = trExpr $ apply (infixOp op) [e1, e2]
+trExpr (LeftSection        _ e op) = trExpr $ apply (infixOp op) [e]
+trExpr (RightSection       _ op e) =
+  trExpr $ apply (Variable NoSpanInfo undefined qFlip) [infixOp op, e]
+trExpr (Lambda             _ ps e) = inNestedScope $
+                                     CLambda <$> mapM trPat ps <*> trExpr e
+trExpr (Let              _ _ ds e) = inNestedScope $
+                                     CLetDecl <$> trLocalDecls ds <*> trExpr e
+trExpr (Do               _ _ ss e) = inNestedScope $
+                                     (\ss' e' -> CDoExpr (ss' ++ [CSExpr e']))
+                                     <$> mapM trStatement ss <*> trExpr e
+trExpr (IfThenElse     _ e1 e2 e3) =
+  trExpr $ apply (Variable NoSpanInfo undefined qIfThenElseId) [e1, e2, e3]
+trExpr (Case          _ _ ct e bs) = CCase (cvCaseType ct)
+                                     <$> trExpr e <*> mapM trAlt bs
+
+cvCaseType :: CaseType -> CCaseType
+cvCaseType Flex  = CFlex
+cvCaseType Rigid = CRigid
+
+trStatement :: Statement PredType -> GAC CStatement
+trStatement (StmtExpr _   e)  = CSExpr     <$> trExpr e
+trStatement (StmtDecl _ _ ds) = CSLet      <$> trLocalDecls ds
+trStatement (StmtBind _ p e)  = flip CSPat <$> trExpr e <*> trPat p
+
+trAlt :: Alt PredType -> GAC (CPattern, CRhs)
+trAlt (Alt _ p rhs) = inNestedScope $ (,) <$> trPat p <*> trRhs rhs
+
+trPat :: Pattern a -> GAC CPattern
+trPat (LiteralPattern         _ _ l) = return (CPLit $ cvLiteral l)
+trPat (VariablePattern        _ _ v) = CPVar <$> getVarIndex v
+trPat (ConstructorPattern  _ _ c ps) = CPComb <$> trQual c <*> mapM trPat ps
+trPat (InfixPattern    _ a p1 op p2) =
+  trPat $ ConstructorPattern NoSpanInfo a op [p1, p2]
+trPat (ParenPattern             _ p) = trPat p
+trPat (RecordPattern       _ _ c fs) = CPRecord <$> trQual c
+                                              <*> mapM (trField trPat) fs
+trPat (TuplePattern            _ ps) =
+  trPat $ ConstructorPattern NoSpanInfo undefined (qTupleId $ length ps) ps
+trPat (ListPattern           _ _ ps) = trPat $
+  foldr (\x1 x2 -> ConstructorPattern NoSpanInfo undefined qConsId [x1, x2])
+        (ConstructorPattern NoSpanInfo undefined qNilId [])
+        ps
+trPat (NegativePattern        _ a l) =
+  trPat $ LiteralPattern NoSpanInfo a $ negateLiteral l
+trPat (AsPattern              _ v p) = CPAs <$> getVarIndex v<*> trPat p
+trPat (LazyPattern              _ p) = CPLazy <$> trPat p
+trPat (FunctionPattern     _ _ f ps) = CPFuncComb <$> trQual f <*> mapM trPat ps
+trPat (InfixFuncPattern _ a p1 f p2) =
+  trPat (FunctionPattern NoSpanInfo a f [p1, p2])
+
+trField :: (a -> GAC b) -> Field a -> GAC (CField b)
+trField act (Field _ l x) = (,) <$> trQual l <*> act x
+
+negateLiteral :: Literal -> Literal
+negateLiteral (Int    i) = Int   (-i)
+negateLiteral (Float  f) = Float (-f)
+negateLiteral _          = internalError "GenAbstractCurry.negateLiteral"
+
+cvLiteral :: Literal -> CLiteral
+cvLiteral (Char   c) = CCharc   c
+cvLiteral (Int    i) = CIntc    i
+cvLiteral (Float  f) = CFloatc  f
+cvLiteral (String s) = CStringc s
+
+trQual :: QualIdent -> GAC QName
+trQual qid
+  | n `elem` [unitId, listId, nilId, consId] = return ("Prelude", idName n)
+  | isTupleId n                              = return ("Prelude", idName n)
+  | otherwise
+  = return (maybe "" moduleName (qidModule qid), idName n)
+  where n = qidIdent qid
+
+trGlobalIdent :: Ident -> GAC QName
+trGlobalIdent i = S.gets moduleId >>= \m -> return (moduleName m, idName i)
+
+trLocalIdent :: Ident -> GAC QName
+trLocalIdent i = return ("", idName i)
+
+qFlip :: QualIdent
+qFlip = qualifyWith preludeMIdent (mkIdent "flip")
+
+qNegateId :: QualIdent
+qNegateId = qualifyWith preludeMIdent (mkIdent "negate")
+
+qIfThenElseId :: QualIdent
+qIfThenElseId = qualifyWith preludeMIdent (mkIdent "ifThenElse")
+
+prelUntyped :: QualIdent
+prelUntyped = qualifyWith preludeMIdent $ mkIdent "untyped"
+
+-------------------------------------------------------------------------------
+-- This part defines an environment containing all necessary information
+-- for generating the AbstractCurry representation of a CurrySyntax term.
+
+-- |Data type for representing an AbstractCurry generator environment
+data AbstractEnv = AbstractEnv
+  { moduleId   :: ModuleIdent                -- ^name of the module
+  , typeEnv    :: ValueEnv                   -- ^known values
+  , tyExports  :: Set.Set Ident              -- ^exported type symbols
+  , valExports :: Set.Set Ident              -- ^exported value symbols
+  , varIndex   :: Int                        -- ^counter for variable indices
+  , tvarIndex  :: Int                        -- ^counter for type variable indices
+  , varEnv     :: NestEnv Int                -- ^stack of variable tables
+  , tvarEnv    :: NestEnv Int                -- ^stack of type variable tables
+  , untypedAcy :: Bool                       -- ^flag to indicate whether untyped
+                                             --  AbstractCurry is generated
+  , typeSigs   :: Map.Map Ident QualTypeExpr -- ^map of user defined type signatures
+  } deriving Show
+
+-- |Initialize the AbstractCurry generator environment
+abstractEnv :: Bool -> CompilerEnv -> Module a -> AbstractEnv
+abstractEnv uacy env (Module _ _ _ mid es _ ds) = AbstractEnv
+  { moduleId   = mid
+  , typeEnv    = valueEnv env
+  , tyExports  = foldr (buildTypeExports  mid) Set.empty es'
+  , valExports = foldr (buildValueExports mid) Set.empty es'
+  , varIndex   = 0
+  , tvarIndex  = 0
+  , varEnv     = globalEnv emptyTopEnv
+  , tvarEnv    = globalEnv emptyTopEnv
+  , untypedAcy = uacy
+  , typeSigs   = if uacy
+                  then Map.fromList $ signatures ds
+                  else Map.empty
+  }
+  where es' = case es of
+          Just (Exporting _ e) -> e
+          _                    -> internalError "GenAbstractCurry.abstractEnv"
+
+-- Builds a table containing all exported identifiers from a module.
+buildTypeExports :: ModuleIdent -> Export -> Set.Set Ident -> Set.Set Ident
+buildTypeExports mid (ExportTypeWith _ tc _)
+  | isLocalIdent mid tc = Set.insert (unqualify tc)
+buildTypeExports _   _  = id
+
+-- Builds a table containing all exported identifiers from a module.
+buildValueExports :: ModuleIdent -> Export -> Set.Set Ident -> Set.Set Ident
+buildValueExports mid (Export             _ q)
+  | isLocalIdent mid q  = Set.insert (unqualify q)
+buildValueExports mid (ExportTypeWith _ tc cs)
+  | isLocalIdent mid tc = flip (foldr Set.insert) cs
+buildValueExports _   _  = id
+
+-- Looks up the unique index for the variable 'ident' in the
+-- variable table of the current scope.
+lookupVarIndex :: Ident -> GAC (Maybe CVarIName)
+lookupVarIndex i = S.gets $ \env -> case lookupNestEnv i $ varEnv env of
+  [v] -> Just (v, idName i)
+  _   -> Nothing
+
+getVarIndex :: Ident -> GAC CVarIName
+getVarIndex i = S.get >>= \env -> case lookupNestEnv i $ varEnv env of
+  [v] -> return (v, idName i)
+  _   -> genVarIndex i
+
+-- Generates an unique index for the  variable 'ident' and inserts it
+-- into the  variable table of the current scope.
+genVarIndex :: Ident -> GAC CVarIName
+genVarIndex i = do
+  env <- S.get
+  let idx = varIndex env
+  S.put $ env { varIndex = idx + 1, varEnv = bindNestEnv i idx (varEnv env) }
+  return (idx, idName i)
+
+-- Looks up the unique index for the type variable 'ident' in the type
+-- variable table of the current scope.
+getTVarIndex :: Ident -> GAC CTVarIName
+getTVarIndex i = S.get >>= \env -> case lookupNestEnv i $ tvarEnv env of
+  [v] -> return (v, idName i)
+  _   -> genTVarIndex i
+
+-- Generates an unique index for the type variable 'ident' and inserts it
+-- into the type variable table of the current scope.
+genTVarIndex :: Ident -> GAC CTVarIName
+genTVarIndex i = do
+  env <- S.get
+  let idx = tvarIndex env
+  S.put $ env { tvarIndex = idx + 1, tvarEnv = bindNestEnv i idx (tvarEnv env) }
+  return (idx, idName i)
+
+withLocalEnv :: GAC a -> GAC a
+withLocalEnv act = do
+  old <- S.get
+  res <- act
+  S.put old
+  return res
+
+inNestedScope :: GAC a -> GAC a
+inNestedScope act = do
+  (vo, to) <- S.gets $ \e -> (varEnv e, tvarEnv e)
+  S.modify $ \e -> e { varEnv = nestEnv $ vo, tvarEnv = globalEnv emptyTopEnv }
+  res <- act
+  S.modify $ \e -> e { varEnv = vo, tvarEnv = to }
+  return res
+
+inNestedTScope :: GAC a -> GAC a
+inNestedTScope act = do
+  (vo, to) <- S.gets $ \e -> (varEnv e, tvarEnv e)
+  S.modify $ \e -> e { varEnv = globalEnv emptyTopEnv, tvarEnv = nestEnv $ to }
+  res <- act
+  S.modify $ \e -> e { varEnv = vo, tvarEnv = to }
+  return res
+
+getQualType :: Ident -> PredType -> GAC CQualTypeExpr
+getQualType f pty = do
+  uacy <- S.gets untypedAcy
+  sigs <- S.gets typeSigs
+  trQualTypeExpr $ case uacy of
+    True  -> Maybe.fromMaybe (QualTypeExpr NoSpanInfo [] $
+                               ConstructorType NoSpanInfo prelUntyped)
+                             (Map.lookup f sigs)
+    False -> fromPredType identSupply pty
+
+getQualType' :: QualIdent -> GAC QualTypeExpr
+getQualType' f = do
+  m     <- S.gets moduleId
+  tyEnv <- S.gets typeEnv
+  return $ case qualLookupValue f tyEnv of
+    [Value _ _ _ (ForAll _ pty)] -> fromPredType identSupply pty
+    _                          -> case qualLookupValue (qualQualify m f) tyEnv of
+      [Value _ _ _ (ForAll _ pty)] -> fromPredType identSupply pty
+      _                          ->
+        internalError $ "GenAbstractCurry.getQualType': " ++ show f
+
+getTypeVisibility :: Ident -> GAC CVisibility
+getTypeVisibility i = S.gets $ \env ->
+  if Set.member i (tyExports env) then Public else Private
+
+getVisibility :: Ident -> GAC CVisibility
+getVisibility i = S.gets $ \env ->
+  if Set.member i (valExports env) then Public else Private
+
+signatures :: [Decl a] -> [(Ident, QualTypeExpr)]
+signatures ds = [(f, qty) | TypeSig _ fs qty <- ds, f <- fs]
diff --git a/src/Generators/GenAnnotatedFlatCurry.hs b/src/Generators/GenAnnotatedFlatCurry.hs
new file mode 100644
--- /dev/null
+++ b/src/Generators/GenAnnotatedFlatCurry.hs
@@ -0,0 +1,488 @@
+{- |
+    Module      :  $Header$
+    Description :  Generation of typed FlatCurry program terms
+    Copyright   :  (c) 2017        Finn Teegen
+                       2018        Kai-Oliver Prott
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module contains the generation of a type-annotated 'FlatCurry'
+    program term for a given module in the intermediate language.
+-}
+{-# LANGUAGE CPP #-}
+module Generators.GenAnnotatedFlatCurry (genAnnotatedFlatCurry) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative        ((<$>), (<*>))
+#endif
+import           Control.Monad              ((<=<))
+import           Control.Monad.Extra        (concatMapM)
+import qualified Control.Monad.State as S   ( State, evalState, get, gets
+                                            , modify, put )
+import           Data.Function              (on)
+import           Data.List                  (nub, sortBy)
+import           Data.Maybe                 (fromMaybe)
+import qualified Data.Map            as Map (Map, empty, insert, lookup)
+import qualified Data.Set            as Set (Set, empty, insert, member)
+
+import           Curry.Base.Ident
+import           Curry.FlatCurry.Annotated.Goodies (typeName)
+import           Curry.FlatCurry.Annotated.Type
+import qualified Curry.Syntax as CS
+
+import Base.Messages       (internalError)
+import Base.NestEnv        ( NestEnv, emptyEnv, bindNestEnv, lookupNestEnv
+                           , nestEnv, unnestEnv )
+import Base.Types
+
+import CompilerEnv
+import Env.TypeConstructor (TCEnv)
+
+import qualified IL
+
+-- transforms intermediate language code (IL) to type-annotated FlatCurry code
+genAnnotatedFlatCurry :: CompilerEnv -> CS.Module Type -> IL.Module
+                  -> AProg TypeExpr
+genAnnotatedFlatCurry env mdl il = patchPrelude $ run env mdl (trModule il)
+
+-- -----------------------------------------------------------------------------
+-- Addition of primitive types for lists and tuples to the Prelude
+-- -----------------------------------------------------------------------------
+
+patchPrelude :: AProg a -> AProg a
+patchPrelude p@(AProg n _ ts fs os)
+  | n == prelude = AProg n [] ts' fs os
+  | otherwise    = p
+  where ts' = sortBy (compare `on` typeName) pts
+        pts = primTypes ++ ts
+
+primTypes :: [TypeDecl]
+primTypes =
+  [ Type arrow Public [(0, KStar), (1, KStar)] []
+  , Type unit Public [] [(Cons unit 0 Public [])]
+  , Type nil Public [(0, KStar)] [ Cons nil  0 Public []
+                                 , Cons cons 2 Public [TVar 0, TCons nil [TVar 0]]
+                                 ]
+  ] ++ map mkTupleType [2 .. maxTupleArity]
+  where arrow = mkPreludeQName "(->)"
+        unit  = mkPreludeQName "()"
+        nil   = mkPreludeQName "[]"
+        cons  = mkPreludeQName ":"
+
+mkTupleType :: Int -> TypeDecl
+mkTupleType arity = Type tuple Public [(i, KStar) | i <- [0 .. arity - 1]]
+  [Cons tuple arity Public $ map TVar [0 .. arity - 1]]
+  where tuple = mkPreludeQName $ '(' : replicate (arity - 1) ',' ++ ")"
+
+mkPreludeQName :: String -> QName
+mkPreludeQName n = (prelude, n)
+
+prelude :: String
+prelude = "Prelude"
+
+-- |Maximal arity of tuples
+maxTupleArity :: Int
+maxTupleArity = 15
+
+-- -----------------------------------------------------------------------------
+
+-- The environment 'FlatEnv' is embedded in the monadic representation
+-- 'FlatState' which allows the usage of 'do' expressions.
+type FlatState a = S.State FlatEnv a
+
+-- Data type for representing an environment which contains information needed
+-- for generating FlatCurry code.
+data FlatEnv = FlatEnv
+  { modIdent     :: ModuleIdent      -- current module
+  -- for visibility calculation
+  , tyExports    :: Set.Set Ident    -- exported types
+  , valExports   :: Set.Set Ident    -- exported values (functions + constructors)
+  , tcEnv        :: TCEnv            -- type constructor environment
+  , typeSynonyms :: [CS.Decl Type]   -- type synonyms
+  , imports      :: [ModuleIdent]    -- module imports
+  -- state for mapping identifiers to indexes
+  , nextVar      :: Int              -- fresh variable index counter
+  , varMap       :: NestEnv VarIndex -- map of identifier to variable index
+  }
+
+-- Runs a 'FlatState' action and returns the result
+run :: CompilerEnv -> CS.Module Type -> FlatState a -> a
+run env (CS.Module _ _ _ mid es is ds) act = S.evalState act env0
+  where
+  es'  = case es of Just (CS.Exporting _ e) -> e
+                    _                       -> []
+  env0 = FlatEnv
+    { modIdent     = mid
+     -- for visibility calculation
+    , tyExports  = foldr (buildTypeExports  mid) Set.empty es'
+    , valExports = foldr (buildValueExports mid) Set.empty es'
+    -- This includes *all* imports, even unused ones
+    , imports      = nub [ m | CS.ImportDecl _ m _ _ _ <- is ]
+    -- Environment to retrieve the type of identifiers
+    , tcEnv        = tyConsEnv env
+    -- Type synonyms in the module
+    , typeSynonyms = [ d | d@CS.TypeDecl{} <- ds ]
+    , nextVar      = 0
+    , varMap       = emptyEnv
+    }
+
+-- Builds a table containing all exported identifiers from a module.
+buildTypeExports :: ModuleIdent -> CS.Export -> Set.Set Ident -> Set.Set Ident
+buildTypeExports mid (CS.ExportTypeWith _ tc _)
+  | isLocalIdent mid tc = Set.insert (unqualify tc)
+buildTypeExports _   _  = id
+
+-- Builds a table containing all exported identifiers from a module.
+buildValueExports :: ModuleIdent -> CS.Export -> Set.Set Ident -> Set.Set Ident
+buildValueExports mid (CS.Export         _     q)
+  | isLocalIdent mid q  = Set.insert (unqualify q)
+buildValueExports mid (CS.ExportTypeWith _ tc cs)
+  | isLocalIdent mid tc = flip (foldr Set.insert) cs
+buildValueExports _   _  = id
+
+getModuleIdent :: FlatState ModuleIdent
+getModuleIdent = S.gets modIdent
+
+-- Retrieve imports
+getImports :: [ModuleIdent] -> FlatState [String]
+getImports imps = (nub . map moduleName . (imps ++)) <$> S.gets imports
+
+-- -----------------------------------------------------------------------------
+-- Stateful part, used for translation of rules and expressions
+-- -----------------------------------------------------------------------------
+
+-- resets var index and environment
+withFreshEnv :: FlatState a -> FlatState a
+withFreshEnv act = S.modify (\ s -> s { nextVar = 0, varMap = emptyEnv }) >> act
+
+-- Execute an action in a nested variable mapping
+inNestedEnv :: FlatState a -> FlatState a
+inNestedEnv act = do
+  S.modify $ \ s -> s { varMap = nestEnv   $ varMap s }
+  res <- act
+  S.modify $ \ s -> s { varMap = unnestEnv $ varMap s }
+  return res
+
+-- Generates a new variable index for an identifier
+newVar :: IL.Type -> Ident -> FlatState (VarIndex, TypeExpr)
+newVar ty i = do
+  idx <- (+1) <$> S.gets nextVar
+  S.modify $ \ s -> s { nextVar = idx, varMap = bindNestEnv i idx (varMap s) }
+  ty' <- trType ty
+  return (idx, ty')
+
+-- Retrieve the variable index assigned to an identifier
+getVarIndex :: Ident -> FlatState VarIndex
+getVarIndex i = S.gets varMap >>= \ varEnv -> case lookupNestEnv i varEnv of
+  [v] -> return v
+  _   -> internalError $ "GenTypeAnnotatedFlatCurry.getVarIndex: " ++ escName i
+
+-- -----------------------------------------------------------------------------
+-- Translation of a module
+-- -----------------------------------------------------------------------------
+
+trModule :: IL.Module -> FlatState (AProg TypeExpr)
+trModule (IL.Module mid is ds) = do
+  is' <- getImports is
+  tds <- concatMapM trTypeDecl ds
+  fds <- concatMapM (return . map runNormalization <=< trAFuncDecl) ds
+  return $ AProg (moduleName mid) is' tds fds []
+
+-- Translate a data declaration
+-- For empty data declarations, an additional constructor is generated. This
+-- is due to the fact that external data declarations are translated into data
+-- declarations with zero constructors and without the additional constructor
+-- empty data declarations could not be distinguished from external ones.
+trTypeDecl :: IL.Decl -> FlatState [TypeDecl]
+trTypeDecl (IL.DataDecl      qid ks []) = do
+  q'  <- trQualIdent qid
+  vis <- getTypeVisibility qid
+  c   <- trQualIdent $ qualify (mkIdent $ "_Constr#" ++ idName (unqualify qid))
+  let ks' = trKind <$> ks
+      tvs = zip [0..] ks'
+  return [Type q' vis tvs [Cons c 1 Private [TCons q' $ TVar <$> fst <$> tvs]]]
+trTypeDecl (IL.DataDecl      qid ks cs) = do
+  q'  <- trQualIdent qid
+  vis <- getTypeVisibility qid
+  cs' <- mapM trConstrDecl cs
+  let ks' = trKind <$> ks
+      tvs = zip [0..] ks'
+  return [Type q' vis tvs cs']
+trTypeDecl (IL.NewtypeDecl   qid ks nc) = do
+  q'  <- trQualIdent qid
+  vis <- getTypeVisibility qid
+  nc' <- trNewConstrDecl nc
+  let ks' = trKind <$> ks
+      tvs = zip [0..] ks'
+  return [TypeNew q' vis tvs nc']
+trTypeDecl (IL.ExternalDataDecl qid ks) = do
+  q'  <- trQualIdent qid
+  vis <- getTypeVisibility qid
+  let ks' = trKind <$> ks
+      tvs = zip [0..] ks'
+  return [Type q' vis tvs []]
+trTypeDecl _                           = return []
+
+-- Translate a constructor declaration
+trConstrDecl :: IL.ConstrDecl -> FlatState ConsDecl
+trConstrDecl (IL.ConstrDecl qid tys) = flip Cons (length tys)
+  <$> trQualIdent qid
+  <*> getVisibility qid
+  <*> mapM trType tys
+
+-- Translate a constructor declaration for newtypes
+trNewConstrDecl :: IL.NewConstrDecl -> FlatState NewConsDecl
+trNewConstrDecl (IL.NewConstrDecl qid ty) = NewCons
+  <$> trQualIdent qid
+  <*> getVisibility qid
+  <*> trType ty
+
+-- Translate a type expression
+trType :: IL.Type -> FlatState TypeExpr
+trType (IL.TypeConstructor t tys) = TCons <$> trQualIdent t <*> mapM trType tys
+trType (IL.TypeVariable      idx) = return $ TVar $ abs idx
+trType (IL.TypeArrow     ty1 ty2) = FuncType <$> trType ty1 <*> trType ty2
+trType (IL.TypeForall    idxs ty) = ForallType (map trTVarWithKind idxs) <$> trType ty
+
+-- Translates a type variable with kind.
+trTVarWithKind :: (Int, IL.Kind) -> (Int, Kind)
+trTVarWithKind (i, k) = (abs i, trKind k)
+
+-- Translate a kind
+trKind :: IL.Kind -> Kind
+trKind IL.KindStar          = KStar
+trKind (IL.KindVariable  _) = KStar
+trKind (IL.KindArrow k1 k2) = KArrow (trKind k1) (trKind k2)
+
+-- -----------------------------------------------------------------------------
+-- Function declarations
+-- -----------------------------------------------------------------------------
+
+-- Translate a function declaration
+trAFuncDecl :: IL.Decl -> FlatState [AFuncDecl TypeExpr]
+trAFuncDecl (IL.FunctionDecl f vs ty e) = do
+  f'  <- trQualIdent f
+  vis <- getVisibility f
+  ty' <- trType ty
+  r'  <- trARule ty vs e
+  return [AFunc f' (length vs) vis ty' r']
+trAFuncDecl (IL.ExternalDecl    f a ty) = do
+  f'   <- trQualIdent f
+  vis  <- getVisibility f
+  ty'  <- trType ty
+  r'   <- trAExternal ty f --TODO: get arity from type?
+  return [AFunc f' a vis ty' r']
+trAFuncDecl _                           = return []
+
+-- Translate a function rule.
+-- Resets variable index so that for every rule variables start with index 1
+trARule :: IL.Type -> [(IL.Type, Ident)] -> IL.Expression
+        -> FlatState (ARule TypeExpr)
+trARule ty vs e = withFreshEnv $ ARule <$> trType ty
+                                    <*> mapM (uncurry newVar) vs
+                                    <*> trAExpr e
+
+trAExternal :: IL.Type -> QualIdent -> FlatState (ARule TypeExpr)
+trAExternal ty f = flip AExternal (qualName f) <$> trType ty
+
+-- Translate an expression
+trAExpr :: IL.Expression -> FlatState (AExpr TypeExpr)
+trAExpr (IL.Literal       ty l) = ALit <$> trType ty <*> trLiteral l
+trAExpr (IL.Variable      ty v) = AVar <$> trType ty <*> getVarIndex v
+trAExpr (IL.Function    ty f a) = genCall Fun ty f a []
+trAExpr (IL.Constructor ty c a) = genCall Con ty c a []
+trAExpr (IL.Apply        e1 e2) = trApply e1 e2
+trAExpr c@(IL.Case      t e bs) = flip ACase (cvEval t) <$> trType (IL.typeOf c) <*> trAExpr e
+                                  <*> mapM (inNestedEnv . trAlt) bs
+trAExpr (IL.Or           e1 e2) = AOr <$> trType (IL.typeOf e1) <*> trAExpr e1 <*> trAExpr e2
+trAExpr (IL.Exist       v ty e) = inNestedEnv $ do
+  v' <- newVar ty v
+  e' <- trAExpr e
+  ty' <- trType (IL.typeOf e)
+  return $ case e' of AFree ty'' vs e'' -> AFree ty'' (v' : vs) e''
+                      _                 -> AFree ty'  (v' : []) e'
+trAExpr (IL.Let (IL.Binding v b) e) = inNestedEnv $ do
+  v' <- newVar (IL.typeOf b) v
+  b' <- trAExpr b
+  e' <- trAExpr e
+  ty' <- trType $ IL.typeOf e
+  return $ case e' of ALet ty'' bs e'' -> ALet ty'' ((v', b'):bs) e''
+                      _                -> ALet ty'  ((v', b'):[]) e'
+trAExpr (IL.Letrec   bs e) = inNestedEnv $ do
+  let (vs, es) = unzip [ ((IL.typeOf b, v), b) | IL.Binding v b <- bs]
+  ALet <$> trType (IL.typeOf e)
+       <*> (zip <$> mapM (uncurry newVar) vs <*> mapM trAExpr es)
+       <*> trAExpr e
+trAExpr (IL.Typed e ty) = ATyped <$> ty' <*> trAExpr e <*> ty'
+  where ty' = trType $ ty
+
+-- Translate a literal
+trLiteral :: IL.Literal -> FlatState Literal
+trLiteral (IL.Char  c) = return $ Charc  c
+trLiteral (IL.Int   i) = return $ Intc   i
+trLiteral (IL.Float f) = return $ Floatc f
+
+-- Translate a higher-order application
+trApply :: IL.Expression -> IL.Expression -> FlatState (AExpr TypeExpr)
+trApply e1 e2 = genFlatApplic e1 [e2]
+  where
+  genFlatApplic e es = case e of
+    IL.Apply        ea eb -> genFlatApplic ea (eb:es)
+    IL.Function    ty f a -> genCall Fun ty f a es
+    IL.Constructor ty c a -> genCall Con ty c a es
+    _ -> do
+      expr <- trAExpr e
+      genApply expr es
+
+-- Translate an alternative
+trAlt :: IL.Alt -> FlatState (ABranchExpr TypeExpr)
+trAlt (IL.Alt p e) = ABranch <$> trPat p <*> trAExpr e
+
+-- Translate a pattern
+trPat :: IL.ConstrTerm -> FlatState (APattern TypeExpr)
+trPat (IL.LiteralPattern        ty l) = ALPattern <$> trType ty <*> trLiteral l
+trPat (IL.ConstructorPattern ty c vs) = do
+  qty <- trType $ foldr IL.TypeArrow ty $ map fst vs
+  APattern  <$> trType ty <*> ((\q -> (q, qty)) <$> trQualIdent c) <*> mapM (uncurry newVar) vs
+trPat (IL.VariablePattern        _ _) = internalError "GenTypeAnnotatedFlatCurry.trPat"
+
+-- Convert a case type
+cvEval :: IL.Eval -> CaseType
+cvEval IL.Rigid = Rigid
+cvEval IL.Flex  = Flex
+
+data Call = Fun | Con
+
+-- Generate a function or constructor call
+genCall :: Call -> IL.Type -> QualIdent -> Int -> [IL.Expression]
+        -> FlatState (AExpr TypeExpr)
+genCall call ty f arity es = do
+  f'    <- trQualIdent f
+  case compare supplied arity of
+    LT -> genAComb ty f' es (part call (arity - supplied))
+    EQ -> genAComb ty f' es (full call)
+    GT -> do
+      let (es1, es2) = splitAt arity es
+      funccall <- genAComb ty f' es1 (full call)
+      genApply funccall es2
+  where
+  supplied = length es
+  full Fun = FuncCall
+  full Con = ConsCall
+  part Fun = FuncPartCall
+  part Con = ConsPartCall
+
+genAComb :: IL.Type -> QName -> [IL.Expression] -> CombType -> FlatState (AExpr TypeExpr)
+genAComb ty qid es ct = do
+  ty' <- trType ty
+  let ty'' = defunc ty' (length es)
+  AComb ty'' ct (qid, ty') <$> mapM trAExpr es
+  where
+  defunc t               0 = t
+  defunc (FuncType _ t2) n = defunc t2 (n - 1)
+  defunc _               _ = internalError "GenTypeAnnotatedFlatCurry.genAComb.defunc"
+
+genApply :: AExpr TypeExpr -> [IL.Expression] -> FlatState (AExpr TypeExpr)
+genApply e es = do
+  ap  <- trQualIdent $ qApplyId
+  es' <- mapM trAExpr es
+  return $ foldl (\e1 e2 -> let FuncType ty1 ty2 = typeOf e1 in AComb ty2 FuncCall (ap, FuncType (FuncType ty1 ty2) (FuncType ty1 ty2)) [e1, e2]) e es'
+
+-- -----------------------------------------------------------------------------
+-- Normalization
+-- -----------------------------------------------------------------------------
+
+runNormalization :: Normalize a => a -> a
+runNormalization x = S.evalState (normalize x) (0, Map.empty)
+
+type NormState a = S.State (Int, Map.Map Int Int) a
+
+class Normalize a where
+  normalize :: a -> NormState a
+
+instance Normalize a => Normalize [a] where
+  normalize = mapM normalize
+
+instance Normalize Int where
+  normalize i = do
+    (n, m) <- S.get
+    case Map.lookup i m of
+      Nothing -> do
+        S.put (n + 1, Map.insert i n m)
+        return n
+      Just n' -> return n'
+
+instance Normalize TypeExpr where
+  normalize (TVar           i) = TVar <$> normalize i
+  normalize (TCons      q tys) = TCons q <$> normalize tys
+  normalize (FuncType ty1 ty2) = FuncType <$> normalize ty1 <*> normalize ty2
+  normalize (ForallType is ty) = ForallType <$> mapM normalizeTypeVar is
+                                            <*> normalize ty
+    where normalizeTypeVar (tv, k) = (,) <$> normalize tv <*> pure k
+
+instance Normalize a => Normalize (AFuncDecl a) where
+  normalize (AFunc f a v ty r) = AFunc f a v <$> normalize ty <*> normalize r
+
+instance Normalize a => Normalize (ARule a) where
+  normalize (ARule     ty vs e) = ARule <$> normalize ty
+                                        <*> mapM normalizeTuple vs
+                                        <*> normalize e
+  normalize (AExternal ty    s) = flip AExternal s <$> normalize ty
+
+normalizeTuple :: Normalize b => (a, b) -> NormState (a, b)
+normalizeTuple (a, b) = (,) <$> pure a <*> normalize b  
+
+instance Normalize a => Normalize (AExpr a) where
+  normalize (AVar  ty       v) = flip AVar  v  <$> normalize ty
+  normalize (ALit  ty       l) = flip ALit  l  <$> normalize ty
+  normalize (AComb ty ct f es) = flip AComb ct <$> normalize ty
+                                               <*> normalizeTuple f
+                                               <*> normalize es
+  normalize (ALet  ty    ds e) = ALet <$> normalize ty
+                                      <*> mapM normalizeBinding ds
+                                      <*> normalize e
+    where normalizeBinding (v, b) = (,) <$> normalizeTuple v <*> normalize b
+  normalize (AOr   ty     a b) = AOr <$> normalize ty <*> normalize a
+                                     <*> normalize b
+  normalize (ACase ty ct e bs) = flip ACase ct <$> normalize ty <*> normalize e
+                                               <*> normalize bs
+  normalize (AFree  ty   vs e) = AFree <$> normalize ty
+                                       <*> mapM normalizeTuple vs
+                                       <*> normalize e
+  normalize (ATyped ty  e ty') = ATyped <$> normalize ty <*> normalize e
+                                        <*> normalize ty'
+
+instance Normalize a => Normalize (ABranchExpr a) where
+  normalize (ABranch p e) = ABranch <$> normalize p <*> normalize e
+
+instance Normalize a => Normalize (APattern a) where
+  normalize (APattern  ty c vs) = APattern <$> normalize ty
+                                           <*> normalizeTuple c
+                                           <*> mapM normalizeTuple vs
+  normalize (ALPattern ty    l) = flip ALPattern l <$> normalize ty
+
+-- -----------------------------------------------------------------------------
+-- Helper functions
+-- -----------------------------------------------------------------------------
+
+trQualIdent :: QualIdent -> FlatState QName
+trQualIdent qid = do
+  mid <- getModuleIdent
+  return $ (moduleName $ fromMaybe mid mid', idName i)
+  where
+  mid' | i `elem` [listId, consId, nilId, unitId] || isTupleId i
+       = Just preludeMIdent
+       | otherwise
+       = qidModule qid
+  i = qidIdent qid
+
+getTypeVisibility :: QualIdent -> FlatState Visibility
+getTypeVisibility i = S.gets $ \s ->
+  if Set.member (unqualify i) (tyExports s) then Public else Private
+
+getVisibility :: QualIdent -> FlatState Visibility
+getVisibility i = S.gets $ \s ->
+  if Set.member (unqualify i) (valExports s) then Public else Private
diff --git a/src/Generators/GenFlatCurry.hs b/src/Generators/GenFlatCurry.hs
new file mode 100644
--- /dev/null
+++ b/src/Generators/GenFlatCurry.hs
@@ -0,0 +1,56 @@
+{- |
+    Module      :  $Header$
+    Description :  Generation of FlatCurry program and interface terms
+    Copyright   :  (c) 2017        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module contains the generation of a 'FlatCurry' program term or
+    a 'FlatCurry' interface out of an 'Annotated FlatCurry' module.
+-}
+module Generators.GenFlatCurry (genFlatCurry, genFlatInterface) where
+
+import Curry.FlatCurry.Goodies
+import Curry.FlatCurry.Type
+import Curry.FlatCurry.Annotated.Goodies
+import Curry.FlatCurry.Annotated.Type
+
+-- transforms annotated FlatCurry code to FlatCurry code
+genFlatCurry :: AProg TypeExpr -> Prog
+genFlatCurry = trAProg
+  (\name imps types funcs ops ->
+    Prog name imps types (map genFlatFuncDecl funcs) ops)
+
+genFlatFuncDecl :: AFuncDecl TypeExpr -> FuncDecl
+genFlatFuncDecl = trAFunc
+  (\name arity vis ty rule -> Func name arity vis ty $ genFlatRule rule)
+
+genFlatRule :: ARule TypeExpr -> Rule
+genFlatRule = trARule
+  (\_ args e -> Rule (map fst args) $ genFlatExpr e)
+  (const External)
+
+genFlatExpr :: AExpr TypeExpr -> Expr
+genFlatExpr = trAExpr
+  (const Var)
+  (const Lit)
+  (\_ ct (name, _) args -> Comb ct name args)
+  (const $ Let . map (\(v, e') -> (fst v, e')))
+  (const $ Free . map fst)
+  (const Or)
+  (const Case)
+  (Branch . genFlatPattern)
+  (const Typed)
+
+genFlatPattern :: APattern TypeExpr -> Pattern
+genFlatPattern = trAPattern
+  (\_ (name, _) args -> Pattern name $ map fst args)
+  (const LPattern)
+
+-- transforms a FlatCurry module to a FlatCurry interface
+genFlatInterface :: Prog -> Prog
+genFlatInterface =
+  updProgFuncs $ map $ updFuncRule $ const $ Rule [] $ Var 0
diff --git a/src/Generators/GenTypedFlatCurry.hs b/src/Generators/GenTypedFlatCurry.hs
new file mode 100644
--- /dev/null
+++ b/src/Generators/GenTypedFlatCurry.hs
@@ -0,0 +1,53 @@
+{- |
+    Module      :  $Header$
+    Description :  Generation of typed FlatCurry program terms
+    Copyright   :  (c) 2017        Finn Teegen
+                       2018        Kai-Oliver Prott
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module contains the generation of a typed 'FlatCurry' program term
+    for a given module in the intermediate language.
+-}
+{-# LANGUAGE CPP #-}
+module Generators.GenTypedFlatCurry (genTypedFlatCurry) where
+
+import Curry.FlatCurry.Annotated.Type
+import Curry.FlatCurry.Annotated.Goodies
+import Curry.FlatCurry.Typed.Type
+
+-- transforms annotated FlatCurry code to typed FlatCurry code
+genTypedFlatCurry :: AProg TypeExpr -> TProg
+genTypedFlatCurry = trAProg
+  (\name imps types funcs ops ->
+    TProg name imps types (map genTypedFuncDecl funcs) ops)
+
+genTypedFuncDecl :: AFuncDecl TypeExpr -> TFuncDecl
+genTypedFuncDecl = trAFunc
+  (\name arity vis ty rule -> TFunc name arity vis ty $ genTypedRule rule)
+
+genTypedRule :: ARule TypeExpr -> TRule
+genTypedRule = trARule
+  (\_ args e -> TRule args $ genTypedExpr e)
+  TExternal
+
+genTypedExpr :: AExpr TypeExpr -> TExpr
+genTypedExpr = trAExpr
+  TVarE
+  TLit
+  (\ty ct (name, _) args -> TComb ty ct name args)
+  (const TLet)
+  (const TFree)
+  (const TOr)
+  (const TCase)
+  (TBranch . genTypedPattern)
+  (const TTyped)
+
+genTypedPattern :: APattern TypeExpr -> TPattern
+genTypedPattern = trAPattern
+  (\ty (name, _) args -> TPattern ty name args)
+  TLPattern
+
diff --git a/src/Html/CurryHtml.hs b/src/Html/CurryHtml.hs
new file mode 100644
--- /dev/null
+++ b/src/Html/CurryHtml.hs
@@ -0,0 +1,185 @@
+{- |
+    Module      :  $Header$
+    Description :  Generating HTML documentation
+    Copyright   :  (c) 2011 - 2016, Björn Peemöller
+                       2016       , Jan Tikovsky
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module defines a function for generating HTML documentation pages
+    for Curry source modules.
+-}
+{-# LANGUAGE TemplateHaskell   #-}
+module Html.CurryHtml (source2html) where
+
+import Prelude         as P
+import Control.Monad.Writer
+import Data.List             (mapAccumL)
+import Data.Maybe            (fromMaybe, isJust)
+import Data.ByteString as BS (ByteString, writeFile)
+import Data.FileEmbed
+import Network.URI           (escapeURIString, isUnreserved)
+import System.FilePath       ((</>))
+
+import Curry.Base.Ident      ( ModuleIdent (..), Ident (..), QualIdent (..)
+                             , unqualify, moduleName)
+import Curry.Base.Monad      (CYIO)
+import Curry.Base.Position   (Position)
+import Curry.Files.Filenames (htmlName)
+import Curry.Syntax          (Module (..), Token)
+
+import Html.SyntaxColoring
+
+
+import CompilerOpts          (Options (..))
+
+-- |Read file via TemplateHaskell at compile time
+cssContent :: ByteString
+cssContent = $(makeRelativeToProject "data/currysource.css" >>= embedFile)
+
+-- | Name of the css file
+-- NOTE: The relative path is given above
+cssFileName :: String
+cssFileName = "currysource.css"
+
+-- |Translate source file into HTML file with syntaxcoloring
+source2html :: Options -> ModuleIdent -> [(Position, Token)] -> Module a
+            -> CYIO ()
+source2html opts mid toks mdl = do
+  liftIO $ P.writeFile (outDir </> htmlName mid) doc
+  updateCSSFile outDir
+  where
+  doc    = program2html mid (genProgram mdl toks)
+  outDir = fromMaybe "." (optHtmlDir opts)
+
+-- |Update the CSS file
+updateCSSFile :: FilePath -> CYIO ()
+updateCSSFile dir = do
+  let target = dir </> cssFileName
+  liftIO $ BS.writeFile target cssContent
+
+-- generates htmlcode with syntax highlighting
+-- @param modulname
+-- @param a program
+-- @return HTMLcode
+program2html :: ModuleIdent -> [Code] -> String
+program2html m codes = unlines
+  [ "<!DOCTYPE html>"
+  , "<html lang=\"en\">"
+  , "<head>"
+  , "<meta charset=\"utf-8\">"
+  , "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
+  , "<title>" ++ titleHtml ++ "</title>"
+  , "<link rel=\"stylesheet\" href=\"" ++ cssFileName ++ "\">"
+  , "</head>"
+  , "<body>"
+  , "<table><tbody><tr>"
+  , "<td class=\"line-numbers\"><pre>" ++ lineHtml ++ "</pre></td>"
+  , "<td class=\"source-code\"><pre>" ++ codeHtml ++ "</pre></td>"
+  , "</tr></tbody></table>"
+  , "</body>"
+  , "</html>"
+  ]
+  where
+  titleHtml = "Module " ++ moduleName m
+  lineHtml  = unlines $ map show [1 .. length (lines codeHtml)]
+  codeHtml  = concat $ snd $ mapAccumL (code2html m) [] codes
+
+code2html :: ModuleIdent -> [QualIdent] -> Code -> ([QualIdent], String)
+code2html m defs c
+  | isCall c  = (defs, maybe tag (addEntityLink m tag) (getQualIdent c))
+  | isDecl c  = case getQualIdent c of
+      Just i | i `notElem` defs
+        -> (i:defs, spanTag (code2class c) (escIdent i) (escCode c))
+      _ -> (defs, tag)
+  | otherwise = case c of
+      ModuleName m' -> (defs, addModuleLink m m' tag)
+      _             -> (defs, tag)
+  where tag = spanTag (code2class c) "" (escCode c)
+
+escCode :: Code -> String
+escCode = htmlQuote . code2string
+
+escIdent :: QualIdent -> String
+escIdent = htmlQuote . idName . unqualify
+
+spanTag :: String -> String -> String -> String
+spanTag clV idV str
+  | null clV && null idV = str
+  | otherwise            = "<span" ++ codeclass ++ idValue ++ ">"
+                           ++ str ++ "</span>"
+  where
+  codeclass = if null clV then "" else " class=\"" ++ clV ++ "\""
+  idValue   = if null idV then "" else " id=\"" ++ idV ++ "\""
+
+-- which code has which css class
+-- @param code
+-- @return css class of the code
+code2class :: Code -> String
+code2class (Space          _) = ""
+code2class NewLine            = ""
+code2class (Keyword        _) = "keyword"
+code2class (Pragma         _) = "pragma"
+code2class (Symbol         _) = "symbol"
+code2class (TypeCons   _ _ _) = "type"
+code2class (DataCons   _ _ _) = "cons"
+code2class (Function   _ _ _) = "func"
+code2class (Identifier _ _ _) = "ident"
+code2class (ModuleName     _) = "module"
+code2class (Commentary     _) = "comment"
+code2class (NumberCode     _) = "number"
+code2class (StringCode     _) = "string"
+code2class (CharCode       _) = "char"
+
+addModuleLink :: ModuleIdent -> ModuleIdent -> String -> String
+addModuleLink m m' str
+  = "<a href=\"" ++ makeRelativePath m m' ++ "\">" ++ str ++ "</a>"
+
+addEntityLink :: ModuleIdent -> String -> QualIdent -> String
+addEntityLink m str qid =
+  "<a href=\"" ++ modPath ++ "#" ++ fragment  ++ "\">" ++ str ++ "</a>"
+  where
+  modPath       = maybe "" (makeRelativePath m) mmid
+  fragment      = string2urlencoded (idName ident)
+  (mmid, ident) = (qidModule qid, qidIdent qid)
+
+makeRelativePath :: ModuleIdent -> ModuleIdent -> String
+makeRelativePath cur new  | cur == new = ""
+                          | otherwise  = htmlName new
+
+isCall :: Code -> Bool
+isCall (TypeCons   TypeExport _ _) = True
+isCall (TypeCons   TypeImport _ _) = True
+isCall (TypeCons   TypeRefer  _ _) = True
+isCall (TypeCons   _          _ _) = False
+isCall (Identifier _          _ _) = False
+isCall c                       = not (isDecl c) && isJust (getQualIdent c)
+
+isDecl :: Code -> Bool
+isDecl (DataCons ConsDeclare _ _) = True
+isDecl (Function FuncDeclare _ _) = True
+isDecl (TypeCons TypeDeclare _ _) = True
+isDecl _                          = False
+
+-- Translates arbitrary strings into equivalent urlencoded string.
+string2urlencoded :: String -> String
+string2urlencoded = escapeURIString isUnreserved
+
+htmlQuote :: String -> String
+htmlQuote [] = []
+htmlQuote (c : cs)
+  | c == '<'  = "&lt;"    ++ htmlQuote cs
+  | c == '>'  = "&gt;"    ++ htmlQuote cs
+  | c == '&'  = "&amp;"   ++ htmlQuote cs
+  | c == '"'  = "&quot;"  ++ htmlQuote cs
+  | c == 'ä'  = "&auml;"  ++ htmlQuote cs
+  | c == 'ö'  = "&ouml;"  ++ htmlQuote cs
+  | c == 'ü'  = "&uuml;"  ++ htmlQuote cs
+  | c == 'Ä'  = "&Auml;"  ++ htmlQuote cs
+  | c == 'Ö'  = "&Ouml;"  ++ htmlQuote cs
+  | c == 'Ü'  = "&Uuml;"  ++ htmlQuote cs
+  | c == 'ß'  = "&szlig;" ++ htmlQuote cs
+  | otherwise = c : htmlQuote cs
diff --git a/src/Html/SyntaxColoring.hs b/src/Html/SyntaxColoring.hs
new file mode 100644
--- /dev/null
+++ b/src/Html/SyntaxColoring.hs
@@ -0,0 +1,564 @@
+{- |
+    Module      :  $Header$
+    Description :  Split module into code fragments
+    Copyright   :  (c) 2014 - 2016 Björn Peemöller
+                       2016        Jan Tikovsky
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module arranges the tokens of the module into different code
+    categories for HTML presentation. The parsed and qualified module
+    is used to establish links between used identifiers and their definitions.
+
+    The fully qualified module is traversed to generate a list of code elements.
+    Code elements representing identifiers are distinguished by their kind
+    (type constructor, data constructor, function, (type) variable).
+    They include information about their usage (i.e., declaration, call etc.)
+    and whether the identifier occurs fully qualified in
+    the source code or not. Initially, all identifier codes are fully qualified.
+
+    In a next step, the token stream of the given program and the code list are
+    traversed sequentially (see `encodeToks`). The information in the token
+    stream is used to:
+
+      * add code elements for newlines, spaces and pragmas
+      * update the qualification information of identifiers in the code list.
+-}
+
+module Html.SyntaxColoring
+  ( Code (..), TypeUsage (..), ConsUsage (..)
+  , IdentUsage (..), FuncUsage (..)
+  , genProgram, code2string, getQualIdent
+  ) where
+
+import Data.Function (on)
+import Data.List     (sortBy)
+
+import Curry.Base.Ident
+import Curry.Base.Position
+import Curry.Base.SpanInfo ()
+import Curry.Syntax
+
+import Base.Messages
+
+-- |Type of codes which are distinguished for HTML output
+-- the boolean flags indicate whether the corresponding identifier
+-- occurs qualified in the source module
+data Code
+  = Keyword     String
+  | Space       Int
+  | NewLine
+  | Pragma      String
+  | TypeCons    TypeUsage  Bool QualIdent
+  | DataCons    ConsUsage  Bool QualIdent
+  | Function    FuncUsage  Bool QualIdent
+  | Identifier  IdentUsage Bool QualIdent
+  | ModuleName  ModuleIdent
+  | Commentary  String
+  | NumberCode  String
+  | StringCode  String
+  | CharCode    String
+  | Symbol      String
+    deriving Show
+
+data TypeUsage
+  = TypeDeclare
+  | TypeRefer
+  | TypeExport
+  | TypeImport
+    deriving Show
+
+data ConsUsage
+  = ConsDeclare
+  | ConsPattern
+  | ConsCall
+  | ConsInfix
+  | ConsExport
+  | ConsImport
+    deriving Show
+
+data FuncUsage
+  = FuncDeclare
+  | FuncTypeSig
+  | FuncCall
+  | FuncInfix
+  | FuncExport
+  | FuncImport
+    deriving Show
+
+data IdentUsage
+  = IdDeclare -- declare a (type) variable
+  | IdRefer   -- refer to a (type) variable
+  | IdUnknown -- unknown usage
+    deriving Show
+
+-- @param fully qualified module
+-- @param lex-Result
+-- @return code list
+genProgram :: Module a -> [(Position, Token)] -> [Code]
+genProgram m pts = encodeToks (first "") (filter validCode (idsModule m)) pts
+
+-- predicate to remove identifier codes for primitives
+-- because they do not form valid link targets
+validCode :: Code -> Bool
+validCode (TypeCons   _ _ t) = t `notElem` [qUnitId, qListId]         && not (isQTupleId t)
+validCode (DataCons   _ _ c) = c `notElem` [qUnitId, qNilId, qConsId] && not (isQTupleId c)
+validCode (Identifier _ _ i) = not $ isAnonId $ unqualify i
+validCode _                  = True
+
+-- @param code
+-- @return qid if available
+getQualIdent :: Code -> Maybe QualIdent
+getQualIdent (DataCons   _ _ qid) = Just qid
+getQualIdent (Function   _ _ qid) = Just qid
+getQualIdent (Identifier _ _ qid) = Just qid
+getQualIdent (TypeCons   _ _ qid) = Just qid
+getQualIdent _                    = Nothing
+
+encodeToks :: Position -> [Code] -> [(Position, Token)] -> [Code]
+encodeToks _   _   []                     = []
+encodeToks cur ids toks@((pos, tok) : ts)
+  -- advance line
+  | line cur   < line   pos = NewLine : encodeToks (nl cur) ids toks
+  -- advance column
+  | column cur < column pos = let d = column pos - column cur
+                              in  Space d : encodeToks (incr cur d) ids toks
+  -- pragma token
+  | isPragmaToken tok       = let (ps, (end:rest)) = break (isPragmaEnd . snd) toks
+                                  s = unwords $ map (showToken . snd) (ps ++ [end])
+                              in  Pragma s : encodeToks (incr cur (length s)) ids rest
+  -- identifier token
+  | isIdentTok tok          = case ids of
+    []     -> encodeTok tok : encodeToks newPos [] ts
+    (i:is)
+      | tokenStr == code2string i' -> i' : encodeToks newPos is ts
+  -- the 'otherwise' case should never occur if the token stream and
+  -- the qualified AST which was used to generate the code list correspond to
+  -- the same module
+      | otherwise                  -> encodeToks cur is toks
+      where i' = setQualified (isQualIdentTok tok) i
+  -- other token
+  | otherwise               = encodeTok tok : encodeToks newPos ids ts
+  where
+  tokenStr = showToken tok
+  newPos   = incr cur (length tokenStr)
+
+setQualified :: Bool -> Code -> Code
+setQualified b (DataCons   u _ c) = DataCons u b c
+setQualified b (Function   u _ f) = Function u b f
+setQualified b (Identifier u _ i) = Identifier u b i
+setQualified b (TypeCons   u _ t) = TypeCons u b t
+setQualified _ m@(ModuleName   _) = m
+setQualified _ s@(Symbol       _) = s
+setQualified _ c                  = internalError $ "Html.SyntaxColoring.setQualified: " ++ show c
+
+code2string :: Code -> String
+code2string (Keyword           s) = s
+code2string (Space             i) = replicate i ' '
+code2string NewLine               = "\n"
+code2string (Pragma            s) = s
+code2string (DataCons    _ b qid) = ident2string b qid
+code2string (TypeCons    _ b qid) = ident2string b qid
+code2string (Function    _ b qid) = ident2string b qid
+code2string (Identifier  _ b qid) = ident2string b qid
+code2string (ModuleName      mid) = moduleName mid
+code2string (Commentary        s) = s
+code2string (NumberCode        s) = s
+code2string (StringCode        s) = s
+code2string (CharCode          s) = s
+code2string (Symbol            s) = s
+
+ident2string :: Bool -> QualIdent -> String
+ident2string False q = idName $ unqualify q
+ident2string True  q = qualName q
+
+encodeTok :: Token -> Code
+encodeTok tok@(Token c _)
+  | c `elem` numCategories          = NumberCode (showToken tok)
+  | c == CharTok                    = CharCode   (showToken tok)
+  | c == StringTok                  = StringCode (showToken tok)
+  | c `elem` keywordCategories      = Keyword    (showToken tok)
+  | c `elem` specialIdentCategories = Keyword    (showToken tok)
+  | c `elem` punctuationCategories  = Symbol     (showToken tok)
+  | c `elem` reservedOpsCategories  = Symbol     (showToken tok)
+  | c `elem` commentCategories      = Commentary (showToken tok)
+  | c `elem` identCategories        = Identifier IdUnknown False $ qualify $ mkIdent
+                                      $ showToken tok
+  | c `elem` whiteSpaceCategories   = Space 0
+  | c `elem` pragmaCategories       = Pragma     (showToken tok)
+  | otherwise                       = internalError $
+    "SyntaxColoring.encodeTok: Unknown token " ++ showToken tok
+
+numCategories :: [Category]
+numCategories = [IntTok, FloatTok]
+
+keywordCategories :: [Category]
+keywordCategories =
+  [ KW_case, KW_class, KW_data, KW_default, KW_deriving, KW_do, KW_else
+  , KW_external, KW_fcase, KW_free, KW_if, KW_import, KW_in
+  , KW_infix, KW_infixl, KW_infixr, KW_instance, KW_let, KW_module, KW_newtype
+  , KW_of, KW_then, KW_type, KW_where
+  ]
+
+specialIdentCategories :: [Category]
+specialIdentCategories =
+  [ Id_as, Id_ccall, Id_forall, Id_hiding
+  , Id_interface, Id_primitive, Id_qualified ]
+
+punctuationCategories :: [Category]
+punctuationCategories =
+  [ LeftParen, RightParen, Semicolon, LeftBrace, RightBrace
+  , LeftBracket, RightBracket, Comma, Underscore, Backquote ]
+
+reservedOpsCategories :: [Category]
+reservedOpsCategories =
+  [ At, Colon, DotDot, DoubleArrow, DoubleColon, Equals, Backslash, Bar
+  , LeftArrow, RightArrow, Tilde ]
+
+commentCategories :: [Category]
+commentCategories = [LineComment, NestedComment]
+
+identCategories :: [Category]
+identCategories = [Id, QId, Sym, QSym, SymDot, SymMinus, SymStar]
+
+isPragmaToken :: Token -> Bool
+isPragmaToken (Token c _) = c `elem` pragmaCategories
+
+isPragmaEnd :: Token -> Bool
+isPragmaEnd (Token c _) = c == PragmaEnd
+
+isIdentTok :: Token -> Bool
+isIdentTok (Token c _) = c `elem` identCategories
+
+isQualIdentTok :: Token -> Bool
+isQualIdentTok (Token c _) = c `elem` [QId, QSym]
+
+whiteSpaceCategories :: [Category]
+whiteSpaceCategories = [EOF, VSemicolon, VRightBrace]
+
+pragmaCategories :: [Category]
+pragmaCategories = [PragmaLanguage, PragmaOptions, PragmaEnd]
+
+cmpDecl :: Decl a -> Decl a -> Ordering
+cmpDecl = compare `on` getPosition
+
+cmpImportDecl :: ImportDecl -> ImportDecl -> Ordering
+cmpImportDecl = compare `on` getPosition
+
+-- -----------------------------------------------------------------------------
+-- Extract all identifiers mentioned in the source code as a Code entity
+-- in the order of their occurrence. The extracted information is then used
+-- to enrich the identifier tokens with additional information, e.g., for
+-- link generation.
+-- -----------------------------------------------------------------------------
+
+idsModule :: Module a -> [Code]
+idsModule (Module _ _ _ mid es is ds) =
+  let hdrCodes = ModuleName mid : idsExportSpec es
+      impCodes = concatMap idsImportDecl (sortBy cmpImportDecl is)
+      dclCodes = concatMap idsDecl       (sortBy cmpDecl ds)
+  in  hdrCodes ++ impCodes ++ dclCodes
+
+-- Exports
+
+idsExportSpec ::  Maybe ExportSpec -> [Code]
+idsExportSpec Nothing                 = []
+idsExportSpec (Just (Exporting _ es)) = concatMap idsExport es
+
+idsExport :: Export -> [Code]
+idsExport (Export            _ qid) = [Function FuncExport False qid]
+idsExport (ExportTypeWith _ qid cs) = TypeCons TypeExport False qid :
+  map (DataCons ConsExport False . qualify) cs
+idsExport (ExportTypeAll     _ qid) = [TypeCons TypeExport False qid]
+idsExport (ExportModule      _ mid) = [ModuleName mid]
+
+-- Imports
+
+idsImportDecl :: ImportDecl -> [Code]
+idsImportDecl (ImportDecl _ mid _ mAlias spec)
+  = ModuleName mid : aliasCode ++ maybe [] (idsImportSpec mid) spec
+  where aliasCode = maybe [] ((:[]) . ModuleName) mAlias
+
+idsImportSpec :: ModuleIdent -> ImportSpec -> [Code]
+idsImportSpec mid (Importing _ is) = concatMap (idsImport mid) is
+idsImportSpec mid (Hiding    _ is) = concatMap (idsImport mid) is
+
+idsImport :: ModuleIdent -> Import -> [Code]
+idsImport mid (Import            _ i) =
+  [Function FuncImport False $ qualifyWith mid i]
+idsImport mid (ImportTypeWith _ t cs) =
+  TypeCons TypeImport False (qualifyWith mid t) :
+    map (DataCons ConsImport False . qualifyWith mid) cs
+idsImport mid (ImportTypeAll     _ t) =
+  [TypeCons TypeImport False $ qualifyWith mid t]
+
+-- Declarations
+
+idsDecl :: Decl a -> [Code]
+idsDecl (InfixDecl         _ _ _ ops) =
+  map (Function FuncInfix False . qualify) ops
+idsDecl (DataDecl    _ d vs cds clss) =
+  TypeCons TypeDeclare False (qualify d) :
+    map (Identifier IdDeclare False . qualify) vs ++
+      concatMap idsConstrDecl cds ++ map (TypeCons TypeRefer False) clss
+idsDecl (ExternalDataDecl     _ d vs) =
+  TypeCons TypeDeclare False (qualify d) :
+    map (Identifier IdDeclare False . qualify) vs
+idsDecl (NewtypeDecl  _ t vs nc clss) =
+  TypeCons TypeDeclare False (qualify t) :
+    map (Identifier IdDeclare False . qualify) vs ++ idsNewConstrDecl nc ++
+      map (TypeCons TypeRefer False) clss
+idsDecl (TypeDecl          _ t vs ty) =
+  TypeCons TypeDeclare False (qualify t) :
+    map (Identifier IdDeclare False . qualify) vs ++ idsTypeExpr ty
+idsDecl (TypeSig            _ fs qty) =
+  map (Function FuncTypeSig False . qualify) fs ++ idsQualTypeExpr qty
+idsDecl (FunctionDecl      _ _ _ eqs) = concatMap idsEquation eqs
+idsDecl (ExternalDecl           _ fs) =
+  map (Function FuncDeclare False . qualify . varIdent) fs
+idsDecl (PatternDecl         _ p rhs) = idsPat p ++ idsRhs rhs
+idsDecl (FreeDecl               _ vs) =
+  map (Identifier IdDeclare False . qualify . varIdent) vs
+idsDecl (DefaultDecl           _ tys) = concatMap idsTypeExpr tys
+idsDecl (ClassDecl     _ _ cx c v ds) =
+  idsContext cx ++ TypeCons TypeDeclare False (qualify c) :
+    Identifier IdDeclare False (qualify v) : concatMap idsClassDecl ds
+idsDecl (InstanceDecl _ _ cx c ty ds) = idsContext cx ++
+  TypeCons TypeRefer False c : idsTypeExpr ty ++ concatMap idsInstanceDecl ds
+
+idsConstrDecl :: ConstrDecl -> [Code]
+idsConstrDecl (ConstrDecl     _ c tys) =
+  DataCons ConsDeclare False (qualify c) : concatMap idsTypeExpr tys
+idsConstrDecl (ConOpDecl _ ty1 op ty2) =
+  idsTypeExpr ty1 ++ (DataCons ConsDeclare False $ qualify op) : idsTypeExpr ty2
+idsConstrDecl (RecordDecl      _ c fs) =
+  DataCons ConsDeclare False (qualify c) : concatMap idsFieldDecl fs
+
+idsNewConstrDecl :: NewConstrDecl -> [Code]
+idsNewConstrDecl (NewConstrDecl _ c     ty) =
+  DataCons ConsDeclare False (qualify c) : idsTypeExpr ty
+idsNewConstrDecl (NewRecordDecl _ c (l,ty)) =
+  DataCons ConsDeclare False (qualify c) :
+    (Function FuncDeclare False $ qualify l) : idsTypeExpr ty
+
+idsClassDecl :: Decl a -> [Code]
+idsClassDecl (TypeSig       _ fs qty) =
+  map (Function FuncDeclare False . qualify) fs ++ idsQualTypeExpr qty
+idsClassDecl (FunctionDecl _ _ _ eqs) = concatMap idsEquation eqs
+idsClassDecl _                        =
+  internalError "SyntaxColoring.idsClassDecl"
+
+idsInstanceDecl :: Decl a -> [Code]
+idsInstanceDecl (FunctionDecl _ _ _ eqs) = concatMap idsEquation eqs
+idsInstanceDecl _                        =
+  internalError "SyntaxColoring.idsInstanceDecl"
+
+idsQualTypeExpr :: QualTypeExpr -> [Code]
+idsQualTypeExpr (QualTypeExpr _ cx ty) = idsContext cx ++ idsTypeExpr ty
+
+idsContext :: Context -> [Code]
+idsContext = concatMap idsConstraint
+
+idsConstraint :: Constraint -> [Code]
+idsConstraint (Constraint _ qcls ty) =
+  TypeCons TypeRefer False qcls : idsTypeExpr ty
+
+idsTypeExpr :: TypeExpr -> [Code]
+idsTypeExpr (ConstructorType _ qid) = [TypeCons TypeRefer False qid]
+idsTypeExpr (ApplyType   _ ty1 ty2) = concatMap idsTypeExpr [ty1, ty2]
+idsTypeExpr (VariableType      _ v) = [Identifier IdRefer False (qualify v)]
+idsTypeExpr (TupleType       _ tys) = concatMap idsTypeExpr tys
+idsTypeExpr (ListType         _ ty) = idsTypeExpr ty
+idsTypeExpr (ArrowType   _ ty1 ty2) = concatMap idsTypeExpr [ty1, ty2]
+idsTypeExpr (ParenType        _ ty) = idsTypeExpr ty
+idsTypeExpr (ForallType    _ vs ty) =
+  map (Identifier IdDeclare False . qualify) vs ++ Symbol "." : idsTypeExpr ty
+
+idsFieldDecl :: FieldDecl -> [Code]
+idsFieldDecl (FieldDecl _ ls ty) =
+  map (Function FuncDeclare False . qualify . unRenameIdent) ls ++ idsTypeExpr ty
+
+idsEquation :: Equation a -> [Code]
+idsEquation (Equation _ lhs rhs) = idsLhs lhs ++ idsRhs rhs
+
+idsLhs :: Lhs a -> [Code]
+idsLhs (FunLhs    _ f ps) =
+  Function FuncDeclare False (qualify f) : concatMap idsPat ps
+idsLhs (OpLhs _ p1 op p2) =
+  idsPat p1 ++ [Function FuncDeclare False $ qualify op] ++ idsPat p2
+idsLhs (ApLhs   _ lhs ps) = idsLhs lhs ++ concatMap idsPat ps
+
+idsRhs :: Rhs a -> [Code]
+idsRhs (SimpleRhs  _ _ e  ds) = idsExpr e ++ concatMap idsDecl ds
+idsRhs (GuardedRhs _ _ ce ds) = concatMap idsCondExpr ce ++ concatMap idsDecl ds
+
+idsCondExpr :: CondExpr a -> [Code]
+idsCondExpr (CondExpr _ e1 e2) = idsExpr e1 ++ idsExpr e2
+
+idsPat :: Pattern a -> [Code]
+idsPat (LiteralPattern          _ _ _) = []
+idsPat (NegativePattern         _ _ _) = []
+idsPat (VariablePattern         _ _ v) = [Identifier IdDeclare False (qualify v)]
+idsPat (ConstructorPattern _ _ qid ps) =
+  DataCons ConsPattern False qid : concatMap idsPat ps
+idsPat (InfixPattern    _ _ p1 qid p2) =
+  idsPat p1 ++ DataCons ConsPattern False qid : idsPat p2
+idsPat (ParenPattern              _ p) = idsPat p
+idsPat (RecordPattern      _ _ qid fs) =
+  DataCons ConsPattern False qid : concatMap (idsField idsPat) fs
+idsPat (TuplePattern            _ ps) = concatMap idsPat ps
+idsPat (ListPattern            _ _ ps) = concatMap idsPat ps
+idsPat (AsPattern               _ v p) =
+  Identifier IdDeclare False (qualify v) : idsPat p
+idsPat (LazyPattern               _ p) = idsPat p
+idsPat (FunctionPattern    _ _ qid ps) =
+  Function FuncCall False qid : concatMap idsPat ps
+idsPat (InfixFuncPattern  _ _ p1 f p2) =
+  idsPat p1 ++ Function FuncInfix False f : idsPat p2
+
+idsExpr :: Expression a -> [Code]
+idsExpr (Literal              _ _ _) = []
+idsExpr (Variable           _ _ qid)
+  | isQualified qid                = [Function FuncCall False qid]
+  | hasGlobalScope (unqualify qid) = [Function FuncCall False qid]
+  | otherwise                      = [Identifier IdRefer False qid]
+idsExpr (Constructor        _ _ qid) = [DataCons ConsCall False qid]
+idsExpr (Paren                  _ e) = idsExpr e
+idsExpr (Typed              _ e qty) = idsExpr e ++ idsQualTypeExpr qty
+idsExpr (Record          _ _ qid fs) =
+  DataCons ConsCall False qid : concatMap (idsField idsExpr) fs
+idsExpr (RecordUpdate        _ e fs) =
+  idsExpr e ++ concatMap (idsField idsExpr) fs
+idsExpr (Tuple                 _ es) = concatMap idsExpr es
+idsExpr (List                _ _ es) = concatMap idsExpr es
+idsExpr (ListCompr        _ e stmts) = idsExpr e ++ concatMap idsStmt stmts
+idsExpr (EnumFrom               _ e) = idsExpr e
+idsExpr (EnumFromThen       _ e1 e2) = concatMap idsExpr [e1, e2]
+idsExpr (EnumFromTo         _ e1 e2) = concatMap idsExpr [e1, e2]
+idsExpr (EnumFromThenTo  _ e1 e2 e3) = concatMap idsExpr [e1, e2, e3]
+idsExpr (UnaryMinus             _ e) = Symbol "-" : idsExpr e
+idsExpr (Apply              _ e1 e2) = idsExpr e1 ++ idsExpr e2
+idsExpr (InfixApply      _ e1 op e2) = idsExpr e1 ++ idsInfix op ++ idsExpr e2
+idsExpr (LeftSection         _ e op) = idsExpr e ++ idsInfix op
+idsExpr (RightSection        _ op e) = idsInfix op ++ idsExpr e
+idsExpr (Lambda              _ ps e) = concatMap idsPat ps ++ idsExpr e
+idsExpr (Let               _ _ ds e) = concatMap idsDecl ds ++ idsExpr e
+idsExpr (Do             _ _ stmts e) = concatMap idsStmt stmts ++ idsExpr e
+idsExpr (IfThenElse      _ e1 e2 e3) = concatMap idsExpr [e1, e2, e3]
+idsExpr (Case          _ _ _ e alts) = idsExpr e ++ concatMap idsAlt alts
+
+idsField :: (a -> [Code]) -> Field a -> [Code]
+idsField f (Field _ l x) = Function FuncCall False l : f x
+
+idsInfix :: InfixOp a -> [Code]
+idsInfix (InfixOp     _ qid) = [Function FuncInfix False qid]
+idsInfix (InfixConstr _ qid) = [DataCons ConsInfix False qid]
+
+idsStmt :: Statement a -> [Code]
+idsStmt (StmtExpr   _ e)  = idsExpr e
+idsStmt (StmtDecl _ _ ds) = concatMap idsDecl ds
+idsStmt (StmtBind _ p e)  = idsPat p ++ idsExpr e
+
+idsAlt :: Alt a -> [Code]
+idsAlt (Alt _ p rhs) = idsPat p ++ idsRhs rhs
+
+-- -----------------------------------------------------------------------------
+-- Conversion from a token to a string
+-- -----------------------------------------------------------------------------
+
+showToken :: Token -> String
+showToken (Token Id                 a) = showAttr a
+showToken (Token QId                a) = showAttr a
+showToken (Token Sym                a) = showAttr a
+showToken (Token QSym               a) = showAttr a
+showToken (Token IntTok             a) = showAttr a
+showToken (Token FloatTok           a) = showAttr a
+showToken (Token CharTok            a) = showAttr a
+showToken (Token StringTok          a) = showAttr a
+showToken (Token LeftParen          _) = "("
+showToken (Token RightParen         _) = ")"
+showToken (Token Semicolon          _) = ";"
+showToken (Token LeftBrace          _) = "{"
+showToken (Token RightBrace         _) = "}"
+showToken (Token LeftBracket        _) = "["
+showToken (Token RightBracket       _) = "]"
+showToken (Token Comma              _) = ","
+showToken (Token Underscore         _) = "_"
+showToken (Token Backquote          _) = "`"
+showToken (Token VSemicolon         _) = ""
+showToken (Token VRightBrace        _) = ""
+showToken (Token At                 _) = "@"
+showToken (Token Colon              _) = ":"
+showToken (Token DotDot             _) = ".."
+showToken (Token DoubleArrow        _) = "=>"
+showToken (Token DoubleColon        _) = "::"
+showToken (Token Equals             _) = "="
+showToken (Token Backslash          _) = "\\"
+showToken (Token Bar                _) = "|"
+showToken (Token LeftArrow          _) = "<-"
+showToken (Token RightArrow         _) = "->"
+showToken (Token Tilde              _) = "~"
+showToken (Token SymDot             _) = "."
+showToken (Token SymMinus           _) = "-"
+showToken (Token SymStar            _) = "*"
+showToken (Token KW_case            _) = "case"
+showToken (Token KW_class           _) = "class"
+showToken (Token KW_data            _) = "data"
+showToken (Token KW_default         _) = "default"
+showToken (Token KW_deriving        _) = "deriving"
+showToken (Token KW_do              _) = "do"
+showToken (Token KW_else            _) = "else"
+showToken (Token KW_external        _) = "external"
+showToken (Token KW_fcase           _) = "fcase"
+showToken (Token KW_free            _) = "free"
+showToken (Token KW_if              _) = "if"
+showToken (Token KW_import          _) = "import"
+showToken (Token KW_in              _) = "in"
+showToken (Token KW_infix           _) = "infix"
+showToken (Token KW_infixl          _) = "infixl"
+showToken (Token KW_infixr          _) = "infixr"
+showToken (Token KW_instance        _) = "instance"
+showToken (Token KW_let             _) = "let"
+showToken (Token KW_module          _) = "module"
+showToken (Token KW_newtype         _) = "newtype"
+showToken (Token KW_of              _) = "of"
+showToken (Token KW_then            _) = "then"
+showToken (Token KW_type            _) = "type"
+showToken (Token KW_where           _) = "where"
+showToken (Token Id_as              _) = "as"
+showToken (Token Id_ccall           _) = "ccall"
+showToken (Token Id_forall          _) = "forall"
+showToken (Token Id_hiding          _) = "hiding"
+showToken (Token Id_interface       _) = "interface"
+showToken (Token Id_primitive       _) = "primitive"
+showToken (Token Id_qualified       _) = "qualified"
+showToken (Token EOF                _) = ""
+showToken (Token PragmaHiding       _) = "{-# HIDING"
+showToken (Token PragmaLanguage     _) = "{-# LANGUAGE"
+showToken (Token PragmaOptions      a) = "{-# OPTIONS" ++ showAttr a
+showToken (Token PragmaMethod       _) = "{-# METHOD"
+showToken (Token PragmaModule       _) = "{-# MODULE"
+showToken (Token PragmaEnd          _) = "#-}"
+showToken (Token LineComment   (StringAttributes s _)) = s
+showToken (Token LineComment   a                     ) = showAttr a
+showToken (Token NestedComment (StringAttributes s _)) = s
+showToken (Token NestedComment                      a) = showAttr a
+
+showAttr :: Attributes -> [Char]
+showAttr NoAttributes             = ""
+showAttr (CharAttributes     c _) = show c
+showAttr (IntAttributes      i _) = show i
+showAttr (FloatAttributes    f _) = show f
+showAttr (StringAttributes   s _) = show s
+showAttr (IdentAttributes    m i)
+  | null m    = idName   $                          (mkIdent i)
+  | otherwise = qualName $ qualifyWith (mkMIdent m) (mkIdent i)
+showAttr (OptionsAttributes mt s) = showTool mt ++ ' ' : s
+
+showTool :: Maybe String -> String
+showTool Nothing  = ""
+showTool (Just t) = '_' : t
diff --git a/src/IL.hs b/src/IL.hs
new file mode 100644
--- /dev/null
+++ b/src/IL.hs
@@ -0,0 +1,19 @@
+{- |
+    Module      :  $Header$
+    Description :  Intermediate language
+    Copyright   :  (c) 2014, Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module is a simple re-export of the definition of the AST of IL
+    and the pretty-printing of IL modules.
+-}
+module IL ( module IL.Type, module IL.Typing, ppModule, showModule ) where
+
+import IL.Pretty     (ppModule)
+import IL.ShowModule (showModule)
+import IL.Type
+import IL.Typing
diff --git a/src/IL/CurryToIL.lhs b/src/IL/CurryToIL.lhs
deleted file mode 100644
--- a/src/IL/CurryToIL.lhs
+++ /dev/null
@@ -1,598 +0,0 @@
-
-% $Id: ILTrans.lhs,v 1.86 2004/02/13 19:23:58 wlux Exp $
-%
-% Copyright (c) 1999-2003, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{ILTrans.lhs}
-\section{Translating Curry into the Intermediate Language}
-After desugaring and lifting have been performed, the source code is
-translated into the intermediate language. Besides translating from
-source terms and expressions into intermediate language terms and
-expressions this phase in particular has to implement the pattern
-matching algorithm for equations and case expressions.
-
-Because of name conflicts between the source and intermediate language
-data structures, we can use only a qualified import for the
-\texttt{IL} module.
-\begin{verbatim}
-
-> module IL.CurryToIL(ilTrans,ilTransIntf, translType) where
-
-> import Data.Maybe
-> import Data.List
-> import qualified Data.Set as Set
-> import qualified Data.Map as Map
-
-> import Curry.Base.Position
-> import Curry.Base.Ident
-> import Curry.Syntax
-> import Curry.Syntax.Utils
-
-> import Types
-> import Base
-> import qualified IL.Type as IL
-> import Utils
-
-
-
-\end{verbatim}
-\paragraph{Modules}
-At the top-level, the compiler has to translate data type, newtype,
-function, and external declarations. When translating a data type or
-newtype declaration, we ignore the types in the declaration and lookup
-the types of the constructors in the type environment instead because
-these types are already fully expanded, i.e., they do not include any
-alias types.
-\begin{verbatim}
-
-> ilTrans :: Bool -> ValueEnv -> TCEnv -> EvalEnv -> Module -> IL.Module
-> ilTrans flat tyEnv tcEnv evEnv (Module m _ ds) = 
->   IL.Module m (imports m ds') ds'
->   where ds' = concatMap (translGlobalDecl flat m tyEnv tcEnv evEnv) ds
-
-> translGlobalDecl :: Bool -> ModuleIdent -> ValueEnv -> TCEnv -> EvalEnv
->                  -> Decl -> [IL.Decl]
-> translGlobalDecl _ m tyEnv tcEnv _ (DataDecl _ tc tvs cs) =
->   [translData m tyEnv tcEnv tc tvs cs]
-> translGlobalDecl _ m tyEnv tcEnv _ (NewtypeDecl _ tc tvs nc) =
->   [translNewtype m tyEnv tcEnv tc tvs nc]
-> translGlobalDecl flat m tyEnv tcEnv evEnv (FunctionDecl pos f eqs) =
->   [translFunction pos flat m tyEnv tcEnv evEnv f eqs]
-> translGlobalDecl _ m tyEnv tcEnv _ (ExternalDecl _ cc ie f _) =
->   [translExternal m tyEnv tcEnv f cc (fromJust ie)]
-> translGlobalDecl _ _ _ _ _ _ = []
-
-> translData :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> [Ident] -> [ConstrDecl]
->            -> IL.Decl
-> translData m tyEnv tcEnv tc tvs cs =
->   IL.DataDecl (qualifyWith m tc) (length tvs)
->               (map (translConstrDecl m tyEnv tcEnv) cs)
-
-> translNewtype :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> [Ident] 
->	        -> NewConstrDecl -> IL.Decl
-> translNewtype m tyEnv tcEnv tc tvs (NewConstrDecl _ _ c _) =
->   IL.NewtypeDecl (qualifyWith m tc) (length tvs)
->                  (IL.ConstrDecl c' (translType' m tyEnv tcEnv ty))
->                  -- (IL.ConstrDecl c' (translType ty))
->   where c' = qualifyWith m c
->         TypeArrow ty _ = constrType tyEnv c'
-
-> translConstrDecl :: ModuleIdent -> ValueEnv -> TCEnv -> ConstrDecl
->                  -> IL.ConstrDecl [IL.Type]
-> translConstrDecl m tyEnv tcEnv d =
->   IL.ConstrDecl c' (map (translType' m tyEnv tcEnv)
->	                  (arrowArgs (constrType tyEnv c')))
->   -- IL.ConstrDecl c' (map translType (arrowArgs (constrType tyEnv c')))
->   where c' = qualifyWith m (constr d)
->         constr (ConstrDecl _ _ c _) = c
->         constr (ConOpDecl _ _ _ op _) = op
-
-> translExternal :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> CallConv
->                -> String -> IL.Decl
-> translExternal m tyEnv tcEnv f cc ie =
->   IL.ExternalDecl f' (callConv cc) ie 
->                   (translType' m tyEnv tcEnv (varType tyEnv f'))
->   -- IL.ExternalDecl f' (callConv cc) ie (translType (varType tyEnv f'))
->   where f' = qualifyWith m f
->         callConv CallConvPrimitive = IL.Primitive
->         callConv CallConvCCall = IL.CCall
-
-\end{verbatim}
-\paragraph{Interfaces}
-In order to generate code, the compiler also needs to know the tags
-and arities of all imported data constructors. For that reason we
-compile the data type declarations of all interfaces into the
-intermediate language, too. In this case we do not lookup the
-types in the environment because the types in the interfaces are
-already fully expanded. Note that we do not translate data types
-which are imported into the interface from some other module.
-\begin{verbatim}
-
-> ilTransIntf :: ValueEnv -> TCEnv -> Interface -> [IL.Decl]
-> ilTransIntf tyEnv tcEnv (Interface m ds) = 
->   foldr (translIntfDecl m tyEnv tcEnv) [] ds
-
-> translIntfDecl :: ModuleIdent -> ValueEnv -> TCEnv -> IDecl -> [IL.Decl] 
->	         -> [IL.Decl]
-> translIntfDecl m tyEnv tcEnv (IDataDecl _ tc tvs cs) ds
->   | not (isQualified tc) = 
->     translIntfData m tyEnv tcEnv (unqualify tc) tvs cs : ds
-> translIntfDecl _ _ _ _ ds = ds
-
-> translIntfData :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> [Ident] 
->	         -> [Maybe ConstrDecl] -> IL.Decl
-> translIntfData m tyEnv tcEnv tc tvs cs =
->   IL.DataDecl (qualifyWith m tc) (length tvs)
->               (map (maybe hiddenConstr 
->	                    (translIntfConstrDecl m tyEnv tcEnv tvs)) cs)
->   where hiddenConstr = IL.ConstrDecl qAnonId []
->         qAnonId = qualify anonId
-
-> translIntfConstrDecl :: ModuleIdent -> ValueEnv -> TCEnv -> [Ident] 
->                      -> ConstrDecl -> IL.ConstrDecl [IL.Type]
-> translIntfConstrDecl m tyEnv tcEnv tvs (ConstrDecl _ _ c tys) =
->   IL.ConstrDecl (qualifyWith m c) (map (translType' m tyEnv tcEnv)
->			                 (toQualTypes m tvs tys))
->   -- IL.ConstrDecl (qualifyWith m c) (map translType (toQualTypes m tvs tys))
-> translIntfConstrDecl m tyEnv tcEnv tvs (ConOpDecl _ _ ty1 op ty2) =
->   IL.ConstrDecl (qualifyWith m op)
->                 (map (translType' m tyEnv tcEnv)
->	               (toQualTypes m tvs [ty1,ty2]))
->   -- IL.ConstrDecl (qualifyWith m op)
->   --              (map translType (toQualTypes m tvs [ty1,ty2]))
-
-\end{verbatim}
-\paragraph{Types}
-The type representation in the intermediate language is the same as
-the internal representation except that it does not support
-constrained type variables and skolem types. The former are fixed and
-the later are replaced by fresh type constructors.
-
-Due to possible occurrence of record types, it is necessary to transform
-them back into their corresponding type constructors.
-\begin{verbatim}
-
-> translType' :: ModuleIdent -> ValueEnv -> TCEnv -> Type -> IL.Type
-> translType' m tyEnv tcEnv ty =
->   translType (elimRecordTypes m tyEnv tcEnv (maximum (0:(typeVars ty))) ty)
-
-> translType :: Type -> IL.Type
-> translType (TypeConstructor tc tys) =
->   IL.TypeConstructor tc (map translType tys)
-> translType (TypeVariable tv) = IL.TypeVariable tv
-> translType (TypeConstrained tys _) = translType (head tys)
-> translType (TypeArrow ty1 ty2) =
->   IL.TypeArrow (translType ty1) (translType ty2)
-> translType (TypeSkolem k) =
->   IL.TypeConstructor (qualify (mkIdent ("_" ++ show k))) []
-
-> elimRecordTypes :: ModuleIdent -> ValueEnv -> TCEnv -> Int -> Type -> Type
-> elimRecordTypes m tyEnv tcEnv n (TypeConstructor t tys) =
->   TypeConstructor t (map (elimRecordTypes m tyEnv tcEnv n) tys)
-> elimRecordTypes m tyEnv tcEnv n (TypeVariable v) =
->   TypeVariable v
-> elimRecordTypes m tyEnv tcEnv n (TypeConstrained tys v) =
->   TypeConstrained (map (elimRecordTypes m tyEnv tcEnv n) tys) v
-> elimRecordTypes m tyEnv tcEnv n (TypeArrow t1 t2) =
->   TypeArrow (elimRecordTypes m tyEnv tcEnv n t1)
->             (elimRecordTypes m tyEnv tcEnv n t2)
-> elimRecordTypes m tyEnv tcEnv n (TypeSkolem v) =
->   TypeSkolem v
-> elimRecordTypes m tyEnv tcEnv n (TypeRecord fs _)
->   | null fs = internalError "elimRecordTypes: empty record type"
->   | otherwise =
->     case (lookupValue (fst (head fs)) tyEnv) of
->       [Label _ r _] ->
->         case (qualLookupTC r tcEnv) of
->           [AliasType _ n' (TypeRecord fs' _)] ->
->	      let is = [0 .. n'-1]
->                 vs = foldl (matchTypeVars fs)
->			     Map.empty
->			     fs'
->		  tys = map (\i -> maybe (TypeVariable (i+n))
->			                 (elimRecordTypes m tyEnv tcEnv n)
->		                         (Map.lookup i vs))
->		            is 
->	      in  TypeConstructor r tys
->	    _ -> internalError "elimRecordTypes: no record type"
->       _ -> internalError "elimRecordTypes: no label"
-
-> matchTypeVars :: [(Ident,Type)] -> Map.Map Int Type -> (Ident,Type) 
->	           -> Map.Map Int Type
-> matchTypeVars fs vs (l,ty) =
->   maybe vs (match vs ty) (lookup l fs)
->   where
->   match vs (TypeVariable i) ty' = Map.insert i ty' vs
->   match vs (TypeConstructor _ tys) (TypeConstructor _ tys') =
->     matchList vs tys tys'
->   match vs (TypeConstrained tys _) (TypeConstrained tys' _) =
->     matchList vs tys tys'
->   match vs (TypeArrow ty1 ty2) (TypeArrow ty1' ty2') =
->     matchList vs [ty1,ty2] [ty1',ty2']
->   match vs (TypeSkolem _) (TypeSkolem _) = vs
->   match vs (TypeRecord fs _) (TypeRecord fs' _) =
->     foldl (matchTypeVars fs') vs fs
->   match vs ty ty' = 
->     internalError ("matchTypeVars: " ++ show ty ++ "\n" ++ show ty')
->
->   matchList vs tys tys' = 
->     foldl (\vs' (ty,ty') -> match vs' ty ty') vs (zip tys tys')
-
-\end{verbatim}
-\paragraph{Functions}
-Each function in the program is translated into a function of the
-intermediate language. The arguments of the function are renamed such
-that all variables occurring in the same position (in different
-equations) have the same name. This is necessary in order to
-facilitate the translation of pattern matching into a \texttt{case}
-expression. We use the following simple convention here: The top-level
-arguments of the function are named from left to right \texttt{\_1},
-\texttt{\_2}, and so on. The names of nested arguments are constructed
-by appending \texttt{\_1}, \texttt{\_2}, etc. from left to right to
-the name that were assigned to a variable occurring at the position of
-the constructor term.
-
-Some special care is needed for the selector functions introduced by
-the compiler in place of pattern bindings. In order to generate the
-code for updating all pattern variables, the equality of names between
-the pattern variables in the first argument of the selector function
-and their repeated occurrences in the remaining arguments must be
-preserved. This means that the second and following arguments of a
-selector function have to be renamed according to the name mapping
-computed for its first argument.
-
-If an evaluation annotation is available for a function, it determines
-the evaluation mode of the case expression. Otherwise, the function
-uses flexible matching.
-\begin{verbatim}
-
-> type RenameEnv = Map.Map Ident Ident
-
-> translFunction :: Position -> Bool -> ModuleIdent -> ValueEnv -> TCEnv
->       -> EvalEnv -> Ident -> [Equation] -> IL.Decl
-> translFunction pos flat m tyEnv tcEnv evEnv f eqs =
->   -- - | f == mkIdent "fun" = error (show (translType' m tyEnv tcEnv ty))
->   -- - | otherwise = 
->     IL.FunctionDecl f' vs (translType' m tyEnv tcEnv ty) expr
->    -- = IL.FunctionDecl f' vs (translType ty)
->    --                  (match ev vs (map (translEquation tyEnv vs vs'') eqs))
->   where f'  = qualifyWith m f
->         ty  = varType tyEnv f'
->         -- ty' = elimRecordType m tyEnv tcEnv (maximum (0:(typeVars ty))) ty
->         ev' = Map.lookup f evEnv
->         ev  = maybe (defaultMode ty) evalMode ev'
->         vs  = if not flat && isFpSelectorId f then translArgs eqs vs' else vs'
->         (vs',vs'') = splitAt (equationArity (head eqs)) 
->                              (argNames (mkIdent ""))
->         expr | ev' == Just EvalChoice
->                = IL.Apply 
->                    (IL.Function 
->                       (qualifyWith preludeMIdent (mkIdent "commit"))
->                       1)
->                    (match (srcRefOf pos) IL.Rigid vs 
->                       (map (translEquation tyEnv vs vs'') eqs))
->              | otherwise
->                =  match (srcRefOf pos) ev vs (map (translEquation tyEnv vs vs'') eqs)
->         ---
->         -- (vs',vs'') = splitAt (arrowArity ty) (argNames (mkIdent ""))
-
-> evalMode :: EvalAnnotation -> IL.Eval
-> evalMode EvalRigid = IL.Rigid
-> evalMode EvalChoice = error "eval choice is not yet supported"
-
-> defaultMode :: Type -> IL.Eval
-> defaultMode _ = IL.Flex
->
-> --defaultMode ty = if isIO (arrowBase ty) then IL.Rigid else IL.Flex
-> --  where TypeConstructor qIOId _ = ioType undefined
-> --        isIO (TypeConstructor tc [_]) = tc == qIOId
-> --        isIO _ = False
-
-> translArgs :: [Equation] -> [Ident] -> [Ident]
-> translArgs [Equation _ (FunLhs _ (t:ts)) _] (v:_) =
->   v : map (translArg (bindRenameEnv v t Map.empty)) ts
->   where translArg env (VariablePattern v) = fromJust (Map.lookup v env)
-
-> translEquation :: ValueEnv -> [Ident] -> [Ident] -> Equation
->                -> ([NestedTerm],IL.Expression)
-> translEquation tyEnv vs vs' (Equation _ (FunLhs _ ts) rhs) =
->   (zipWith translTerm vs ts,
->    translRhs tyEnv vs' (foldr2 bindRenameEnv Map.empty vs ts) rhs)
-
-> translRhs :: ValueEnv -> [Ident] -> RenameEnv -> Rhs -> IL.Expression
-> translRhs tyEnv vs env (SimpleRhs _ e _) = translExpr tyEnv vs env e
-
-
-> equationArity :: Equation -> Int
-> equationArity (Equation _ lhs _) = p_equArity lhs
->  where
->    p_equArity (FunLhs _ ts) = length ts
->    p_equArity (OpLhs _ _ _) = 2
->    p_equArity _             = error "ILTrans - illegal equation"
-
-
-\end{verbatim}
-\paragraph{Pattern Matching}
-The pattern matching code searches for the left-most inductive
-argument position in the left hand sides of all rules defining an
-equation. An inductive position is a position where all rules have a
-constructor rooted term. If such a position is found, a \texttt{case}
-expression is generated for the argument at that position. The
-matching code is then computed recursively for all of the alternatives
-independently. If no inductive position is found, the algorithm looks
-for the left-most demanded argument position, i.e., a position where
-at least one of the rules has a constructor rooted term. If such a
-position is found, an \texttt{or} expression is generated with those
-cases that have a variable at the argument position in one branch and
-all other rules in the other branch. If there is no demanded position,
-the pattern matching is finished and the compiler translates the right
-hand sides of the remaining rules, eventually combining them using
-\texttt{or} expressions.
-
-Actually, the algorithm below combines the search for inductive and
-demanded positions. The function \texttt{match} scans the argument
-lists for the left-most demanded position. If this turns out to be
-also an inductive position, the function \texttt{matchInductive} is
-called in order to generate a \texttt{case} expression. Otherwise, the
-function \texttt{optMatch} is called that tries to find an inductive
-position in the remaining arguments. If one is found,
-\texttt{matchInductive} is called, otherwise the function
-\texttt{optMatch} uses the demanded argument position found by
-\texttt{match}.
-\begin{verbatim}
-
-> data NestedTerm = NestedTerm IL.ConstrTerm [NestedTerm] deriving Show
-
-> pattern (NestedTerm t _) = t
-> arguments (NestedTerm _ ts) = ts
-
-> translLiteral :: Literal -> IL.Literal
-> translLiteral (Char p c) = IL.Char p c
-> translLiteral (Int id i) = IL.Int (srcRefOf (positionOfIdent id)) i
-> translLiteral (Float p f) = IL.Float p f
-> translLiteral _ = internalError "translLiteral"
-
-> translTerm :: Ident -> ConstrTerm -> NestedTerm
-> translTerm _ (LiteralPattern l) =
->   NestedTerm (IL.LiteralPattern (translLiteral l)) []
-> translTerm v (VariablePattern _) = NestedTerm (IL.VariablePattern v) []
-> translTerm v (ConstructorPattern c ts) =
->   NestedTerm (IL.ConstructorPattern c (take (length ts) vs))
->              (zipWith translTerm vs ts)
->   where vs = argNames v
-> translTerm v (AsPattern _ t) = translTerm v t
-> translTerm _ _ = internalError "translTerm"
-
-> bindRenameEnv :: Ident -> ConstrTerm -> RenameEnv -> RenameEnv
-> bindRenameEnv _ (LiteralPattern _) env = env
-> bindRenameEnv v (VariablePattern v') env = Map.insert v' v env
-> bindRenameEnv v (ConstructorPattern _ ts) env =
->   foldr2 bindRenameEnv env (argNames v) ts
-> bindRenameEnv v (AsPattern v' t) env = Map.insert v' v (bindRenameEnv v t env)
-> bindRenameEnv _ _ env = internalError "bindRenameEnv"
-
-> argNames :: Ident -> [Ident]
-> argNames v = [mkIdent (prefix ++ show i) | i <- [1..]]
->   where prefix = name v ++ "_"
-
-> type Match = ([NestedTerm],IL.Expression)
-> type Match' = ([NestedTerm] -> [NestedTerm],[NestedTerm],IL.Expression)
-
-> isDefaultPattern :: IL.ConstrTerm -> Bool
-> isDefaultPattern (IL.VariablePattern _) = True
-> isDefaultPattern _ = False
-
-> isDefaultMatch :: (IL.ConstrTerm,a) -> Bool
-> isDefaultMatch = isDefaultPattern . fst
-
-> match :: SrcRef -> IL.Eval -> [Ident] -> [Match] -> IL.Expression
-> match _   ev [] alts = foldl1 IL.Or (map snd alts)
-> match pos ev (v:vs) alts
->   | null vars = e1
->   | null nonVars = e2
->   | otherwise = optMatch pos ev (IL.Or e1 e2) (v:) vs (map skipArg alts)
->   where (vars,nonVars) = partition isDefaultMatch (map tagAlt alts)
->         e1 = matchInductive pos ev id v vs nonVars
->         e2 = match pos ev vs (map snd vars)
->         tagAlt (t:ts,e) = (pattern t,(arguments t ++ ts,e))
->         skipArg (t:ts,e) = ((t:),ts,e)
-
-> optMatch :: SrcRef -> IL.Eval -> IL.Expression -> ([Ident] -> [Ident]) 
->    -> [Ident] ->[Match'] -> IL.Expression
-> optMatch _ ev e prefix [] alts = e
-> optMatch pos ev e prefix (v:vs) alts
->   | null vars = matchInductive pos ev prefix v vs nonVars
->   | otherwise = optMatch pos ev e (prefix . (v:)) vs (map skipArg alts)
->   where (vars,nonVars) = partition isDefaultMatch (map tagAlt alts)
->         tagAlt (prefix,t:ts,e) = (pattern t,(prefix (arguments t ++ ts),e))
->         skipArg (prefix,t:ts,e) = (prefix . (t:),ts,e)
-
-> matchInductive :: SrcRef -> IL.Eval -> ([Ident] -> [Ident]) -> Ident 
->    -> [Ident] ->[(IL.ConstrTerm,Match)] -> IL.Expression
-> matchInductive pos ev prefix v vs alts =
->   IL.Case pos ev (IL.Variable v) (matchAlts ev prefix vs alts)
-
-> matchAlts :: IL.Eval -> ([Ident] -> [Ident]) -> [Ident] ->
->     [(IL.ConstrTerm,Match)] -> [IL.Alt]
-> matchAlts ev prefix vs [] = []
-> matchAlts ev prefix vs ((t,alt):alts) =
->   IL.Alt t (match (srcRefOf t) 
->                   ev (prefix (vars t ++ vs)) (alt : map snd same)) :
->   matchAlts ev prefix vs others
->   where (same,others) = partition ((t ==) . fst) alts 
->         vars (IL.ConstructorPattern _ vs) = vs
->         vars _ = []
-
-\end{verbatim}
-Matching in a \texttt{case}-expression works a little bit differently.
-In this case, the alternatives are matched from the first to the last
-alternative and the first matching alternative is chosen. All
-remaining alternatives are discarded.
-
-\ToDo{The case matching algorithm should use type information in order
-to detect total matches and immediately discard all alternatives which
-cannot be reached.}
-\begin{verbatim}
-
-> caseMatch :: SrcRef -> ([Ident] -> [Ident]) -> [Ident] -> [Match'] 
->    -> IL.Expression
-> caseMatch _ prefix [] alts = thd3 (head alts)
-> caseMatch r prefix (v:vs) alts
->   | isDefaultMatch (head alts') =
->       caseMatch r (prefix . (v:)) vs (map skipArg alts)
->   | otherwise =
->       IL.Case r IL.Rigid (IL.Variable v) (caseMatchAlts prefix vs alts')
->   where alts' = map tagAlt alts
->         tagAlt (prefix,t:ts,e) = (pattern t,(prefix,arguments t ++ ts,e))
->         skipArg (prefix,t:ts,e) = (prefix . (t:),ts,e)
-
-> caseMatchAlts ::
->     ([Ident] -> [Ident]) -> [Ident] -> [(IL.ConstrTerm,Match')] -> [IL.Alt]
-> caseMatchAlts prefix vs alts = map caseAlt (ts ++ ts')
->   where (ts',ts) = partition isDefaultPattern (nub (map fst alts))
->         caseAlt t =
->           IL.Alt t (caseMatch (srcRefOf t) id (prefix (vars t ++ vs))
->                               (matchingCases t alts))
->         matchingCases t =
->           map (joinArgs (vars t)) . filter (matches t . fst)
->         matches t t' = t == t' || isDefaultPattern t'
->         joinArgs vs (IL.VariablePattern _,(prefix,ts,e)) =
->            (id,prefix (map varPattern vs ++ ts),e)
->         joinArgs _ (_,(prefix,ts,e)) = (id,prefix ts,e)
->         varPattern v = NestedTerm (IL.VariablePattern v) []
->         vars (IL.ConstructorPattern _ vs) = vs
->         vars _ = []
-
-\end{verbatim}
-\paragraph{Expressions}
-Note that the case matching algorithm assumes that the matched
-expression is accessible through a variable. The translation of case
-expressions therefore introduces a let binding for the scrutinized
-expression and immediately throws it away after the matching -- except
-if the matching algorithm has decided to use that variable in the
-right hand sides of the case expression. This may happen, for
-instance, if one of the alternatives contains an \texttt{@}-pattern.
-\begin{verbatim}
-
-> translExpr :: ValueEnv -> [Ident] -> RenameEnv -> Expression -> IL.Expression
-> translExpr _ _ _ (Literal l) = IL.Literal (translLiteral l)
-> translExpr tyEnv _ env (Variable v) =
->   case lookupVar v env of
->     Just v' -> IL.Variable v'
->     Nothing -> IL.Function v (arrowArity (varType tyEnv v))
->   where lookupVar v env
->           | isQualified v = Nothing
->           | otherwise = Map.lookup (unqualify v) env
-> translExpr tyEnv _ _ (Constructor c) =
->   IL.Constructor c (arrowArity (constrType tyEnv c))
-> translExpr tyEnv vs env (Apply e1 e2) =
->   IL.Apply (translExpr tyEnv vs env e1) (translExpr tyEnv vs env e2)
-> translExpr tyEnv vs env (Let ds e) =
->   case ds of
->     [ExtraVariables _ vs] -> foldr IL.Exist e' vs
->     [d] | all (`notElem` bv d) (qfv emptyMIdent d) ->
->       IL.Let (translBinding env' d) e'
->     _ -> IL.Letrec (map (translBinding env') ds) e'
->   where e' = translExpr tyEnv vs env' e
->         env' = foldr2 Map.insert env bvs bvs
->         bvs = bv ds
->         translBinding env (PatternDecl _ (VariablePattern v) rhs) =
->           IL.Binding v (translRhs tyEnv vs env rhs)
->         translBinding env p = error $ "unexpected binding: "++show p
-> translExpr tyEnv ~(v:vs) env (Case r e alts) =
->   case caseMatch r id [v] (map (translAlt v) alts) of
->     IL.Case r mode (IL.Variable v') alts'
->       | v == v' && v `notElem` fv alts' -> IL.Case r mode e' alts'
->     e''
->       | v `elem` fv e'' -> IL.Let (IL.Binding v e') e''
->       | otherwise -> e''
->   where e' = translExpr tyEnv vs env e
->         translAlt v (Alt _ t rhs) =
->           (id,
->            [translTerm v t],
->            translRhs tyEnv vs (bindRenameEnv v t env) rhs)
-> translExpr _ _ _ _ = internalError "translExpr"
-
-> instance Expr IL.Expression where
->   fv (IL.Variable v) = [v]
->   fv (IL.Apply e1 e2) = fv e1 ++ fv e2
->   fv (IL.Case _ _ e alts) = fv e ++ fv alts
->   fv (IL.Or e1 e2) = fv e1 ++ fv e2
->   fv (IL.Exist v e) = filter (/= v) (fv e)
->   fv (IL.Let (IL.Binding v e1) e2) = fv e1 ++ filter (/= v) (fv e2)
->   fv (IL.Letrec bds e) = filter (`notElem` vs) (fv es ++ fv e)
->     where (vs,es) = unzip [(v,e) | IL.Binding v e <- bds]
->   fv _ = []
-
-> instance Expr IL.Alt where
->   fv (IL.Alt (IL.ConstructorPattern _ vs) e) = filter (`notElem` vs) (fv e)
->   fv (IL.Alt (IL.VariablePattern v) e) = filter (v /=) (fv e)
->   fv (IL.Alt _ e) = fv e
-
-\end{verbatim}
-\paragraph{Auxiliary Definitions}
-The functions \texttt{varType} and \texttt{constrType} return the type
-of variables and constructors, respectively. The quantifiers are
-stripped from the types.
-\begin{verbatim}
-
-> varType :: ValueEnv -> QualIdent -> Type
-> varType tyEnv f =
->   case qualLookupValue f tyEnv of
->     [Value _ (ForAll _ ty)] -> ty
->     _ -> internalError ("varType: " ++ show f)
-
-> constrType :: ValueEnv -> QualIdent -> Type
-> constrType tyEnv c =
->   case qualLookupValue c tyEnv of
->     [DataConstructor _ (ForAllExist _ _ ty)] -> ty
->     [NewtypeConstructor _ (ForAllExist _ _ ty)] -> ty
->     _ -> internalError ("constrType: " ++ show c)
-
-\end{verbatim}
-The list of import declarations in the intermediate language code is
-determined by collecting all module qualifiers used in the current
-module.
-\begin{verbatim}
-
-> imports :: ModuleIdent -> [IL.Decl] -> [ModuleIdent]
-> imports m = Set.toList . Set.delete m . Set.fromList . foldr modulesDecl []
-
-> modulesDecl :: IL.Decl -> [ModuleIdent] -> [ModuleIdent]
-> modulesDecl (IL.DataDecl _ _ cs) ms = foldr modulesConstrDecl ms cs
->   where modulesConstrDecl (IL.ConstrDecl _ tys) ms = foldr modulesType ms tys
-> modulesDecl (IL.NewtypeDecl _ _ (IL.ConstrDecl _ ty)) ms = modulesType ty ms
-> modulesDecl (IL.FunctionDecl _ _ ty e) ms = modulesType ty (modulesExpr e ms)
-> modulesDecl (IL.ExternalDecl _ _ _ ty) ms = modulesType ty ms
-
-> modulesType :: IL.Type -> [ModuleIdent] -> [ModuleIdent]
-> modulesType (IL.TypeConstructor tc tys) ms =
->   modules tc (foldr modulesType ms tys)
-> modulesType (IL.TypeVariable _) ms = ms
-> modulesType (IL.TypeArrow ty1 ty2) ms = modulesType ty1 (modulesType ty2 ms)
-
-> modulesExpr :: IL.Expression -> [ModuleIdent] -> [ModuleIdent]
-> modulesExpr (IL.Function f _) ms = modules f ms
-> modulesExpr (IL.Constructor c _) ms = modules c ms
-> modulesExpr (IL.Apply e1 e2) ms = modulesExpr e1 (modulesExpr e2 ms)
-> modulesExpr (IL.Case _ _ e as) ms = modulesExpr e (foldr modulesAlt ms as)
->   where modulesAlt (IL.Alt t e) ms = modulesConstrTerm t (modulesExpr e ms)
->         modulesConstrTerm (IL.ConstructorPattern c _) ms = modules c ms
->         modulesConstrTerm _ ms = ms
-> modulesExpr (IL.Or e1 e2) ms = modulesExpr e1 (modulesExpr e2 ms)
-> modulesExpr (IL.Exist _ e) ms = modulesExpr e ms
-> modulesExpr (IL.Let b e) ms = modulesBinding b (modulesExpr e ms)
-> modulesExpr (IL.Letrec bs e) ms = foldr modulesBinding (modulesExpr e ms) bs
-> modulesExpr _ ms = ms
-
-> modulesBinding :: IL.Binding -> [ModuleIdent] -> [ModuleIdent]
-> modulesBinding (IL.Binding _ e) = modulesExpr e
-
-> modules :: QualIdent -> [ModuleIdent] -> [ModuleIdent]
-> modules x ms = maybe ms (: ms) (qualidMod x)
-
-\end{verbatim}
-
diff --git a/src/IL/Pretty.hs b/src/IL/Pretty.hs
new file mode 100644
--- /dev/null
+++ b/src/IL/Pretty.hs
@@ -0,0 +1,189 @@
+{- |
+    Module      :  $Header$
+    Description :  Pretty printer for IL
+    Copyright   :  (c) 1999 - 2003 Wolfgang Lux
+                                   Martin Engelke
+                       2011 - 2015 Björn Peemöller
+                       2017        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   This module implements just another pretty printer, this time for the
+   intermediate language. It was mainly adapted from the Curry pretty
+   printer which, in turn, is based on Simon Marlow's pretty printer
+   for Haskell.
+-}
+{-# LANGUAGE CPP #-}
+module IL.Pretty (ppModule) where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+import Curry.Base.Ident
+import Curry.Base.Pretty
+import IL.Type
+
+dataIndent :: Int
+dataIndent = 2
+
+bodyIndent :: Int
+bodyIndent = 2
+
+exprIndent :: Int
+exprIndent = 2
+
+caseIndent :: Int
+caseIndent = 2
+
+altIndent :: Int
+altIndent = 2
+
+orIndent :: Int
+orIndent = 2
+
+ppModule :: Module -> Doc
+ppModule (Module m is ds) = sepByBlankLine
+  [ppHeader m, vcat (map ppImport is), sepByBlankLine (map ppDecl ds)]
+
+ppHeader :: ModuleIdent -> Doc
+ppHeader m = text "module" <+> text (moduleName m) <+> text "where"
+
+ppImport :: ModuleIdent -> Doc
+ppImport m = text "import" <+> text (moduleName m)
+
+ppDecl :: Decl -> Doc
+ppDecl (DataDecl                   tc ks cs) = sep $
+  text "data" <+> ppTypeLhs tc (length ks) :
+  map (nest dataIndent)
+      (zipWith (<+>) (equals : repeat (char '|')) (map ppConstr cs))
+ppDecl (NewtypeDecl                tc ks nc) = sep $
+  text "newtype" <+> ppTypeLhs tc (length ks) :
+  [nest dataIndent (equals <+> ppNewConstr nc)]
+ppDecl (ExternalDataDecl              tc ks) =
+  text "external data" <+> ppTypeLhs tc (length ks)
+ppDecl (FunctionDecl             f vs ty e) = ppTypeSig f ty $$ sep
+  [ ppQIdent f <+> hsep (map (ppIdent . snd) vs) <+> equals
+  , nest bodyIndent (ppExpr 0 e)]
+ppDecl (ExternalDecl f _ ty) = text "external" <+> ppTypeSig f ty
+
+ppTypeLhs :: QualIdent -> Int -> Doc
+ppTypeLhs tc n = ppQIdent tc <+> hsep (map text (take n typeVars))
+
+ppConstr :: ConstrDecl -> Doc
+ppConstr (ConstrDecl c tys) = ppQIdent c <+> fsep (map (ppType 2) tys)
+
+ppNewConstr :: NewConstrDecl -> Doc
+ppNewConstr (NewConstrDecl c ty) = ppQIdent c <+> fsep [ppType 2 ty]
+
+ppTypeSig :: QualIdent -> Type -> Doc
+ppTypeSig f ty = ppQIdent f <+> text "::" <+> ppType 0 ty
+
+ppType :: Int -> Type -> Doc
+ppType p (TypeConstructor tc tys)
+  | isQTupleId tc                    = parens
+    (fsep (punctuate comma (map (ppType 0) tys)))
+  | tc == qListId && length tys == 1 = brackets (ppType 0 (head tys))
+  | otherwise                        = parenIf (p > 1 && not (null tys))
+    (ppQIdent tc <+> fsep (map (ppType 2) tys))
+ppType _ (TypeVariable      n) = ppTypeVar n
+ppType p (TypeArrow   ty1 ty2) = parenIf (p > 0)
+                                 (fsep (ppArrow (TypeArrow ty1 ty2)))
+  where
+  ppArrow (TypeArrow ty1' ty2') = ppType 1 ty1' <+> text "->" : ppArrow ty2'
+  ppArrow ty                    = [ppType 0 ty]
+ppType p (TypeForall ns ty)
+  | null ns   = ppType p ty
+  | otherwise = parenIf (p > 0) $ ppQuantifiedTypeVars ns <+> ppType 0 ty
+
+ppTypeVar :: Int -> Doc
+ppTypeVar n
+  | n >= 0    = text (typeVars !! n)
+  | otherwise = text ('_':show (-n))
+
+ppQuantifiedTypeVars :: [(Int, Kind)] -> Doc
+ppQuantifiedTypeVars ns
+  | null ns = empty
+  | otherwise = text "forall" <+> hsep (map (ppTypeVar . fst) ns) <> char '.'
+
+ppBinding :: Binding -> Doc
+ppBinding (Binding v expr) = sep
+  [ppIdent v <+> equals, nest bodyIndent (ppExpr 0 expr)]
+
+ppAlt :: Alt -> Doc
+ppAlt (Alt pat expr) = sep
+  [ppConstrTerm pat <+> text "->", nest altIndent (ppExpr 0 expr)]
+
+ppLiteral :: Literal -> Doc
+ppLiteral (Char  c) = text (show c)
+ppLiteral (Int   i) = integer i
+ppLiteral (Float f) = double f
+
+ppConstrTerm :: ConstrTerm -> Doc
+ppConstrTerm (LiteralPattern     _                    l) = ppLiteral l
+ppConstrTerm (ConstructorPattern _ c [(_, v1), (_, v2)])
+  | isQInfixOp c = ppIdent v1 <+> ppQInfixOp c <+> ppIdent v2
+ppConstrTerm (ConstructorPattern _ c                 vs)
+  | isQTupleId c = parens $ fsep (punctuate comma $ map (ppIdent . snd) vs)
+  | otherwise    = ppQIdent c <+> fsep (map (ppIdent . snd) vs)
+ppConstrTerm (VariablePattern    _                    v) = ppIdent v
+
+ppExpr :: Int -> Expression -> Doc
+ppExpr _ (Literal       _ l) = ppLiteral l
+ppExpr _ (Variable      _ v) = ppIdent v
+ppExpr _ (Function    _ f _) = ppQIdent f
+ppExpr _ (Constructor _ c _) = ppQIdent c
+ppExpr p (Apply (Apply (Function    _ f _) e1) e2)
+  | isQInfixOp f = ppInfixApp p e1 f e2
+ppExpr p (Apply (Apply (Constructor _ c _) e1) e2)
+  | isQInfixOp c = ppInfixApp p e1 c e2
+ppExpr p (Apply       e1 e2) = parenIf (p > 2) $ sep
+  [ppExpr 2 e1, nest exprIndent (ppExpr 3 e2)]
+ppExpr p (Case    ev e alts) = parenIf (p > 0) $
+  text "case" <+> ppEval ev <+> ppExpr 0 e <+> text "of"
+  $$ nest caseIndent (vcat $ map ppAlt alts)
+  where ppEval Rigid = text "rigid"
+        ppEval Flex  = text "flex"
+ppExpr p (Or          e1 e2) = parenIf (p > 0) $ sep
+  [nest orIndent (ppExpr 0 e1), char '|', nest orIndent (ppExpr 0 e2)]
+ppExpr p (Exist       v _ e) = parenIf (p > 0) $ sep
+  [text "let" <+> ppIdent v <+> text "free" <+> text "in", ppExpr 0 e]
+ppExpr p (Let           b e) = parenIf (p > 0) $ sep
+  [text "let" <+> ppBinding b <+> text "in",ppExpr 0 e]
+ppExpr p (Letrec       bs e) = parenIf (p > 0) $ sep
+  [text "letrec" <+> vcat (map ppBinding bs) <+> text "in", ppExpr 0 e]
+ppExpr p (Typed        e ty) = parenIf (p > 0) $ sep
+  [ppExpr 0 e, text "::", ppType 0 ty]
+
+ppInfixApp :: Int -> Expression -> QualIdent -> Expression -> Doc
+ppInfixApp p e1 op e2 = parenIf (p > 1) $ sep
+  [ppExpr 2 e1 <+> ppQInfixOp op, nest exprIndent (ppExpr 2 e2)]
+
+ppIdent :: Ident -> Doc
+ppIdent ident
+  | isInfixOp ident = parens (ppName ident)
+  | otherwise       = ppName ident
+
+ppQIdent :: QualIdent -> Doc
+ppQIdent ident
+  | isQInfixOp ident = parens (ppQual ident)
+  | otherwise        = ppQual ident
+
+ppQInfixOp :: QualIdent -> Doc
+ppQInfixOp op
+  | isQInfixOp op = ppQual op
+  | otherwise     = char '`' <> ppQual op <> char '`'
+
+ppName :: Ident -> Doc
+ppName x = text (idName x)
+
+ppQual :: QualIdent -> Doc
+ppQual x = text (qualName x)
+
+typeVars :: [String]
+typeVars = [mkTypeVar c i | i <- [0 .. ], c <- ['a' .. 'z']] where
+  mkTypeVar :: Char -> Int -> String
+  mkTypeVar c i = c : if i == 0 then [] else show i
diff --git a/src/IL/Pretty.lhs b/src/IL/Pretty.lhs
deleted file mode 100644
--- a/src/IL/Pretty.lhs
+++ /dev/null
@@ -1,167 +0,0 @@
-% $Id: ILPP.lhs,v 1.22 2003/10/28 05:43:43 wlux Exp $
-%
-% Copyright (c) 1999-2003 Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{ILPP.lhs}
-\section{A pretty printer for the intermediate language}
-This module implements just another pretty printer, this time for the
-intermediate language. It was mainly adapted from the Curry pretty
-printer (see sect.~\ref{sec:CurryPP}) which, in turn, is based on Simon
-Marlow's pretty printer for Haskell.
-\begin{verbatim}
-
-> module IL.Pretty(ppModule)  where
-> 
-> import Text.PrettyPrint.HughesPJ
-
-> import Curry.Base.Ident
-> import IL.Type
-
-> default(Int,Double)
-
-> dataIndent = 2
-> bodyIndent = 2
-> exprIndent = 2
-> caseIndent = 2
-> altIndent = 2
-
-> ppModule :: Module -> Doc
-> ppModule (Module m is ds) =
->   vcat (text "module" <+> text (show m) <+> text "where" :
->         map ppImport is ++ map ppDecl ds)
-
-> ppImport :: ModuleIdent -> Doc
-> ppImport m = text "import" <+> text (show m)
-
-> ppDecl :: Decl -> Doc
-> ppDecl (DataDecl tc n cs) =
->   sep (text "data" <+> ppTypeLhs tc n :
->        map (nest dataIndent)
->            (zipWith (<+>) (equals : repeat (char '|')) (map ppConstr cs)))
-> ppDecl (NewtypeDecl tc n (ConstrDecl c ty)) =
->   sep [text "newtype" <+> ppTypeLhs tc n <+> equals,
->        nest dataIndent (ppConstr (ConstrDecl c [ty]))]
-> ppDecl (FunctionDecl f vs ty exp) =
->   ppTypeSig f ty $$
->   sep [ppQIdent f <+> hsep (map ppIdent vs) <+> equals,
->        nest bodyIndent (ppExpr 0 exp)]
-> ppDecl (ExternalDecl f cc ie ty) =
->   sep [text "external" <+> ppCallConv cc <+> text (show ie),
->        nest bodyIndent (ppTypeSig f ty)]
->   where ppCallConv Primitive = text "primitive"
->         ppCallConv CCall = text "ccall"
-
-> ppTypeLhs :: QualIdent -> Int -> Doc
-> ppTypeLhs tc n = ppQIdent tc <+> hsep (map text (take n typeVars))
-
-> ppConstr :: ConstrDecl [Type] -> Doc
-> ppConstr (ConstrDecl c tys) = ppQIdent c <+> fsep (map (ppType 2) tys)
-
-> ppTypeSig :: QualIdent -> Type -> Doc
-> ppTypeSig f ty = ppQIdent f <+> text "::" <+> ppType 0 ty
-
-> ppType :: Int -> Type -> Doc
-> ppType p (TypeConstructor tc tys)
->   | isQTupleId tc = parens (fsep (punctuate comma (map (ppType 0) tys)))
->   | unqualify tc == nilId = brackets (ppType 0 (head tys))
->   | otherwise =
->       ppParen (p > 1 && not (null tys))
->               (ppQIdent tc <+> fsep (map (ppType 2) tys))
-> ppType _ (TypeVariable n)
->   | n >= 0 = text (typeVars !! n)
->   | otherwise = text ('_':show (-n))
-> ppType p (TypeArrow ty1 ty2) =
->   ppParen (p > 0) (fsep (ppArrow (TypeArrow ty1 ty2)))
->   where ppArrow (TypeArrow ty1 ty2) =
->           ppType 1 ty1 <+> text "->" : ppArrow ty2
->         ppArrow ty = [ppType 0 ty]
-
-> ppBinding :: Binding -> Doc
-> ppBinding (Binding v exp) =
->   sep [ppIdent v <+> equals,nest bodyIndent (ppExpr 0 exp)]
-
-> ppAlt :: Alt -> Doc
-> ppAlt (Alt pat exp) =
->   sep [ppConstrTerm pat <+> text "->",nest altIndent (ppExpr 0 exp)]
-
-> ppLiteral :: Literal -> Doc
-> ppLiteral (Char _ c) = text (show c)
-> ppLiteral (Int _ i) = integer i
-> ppLiteral (Float _ f) = double f
-
-> ppConstrTerm :: ConstrTerm -> Doc
-> ppConstrTerm (LiteralPattern l) = ppLiteral l
-> ppConstrTerm (ConstructorPattern c [v1,v2])
->   | isQInfixOp c = ppIdent v1 <+> ppQInfixOp c <+> ppIdent v2
-> ppConstrTerm (ConstructorPattern c vs)
->   | isQTupleId c = parens (fsep (punctuate comma (map ppIdent vs)))
->   | otherwise = ppQIdent c <+> fsep (map ppIdent vs)
-> ppConstrTerm (VariablePattern v) = ppIdent v
-
-> ppExpr :: Int -> Expression -> Doc
-> ppExpr p (Literal l) = ppLiteral l
-> ppExpr p (Variable v) = ppIdent v
-> ppExpr p (Function f _) = ppQIdent f
-> ppExpr p (Constructor c _) = ppQIdent c
-> ppExpr p (Apply (Apply (Function f _) e1) e2)
->   | isQInfixOp f = ppInfixApp p e1 f e2
-> ppExpr p (Apply (Apply (Constructor c _) e1) e2)
->   | isQInfixOp c = ppInfixApp p e1 c e2
-> ppExpr p (Apply e1 e2) =
->   ppParen (p > 2) (sep [ppExpr 2 e1,nest exprIndent (ppExpr 3 e2)])
-> ppExpr p (Case _ ev e alts) =
->   ppParen (p > 0)
->           (text "case" <+> ppEval ev <+> ppExpr 0 e <+> text "of" $$
->            nest caseIndent (vcat (map ppAlt alts)))
->   where ppEval Rigid = text "rigid"
->         ppEval Flex = text "flex"
-> ppExpr p (Or e1 e2) =
->   ppParen (p > 0) (sep [ppExpr 0 e1,char '|' <+> ppExpr 0 e2])
-> ppExpr p (Exist v e) =
->   ppParen (p > 0)
->           (sep [text "let" <+> ppIdent v <+> text "free" <+> text "in",
->                 ppExpr 0 e])
-> ppExpr p (Let b e) =
->   ppParen (p > 0) (sep [text "let" <+> ppBinding b <+> text "in",ppExpr 0 e])
-> ppExpr p (Letrec bs e) =
->   ppParen (p > 0)
->           (sep [text "letrec" <+> vcat (map ppBinding bs) <+> text "in",
->                 ppExpr 0 e])
-
-> ppInfixApp :: Int -> Expression -> QualIdent -> Expression -> Doc
-> ppInfixApp p e1 op e2 =
->   ppParen (p > 1)
->           (sep [ppExpr 2 e1 <+> ppQInfixOp op,nest exprIndent (ppExpr 2 e2)])
-
-> ppIdent :: Ident -> Doc
-> ppIdent ident
->   | isInfixOp ident = parens (ppName ident)
->   | otherwise = ppName ident
-
-> ppQIdent :: QualIdent -> Doc
-> ppQIdent ident
->   | isQInfixOp ident = parens (ppQual ident)
->   | otherwise = ppQual ident
-
-> ppQInfixOp :: QualIdent -> Doc
-> ppQInfixOp op
->   | isQInfixOp op = ppQual op
->   | otherwise = char '`' <> ppQual op <> char '`'
-
-> ppName :: Ident -> Doc
-> ppName x = text (name x)
-
-> ppQual :: QualIdent -> Doc
-> ppQual x = text (qualName x)
-
-> typeVars :: [String]
-> typeVars = [mkTypeVar c i | i <- [0..], c <- ['a' .. 'z']]
->   where mkTypeVar c i = c : if i == 0 then [] else show i
-
-> ppParen :: Bool -> Doc -> Doc
-> ppParen p = if p then parens else id
-
-\end{verbatim}
diff --git a/src/IL/Scope.hs b/src/IL/Scope.hs
deleted file mode 100644
--- a/src/IL/Scope.hs
+++ /dev/null
@@ -1,124 +0,0 @@
-module IL.Scope (getModuleScope,
-		insertDeclScope, insertConstrDeclScope,
-		insertCallConvScope, insertTypeScope,
-		insertLiteralScope, insertConstrTermScope,
-		insertExprScope, insertAltScope,
-		insertBindingScope) where
-
-import Curry.Base.Ident
-
-import IL.Type
-import OldScopeEnv as ScopeEnv
-
-
--------------------------------------------------------------------------------
-
---
-getModuleScope :: Module -> ScopeEnv
-getModuleScope (Module _ _ decls) = foldl insertDecl newScopeEnv decls
-
-
---
-insertDeclScope :: ScopeEnv -> Decl -> ScopeEnv
-insertDeclScope env (DataDecl _ _ _) = env
-insertDeclScope env (NewtypeDecl _ _ _) = env
-insertDeclScope env (FunctionDecl _ params _ _)
-   = foldr ScopeEnv.insertIdent (ScopeEnv.beginScope env) params
-insertDeclScope env (ExternalDecl _ _ _ _) = env
-
-
---
-insertConstrDeclScope :: ScopeEnv -> ConstrDecl [Type] -> ScopeEnv
-insertConstrDeclScope env _ = env
-
-
---
-insertCallConvScope :: ScopeEnv -> CallConv -> ScopeEnv
-insertCallConvScope env _ = env
-
-
---
-insertTypeScope :: ScopeEnv -> Type -> ScopeEnv
-insertTypeScope env _ = env
-
-
---
-insertLiteralScope :: ScopeEnv -> Literal -> ScopeEnv
-insertLiteralScope env _ = env
-
-
---
-insertConstrTermScope :: ScopeEnv -> ConstrTerm -> ScopeEnv
-insertConstrTermScope env _ = env
-
-
---
-insertExprScope :: ScopeEnv -> Expression -> ScopeEnv
-insertExprScope env (Literal _) = env
-insertExprScope env (Variable _) = env
-insertExprScope env (Function _ _) = env
-insertExprScope env (Constructor _ _) = env
-insertExprScope env (Apply _ _) = env
-insertExprScope env (Case _ _ _ _) = env
-insertExprScope env (Or _ _) = env
-insertExprScope env (Exist ident _)
-   = ScopeEnv.insertIdent ident (ScopeEnv.beginScope env)
-insertExprScope env (Let bind _)
-   = insertBinding (beginScope env) bind
-insertExprScope env (Letrec binds _)
-   = foldl insertBinding (beginScope env) binds
-
-
---
-insertAltScope :: ScopeEnv -> Alt -> ScopeEnv
-insertAltScope env (Alt cterm _)
-   = insertConstrTerm (ScopeEnv.beginScope env) cterm
-
-
---
-insertBindingScope :: ScopeEnv -> Binding -> ScopeEnv
-insertBindingScope env _ = env
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
---
-insertDecl :: ScopeEnv -> Decl -> ScopeEnv
-insertDecl env (DataDecl qident _ cdecls)
-   = foldl insertConstrDecl
-	 (ScopeEnv.insertIdent (unqualify qident) env)
-	 cdecls
-
-insertDecl env (NewtypeDecl qident _ cdecl)
-   = insertConstrDecl (ScopeEnv.insertIdent (unqualify qident) env) cdecl
-
-insertDecl env (FunctionDecl qident _ _ _)
-   = ScopeEnv.insertIdent (unqualify qident) env
-
-insertDecl env (ExternalDecl qident _ _ _)
-   = ScopeEnv.insertIdent (unqualify qident) env
-
-
---
-insertConstrDecl :: ScopeEnv -> ConstrDecl a -> ScopeEnv
-insertConstrDecl env (ConstrDecl qident _)
-   = ScopeEnv.insertIdent (unqualify qident) env
-
-
---
-insertConstrTerm :: ScopeEnv -> ConstrTerm -> ScopeEnv
-insertConstrTerm env (LiteralPattern _) = env
-insertConstrTerm env (ConstructorPattern _ params)
-   = foldr ScopeEnv.insertIdent env params
-insertConstrTerm env (VariablePattern ident)
-   = ScopeEnv.insertIdent ident env
-
-
---
-insertBinding :: ScopeEnv -> Binding -> ScopeEnv
-insertBinding env (Binding ident _) = ScopeEnv.insertIdent ident env
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
diff --git a/src/IL/ShowModule.hs b/src/IL/ShowModule.hs
new file mode 100644
--- /dev/null
+++ b/src/IL/ShowModule.hs
@@ -0,0 +1,263 @@
+{- |
+    Module      :  $Header$
+    Description :  Custom Show implementation for IL
+    Copyright   :  (c) 2015        Björn Peemöller
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   This module implements a generic show function comparable to the one
+   obtained by @deriving Show@. However, the internal representation of
+   identifiers is hidden to avoid syntactic clutter.
+-}
+
+module IL.ShowModule (showModule) where
+
+import Curry.Base.Ident
+import Curry.Base.Position
+
+import IL.Type
+
+-- |Show a IL module like by an devired 'Show' instance
+showModule :: Module -> String
+showModule m = showsModule m "\n"
+
+showsModule :: Module -> ShowS
+showsModule (Module mident imps decls)
+  = showsString "Module "
+  . showsModuleIdent mident . newline
+  . showsList (\i -> showsModuleIdent i . newline) imps
+  . showsList (\d -> showsDecl d . newline) decls
+
+showsDecl :: Decl -> ShowS
+showsDecl (DataDecl qident arity constrdecls)
+  = showsString "(DataDecl "
+  . showsQualIdent qident . space
+  . shows arity . space
+  . showsList showsConstrDecl constrdecls
+  . showsString ")"
+showsDecl (NewtypeDecl qident arity newconstrdecl)
+  = showsString "(NewtypeDecl "
+  . showsQualIdent qident . space
+  . shows arity . space
+  . showsNewConstrDecl newconstrdecl
+  . showsString ")"
+showsDecl (ExternalDataDecl qident arity)
+  = showsString "(ExternalDataDecl "
+  . showsQualIdent qident . space
+  . shows arity
+  . showsString ")"
+showsDecl (FunctionDecl qident idents typ expr)
+  = showsString "(FunctionDecl "
+  . showsQualIdent qident . space
+  . showsList (showsIdent . snd) idents . space
+  . showsType typ . space
+  . showsExpression expr
+  . showsString ")"
+showsDecl (ExternalDecl qident arity typ)
+  = showsString "(ExternalDecl "
+  . showsQualIdent qident . space
+  . shows arity
+  . showsType typ
+  . showsString ")"
+
+showsConstrDecl :: ConstrDecl -> ShowS
+showsConstrDecl (ConstrDecl qident tys)
+  = showsString "(ConstrDecl "
+  . showsQualIdent qident . space
+  . showsList showsType tys
+  . showsString ")"
+
+showsNewConstrDecl :: NewConstrDecl -> ShowS
+showsNewConstrDecl (NewConstrDecl qident ty)
+  = showsString "(NewConstrDecl "
+  . showsQualIdent qident . space
+  . showsType ty
+  . showsString ")"
+
+showsType :: Type -> ShowS
+showsType (TypeConstructor qident types)
+  = showsString "(TypeConstructor "
+  . showsQualIdent qident . space
+  . showsList showsType types
+  . showsString ")"
+showsType (TypeVariable int)
+  = showsString "(TypeVariable "
+  . shows int
+  . showsString ")"
+showsType (TypeArrow type1 type2)
+  = showsString "(TypeArrow "
+  . showsType type1 . space
+  . showsType type2
+  . showsString ")"
+showsType (TypeForall ints typ)
+  = showsString "(TypeForall "
+  . showsList shows ints . space
+  . showsType typ
+  . showsString ")"
+
+showsLiteral :: Literal -> ShowS
+showsLiteral (Char c)
+  = showsString "(Char "
+  . shows c
+  . showsString ")"
+showsLiteral (Int n)
+  = showsString "(Int "
+  . shows n
+  . showsString ")"
+showsLiteral (Float x)
+  = showsString "(Float "
+  . shows x
+  . showsString ")"
+
+showsConstrTerm :: ConstrTerm -> ShowS
+showsConstrTerm (LiteralPattern ty lit)
+  = showsString "(LiteralPattern "
+  . showsType ty
+  . showsLiteral lit
+  . showsString ")"
+showsConstrTerm (ConstructorPattern ty qident idents)
+  = showsString "(ConstructorPattern "
+  . showsType ty
+  . showsQualIdent qident . space
+  . showsList (showsIdent . snd) idents
+  . showsString ")"
+showsConstrTerm (VariablePattern ty ident)
+  = showsString "(VariablePattern "
+  . showsType ty
+  . showsIdent ident
+  . showsString ")"
+
+showsExpression :: Expression -> ShowS
+showsExpression (Literal ty lit)
+  = showsString "(Literal "
+  . showsType ty
+  . showsLiteral lit
+  . showsString ")"
+showsExpression (Variable ty ident)
+  = showsString "(Variable "
+  . showsType ty
+  . showsIdent ident
+  . showsString ")"
+showsExpression (Function ty qident int)
+  = showsString "(Function "
+  . showsType ty
+  . showsQualIdent qident . space
+  . shows int
+  . showsString ")"
+showsExpression (Constructor ty qident int)
+  = showsString "(Constructor "
+  . showsType ty
+  . showsQualIdent qident . space
+  . shows int
+  . showsString ")"
+showsExpression (Apply exp1 exp2)
+  = showsString "(Apply "
+  . showsExpression exp1 . space
+  . showsExpression exp2
+  . showsString ")"
+showsExpression (Case eval expr alts)
+  = showsString "(Case "
+  . showsEval eval . space
+  . showsExpression expr . space
+  . showsList showsAlt alts
+  . showsString ")"
+showsExpression (Or exp1 exp2)
+  = showsString "(Or "
+  . showsExpression exp1 . space
+  . showsExpression exp2
+  . showsString ")"
+showsExpression (Exist ident ty expr)
+  = showsString "(Exist "
+  . showsIdent ident . space
+  . showsType ty . space
+  . showsExpression expr
+  . showsString ")"
+showsExpression (Let bind expr)
+  = showsString "(Let "
+  . showsBinding bind . space
+  . showsExpression expr
+  . showsString ")"
+showsExpression (Letrec binds expr)
+  = showsString "(Letrec "
+  . showsList showsBinding binds . space
+  . showsExpression expr
+  . showsString ")"
+showsExpression (Typed expr typ)
+  = showsString "(Typed "
+  . showsExpression expr . space
+  . showsType typ
+  . showsString ")"
+
+showsEval :: Eval -> ShowS
+showsEval Rigid = showsString "Rigid"
+showsEval Flex  = showsString "Flex"
+
+showsAlt :: Alt -> ShowS
+showsAlt (Alt constr expr)
+  = showsString "(Alt "
+  . showsConstrTerm constr . space
+  . showsExpression expr
+  . showsString ")"
+
+showsBinding :: Binding -> ShowS
+showsBinding (Binding ident expr)
+  = showsString "(Binding "
+  . showsIdent ident . space
+  . showsExpression expr
+  . showsString ")"
+
+showsPosition :: Position -> ShowS
+showsPosition Position { line = l, column = c } = showsPair shows shows (l, c)
+showsPosition _ = showsString "(0,0)"
+
+showsString :: String -> ShowS
+showsString = (++)
+
+space :: ShowS
+space = showsString " "
+
+newline :: ShowS
+newline = showsString "\n"
+
+showsMaybe :: (a -> ShowS) -> Maybe a -> ShowS
+showsMaybe shs = maybe (showsString "Nothing")
+                       (\x -> showsString "(Just " . shs x . showsString ")")
+
+showsList :: (a -> ShowS) -> [a] -> ShowS
+showsList _   [] = showsString "[]"
+showsList shs (x:xs)
+  = showsString "["
+  . foldl (\sys y -> sys . showsString "," . shs y) (shs x) xs
+  . showsString "]"
+
+showsPair :: (a -> ShowS) -> (b -> ShowS) -> (a,b) -> ShowS
+showsPair sa sb (a,b)
+  = showsString "(" . sa a . showsString "," . sb b . showsString ")"
+
+showsIdent :: Ident -> ShowS
+showsIdent (Ident spi x n)
+  = showsString "(Ident " . showsPosition (getPosition spi) . space
+  . shows x . space . shows n . showsString ")"
+
+showsQualIdent :: QualIdent -> ShowS
+showsQualIdent (QualIdent _ mident ident)
+  = showsString "(QualIdent "
+  . showsMaybe showsModuleIdent mident
+  . space
+  . showsIdent ident
+  . showsString ")"
+
+showsModuleIdent :: ModuleIdent -> ShowS
+showsModuleIdent (ModuleIdent spi ss)
+  = showsString "(ModuleIdent "
+  . showsPosition (getPosition spi) . space
+  . showsList (showsQuotes showsString) ss
+  . showsString ")"
+
+showsQuotes :: (a -> ShowS) -> a -> ShowS
+showsQuotes sa a
+  = showsString "\"" . sa a . showsString "\""
diff --git a/src/IL/Type.hs b/src/IL/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/IL/Type.hs
@@ -0,0 +1,155 @@
+{- |
+    Module      :  $Header$
+    Description :  Definition of the intermediate language (IL)
+    Copyright   :  (c) 1999 - 2003 Wolfgang Lux
+                                   Martin Engelke
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   The module 'IL' defines the intermediate language which will be
+   compiled into abstract machine code. The intermediate language removes
+   a lot of syntactic sugar from the Curry source language.  Top-level
+   declarations are restricted to data type and function definitions. A
+   newtype definition serves mainly as a hint to the backend that it must
+   provide an auxiliary function for partial applications of the
+   constructor (Newtype constructors must not occur in patterns
+   and may be used in expressions only as partial applications.).
+
+   Type declarations use a de-Bruijn indexing scheme (starting at 0) for
+   type variables. In the type of a function, all type variables are
+   numbered in the order of their occurence from left to right, i.e., a
+   type '(Int -> b) -> (a,b) -> c -> (a,c)' is translated into the
+   type (using integer numbers to denote the type variables)
+   '(Int -> 0) -> (1,0) -> 2 -> (1,2)'.
+
+   Pattern matching in an equation is handled via flexible and rigid
+   'Case' expressions. Overlapping rules are translated with the
+   help of 'Or' expressions. The intermediate language has three
+   kinds of binding expressions, 'Exist' expressions introduce a
+   new logical variable, 'Let' expression support a single
+   non-recursive variable binding, and 'Letrec' expressions
+   introduce multiple variables with recursive initializer expressions.
+   The intermediate language explicitly distinguishes (local) variables
+   and (global) functions in expressions.
+
+   Note: this modified version uses haskell type 'Integer'
+   instead of 'Int' for representing integer values. This provides
+   an unlimited range of integer constants in Curry programs.
+-}
+
+module IL.Type
+  ( -- * Representation of (type) variables
+    TypeVariableWithKind
+    -- * Data types
+  , Module (..), Decl (..), ConstrDecl (..), NewConstrDecl (..), Type (..)
+  , Kind (..), Literal (..), ConstrTerm (..), Expression (..), Eval (..)
+  , Alt (..), Binding (..)
+  ) where
+
+import Curry.Base.Ident
+
+import Base.Expr
+
+data Module = Module ModuleIdent [ModuleIdent] [Decl]
+    deriving (Eq, Show)
+
+data Decl
+  = DataDecl         QualIdent [Kind] [ConstrDecl]
+  | NewtypeDecl      QualIdent [Kind] NewConstrDecl
+  | ExternalDataDecl QualIdent [Kind]
+  | FunctionDecl     QualIdent [(Type, Ident)] Type Expression
+  | ExternalDecl     QualIdent Int Type
+    deriving (Eq, Show)
+
+data NewConstrDecl = NewConstrDecl QualIdent Type
+    deriving (Eq, Show)
+
+data ConstrDecl = ConstrDecl QualIdent [Type]
+    deriving (Eq, Show)
+
+type TypeVariableWithKind = (Int, Kind)
+
+data Type
+  = TypeConstructor QualIdent [Type]
+  | TypeVariable    Int
+  | TypeArrow       Type Type
+  | TypeForall      [TypeVariableWithKind] Type
+    deriving (Eq, Show)
+
+data Kind
+  = KindStar
+  | KindVariable Int
+  | KindArrow Kind Kind
+    deriving (Eq, Ord, Show)
+
+data Literal
+  = Char  Char
+  | Int   Integer
+  | Float Double
+    deriving (Eq, Show)
+
+data ConstrTerm
+    -- |literal patterns
+  = LiteralPattern Type Literal
+    -- |constructors
+  | ConstructorPattern Type QualIdent [(Type, Ident)]
+    -- |default
+  | VariablePattern Type Ident
+  deriving (Eq, Show)
+
+data Expression
+    -- |literal constants
+  = Literal Type Literal
+    -- |variables
+  | Variable Type Ident
+    -- |functions
+  | Function Type QualIdent Int
+    -- |constructors
+  | Constructor Type QualIdent Int
+    -- |applications
+  | Apply Expression Expression
+    -- |case expressions
+  | Case Eval Expression [Alt]
+    -- |non-deterministic or
+  | Or Expression Expression
+    -- |exist binding (introduction of a free variable)
+  | Exist Ident Type Expression
+    -- |let binding
+  | Let Binding Expression
+    -- |letrec binding
+  | Letrec [Binding] Expression
+    -- |typed expression
+  | Typed Expression Type
+  deriving (Eq, Show)
+
+data Eval
+  = Rigid
+  | Flex
+    deriving (Eq, Show)
+
+data Alt = Alt ConstrTerm Expression
+    deriving (Eq, Show)
+
+data Binding = Binding Ident Expression
+    deriving (Eq, Show)
+
+instance Expr Expression where
+  fv (Variable          _ v) = [v]
+  fv (Apply           e1 e2) = fv e1 ++ fv e2
+  fv (Case         _ e alts) = fv e  ++ fv alts
+  fv (Or              e1 e2) = fv e1 ++ fv e2
+  fv (Exist           v _ e) = filter (/= v) (fv e)
+  fv (Let (Binding v e1) e2) = fv e1 ++ filter (/= v) (fv e2)
+  fv (Letrec          bds e) = filter (`notElem` vs) (fv es ++ fv e)
+    where (vs, es) = unzip [(v, e') | Binding v e' <- bds]
+  fv (Typed             e _) = fv e
+  fv _                       = []
+
+instance Expr Alt where
+  fv (Alt (ConstructorPattern _ _ vs) e) = filter (`notElem` map snd vs) (fv e)
+  fv (Alt (VariablePattern       _ v) e) = filter (v /=) (fv e)
+  fv (Alt _                           e) = fv e
diff --git a/src/IL/Type.lhs b/src/IL/Type.lhs
deleted file mode 100644
--- a/src/IL/Type.lhs
+++ /dev/null
@@ -1,112 +0,0 @@
-> {-# LANGUAGE DeriveDataTypeable #-}
-
-% $Id: IL.lhs,v 1.18 2003/10/28 05:43:38 wlux Exp $
-%
-% Copyright (c) 1999-2003 Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{IL.lhs}
-\section{The intermediate language}
-The module \texttt{IL} defines the intermediate language which will be
-compiled into abstract machine code. The intermediate language removes
-a lot of syntactic sugar from the Curry source language.  Top-level
-declarations are restricted to data type and function definitions. A
-newtype definition serves mainly as a hint to the backend that it must
-provide an auxiliary function for partial applications of the
-constructor. \textbf{Newtype constructors must not occur in patterns
-and may be used in expressions only as partial applications.}
-
-Type declarations use a de-Bruijn indexing scheme (starting at 0) for
-type variables. In the type of a function, all type variables are
-numbered in the order of their occurence from left to right, i.e., a
-type \texttt{(Int -> b) -> (a,b) -> c -> (a,c)} is translated into the
-type (using integer numbers to denote the type variables)
-\texttt{(Int -> 0) -> (1,0) -> 2 -> (1,2)}.
-
-Pattern matching in an equation is handled via flexible and rigid
-\texttt{Case} expressions. Overlapping rules are translated with the
-help of \texttt{Or} expressions. The intermediate language has three
-kinds of binding expressions, \texttt{Exist} expressions introduce a
-new logical variable, \texttt{Let} expression support a single
-non-recursive variable binding, and \texttt{Letrec} expressions
-introduce multiple variables with recursive initializer expressions.
-The intermediate language explicitly distinguishes (local) variables
-and (global) functions in expressions.
-
-\em{Note:} this modified version uses haskell type \texttt{Integer}
-instead of \texttt{Int} for representing integer values. This provides
-an unlimited range of integer constants in Curry programs.
-\begin{verbatim}
-
-> module IL.Type where
-
-> import Data.Generics
-> import Curry.Base.Ident
-> import Curry.Base.Position (SrcRef(..))
-
-> data Module = Module ModuleIdent [ModuleIdent] [Decl] deriving (Eq,Show)
-
-> data Decl = 
->     DataDecl QualIdent Int [ConstrDecl [Type]]
->   | NewtypeDecl QualIdent Int (ConstrDecl Type)
->   | FunctionDecl QualIdent [Ident] Type Expression
->   | ExternalDecl QualIdent CallConv String Type
->   deriving (Eq,Show)
-
-> data ConstrDecl a = ConstrDecl QualIdent a deriving (Eq,Show)
-> data CallConv = Primitive | CCall deriving (Eq,Show)
-
-> data Type =
->     TypeConstructor QualIdent [Type]
->   | TypeVariable Int
->   | TypeArrow Type Type
->   deriving (Eq,Show, Typeable, Data)
-
-> data Literal = Char SrcRef Char | Int SrcRef Integer | Float SrcRef Double deriving (Eq,Show)
-
-> data ConstrTerm =
->   -- literal patterns
->     LiteralPattern Literal
->   -- constructors
->   | ConstructorPattern QualIdent [Ident]
->   -- default
->   | VariablePattern Ident
->   deriving (Eq,Show)
-
-> data Expression =
->   -- literal constants
->     Literal Literal
->   -- variables, functions, constructors
->   | Variable Ident | Function QualIdent Int | Constructor QualIdent Int
->   -- applications
->   | Apply Expression Expression
->   -- case expressions
->   | Case SrcRef Eval Expression [Alt]
->   -- non-determinisismic or
->   | Or Expression Expression
->   -- binding forms
->   | Exist Ident Expression
->   | Let Binding Expression
->   | Letrec [Binding] Expression
->   deriving (Eq,Show)
-
-> data Eval = Rigid | Flex deriving (Eq,Show)
-> data Alt = Alt ConstrTerm Expression deriving (Eq,Show)
-> data Binding = Binding Ident Expression deriving (Eq,Show)
-
-\end{verbatim}
-
-> instance SrcRefOf ConstrTerm where
->   srcRefOf (LiteralPattern l) = srcRefOf l
->   srcRefOf (ConstructorPattern i _) = srcRefOf i
->   srcRefOf (VariablePattern i) = srcRefOf i
-
-
-> instance SrcRefOf Literal where
->   srcRefOf (Char s _)   = s
->   srcRefOf (Int s _)    = s
->   srcRefOf (Float s _)  = s  
-
-
diff --git a/src/IL/Typing.hs b/src/IL/Typing.hs
new file mode 100644
--- /dev/null
+++ b/src/IL/Typing.hs
@@ -0,0 +1,44 @@
+{- |
+    Module      :  $Header$
+    Description :  TODO
+    Copyright   :  (c)        2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   TODO
+-}
+
+module IL.Typing (Typeable(..)) where
+
+import Base.Messages (internalError)
+
+import IL.Type
+
+class Typeable a where
+  typeOf :: a -> Type
+
+instance Typeable ConstrTerm where
+  typeOf (LiteralPattern ty _) = ty
+  typeOf (ConstructorPattern ty _ _) = ty
+  typeOf (VariablePattern ty _) = ty
+
+instance Typeable Expression where
+  typeOf (Literal ty _) = ty
+  typeOf (Variable ty _) = ty
+  typeOf (Function ty _ _) = ty
+  typeOf (Constructor ty _ _) = ty
+  typeOf (Apply e _) = case typeOf e of
+    TypeArrow _ ty -> ty
+    _ -> internalError "IL.Typing.typeOf: application"
+  typeOf (Case _ _ as) = typeOf $ head as
+  typeOf (Or e _) = typeOf e
+  typeOf (Exist _ _ e) = typeOf e
+  typeOf (Let _ e) = typeOf e
+  typeOf (Letrec _ e) = typeOf e
+  typeOf (Typed e _) = typeOf e
+
+instance Typeable Alt where
+  typeOf (Alt _ e) = typeOf e
diff --git a/src/IL/XML.lhs b/src/IL/XML.lhs
deleted file mode 100644
--- a/src/IL/XML.lhs
+++ /dev/null
@@ -1,518 +0,0 @@
-
-% $Id: ILxml.lhs,v 1.0 2001/06/19 12:19:18 rafa Exp $
-%
-% $Log: ILxml.lhs,v $
-%
-% Revision 1.1  2001/06/19 12:19:18  rafa
-% Pretty printer in XML for the intermediate language added.
-%
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{ILxml.lhs}
-\section{A pretty printer in XML for the intermediate language}
-This module implements just another pretty printer, this time in XML and for
-the intermediate language. It was mainly adapted from the Curry pretty
-printer (see sect.~\ref{sec:CurryPP}), which in turn is based on Simon
-Marlow's pretty printer for Haskell. The format of the output intends to be
-similar to that of Flat-Curry XML representation.
-\begin{verbatim}
-
-> module IL.XML(module IL.XML) where
-
-> import Text.PrettyPrint.HughesPJ
-> import Data.Maybe
-
-> import Curry.Base.Ident
-> import qualified Curry.Syntax as CS
-
-> import IL.Type
-> import CurryEnv
-
-
-
-> -- identation level
-> level::Int
-> level = 3
-
-> xmlModule :: CurryEnv -> Module -> Doc
-> xmlModule cEnv m = text "<prog>" $$ nest level (xmlBody cEnv m) 
->	                           $$ text "</prog>"
-
-> xmlBody :: CurryEnv -> Module -> Doc
-> xmlBody cEnv (Module name imports decls) =
->                   xmlElement "module"      xmlModuleDecl      moduleDecl   $$
->                   xmlElement "import"      xmlImportDecl      importDecl   $$
->                   xmlElement "types"       xmlTypeDecl        typeDecl     $$
->                   xmlElement "functions"   xmlFunctionDecl    functionDecl $$
->                   xmlElement "operators"   xmlOperatorDecl    operatorDecl $$
->                   xmlElement "translation" xmlTranslationDecl translationDecl
->               where
->                 moduleDecl      = [name]
->                 importDecl      = imports
->                 operatorDecl    = infixDecls cEnv
->                 translationDecl = foldl (qualIDeclId (moduleId cEnv))
->			                  [] 
->				          (interface cEnv)
->                 (functionDecl,typeDecl) = splitDecls decls
-
-> -- =========================================================================
-
-> xmlModuleDecl :: ModuleIdent -> Doc
-> xmlModuleDecl name = xmlModuleIdent name
-
-> -- =========================================================================
-
-> xmlImportDecl :: ModuleIdent -> Doc
-> xmlImportDecl name = xmlElement "module" xmlModuleDecl  [name]
-
-
-> -- =========================================================================
-> --            T Y P E S
-> -- =========================================================================
-
-> xmlTypeDecl :: Decl -> Doc
-> xmlTypeDecl (DataDecl tc arity cs) =
->   beginType                                  $$
->   nest level (xmlTypeParams arity)           $$
->   xmlLines xmlConstructor cs                 $$
->   endType
->  where
->   beginType = text "<type name=\"" <> (xmlQualIdent tc) <> text "\">"
->   endType   = text "</type>"
-
-> xmlTypeParams :: Int -> Doc
-> xmlTypeParams n = xmlElement "params" xmlTypeVar [0..(n-1)]
-
-> xmlConstructor :: ConstrDecl [Type] -> Doc
-> xmlConstructor (ConstrDecl ident []) = xmlConstructorBegin ident 0
-> xmlConstructor (ConstrDecl ident l)  =
->   xmlConstructorBegin ident (length l) $$
->   xmlLines xmlType l $$
->   xmlConstructorEnd
->  where
->   xmlConstructorEnd = text "</cons>"
-
-> xmlConstructorBegin :: QualIdent -> Int -> Doc
-> xmlConstructorBegin ident n = xmlHeadingWithArity "cons" ident n (n==0)
-
-> xmlHeadingWithArity :: String -> QualIdent -> Int -> Bool -> Doc
-> xmlHeadingWithArity tagName ident n single =
->   if single
->   then prefix<>text "/>"
->   else prefix<> text ">"
->   where
->     prefix = text ("<"++tagName++" name=\"") <> name <> text "\" " <> arity
->     arity  = text "arity=\"" <> xmlInt n <> text "\""
->     name   = xmlQualIdent ident
-
-
-> xmlType :: Type -> Doc
-> xmlType (TypeConstructor ident []) = xmlTypeConsBegin ident True
-> xmlType (TypeConstructor ident l)  = xmlTypeConsBegin ident False $$
->                                      xmlLines xmlType l           $$
->                                      xmlTypeConsEnd
->                                      where
->                                        xmlTypeConsEnd = text "</tcons>"
-
-> xmlType (TypeVariable n) = xmlTypeVar n
-> xmlType (TypeArrow  a b) = xmlTypeFun a b
-
-> xmlTypeConsBegin :: QualIdent -> Bool -> Doc
-> xmlTypeConsBegin ident single =
->   if single
->   then prefix <> text "/>"
->   else prefix <> text ">"
->   where
->     name   = xmlQualIdent ident
->     prefix = text "<tcons name=\"" <> name <> text "\""
-
-> xmlTypeVar :: Int -> Doc
-> xmlTypeVar n = text "<tvar>"<> xmlInt n <> text "</tvar>"
-
-> xmlTypeFun :: Type -> Type -> Doc
-> xmlTypeFun a b =  xmlElement "functype" xmlType  [a,b]
-
-
-> -- =========================================================================
-> --            F U N C T I O N S
-> -- =========================================================================
-
-> xmlFunctionDecl :: Decl -> Doc
-> xmlFunctionDecl (NewtypeDecl tc arity (ConstrDecl ident ty)) =
->   xmlFunctionDecl (FunctionDecl ident [arg] ftype (Variable arg))
->   where
->    arg = mkIdent "_1"
->    ftype = TypeArrow ty (TypeConstructor tc (map TypeVariable [0..arity-1]))
-
-> xmlFunctionDecl (FunctionDecl ident largs fType expr) =
->    heading $$ nest level (xmlRule largs expr) $$ end
->  where
->    heading = xmlBeginFunction ident (length largs) fType
->    end     = text "</func>"
-
-> xmlFunctionDecl (ExternalDecl ident callConv internalName fType) =
->    heading $$ external $$ end
->  where
->    heading  = xmlBeginFunction ident (xmlFunctionArity fType) fType
->    external = text ("<external>"
->                     ++ xmlFormat internalName
->                     ++ "</external>")
->    end      = text "</func>"
-
-> xmlBeginFunction :: QualIdent -> Int -> Type -> Doc
-> xmlBeginFunction ident n fType =
->    heading $$ typeDecls
->    where
->      heading   = xmlHeadingWithArity "func" ident n False
->      typeDecls = nest level (xmlType fType)
-
-> xmlEndFunction ::  Doc
-> xmlEndFunction  = text "</func>"
-
-> xmlFunctionArity :: Type -> Int
-> xmlFunctionArity (TypeConstructor ident l) = 0
-> xmlFunctionArity (TypeVariable n)          = 0
-> xmlFunctionArity (TypeArrow  a b)          = 1 + (xmlFunctionArity b)
-
-> xmlRule :: [Ident] -> Expression -> Doc
-> xmlRule lArgs e = text "<rule>"               $$
->                   nest level (xmlLhs lArgs)   $$
->                   nest level (xmlRhs lArgs e) $$
->                   text "</rule>"
-
-> xmlLhs :: [Ident] -> Doc
-> xmlLhs l  = xmlElement "lhs" xmlVar [0..((length l)-1)]
-
-> xmlRhs :: [Ident] -> Expression -> Doc
-> xmlRhs l e = text "<rhs>"  $$ nest level rhs $$ text "</rhs>"
->              where
->                varDicc    = xmlBuildDicc l
->                (rhs, _) = xmlExpr varDicc e
-
-> -- =========================================================================
-
-> -- =========================================================================
-> --            E X P R E S S I O N S
-> -- =========================================================================
-
-> xmlExpr :: [(Int,Ident)] -> Expression -> (Doc,[(Int,Ident)])
-> xmlExpr d (Literal lit)  = (xmlLiteral (xmlLit lit),d)
-> xmlExpr d (Variable ident)  = xmlExprVar d ident
-> xmlExpr d (Function ident arity)    = (xmlSingleApp ident arity True,d)
-> xmlExpr d (Constructor ident arity) = (xmlSingleApp ident arity False,d)
-> xmlExpr d exp@(Apply e1 e2)         = xmlApply  d exp (xmlAppArgs exp)
-> xmlExpr d (Case _ eval expr alt)      = xmlCase   d eval expr alt
-> xmlExpr d (Or expr1 expr2)          = xmlOr     d expr1 expr2
-> xmlExpr d (Exist ident expr)        = xmlFree   d ident expr
-> xmlExpr d (Let binding expr)        = xmlLet    d binding expr
-> xmlExpr d (Letrec lBinding expr)    = xmlLetrec d lBinding expr
->   --error "Recursive let bindings not supported in FlatCurry"
-
-> -- =========================================================================
-
-> xmlSingleApp :: QualIdent -> Int -> Bool -> Doc
-> xmlSingleApp ident arity isFunction =
->    if arity>0
->    then xmlCombHeading identDoc (text "PartCall") True
->    else xmlCombHeading identDoc (text totalApp) True
->    where
->       identDoc = xmlQualIdent ident
->       totalApp = if isFunction then "FuncCall" else "ConsCall"
-
-
-> xmlCombHeading :: Doc -> Doc -> Bool -> Doc
-> xmlCombHeading name cType single =
->     if single
->     then prefix <> text " />"
->     else prefix <> text ">"
->     where
->       prefix = text "<comb type=\""<>cType<>text "\" name=\""<>name<>text "\""
-
-> -- =========================================================================
-
-> xmlExprVar :: [(Int,Ident)] -> Ident -> (Doc,[(Int,Ident)])
-> xmlExprVar d ident =
->    if isNew
->    then (xmlVar newVar, (newVar,ident):d)
->    else (xmlVar var, d)
->    where
->       var    = xmlLookUp ident d
->       isNew  = var == -1
->       newVar = xmlNewVar d
-
-> -- =========================================================================
-
-
-> xmlApply :: [(Int,Ident)] -> Expression -> (Expression,[Expression]) ->
->              (Doc,[(Int,Ident)])
-
-> xmlApply d exp ((Function ident arity),lExp) =
->   xmlApplyFunctor d ident arity lExp True
-
-> xmlApply d exp ((Constructor ident arity),lExp) =
->   xmlApplyFunctor d ident arity lExp False
-
-> xmlApply d (Apply expr1 expr2) e' =
->   (text "<apply>" $$ nest level e1 $$ nest level e2 $$ text "</apply>", d2)
->     where
->        (e1,d1) = xmlExpr d  expr1
->        (e2,d2) = xmlExpr d1 expr2
-
-> xmlApplyFunctor ::[(Int,Ident)] -> QualIdent -> Int -> [Expression] ->
->                     Bool -> (Doc,[(Int,Ident)])
-> xmlApplyFunctor d ident arity lArgs isFunction =
->    xmlCombApply d (xmlQualIdent ident)  (text cTypeS) n lArgs
->    where
->       n     = length (lArgs)
->       cTypeS = if n==arity
->               then if isFunction
->                    then "FuncCall"
->                    else "ConsCall"
->               else "PartCall"
-
-
-> xmlCombApply :: [(Int,Ident)] -> Doc -> Doc -> Int ->
->                                 [Expression] -> (Doc,[(Int,Ident)])
-> xmlCombApply d name cType 0 lArgs =
->    (xmlCombHeading name cType True,d)
-> xmlCombApply d name cType n lArgs =
->    (xmlCombHeading name cType False $$ xmlLines id lDocs$$ text "</comb>", d1)
->    where
->      (lDocs,d1) = xmlMapDicc d xmlExpr lArgs
-
-
-> xmlAppArgs :: Expression -> (Expression,[Expression])
-> xmlAppArgs (Apply e1 e2) = (e,lArgs++[e2])
->                            where
->                                (e,lArgs) = (xmlAppArgs e1)
-> xmlAppArgs e             = (e,[])
-> -- =========================================================================
-
-
-> -- =========================================================================
-
-> xmlCase :: [(Int,Ident)] -> Eval -> Expression -> [Alt] -> (Doc,[(Int,Ident)])
-> xmlCase d eval expr lAlt =
->   (heading $$ nest level e1 $$ xmlLines id lDocs$$ end,d2)
->   where
->     sEval      = if eval==Rigid then "\"Rigid\"" else "\"Flex\""
->     heading    = text "<case type=" <> text sEval <> text ">"
->     end        = text "</case>"
->     (e1,_)    = xmlExpr d expr
->     (lDocs,d2) = xmlMapDicc d xmlBranch  lAlt
-
-> xmlOr :: [(Int,Ident)] -> Expression -> Expression -> (Doc,[(Int,Ident)])
-> xmlOr d  expr1 expr2 =
->    (text "<or>" $$ nest level e1 $$ nest level e2 $$  text "</or>",d2)
->    where
->      (e1,d1) = xmlExpr d expr1
->      (e2,d2) = xmlExpr d1 expr2
-
-
-> xmlBranch :: [(Int,Ident)] -> Alt -> (Doc,[(Int,Ident)])
-> xmlBranch d (Alt pattern expr) =
->    (text "<branch>" $$ nest level e1 $$ nest level e2 $$ text "</branch>",d2)
->    where
->      (e1,d1) = xmlPattern d pattern
->      (e2,d2) = xmlExpr d1 expr
-
-
-> xmlPattern :: [(Int,Ident)] -> ConstrTerm -> (Doc,[(Int,Ident)])
-> xmlPattern d (LiteralPattern lit) = (xmlLitPattern (xmlLit lit),d)
-> xmlPattern d (ConstructorPattern ident lArgs) = xmlConsPattern d ident  lArgs
-> xmlPattern d (VariablePattern _) = error "Variable patterns not allowed in Flat Curry"
-
-> xmlConsPattern :: [(Int,Ident)] -> QualIdent -> [Ident] -> (Doc,[(Int,Ident)])
-> xmlConsPattern d ident lArgs =
->    (heading $$ xmlLines id lDocs $$ end,d2)
->    where
->      heading    = text "<pattern name=\""<> (xmlQualIdent ident) <>
->                   text "\"" <> endh
->      endh       = if (length lArgs)>0 then text ">" else text "/>"
->      end        = if (length lArgs)>0 then text "</pattern>" else empty
->      (lDocs,d2) = xmlMapDicc d xmlExprVar lArgs
-
-> -- =========================================================================
-
-
-> xmlFree :: [(Int,Ident)] -> Ident -> Expression -> (Doc,[(Int,Ident)])
-> xmlFree d ident exp =
->  (text "<freevars>" $$ nest level v $$ nest level e $$ text "</freevars>",d2)
->                    where
->                       (v,d1) = xmlExprVar d  ident
->                       (e,d2) = xmlExpr d1 exp
-
-
-> -- =========================================================================
-
-> xmlLet :: [(Int,Ident)] -> Binding -> Expression -> (Doc,[(Int,Ident)])
-> xmlLet d binding exp =
->   (text "<let>" $$ nest level b $$ nest level e $$ text "</let>", d2)
->   where
->    (b,d1) = xmlBinding d binding
->    (e,d2) = xmlExpr d1 exp
-
-> xmlBinding :: [(Int,Ident)] -> Binding -> (Doc,[(Int,Ident)])
-> xmlBinding d  (Binding ident exp) =
->    (text "<binding>" $$ nest level v $$ nest level e $$ text "</binding>",d2)
->    where
->       (v,_)  = xmlExprVar d ident
->       (e,d2) = xmlExpr d exp
-
-> -- =========================================================================
-
-> xmlLetrec :: [(Int,Ident)] -> [Binding] -> Expression -> (Doc,[(Int,Ident)])
-> xmlLetrec d lB exp =
->   (text "<letrec>" $$ xmlLines id b $$ nest level e $$ text "</letrec>",d2)
->   where
->     (b,d1) = xmlMapDicc d xmlBinding lB
->     (e,d2) = xmlExpr d1 exp
-
-> -- =========================================================================
-
-
-> -- =========================================================================
-> --            A U X I L I A R Y  F U N C T I O N S
-> -- =========================================================================
-
-> splitDecls :: [Decl] -> ([Decl],[Decl])
-> splitDecls []     = ([],[])
-> splitDecls (x:xs) = case x of
->                      DataDecl     _ _ _   -> (functionDecl,x:typeDecl)
->                      NewtypeDecl  _ _ _   -> (x:functionDecl,typeDecl)
->                      FunctionDecl _ _ _ _ -> (x:functionDecl,typeDecl)
->                      ExternalDecl _ _ _ _   -> (x:functionDecl,typeDecl)
->                   where
->                       (functionDecl,typeDecl) = splitDecls xs
-
-
-
-
-> xmlElement :: Eq a => String -> (a -> Doc) -> [a] -> Doc
-> xmlElement name f []     = text ("<"++name++" />")
-> xmlElement name f lDecls = beginElement $$ xmlLines f lDecls $$ endElement
->                            where
->                                beginElement = text ("<"++name++">")
->                                endElement   = text ("</"++name++">")
->
-
-> xmlLines :: (a -> Doc) -> [a] -> Doc
-> xmlLines f = (nest level).vcat.(map f)
-
-
-> xmlMapDicc::[(Int,Ident)] -> ([(Int,Ident)] -> a -> (Doc,[(Int,Ident)])) ->
->              [a] -> ([Doc],[(Int,Ident)])
-> xmlMapDicc d f lArgs = foldl newArg ([],d) lArgs
->                             where
->                               newArg (l,d)  e = (l++[v'],d')
->                                                 where (v',d') = f d e
->
-
-
-> -- The dictionary identifies var names with integers
-> -- it will be ordered starting at the greatest integer
-> xmlBuildDicc :: [Ident] -> [(Int,Ident)]
-> xmlBuildDicc l = reverse (zip [0..((length l)-1)] l)
-
-> -- looks for a ident in the dictorionary. If it appears returns its
-> -- associated value. Otherwise, -1 is returned
-> xmlLookUp :: Ident -> [(Int,Ident)] -> Int
-> xmlLookUp ident []          = -1
-> xmlLookUp ident ((n,name):xs) = if ident==name
->                                 then n
->                                 else xmlLookUp ident xs
-
-> -- generates a integer corresponding to a new var
-> xmlNewVar :: [(Int,Ident)] -> Int
-> xmlNewVar []             = 0
-> xmlNewVar ((n,ident):xs) = n+1
-
-> xmlVar :: Int -> Doc
-> xmlVar n = text "<var>" <> xmlInt n <> text "</var>"
-
-> xmlLiteral :: Doc -> Doc
-> xmlLiteral d =   text "<lit>" $$ nest level d $$ text "</lit>"
-
-> xmlLitPattern :: Doc -> Doc
-> xmlLitPattern d =   text "<lpattern>" $$ nest level d $$ text "</lpattern>"
-
-
-> xmlLit :: Literal -> Doc
-> xmlLit (Char _ c) = text "<charc>" <>  xmlInt (fromEnum c) <> text "</charc>"
-> xmlLit (Int _ n) = text "<intc>" <>  xmlInteger n <> text "</intc>"
-> xmlLit (Float _ n) = text "<floatc>" <>  xmlFloat n <> text "</floatc>"
-
-> xmlOperatorDecl :: CS.IDecl -> Doc
-> xmlOperatorDecl (CS.IInfixDecl _ fixity prec qident) =
->     text "<op fixity=\"" <> xmlFixity fixity 
->     <> text "\" prec=\"" <> xmlInteger prec <> text "\">"
->     <> xmlIdent (unqualify qident)
->     <> text "</op>"
-
-> xmlFixity :: CS.Infix -> Doc
-> xmlFixity CS.InfixL = text "InfixlOp"
-> xmlFixity CS.InfixR = text "InfixrOp"
-> xmlFixity CS.Infix  = text "InfixOp"
-
-
-> xmlTranslationDecl :: QualIdent -> Doc
-> xmlTranslationDecl expId =
->       text "<trans>" 
->    $$ nest level (   text "<name>"    <> xmlIdent (unqualify expId) <> text "</name>"
->                   $$ text "<intname>" <> xmlQualIdent expId         <> text "</intname>")
->    $$ text "</trans>"
-
-
-> xmlIdent :: Ident -> Doc
-> xmlIdent ident = text (xmlFormat (name ident))
-
-> xmlInt :: Int -> Doc
-> xmlInt n = text (show n)
-
-> xmlInteger :: Integer -> Doc
-> xmlInteger n = text (show n)
-
-> xmlFloat :: Double -> Doc
-> xmlFloat n = text (show n)
-
-> xmlQualIdent :: QualIdent -> Doc
-> xmlQualIdent ident = text (xmlFormat (qualName ident))
-
-> xmlModuleIdent:: ModuleIdent -> Doc
-> xmlModuleIdent name = text (xmlFormat (moduleName name))
-
-> xmlFormat :: String -> String
-> xmlFormat []       = []
-> xmlFormat ('>':xs) = "&gt;"++xmlFormat xs
-> xmlFormat ('<':xs) = "&lt;"++xmlFormat xs
-> xmlFormat ('&':xs) = "&amp;"++xmlFormat xs
-> xmlFormat (x:xs)   = x:(xmlFormat xs)
-
-> -- =========================================================================
-
-> qualIDeclId :: ModuleIdent -> [QualIdent] -> CS.IDecl -> [QualIdent]
-> qualIDeclId mid qids (CS.IDataDecl _ qid _ mcdecls)
->    = foldl (qualConstrDeclId mid) (qid:qids) (catMaybes mcdecls)
-> qualIDeclId mid qids (CS.INewtypeDecl _ qid _ ncdecl)
->    = qualNewConstrDeclId mid (qid:qids) ncdecl
-> qualIDeclId mid qids (CS.ITypeDecl _ qid _ _)
->    = qid:qids
-> qualIDeclId mid qids (CS.IFunctionDecl _ qid _ _)
->    = qid:qids
-> qualIDeclId mid qids _ = qids
-
-> qualConstrDeclId :: ModuleIdent -> [QualIdent] -> CS.ConstrDecl 
->	              -> [QualIdent]
-> qualConstrDeclId mid qids (CS.ConstrDecl _ _ id _)
->    = (qualifyWith mid id):qids
-> qualConstrDeclId mid qids (CS.ConOpDecl _ _ _ id _)
->    = (qualifyWith mid id):qids
-
-> qualNewConstrDeclId :: ModuleIdent -> [QualIdent] -> CS.NewConstrDecl 
->	                 -> [QualIdent]
-> qualNewConstrDeclId mid qids (CS.NewConstrDecl _ _ id _)
->    = (qualifyWith mid id):qids
-
-
-\end{verbatim}
diff --git a/src/Imports.hs b/src/Imports.hs
new file mode 100644
--- /dev/null
+++ b/src/Imports.hs
@@ -0,0 +1,402 @@
+{- |
+    Module      :  $Header$
+    Description :  Importing interface declarations
+    Copyright   :  (c) 2000 - 2003 Wolfgang Lux
+                       2011        Björn Peemöller
+                       2016        Jan Tikovsky
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module provides the function 'importModules' to bring the imported
+    entities into the module's scope, and the function 'qualifyEnv' to
+    qualify the environment prior to computing the export interface.
+-}
+module Imports (importInterfaces, importModules, qualifyEnv) where
+
+import           Data.List                  (nubBy, find)
+import qualified Data.Map            as Map
+import           Data.Maybe                 (catMaybes, fromMaybe, isJust)
+import qualified Data.Set            as Set
+
+import Curry.Base.Ident
+import Curry.Base.SpanInfo
+import Curry.Base.Monad
+import Curry.Syntax
+
+import Base.CurryKinds (toKind')
+import Base.CurryTypes ( toQualType, toQualTypes, toQualPredType, toConstrType
+                       , toMethodType )
+
+import Base.Kinds
+import Base.Messages
+import Base.TopEnv
+import Base.Types
+import Base.TypeSubst
+
+import Env.Class
+import Env.Instance
+import Env.Interface
+import Env.ModuleAlias (importAliases, initAliasEnv)
+import Env.OpPrec
+import Env.TypeConstructor
+import Env.Value
+
+import CompilerEnv
+
+importModules :: Monad m => Module a -> InterfaceEnv -> [ImportDecl]
+              -> CYT m CompilerEnv
+importModules mdl@(Module _ _ _ mid _ _ _) iEnv expImps
+  = ok $ foldl importModule initEnv expImps
+  where
+    initEnv = (initCompilerEnv mid)
+      { aliasEnv     = importAliases expImps -- import module aliases
+      , interfaceEnv = iEnv                  -- imported interfaces
+      , extensions   = knownExtensions mdl
+      }
+    importModule env (ImportDecl _ m q asM is) =
+      case Map.lookup m iEnv of
+        Just intf -> importInterface (fromMaybe m asM) q is intf env
+        Nothing   -> internalError $ "Imports.importModules: no interface for "
+                                     ++ show m
+
+-- |The function 'importInterfaces' brings the declarations of all
+-- imported interfaces into scope for the current 'Interface'.
+importInterfaces :: Interface -> InterfaceEnv -> CompilerEnv
+importInterfaces (Interface m is _) iEnv
+  = importUnifyData $ foldl importModule initEnv is
+  where
+    initEnv = (initCompilerEnv m) { aliasEnv = initAliasEnv, interfaceEnv = iEnv }
+    importModule env (IImportDecl _ i) = case Map.lookup i iEnv of
+      Just intf -> importInterfaceIntf intf env
+      Nothing   -> internalError $ "Imports.importInterfaces: no interface for "
+                                   ++ show m
+
+-- ---------------------------------------------------------------------------
+-- Importing an interface into the module
+-- ---------------------------------------------------------------------------
+
+-- Four kinds of environments are computed from the interface:
+--
+-- 1. The operator precedences
+-- 2. The type constructors
+-- 3. The types of the data constructors and functions (values)
+-- 4. The instances
+--
+-- Note that the original names of all entities defined in the imported module
+-- are qualified appropriately. The same is true for type expressions.
+
+-- When an interface is imported, the compiler first transforms the
+-- interface into these environments. If an import specification is
+-- present, the environments are restricted to only those entities which
+-- are included in the specification or not hidden by it, respectively.
+-- The resulting environments are then imported into the current module
+-- using either a qualified import (if the module is imported qualified)
+-- or both a qualified and an unqualified import (non-qualified import).
+-- Regardless of the type of import, all instance declarations are always
+-- imported into the current module.
+
+importInterface :: ModuleIdent -> Bool -> Maybe ImportSpec -> Interface
+                -> CompilerEnv -> CompilerEnv
+importInterface m q is (Interface mid _ ds) env = env'
+  where
+  env' = env
+    { opPrecEnv = importEntities (precs  mid) m q vs id              ds $ opPrecEnv env
+    , tyConsEnv = importEntities (types  mid) m q ts (importData vs) ds $ tyConsEnv env
+    , valueEnv  = importEntities (values mid) m q vs id              ds $ valueEnv  env
+    , classEnv  = importClasses   mid                                ds $ classEnv  env
+    , instEnv   = importInstances mid                                ds $ instEnv   env
+    }
+  ts = isVisible addType  is
+  vs = isVisible addValue is
+
+addType :: Import -> [Ident] -> [Ident]
+addType (Import            _ _) tcs = tcs
+addType (ImportTypeWith _ tc _) tcs = tc : tcs
+addType (ImportTypeAll     _ _) _   = internalError "Imports.addType"
+
+addValue :: Import -> [Ident] -> [Ident]
+addValue (Import            _ f) fs = f : fs
+addValue (ImportTypeWith _ _ cs) fs = cs ++ fs
+addValue (ImportTypeAll     _ _) _  = internalError "Imports.addValue"
+
+isVisible :: (Import -> [Ident] -> [Ident]) -> Maybe ImportSpec
+          -> Ident -> Bool
+isVisible _   Nothing                 = const True
+isVisible add (Just (Importing _ xs)) = (`Set.member`    Set.fromList (foldr add [] xs))
+isVisible add (Just (Hiding    _ xs)) = (`Set.notMember` Set.fromList (foldr add [] xs))
+
+importEntities :: Entity a => (IDecl -> [a]) -> ModuleIdent -> Bool
+               -> (Ident -> Bool) -> (a -> a) -> [IDecl] -> TopEnv a -> TopEnv a
+importEntities ents m q isVisible' f ds env =
+  foldr (uncurry (if q then qualImportTopEnv m else importUnqual m)) env
+        [ (x, f y) | y <- concatMap ents ds
+        , let x = unqualify (origName y), isVisible' x
+        ]
+  where importUnqual m' x y = importTopEnv m' x y . qualImportTopEnv m' x y
+
+importData :: (Ident -> Bool) -> TypeInfo -> TypeInfo
+importData isVisible' (DataType tc k cs) =
+  DataType tc k $ catMaybes $ map (importConstr isVisible') cs
+importData isVisible' (RenamingType tc k nc) =
+  maybe (DataType tc k []) (RenamingType tc k) (importConstr isVisible' nc)
+importData _ (AliasType tc k n ty) = AliasType tc k n ty
+importData isVisible' (TypeClass qcls k ms) =
+  TypeClass qcls k $ catMaybes $ map (importMethod isVisible') ms
+importData _ (TypeVar _) = internalError "Imports.importData: type variable"
+
+importConstr :: (Ident -> Bool) -> DataConstr -> Maybe DataConstr
+importConstr isVisible' dc
+  | isVisible' (constrIdent dc) = Just dc
+  | otherwise                   = Nothing
+
+importMethod :: (Ident -> Bool) -> ClassMethod -> Maybe ClassMethod
+importMethod isVisible' mthd
+  | isVisible' (methodName mthd) = Just mthd
+  | otherwise                    = Nothing
+
+importClasses :: ModuleIdent -> [IDecl] -> ClassEnv -> ClassEnv
+importClasses m = flip $ foldr (bindClass m)
+
+bindClass :: ModuleIdent -> IDecl -> ClassEnv -> ClassEnv
+bindClass m (HidingClassDecl p cx cls k tv) =
+  bindClass m (IClassDecl p cx cls k tv [] [])
+bindClass m (IClassDecl _ cx cls _ _ ds ids) =
+  bindClassInfo (qualQualify m cls) (sclss, ms)
+  where sclss = map (\(Constraint _ scls _) -> qualQualify m scls) cx
+        ms = map (\d -> (imethod d, isJust $ imethodArity d)) $ filter isVis ds
+        isVis (IMethodDecl _ idt _ _ ) = idt `notElem` ids
+bindClass _ _ = id
+
+importInstances :: ModuleIdent -> [IDecl] -> InstEnv -> InstEnv
+importInstances m = flip $ foldr (bindInstance m)
+
+bindInstance :: ModuleIdent -> IDecl -> InstEnv -> InstEnv
+bindInstance m (IInstanceDecl _ cx qcls ty is mm) = bindInstInfo
+  (qualQualify m qcls, qualifyTC m $ typeConstr ty) (fromMaybe m mm, ps, is)
+  where PredType ps _ = toQualPredType m [] $ QualTypeExpr NoSpanInfo cx ty
+bindInstance _ _ = id
+
+-- ---------------------------------------------------------------------------
+-- Building the initial environment
+-- ---------------------------------------------------------------------------
+
+-- In a first step, the four export environments are initialized from
+-- the interface's declarations.
+
+-- operator precedences
+precs :: ModuleIdent -> IDecl -> [PrecInfo]
+precs m (IInfixDecl _ fix prec op) = [PrecInfo (qualQualify m op) (OpPrec fix prec)]
+precs _ _                          = []
+
+hiddenTypes :: ModuleIdent -> IDecl -> [TypeInfo]
+hiddenTypes m (HidingDataDecl     _ tc k tvs) = [typeCon DataType m tc k tvs []]
+hiddenTypes m (HidingClassDecl  _ _ qcls k _) = [typeCls m qcls k []]
+hiddenTypes m d                               = types m d
+
+-- type constructors and type classes
+types :: ModuleIdent -> IDecl -> [TypeInfo]
+types m (IDataDecl _ tc k tvs cs _) =
+  [typeCon DataType m tc k tvs (map mkData cs)]
+  where
+    mkData (ConstrDecl _ c tys) =
+      DataConstr c (toQualTypes m tvs tys)
+    mkData (ConOpDecl _  ty1 c ty2) =
+      DataConstr c (toQualTypes m tvs [ty1, ty2])
+    mkData (RecordDecl _ c fs) =
+      RecordConstr c labels (toQualTypes m tvs tys)
+      where (labels, tys) = unzip [(l, ty) | FieldDecl _ ls ty <- fs, l <- ls]
+types m (INewtypeDecl _ tc k tvs nc _) =
+  [typeCon RenamingType m tc k tvs (mkData nc)]
+  where
+    mkData (NewConstrDecl _ c ty) =
+      DataConstr c [toQualType m tvs ty]
+    mkData (NewRecordDecl _ c (l, ty)) =
+      RecordConstr c [l] [toQualType m tvs ty]
+types m (ITypeDecl _ tc k tvs ty) =
+  [typeCon aliasType m tc k tvs (toQualType m tvs ty)]
+  where
+    aliasType tc' k' = AliasType tc' k' (length tvs)
+types m (IClassDecl _ _ qcls k tv ds ids) =
+  [typeCls m qcls k (map mkMethod $ filter isVis ds)]
+  where
+    isVis (IMethodDecl _ f _ _ ) = f `notElem` ids
+    mkMethod (IMethodDecl _ f a qty) = ClassMethod f a $
+      qualifyPredType m $ normalize 1 $ toMethodType qcls tv qty
+types _ _ = []
+
+-- type constructors
+typeCon :: (QualIdent -> Kind -> a) -> ModuleIdent -> QualIdent
+        -> Maybe KindExpr -> [Ident] -> a
+typeCon f m tc k tvs = f (qualQualify m tc) (toKind' k (length tvs))
+
+-- type classes
+typeCls :: ModuleIdent -> QualIdent -> Maybe KindExpr -> [ClassMethod]
+        -> TypeInfo
+typeCls m qcls k ms = TypeClass (qualQualify m qcls) (toKind' k 0) ms
+
+-- data constructors, record labels, functions and class methods
+values :: ModuleIdent -> IDecl -> [ValueInfo]
+values m (IDataDecl _ tc _ tvs cs hs) =
+  map (dataConstr m tc' tvs)
+      (filter ((\con -> con `notElem` hs || isHiddenButNeeded con)
+              . constrId) cs) ++
+  map (recLabel m tc' tvs ty') (nubBy sameLabel clabels)
+  where tc' = qualQualify m tc
+        ty' = constrType tc' tvs
+        labels   = [ (l, lty) | RecordDecl _ _ fs <- cs
+                   , FieldDecl _ ls lty <- fs, l <- ls, l `notElem` hs
+                   ]
+        clabels  = [(l, constr l, ty) | (l, ty) <- labels]
+        constr l = [constrId c | c <- cs, l `elem` recordLabels c]
+        -- hidden constructors needed for record updates with visible labels
+        hiddenCs = [c | (l, _) <- labels, c <- constr l, c `elem` hs]
+        isHiddenButNeeded = flip elem hiddenCs
+        sameLabel (l1,_,_) (l2,_,_) = l1 == l2
+values m (INewtypeDecl _ tc _ tvs nc hs) =
+  map (newConstr m tc' tvs) [nc | nconstrId nc `notElem` hs] ++
+  case nc of
+    NewConstrDecl _ _ _        -> []
+    NewRecordDecl _ c (l, lty) ->
+      [recLabel m tc' tvs ty' (l, [c], lty) | l `notElem` hs]
+  where tc' = qualQualify m tc
+        ty' = constrType tc' tvs
+values m (IFunctionDecl _ f Nothing a qty) =
+  [Value (qualQualify m f) Nothing a (typeScheme (toQualPredType m [] qty))]
+values m (IFunctionDecl _ f (Just tv) _ qty) =
+  let mcls = case qty of
+        QualTypeExpr _ ctx _ -> fmap (\(Constraint _ qcls _) -> qcls) $
+                                find (\(Constraint _ _ ty) -> isVar ty) ctx
+  in [Value (qualQualify m f) mcls 0 (typeScheme (toQualPredType m [tv] qty))]
+  where
+    isVar (VariableType _ i) = i == tv
+    isVar _                  = False
+values m (IClassDecl _ _ qcls _ tv ds hs) =
+  map (classMethod m qcls' tv hs) ds
+  where qcls' = qualQualify m qcls
+values _ _                        = []
+
+dataConstr :: ModuleIdent -> QualIdent -> [Ident] -> ConstrDecl -> ValueInfo
+dataConstr m tc tvs (ConstrDecl _ c tys) =
+  DataConstructor (qualifyLike tc c) a labels $
+    constrType' m tc tvs tys
+  where a      = length tys
+        labels = replicate a anonId
+dataConstr m tc tvs (ConOpDecl _ ty1 op ty2) =
+  DataConstructor (qualifyLike tc op) 2 [anonId, anonId] $
+    constrType' m tc tvs [ty1, ty2]
+dataConstr m tc tvs (RecordDecl _ c fs) =
+  DataConstructor (qualifyLike tc c) a labels $
+    constrType' m tc tvs tys
+  where fields        = [(l, ty) | FieldDecl _ ls ty <- fs, l <- ls]
+        (labels, tys) = unzip fields
+        a             = length labels
+
+newConstr :: ModuleIdent -> QualIdent -> [Ident] -> NewConstrDecl -> ValueInfo
+newConstr m tc tvs (NewConstrDecl _ c ty1) =
+  NewtypeConstructor (qualifyLike tc c) anonId $
+  constrType' m tc tvs [ty1]
+newConstr m tc tvs (NewRecordDecl _ c (l, ty1)) =
+  NewtypeConstructor (qualifyLike tc c) l $
+  constrType' m tc tvs [ty1]
+
+recLabel :: ModuleIdent -> QualIdent -> [Ident] -> TypeExpr
+           -> (Ident, [Ident], TypeExpr) -> ValueInfo
+recLabel m tc tvs ty0 (l, cs, lty) = Label ql qcs tySc
+  where ql   = qualifyLike tc l
+        qcs  = map (qualifyLike tc) cs
+        tySc = polyType (toQualType m tvs (ArrowType NoSpanInfo ty0 lty))
+
+constrType' :: ModuleIdent -> QualIdent -> [Ident] -> [TypeExpr] -> TypeScheme
+constrType' m tc tvs tys = ForAll (length tvs) pty
+  where pty  = qualifyPredType m $ toConstrType tc tvs tys
+
+constrType :: QualIdent -> [Ident] -> TypeExpr
+constrType tc tvs = foldl (ApplyType NoSpanInfo) (ConstructorType NoSpanInfo tc)
+                      $ map (VariableType NoSpanInfo) tvs
+
+-- We always enter class methods with an arity of 0 into the value environment
+-- because there may be different implementations with different arities.
+
+classMethod :: ModuleIdent -> QualIdent -> Ident -> [Ident] -> IMethodDecl
+            -> ValueInfo
+classMethod m qcls tv hs (IMethodDecl _ f _ qty) =
+  Value (qualifyLike qcls f) mcls 0 $
+    typeScheme $ qualifyPredType m $ toMethodType qcls tv qty
+  where
+    mcls = if f `elem` hs then Nothing else Just qcls
+
+-- ---------------------------------------------------------------------------
+
+-- After all modules have been imported, the compiler has to ensure that
+-- all references to a data type use the same list of constructors.
+
+importUnifyData :: CompilerEnv -> CompilerEnv
+importUnifyData cEnv = cEnv { tyConsEnv = importUnifyData' $ tyConsEnv cEnv }
+
+importUnifyData' :: TCEnv -> TCEnv
+importUnifyData' tcEnv = fmap (setInfo allTyCons) tcEnv
+  where
+  setInfo tcs t   = case Map.lookup (origName t) tcs of
+                         Nothing -> error "Imports.importUnifyData'"
+                         Just ty -> ty
+  allTyCons       = foldr (mergeData . snd) Map.empty $ allImports tcEnv
+  mergeData t tcs =
+    Map.insert tc (maybe t (sureMerge t) $ Map.lookup tc tcs) tcs
+    where tc = origName t
+  sureMerge x y = case merge x y of
+                       Nothing -> error "Imports.importUnifyData'.sureMerge"
+                       Just z  -> z
+
+-- ---------------------------------------------------------------------------
+
+-- |
+qualifyEnv :: CompilerEnv -> CompilerEnv
+qualifyEnv env = qualifyLocal env
+               $ foldl (flip importInterfaceIntf) initEnv
+               $ Map.elems
+               $ interfaceEnv env
+  where initEnv = initCompilerEnv $ moduleIdent env
+
+qualifyLocal :: CompilerEnv -> CompilerEnv -> CompilerEnv
+qualifyLocal currentEnv initEnv = currentEnv
+  { opPrecEnv = foldr bindQual   pEnv  $ localBindings $ opPrecEnv currentEnv
+  , tyConsEnv = foldr bindQual   tcEnv $ localBindings $ tyConsEnv currentEnv
+  , valueEnv  = foldr bindGlobal tyEnv $ localBindings $ valueEnv  currentEnv
+  , classEnv  = Map.unionWith mergeClassInfo clsEnv $ classEnv currentEnv
+  , instEnv   = Map.union                    iEnv   $ instEnv  currentEnv
+  }
+  where
+    pEnv   = opPrecEnv initEnv
+    tcEnv  = tyConsEnv initEnv
+    tyEnv  = valueEnv  initEnv
+    clsEnv = classEnv  initEnv
+    iEnv   = instEnv   initEnv
+    bindQual   (_, y) = qualBindTopEnv (origName y) y
+    bindGlobal (x, y)
+      | hasGlobalScope x = bindQual (x, y)
+      | otherwise        = bindTopEnv x y
+
+-- Importing an interface into another interface is somewhat simpler
+-- because all entities are imported into the environment. In addition,
+-- only a qualified import is necessary. Note that the hidden data types
+-- are imported as well because they may be used in type expressions in
+-- an interface.
+
+importInterfaceIntf :: Interface -> CompilerEnv -> CompilerEnv
+importInterfaceIntf (Interface m _ ds) env = env
+  { opPrecEnv = importEntitiesIntf m (precs  m)       ds $ opPrecEnv env
+  , tyConsEnv = importEntitiesIntf m (hiddenTypes  m) ds $ tyConsEnv env
+  , valueEnv  = importEntitiesIntf m (values m)       ds $ valueEnv  env
+  , classEnv  = importClasses      m                  ds $ classEnv  env
+  , instEnv   = importInstances    m                  ds $ instEnv   env
+  }
+
+importEntitiesIntf :: Entity a => ModuleIdent -> (IDecl -> [a]) -> [IDecl]
+                    -> TopEnv a -> TopEnv a
+importEntitiesIntf m ents ds env = foldr importEntity env (concatMap ents ds)
+  where importEntity x = qualImportTopEnv (fromMaybe m (qidModule (origName x)))
+                                          (unqualify (origName x)) x
diff --git a/src/Imports.lhs b/src/Imports.lhs
deleted file mode 100644
--- a/src/Imports.lhs
+++ /dev/null
@@ -1,379 +0,0 @@
-
-% $Id: Imports.lhs,v 1.25 2004/02/13 19:24:00 wlux Exp $
-%
-% Copyright (c) 2000-2003, Wolfgang Lux
-% See LICENSE for the full license.
-%
-\nwfilename{Imports.lhs}
-\section{Importing interfaces}
-This module provides a few functions which can be used to import
-interfaces into the current module.
-\begin{verbatim}
-
-> module Imports(importInterface,importInterfaceIntf,importUnifyData) where
-
-> import Data.Maybe
-> import qualified Data.Set as Set
-> import qualified Data.Map as Map
-
-> import Curry.Syntax
-> import Types
-> import Curry.Base.Position
-> import Curry.Base.Ident
-> import Base
-> import TopEnv
-
-
-\end{verbatim}
-Four kinds of environments are computed from the interface, one
-containing the operator precedences, another for the type
-constructors, the third containing the types of the data
-constructors and functions, and the last contains the arity for each
-function and constructor. Note that the original names of all
-entities defined in the imported module are qualified appropriately.
-The same is true for type expressions.
-\begin{verbatim}
-
-> type ExpPEnv = Map.Map Ident PrecInfo
-> type ExpTCEnv = Map.Map Ident TypeInfo
-> type ExpValueEnv = Map.Map Ident ValueInfo
-> type ExpArityEnv = Map.Map Ident ArityInfo
-
-\end{verbatim}
-When an interface is imported, the compiler first transforms the
-interface into these environments. If an import specification is
-present, the environments are restricted to only those entities which
-are included in the specification or not hidden by it, respectively.
-The resulting environments are then imported into the current module
-using either a qualified import or both a qualified and an unqualified
-import.
-\begin{verbatim}
-
-> importInterface :: Position -> ModuleIdent -> Bool -> Maybe ImportSpec
->                 -> Interface -> PEnv -> TCEnv -> ValueEnv -> ArityEnv
->                 -> (PEnv,TCEnv,ValueEnv,ArityEnv)
-> importInterface p m q is i pEnv tcEnv tyEnv aEnv =
->   (importEntities m q vs id mPEnv pEnv,
->    importEntities m q ts (importData vs) mTCEnv tcEnv,
->    importEntities m q vs id mTyEnv tyEnv,
->    importEntities m q as id mAEnv aEnv)
->   where mPEnv  = intfEnv bindPrec i
->         mTCEnv = intfEnv bindTC i
->         mTyEnv = intfEnv bindTy i
->         mAEnv  = intfEnv bindA i
->         is' = maybe [] (expandSpecs m mTCEnv mTyEnv) is
->         ts  = isVisible is (Set.fromList (foldr addType [] is'))
->         vs  = isVisible is (Set.fromList (foldr addValue [] is'))
->         as  = isVisible is (Set.fromList (foldr addArity [] is'))
-
-> isVisible :: Maybe ImportSpec -> Set.Set Ident -> Ident -> Bool
-> isVisible (Just (Importing _ _)) xs = (`Set.member` xs)
-> isVisible (Just (Hiding _ _)) xs = (`Set.notMember` xs)
-> isVisible _ _ = const True
-
-> importEntities :: Entity a => ModuleIdent -> Bool -> (Ident -> Bool)
->                -> (a -> a) -> Map.Map Ident a -> TopEnv a -> TopEnv a
-> importEntities m q isVisible f mEnv env =
->   foldr (uncurry (if q then qualImportTopEnv m else importUnqual m)) env
->         [(x,f y) | (x,y) <- Map.toList mEnv, isVisible x]
->   where importUnqual m x y = importTopEnv m x y . qualImportTopEnv m x y
-
-> importData :: (Ident -> Bool) -> TypeInfo -> TypeInfo
-> importData isVisible (DataType tc n cs) =
->   DataType tc n (map (>>= importConstr isVisible) cs)
-> importData isVisible (RenamingType tc n nc) =
->   maybe (DataType tc n []) (RenamingType tc n) (importConstr isVisible nc)
-> importData isVisible (AliasType tc  n ty) = AliasType tc n ty
-
-> importConstr :: (Ident -> Bool) -> Data a -> Maybe (Data a)
-> importConstr isVisible (Data c n tys)
->   | isVisible c = Just (Data c n tys)
->   | otherwise = Nothing
-
-\end{verbatim}
-Importing an interface into another interface is somewhat simpler
-because all entities are imported into the environment. In addition,
-only a qualified import is necessary. Note that the hidden data types
-are imported as well because they may be used in type expressions in
-an interface.
-\begin{verbatim}
-
-> importInterfaceIntf :: Interface -> PEnv -> TCEnv -> ValueEnv -> ArityEnv
->                     -> (PEnv,TCEnv,ValueEnv,ArityEnv)
-> importInterfaceIntf i pEnv tcEnv tyEnv aEnv =
->   (importEntities m True (const True) id (intfEnv bindPrec i) pEnv,
->    importEntities m True (const True) id (intfEnv bindTCHidden i) tcEnv,
->    importEntities m True (const True) id (intfEnv bindTy i) tyEnv,
->    importEntities m True (const True) id (intfEnv bindA i) aEnv)
->   where Interface m _ = i
-
-\end{verbatim}
-In a first step, the three export environments are initialized from
-the interface's declarations. This step also qualifies the names of
-all entities defined in (but not imported into) the interface with its
-module name.  
-\begin{verbatim}
-
-> intfEnv :: (ModuleIdent -> IDecl -> Map.Map Ident a -> Map.Map Ident a)
->         -> Interface -> Map.Map Ident a
-> intfEnv bind (Interface m ds) = foldr (bind m) Map.empty ds
-
-> bindPrec :: ModuleIdent -> IDecl -> ExpPEnv -> ExpPEnv
-> bindPrec m (IInfixDecl _ fix p op) =
->   Map.insert (unqualify op) (PrecInfo (qualQualify m op) (OpPrec fix p))
-> bindPrec _ _ = id
-
-> bindTC :: ModuleIdent -> IDecl -> ExpTCEnv -> ExpTCEnv
-> bindTC m (IDataDecl _ tc tvs cs) mTCEnv 
->   | isJust (Map.lookup (unqualify tc) mTCEnv) =
->     mTCEnv
->   | otherwise =
->     bindType DataType m tc tvs (map (fmap mkData) cs) mTCEnv
->   where mkData (ConstrDecl _ evs c tys) =
->           Data c (length evs) (toQualTypes m tvs tys)
->         mkData (ConOpDecl _ evs ty1 c ty2) =
->           Data c (length evs) (toQualTypes m tvs [ty1,ty2])
-> bindTC m (INewtypeDecl _ tc tvs (NewConstrDecl _ evs c ty)) mTCEnv =
->   bindType RenamingType m tc tvs 
->	 (Data c (length evs) (toQualType m tvs ty)) mTCEnv
-> bindTC m (ITypeDecl _ tc tvs ty) mTCEnv
->   | isRecordExtId tc' = 
->     bindType AliasType m (qualify (fromRecordExtId tc')) tvs 
->	   (toQualType m tvs ty) mTCEnv
->   | otherwise =
->     bindType AliasType m tc tvs (toQualType m tvs ty) mTCEnv
->   where tc' = unqualify tc
-> bindTC m _ mTCEnv = mTCEnv
-
-> bindTCHidden :: ModuleIdent -> IDecl -> ExpTCEnv -> ExpTCEnv
-> bindTCHidden m (HidingDataDecl _ tc tvs) =
->   bindType DataType m (qualify tc) tvs []
-> bindTCHidden m d = bindTC m d
-
-> bindType :: (QualIdent -> Int -> a -> TypeInfo) -> ModuleIdent -> QualIdent
->          -> [Ident] -> a -> ExpTCEnv -> ExpTCEnv
-> bindType f m tc tvs =
->   Map.insert (unqualify tc) . f (qualQualify m tc) (length tvs) 
-
-> bindTy :: ModuleIdent -> IDecl -> ExpValueEnv -> ExpValueEnv
-> bindTy m (IDataDecl _ tc tvs cs) =
->   flip (foldr (bindConstr m tc' tvs (constrType tc' tvs))) (catMaybes cs)
->   where tc' = qualQualify m tc
-> bindTy m (INewtypeDecl _ tc tvs nc) =
->   bindNewConstr m tc' tvs (constrType tc' tvs) nc
->   where tc' = qualQualify m tc
-> --bindTy m (ITypeDecl _ r tvs (RecordType fs _)) =
-> --  flip (foldr (bindRecLabel m r')) fs
-> --  where r' = qualifyWith m (fromRecordExtId (unqualify r))
-> bindTy m (IFunctionDecl _ f _ ty) =
->   Map.insert (unqualify f)
->           (Value (qualQualify m f) (polyType (toQualType m [] ty)))
-> bindTy m _ = id
-
-> bindConstr :: ModuleIdent -> QualIdent -> [Ident] -> TypeExpr -> ConstrDecl
->            -> ExpValueEnv -> ExpValueEnv
-> bindConstr m tc tvs ty0 (ConstrDecl _ evs c tys) =
->   bindValue DataConstructor m tc tvs c evs (foldr ArrowType ty0 tys)
-> bindConstr m tc tvs ty0 (ConOpDecl _ evs ty1 op ty2) =
->   bindValue DataConstructor m tc tvs op evs
->             (ArrowType ty1 (ArrowType ty2 ty0))
-
-> bindNewConstr :: ModuleIdent -> QualIdent -> [Ident] -> TypeExpr
->               -> NewConstrDecl -> ExpValueEnv -> ExpValueEnv
-> bindNewConstr m tc tvs ty0 (NewConstrDecl _ evs c ty1) =
->   bindValue NewtypeConstructor m tc tvs c evs (ArrowType ty1 ty0)
-
-> --bindRecLabel :: ModuleIdent -> QualIdent -> ([Ident],TypeExpr)
-> --      -> ExpValueEnv -> ExpValueEnv
-> --bindRecLabel m r ([l],ty) =
-> --  Map.insert l (Label (qualify l) r (polyType (toQualType m [] ty)))
-
-> bindValue :: (QualIdent -> ExistTypeScheme -> ValueInfo) -> ModuleIdent
->           -> QualIdent -> [Ident] -> Ident -> [Ident] -> TypeExpr
->           -> ExpValueEnv -> ExpValueEnv
-> bindValue f m tc tvs c evs ty = Map.insert c (f (qualifyLike tc c) sigma)
->   where sigma = ForAllExist (length tvs) (length evs) (toQualType m tvs ty)
->         qualifyLike x = maybe qualify qualifyWith (qualidMod x)
-
-> bindA :: ModuleIdent -> IDecl -> ExpArityEnv -> ExpArityEnv
-> bindA m (IDataDecl _ _ _ cs) expAEnv
->    = foldr (bindConstrA m) expAEnv (catMaybes cs)
-> bindA m (IFunctionDecl _ f a _) expAEnv
->    = Map.insert (unqualify f) (ArityInfo (qualQualify m f) a) expAEnv
-> bindA _ _ expAEnv = expAEnv
-
-> bindConstrA :: ModuleIdent -> ConstrDecl -> ExpArityEnv -> ExpArityEnv
-> bindConstrA m (ConstrDecl _ _ c tys) expAEnv
->    = Map.insert c (ArityInfo (qualifyWith m c) (length tys)) expAEnv
-> bindConstrA m (ConOpDecl _ _ _ c _) expAEnv
->    = Map.insert c (ArityInfo (qualifyWith m c) 2) expAEnv
-
-\end{verbatim}
-After the environments have been initialized, the optional import
-specifications can be checked. There are two kinds of import
-specifications, a ``normal'' one, which names the entities that shall
-be imported, and a hiding specification, which lists those entities
-that shall not be imported.
-
-There is a subtle difference between both kinds of
-specifications. While it is not allowed to list a data constructor
-outside of its type in a ``normal'' specification, it is allowed to
-hide a data constructor explicitly. E.g., if module \texttt{A} exports
-the data type \texttt{T} with constructor \texttt{C}, the data
-constructor can be imported with one of the two specifications
-\begin{verbatim}
-import A(T(C))
-import A(T(..))
-\end{verbatim}
-but can be hidden in three different ways:
-\begin{verbatim}
-import A hiding(C)
-import A hiding(T(C))
-import A hiding(T(..))
-\end{verbatim}
-
-The functions \texttt{expandImport} and \texttt{expandHiding} check
-that all entities in an import specification are actually exported
-from the module. In addition, all imports of type constructors are
-changed into a \texttt{T()} specification and explicit imports for the
-data constructors are added.
-\begin{verbatim}
-
-> expandSpecs :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> ImportSpec
->             -> [Import]
-> expandSpecs m tcEnv tyEnv (Importing _ is) =
->   concat (map (expandImport m tcEnv tyEnv) is)
-> expandSpecs m tcEnv tyEnv (Hiding _ is) =
->   concat (map (expandHiding m tcEnv tyEnv) is)
-
-> expandImport :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> Import
->              -> [Import]
-> expandImport m tcEnv tyEnv (Import x) = expandThing m tcEnv tyEnv x
-> expandImport m tcEnv tyEnv (ImportTypeWith tc cs) =
->   [expandTypeWith m tcEnv tc cs]
-> expandImport m tcEnv tyEnv (ImportTypeAll tc) =
->   [expandTypeAll m tcEnv tc]
-
-> expandHiding :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> Import
->              -> [Import]
-> expandHiding m tcEnv tyEnv (Import x) = expandHide m tcEnv tyEnv x
-> expandHiding m tcEnv tyEnv (ImportTypeWith tc cs) =
->   [expandTypeWith m tcEnv tc cs]
-> expandHiding m tcEnv tyEnv (ImportTypeAll tc) =
->   [expandTypeAll m tcEnv tc]
-
-> expandThing :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> Ident
->             -> [Import]
-> expandThing m tcEnv tyEnv tc =
->   case Map.lookup tc tcEnv of
->     Just _ -> expandThing' m tyEnv tc (Just [ImportTypeWith tc []])
->     Nothing -> expandThing' m tyEnv tc Nothing
-
-> expandThing' :: ModuleIdent -> ExpValueEnv -> Ident
->              -> Maybe [Import] -> [Import]
-> expandThing' m tyEnv f tcImport =
->   case Map.lookup f tyEnv of
->     Just v
->       | isConstr v -> maybe (errorAt' (importDataConstr m f)) id tcImport
->       | otherwise -> Import f : maybe [] id tcImport
->     Nothing -> maybe (errorAt' (undefinedEntity m f)) id tcImport
->   where isConstr (DataConstructor _ _) = True
->         isConstr (NewtypeConstructor _ _) = True
->         isConstr (Value _ _) = False
-
-> expandHide :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> Ident
->            -> [Import]
-> expandHide m tcEnv tyEnv tc =
->   case Map.lookup tc tcEnv of
->     Just _ -> expandHide' m tyEnv tc (Just [ImportTypeWith tc []])
->     Nothing -> expandHide' m tyEnv tc Nothing
-
-> expandHide' :: ModuleIdent -> ExpValueEnv -> Ident
->             -> Maybe [Import] -> [Import]
-> expandHide' m tyEnv f tcImport =
->   case Map.lookup f tyEnv of
->     Just _ -> Import f : maybe [] id tcImport
->     Nothing -> maybe (errorAt' (undefinedEntity m f)) id tcImport
-
-> expandTypeWith ::  ModuleIdent -> ExpTCEnv -> Ident -> [Ident]
->                -> Import
-> expandTypeWith m tcEnv tc cs =
->   case Map.lookup tc tcEnv of
->     Just (DataType _ _ cs') ->
->       ImportTypeWith tc (map (checkConstr [c | Just (Data c _ _) <- cs']) cs)
->     Just (RenamingType _ _ (Data c _ _)) ->
->       ImportTypeWith tc (map (checkConstr [c]) cs)
->     Just _ -> errorAt' (nonDataType m tc)
->     Nothing -> errorAt' (undefinedEntity m tc)
->   where checkConstr cs c
->           | c `elem` cs = c
->           | otherwise = errorAt' (undefinedDataConstr m tc c)
-
-> expandTypeAll :: ModuleIdent -> ExpTCEnv -> Ident -> Import
-> expandTypeAll m tcEnv tc =
->   case Map.lookup tc tcEnv of
->     Just (DataType _ _ cs) -> ImportTypeWith tc [c | Just (Data c _ _) <- cs]
->     Just (RenamingType _ _ (Data c _ _)) -> ImportTypeWith tc [c]
->     Just _ -> errorAt' (nonDataType m tc)
->     Nothing -> errorAt' (undefinedEntity m tc)
-
-\end{verbatim}
-After all modules have been imported, the compiler has to ensure that
-all references to a data type use the same list of constructors.
-\begin{verbatim}
-
-> importUnifyData :: TCEnv -> TCEnv
-> importUnifyData tcEnv =
->   fmap (setInfo (foldr (mergeData . snd) Map.empty (allImports tcEnv))) tcEnv
->   where setInfo tcs t = fromJust (Map.lookup (origName t) tcs)
->         mergeData t tcs =
->           Map.insert tc (maybe t (fromJust . merge t) (Map.lookup tc tcs)) tcs
->           where tc = origName t
-
-\end{verbatim}
-Auxiliary functions:
-\begin{verbatim}
-
-> addType :: Import -> [Ident] -> [Ident]
-> addType (Import _) tcs = tcs
-> addType (ImportTypeWith tc _) tcs = tc : tcs
-> addType (ImportTypeAll _) _ = internalError "types"
-
-> addValue :: Import -> [Ident] -> [Ident]
-> addValue (Import f) fs = f : fs
-> addValue (ImportTypeWith _ cs) fs = cs ++ fs
-> addValue (ImportTypeAll _) _ = internalError "values"
-
-> addArity :: Import -> [Ident] -> [Ident]
-> addArity (Import f) ids = f:ids
-> addArity (ImportTypeWith _ cs) ids = cs ++ ids
-> addArity (ImportTypeAll _) _ = internalError "arities"
-
-> constrType :: QualIdent -> [Ident] -> TypeExpr
-> constrType tc tvs = ConstructorType tc (map VariableType tvs)
-
-\end{verbatim}
-Error messages:
-\begin{verbatim}
-
-> undefinedEntity :: ModuleIdent -> Ident -> (Position,String)
-> undefinedEntity m x =
->  (positionOfIdent x,
->   "Module " ++ moduleName m ++ " does not export " ++ name x)
-
-> undefinedDataConstr :: ModuleIdent -> Ident -> Ident -> (Position,String)
-> undefinedDataConstr m tc c =
->  (positionOfIdent c,   
->   name c ++ " is not a data constructor of type " ++ name tc)
-
-> nonDataType :: ModuleIdent -> Ident -> (Position,String)
-> nonDataType m tc = 
->  (positionOfIdent tc,
->   name tc ++ " is not a data type")
-
-> importDataConstr :: ModuleIdent -> Ident -> (Position,String)
-> importDataConstr m c = 
->  (positionOfIdent c,
->   "Explicit import for data constructor " ++ name c)
-
-\end{verbatim}
diff --git a/src/InterfaceCheck.hs b/src/InterfaceCheck.hs
deleted file mode 100644
--- a/src/InterfaceCheck.hs
+++ /dev/null
@@ -1,142 +0,0 @@
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---
--- InterfaceCheck - Checks the equality of the interfaces of two FlatCurry 
---                  programs 
---
--- January 2006,
--- Martin Engelke (men@informatik.uni-kiel.de)
---
-module InterfaceCheck where
-
-import Data.List
-
-import Curry.ExtendedFlat.Type
-
-
-
--------------------------------------------------------------------------------
-
--- Checks whether the interfaces of two FlatCurry programs are equal 
-interfaceCheck :: Prog -> Prog -> Bool
-interfaceCheck (Prog m1 is1 ts1 fs1 os1) (Prog m2 is2 ts2 fs2 os2)
-   = m1 == m2 
-     && sort is1 == sort is2
-     && checkTypeDecls ts1 ts2
-     && checkFuncDecls fs1 fs2
-     && checkOpDecls os1 os2
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
---
-checkTypeDecls :: [TypeDecl] -> [TypeDecl] -> Bool
-checkTypeDecls ts1 [] = null ts1
-checkTypeDecls ts1 ((Type qname vis2 is2 cs2):ts2')
-   = let (mt,ts1') = extract (isDataType qname) ts1
-     in  maybe False 
-               (\ (Type _ vis1 is1 cs1) 
-		-> vis1 == vis2 
-		   && is1 == is2 
-		   && checkConsDecls cs1 cs2
-		   && checkTypeDecls ts1' ts2')
-	       mt
-checkTypeDecls ts1 ((TypeSyn qname vis2 is2 texpr2):ts2')
-   = let (mt,ts1') = extract (isTypeSyn qname) ts1
-     in  maybe False
-	       (\ (TypeSyn _ vis1 is1 texpr1)
-		-> vis1 == vis2
-		   && is1 == is2
-		   && texpr1 == texpr2
-		   && checkTypeDecls ts1' ts2')
-	       mt
-
---
-checkConsDecls :: [ConsDecl] -> [ConsDecl] -> Bool
-checkConsDecls cs1 [] = null cs1
-checkConsDecls cs1 ((Cons qname arity2 vis2 texprs2):cs2')
-   = let (mc,cs1') = extract (isCons qname) cs1
-     in  maybe False
-	       (\ (Cons _ arity1 vis1 texprs1)
-		-> arity1 == arity2
-		   && vis1 == vis2
-		   && texprs1 == texprs2
-		   && checkConsDecls cs1' cs2')
-	       mc
-
---
-checkFuncDecls :: [FuncDecl] -> [FuncDecl] -> Bool
-checkFuncDecls fs1 [] = null fs1
-checkFuncDecls fs1 ((Func qname arity2 vis2 texpr2 rule2):fs2')
-   = let (mf,fs1') = extract (isFunc qname) fs1
-     in  maybe False
-	       (\ (Func _ arity1 vis1 texpr1 rule1)
-		-> arity1 == arity2
-		   && vis1 == vis2
-		   && texpr1 == texpr2
-		   && checkRule rule1 rule2
-		   && checkFuncDecls fs1' fs2')
-	       mf
-
---
-checkRule :: Rule -> Rule -> Bool
-checkRule (Rule _ _)   (Rule _ _)   = True
-checkRule (External _) (External _) = True
-checkRule _            _            = False
-
---
-checkOpDecls :: [OpDecl] -> [OpDecl] -> Bool
-checkOpDecls os1 [] = null os1
-checkOpDecls os1 ((Op qname fix2 prec2):os2')
-   = let (mo,os1') = extract (isOp qname) os1
-     in  maybe False
-	       (\ (Op _ fix1 prec1)
-		-> prec1 == prec2
-		   && fix1 == fix2
-		   && checkOpDecls os1' os2')
-	       mo
-
-
--------------------------------------------------------------------------------
-
---
-isDataType :: QName -> TypeDecl -> Bool
-isDataType qname (Type qname' _ _ _) = qname == qname'
-isDataType _     _                   = False
-
---
-isTypeSyn :: QName -> TypeDecl -> Bool
-isTypeSyn qname (TypeSyn qname' _ _ _) = qname == qname'
-isTypeSyn _     _                      = False
-
---
-isCons :: QName -> ConsDecl -> Bool
-isCons qname (Cons qname' _ _ _) = qname == qname'
-
---
-isFunc :: QName -> FuncDecl -> Bool
-isFunc qname (Func qname' _ _ _ _) = qname == qname'
-
---
-isOp :: QName -> OpDecl -> Bool
-isOp qname (Op qname' _ _) = qname == qname'
-
-
--------------------------------------------------------------------------------
-
---
-extract :: (a -> Bool) -> [a] -> (Maybe a, [a])
-extract _ [] = (Nothing, [])
-extract c (x:xs) | c x       = (Just x, xs)
-		 | otherwise = let (res, xs') = extract c xs in (res, x:xs')
-
-{-
--- Alternativ:
-extract :: (a -> Bool) -> [a] -> (Maybe a, [a])
-extract c xs = maybe (Nothing, xs) (\x -> (Just x, delete x xs)) (find c xs)
--}
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
diff --git a/src/Interfaces.hs b/src/Interfaces.hs
new file mode 100644
--- /dev/null
+++ b/src/Interfaces.hs
@@ -0,0 +1,151 @@
+{- |
+    Module      :  $Header$
+    Description :  Loading interfaces
+    Copyright   :  (c) 2000 - 2004, Wolfgang Lux
+                       2011 - 2013, Björn Peemöller
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    The compiler maintains a global environment holding all (directly or
+    indirectly) imported interface declarations for a module.
+
+    This module contains a function to load *all* interface declarations
+    declared by the (directly or indirectly) imported modules, regardless
+    whether they are included by the import specification or not.
+
+    The declarations are later brought into the scope of the module via the
+    function 'importModules', see module "Imports".
+
+    Interface files are updated by the Curry builder when necessary,
+    see module "CurryBuilder".
+-}
+{-# LANGUAGE CPP #-}
+module Interfaces (loadInterfaces) where
+
+#if __GLASGOW_HASKELL__ >= 804
+import Prelude hiding ((<>))
+#endif
+
+import           Control.Monad               (unless)
+import qualified Control.Monad.State    as S (StateT, execStateT, gets, modify)
+import qualified Data.Map               as M (insert, member)
+
+import           Curry.Base.Ident
+import           Curry.Base.Monad
+import           Curry.Base.Position
+import           Curry.Base.SpanInfo ()
+import           Curry.Base.Pretty
+import           Curry.Files.PathUtils
+import           Curry.Syntax
+
+import Base.Messages
+import Env.Interface
+
+import Checks.InterfaceSyntaxCheck (intfSyntaxCheck)
+
+-- Interface accumulating monad
+type IntfLoader a = S.StateT LoaderState IO a
+
+data LoaderState = LoaderState
+  { iEnv   :: InterfaceEnv
+  , spaths :: [FilePath]
+  , errs   :: [Message]
+  }
+
+-- Report an error.
+report :: [Message] -> IntfLoader ()
+report msg = S.modify $ \ s -> s { errs = msg ++ errs s }
+
+-- Check whether a module interface is already loaded.
+loaded :: ModuleIdent -> IntfLoader Bool
+loaded m = S.gets $ \ s -> m `M.member` iEnv s
+
+-- Retrieve the search paths
+searchPaths :: IntfLoader [FilePath]
+searchPaths = S.gets spaths
+
+-- Add an interface to the environment.
+addInterface :: ModuleIdent -> Interface -> IntfLoader ()
+addInterface m intf = S.modify $ \ s -> s { iEnv = M.insert m intf $ iEnv s }
+
+-- |Load the interfaces needed by a given module.
+-- This function returns an 'InterfaceEnv' containing the 'Interface's which
+-- were successfully loaded.
+loadInterfaces :: [FilePath] -- ^ 'FilePath's to search in for interfaces
+               -> Module a   -- ^ 'Module' header with import declarations
+               -> CYIO InterfaceEnv
+loadInterfaces paths (Module _ _ _ m _ is _) = do
+  res <- liftIO $ S.execStateT load (LoaderState initInterfaceEnv paths [])
+  if null (errs res) then ok (iEnv res) else failMessages (reverse $ errs res)
+  where load = mapM_ (loadInterface [m]) [(p, m') | ImportDecl p m' _ _ _ <- is]
+
+-- |Load an interface into the given environment.
+--
+-- If an import declaration for a module is found, the compiler first
+-- checks whether an import for the module is already pending.
+-- In this case the module imports are cyclic which is not allowed in Curry.
+-- Therefore, the import will be skipped and an error will be issued.
+-- Otherwise, the compiler checks whether the module has already been imported.
+-- If so, nothing needs to be done, otherwise the interface will be searched
+-- for in the import paths and compiled.
+loadInterface :: HasPosition a => [ModuleIdent] -> (a, ModuleIdent)
+              -> IntfLoader ()
+loadInterface ctxt (_, m)
+  | m `elem` ctxt = report [errCyclicImport $ m : takeWhile (/= m) ctxt]
+  | otherwise     = do
+    isLoaded <- loaded m
+    unless isLoaded $ do
+      paths  <- searchPaths
+      mbIntf <- liftIO $ lookupCurryInterface paths m
+      case mbIntf of
+        Nothing -> report [errInterfaceNotFound m]
+        Just fn -> compileInterface ctxt m fn
+
+-- |Compile an interface by recursively loading its dependencies.
+--
+-- After reading an interface, all imported interfaces are recursively
+-- loaded and inserted into the interface's environment.
+compileInterface :: [ModuleIdent] -> ModuleIdent -> FilePath
+                 -> IntfLoader ()
+compileInterface ctxt m fn = do
+  mbSrc <- liftIO $ readModule fn
+  case mbSrc of
+    Nothing  -> report [errInterfaceNotFound m]
+    Just src -> case runCYMIgnWarn (parseInterface fn src) of
+      Left err -> report err
+      Right intf@(Interface n is _) ->
+        if m /= n
+          then report [errWrongInterface m n]
+          else do
+            let (intf', intfErrs) = intfSyntaxCheck intf
+            mapM_ report [intfErrs]
+            mapM_ (loadInterface (m : ctxt)) [ (q, i) | IImportDecl q i <- is ]
+            addInterface m intf'
+
+-- Error message for required interface that could not be found.
+errInterfaceNotFound :: ModuleIdent -> Message
+errInterfaceNotFound m = spanInfoMessage m $
+  text "Interface for module" <+> text (moduleName m) <+> text "not found"
+
+-- Error message for an unexpected interface.
+errWrongInterface :: ModuleIdent -> ModuleIdent -> Message
+errWrongInterface m n = spanInfoMessage m $
+  text "Expected interface for" <+> text (moduleName m)
+  <> comma <+> text "but found" <+> text (moduleName n)
+
+-- Error message for a cyclic import.
+errCyclicImport :: [ModuleIdent] -> Message
+errCyclicImport []  = internalError "Interfaces.errCyclicImport: empty list"
+errCyclicImport [m] = spanInfoMessage m $
+  text "Recursive import for module" <+> text (moduleName m)
+errCyclicImport ms  = spanInfoMessage (head ms) $
+  text "Cyclic import dependency between modules"
+  <+> hsep (punctuate comma (map text inits)) <+> text "and" <+> text lastm
+  where
+  (inits, lastm)         = splitLast $ map moduleName ms
+  splitLast []           = internalError "Interfaces.splitLast: empty list"
+  splitLast (x : [])     = ([]  , x)
+  splitLast (x : y : ys) = (x : xs, z) where (xs, z) = splitLast (y : ys)
diff --git a/src/KindCheck.lhs b/src/KindCheck.lhs
deleted file mode 100644
--- a/src/KindCheck.lhs
+++ /dev/null
@@ -1,320 +0,0 @@
-
-% $Id: KindCheck.lhs,v 1.33 2004/02/13 19:24:04 wlux Exp $
-%
-% Copyright (c) 1999-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{KindCheck.lhs}
-\section{Checking Type Definitions}
-After the source file has been parsed and all modules have been
-imported, the compiler first performs kind checking on all type
-definitions and signatures. Because Curry currently does not support
-type classes, kind checking is rather trivial. All types must be of
-first order kind ($\star$), i.e., all type constructor applications
-must be saturated.
-
-During kind checking, this module will also disambiguate nullary
-constructors and type variables which -- in contrast to Haskell -- is
-not possible on purely syntactic criteria. In addition it is checked
-that all type constructors and type variables occurring on the right
-hand side of a type declaration are actually defined and no identifier
-is defined more than once.
-\begin{verbatim}
-
-> module KindCheck(kindCheck) where
-
-> import Data.Maybe
-
-> import Curry.Syntax
-> import Curry.Syntax.Utils(isTypeDecl)
-> import Curry.Base.Position
-> import Curry.Base.Ident
-> import Base hiding (bindArity)
-> import TopEnv
-
-\end{verbatim}
-In order to check type constructor applications, the compiler
-maintains an environment containing the kind information for all type
-constructors. The function \texttt{kindCheck} first initializes this
-environment by filtering out the arity of each type constructor from
-the imported type environment. Next, the arities of all locally
-defined type constructors are inserted into the environment, and,
-finally, the declarations are checked within this environment.
-\begin{verbatim}
-
-> kindCheck :: ModuleIdent -> TCEnv -> [Decl] -> [Decl]
-> kindCheck m tcEnv ds =
->   case findDouble (map tconstr ds') of
->     Nothing -> map (checkDecl m kEnv) ds
->     Just tc -> errorAt' (duplicateType tc)
->   where ds' = filter isTypeDecl ds
->         kEnv = foldr (bindArity m) (fmap tcArity tcEnv) ds'
-
-\end{verbatim}
-The kind environment only needs to record the arity of each type constructor.
-\begin{verbatim}
-
-> type KindEnv = TopEnv Int
-
-> bindArity :: ModuleIdent -> Decl -> KindEnv -> KindEnv
-> bindArity m (DataDecl _ tc tvs _) = bindArity' m  tc tvs
-> bindArity m (NewtypeDecl _ tc tvs _) = bindArity' m  tc tvs
-> bindArity m (TypeDecl _ tc tvs _) = bindArity' m  tc tvs
-> bindArity _ _ = id
-
-> bindArity' :: ModuleIdent -> Ident -> [Ident]
->            -> KindEnv -> KindEnv
-> bindArity' m tc tvs 
->   = bindTopEnv "KindCheck.bindArity'" tc n 
->                . qualBindTopEnv "KindCheck.bindArity'" (qualifyWith m tc) n
->   where n = length tvs
-
-> lookupKind :: Ident -> KindEnv -> [Int]
-> lookupKind = lookupTopEnv
-
-> qualLookupKind :: QualIdent -> KindEnv -> [Int]
-> qualLookupKind = qualLookupTopEnv
-
-\end{verbatim}
-When type declarations are checked, the compiler will allow anonymous
-type variables on the left hand side of the declaration, but not on
-the right hand side. Function and pattern declarations must be
-traversed because they can contain local type signatures.
-\begin{verbatim}
-
-> checkDecl :: ModuleIdent -> KindEnv -> Decl -> Decl
-> checkDecl m kEnv (DataDecl p tc tvs cs) =
->   DataDecl p tc tvs' (map (checkConstrDecl m kEnv tvs') cs)
->   where tvs' = checkTypeLhs kEnv tvs
-> checkDecl m kEnv (NewtypeDecl p tc tvs nc) =
->   NewtypeDecl p tc tvs' (checkNewConstrDecl m kEnv tvs' nc)
->   where tvs' = checkTypeLhs kEnv tvs
-> checkDecl m kEnv (TypeDecl p tc tvs ty) =
->   TypeDecl p tc tvs' (checkClosedType m kEnv tvs' ty)
->   where tvs' = checkTypeLhs kEnv tvs
-> checkDecl m kEnv (TypeSig p vs ty) =
->   TypeSig p vs (checkType m kEnv ty)
-> checkDecl m kEnv (FunctionDecl p f eqs) =
->   FunctionDecl p f (map (checkEquation m kEnv) eqs)
-> checkDecl m kEnv (PatternDecl p t rhs) =
->   PatternDecl p t (checkRhs m kEnv rhs)
-> checkDecl m kEnv (ExternalDecl p cc ie f ty) =
->   ExternalDecl p cc ie f (checkType m kEnv ty)
-> checkDecl _ _ d = d
-
-> checkTypeLhs :: KindEnv -> [Ident] -> [Ident]
-> checkTypeLhs kEnv (tv:tvs)
->   | tv == anonId = tv : checkTypeLhs kEnv tvs
->   | isTypeConstr tv = errorAt' (noVariable tv)
->   | tv `elem` tvs = errorAt' (nonLinear tv)
->   | otherwise = tv : checkTypeLhs kEnv tvs
->   where isTypeConstr tv = not (null (lookupKind tv kEnv))
-> checkTypeLhs _ [] = []
-
-> checkConstrDecl :: ModuleIdent -> KindEnv -> [Ident] -> ConstrDecl -> ConstrDecl
-> checkConstrDecl m kEnv tvs (ConstrDecl p evs c tys) =
->   ConstrDecl p evs' c (map (checkClosedType m kEnv tvs') tys)
->   where evs' = checkTypeLhs kEnv evs
->         tvs' = evs' ++ tvs
-> checkConstrDecl m kEnv tvs (ConOpDecl p evs ty1 op ty2) =
->   ConOpDecl p evs' (checkClosedType m kEnv tvs' ty1) op
->             (checkClosedType m kEnv tvs' ty2)
->   where evs' = checkTypeLhs kEnv evs
->         tvs' = evs' ++ tvs
-
-> checkNewConstrDecl :: ModuleIdent -> KindEnv -> [Ident] -> NewConstrDecl 
->	     -> NewConstrDecl
-> checkNewConstrDecl m kEnv tvs (NewConstrDecl p evs c ty) =
->   NewConstrDecl p evs' c (checkClosedType m kEnv tvs' ty)
->   where evs' = checkTypeLhs kEnv evs
->         tvs' = evs' ++ tvs
-
-\end{verbatim}
-Checking expressions is rather straight forward. The compiler must
-only traverse the structure of expressions in order to find local
-declaration groups.
-\begin{verbatim}
-
-> checkEquation :: ModuleIdent -> KindEnv -> Equation -> Equation
-> checkEquation m kEnv (Equation p lhs rhs) = 
->     Equation p lhs (checkRhs m kEnv rhs)
-
-> checkRhs :: ModuleIdent -> KindEnv -> Rhs -> Rhs
-> checkRhs m kEnv (SimpleRhs p e ds) =
->   SimpleRhs p (checkExpr m kEnv e) (map (checkDecl m kEnv) ds)
-> checkRhs m kEnv (GuardedRhs es ds) =
->   GuardedRhs (map (checkCondExpr m kEnv) es) (map (checkDecl m kEnv) ds)
-
-> checkCondExpr :: ModuleIdent -> KindEnv -> CondExpr -> CondExpr
-> checkCondExpr m kEnv (CondExpr p g e) =
->   CondExpr p (checkExpr m kEnv g) (checkExpr m kEnv e)
-
-> checkExpr :: ModuleIdent -> KindEnv -> Expression -> Expression
-> checkExpr _ _ (Literal l) = Literal l
-> checkExpr _ _ (Variable v) = Variable v
-> checkExpr _ _ (Constructor c) = Constructor c
-> checkExpr m kEnv (Paren e) = Paren (checkExpr m kEnv e)
-> checkExpr m kEnv (Typed e ty) =
->   Typed (checkExpr m kEnv e) (checkType m kEnv ty)
-> checkExpr m kEnv (Tuple p es) = Tuple p (map (checkExpr m kEnv ) es)
-> checkExpr m kEnv (List p es) = List p (map (checkExpr m kEnv ) es)
-> checkExpr m kEnv (ListCompr p e qs) =
->   ListCompr p (checkExpr m kEnv e) (map (checkStmt m kEnv ) qs)
-> checkExpr m kEnv  (EnumFrom e) = EnumFrom (checkExpr m kEnv  e)
-> checkExpr m kEnv  (EnumFromThen e1 e2) =
->   EnumFromThen (checkExpr m kEnv  e1) (checkExpr m kEnv  e2)
-> checkExpr m kEnv  (EnumFromTo e1 e2) =
->   EnumFromTo (checkExpr m kEnv  e1) (checkExpr m kEnv  e2)
-> checkExpr m kEnv  (EnumFromThenTo e1 e2 e3) =
->   EnumFromThenTo (checkExpr m kEnv  e1) (checkExpr m kEnv  e2)
->                  (checkExpr m kEnv  e3)
-> checkExpr m kEnv  (UnaryMinus op e) = UnaryMinus op (checkExpr m kEnv  e)
-> checkExpr m kEnv  (Apply e1 e2) =
->   Apply (checkExpr m kEnv  e1) (checkExpr m kEnv  e2)
-> checkExpr m kEnv  (InfixApply e1 op e2) =
->   InfixApply (checkExpr m kEnv  e1) op (checkExpr m kEnv  e2)
-> checkExpr m kEnv  (LeftSection e op) = LeftSection (checkExpr m kEnv  e) op
-> checkExpr m kEnv  (RightSection op e) = RightSection op (checkExpr m kEnv  e)
-> checkExpr m kEnv  (Lambda r ts e) = Lambda r ts (checkExpr m kEnv  e)
-> checkExpr m kEnv  (Let ds e) =
->   Let (map (checkDecl m kEnv) ds) (checkExpr m kEnv  e)
-> checkExpr m kEnv  (Do sts e) =
->   Do (map (checkStmt m kEnv ) sts) (checkExpr m kEnv  e)
-> checkExpr m kEnv  (IfThenElse r e1 e2 e3) =
->   IfThenElse r (checkExpr m kEnv  e1) (checkExpr m kEnv  e2)
->              (checkExpr m kEnv  e3)
-> checkExpr m kEnv  (Case r e alts) =
->   Case r (checkExpr m kEnv  e) (map (checkAlt m kEnv) alts)
-> checkExpr m kEnv  (RecordConstr fs) =
->   RecordConstr (map (checkFieldExpr m kEnv) fs)
-> checkExpr m kEnv  (RecordSelection e l) =
->   RecordSelection (checkExpr m kEnv  e) l
-> checkExpr m kEnv  (RecordUpdate fs e) =
->   RecordUpdate (map (checkFieldExpr m kEnv) fs) (checkExpr m kEnv  e)
-
-> checkStmt :: ModuleIdent -> KindEnv -> Statement -> Statement
-> checkStmt m kEnv  (StmtExpr p e) = StmtExpr p (checkExpr m kEnv  e)
-> checkStmt m kEnv  (StmtBind p t e) = StmtBind p t (checkExpr m kEnv  e)
-> checkStmt m kEnv  (StmtDecl ds) = StmtDecl (map (checkDecl m kEnv) ds)
-
-> checkAlt :: ModuleIdent -> KindEnv -> Alt -> Alt
-> checkAlt m kEnv (Alt p t rhs) = Alt p t (checkRhs m kEnv rhs)
-
-> checkFieldExpr :: ModuleIdent -> KindEnv -> Field Expression
->	            -> Field Expression
-> checkFieldExpr m kEnv (Field p l e) = Field p l (checkExpr m kEnv e)
-
-\end{verbatim}
-The parser cannot distinguish unqualified nullary type constructors
-and type variables. Therefore, if the compiler finds an unbound
-identifier in a position where a type variable is admissible, it will
-interpret the identifier as such.
-\begin{verbatim}
-
-> checkClosedType :: ModuleIdent -> KindEnv -> [Ident] -> TypeExpr 
->	  -> TypeExpr
-> checkClosedType m kEnv tvs ty = checkClosed tvs (checkType m kEnv  ty)
-
-> checkType :: ModuleIdent -> KindEnv -> TypeExpr -> TypeExpr
-> checkType m kEnv (ConstructorType tc tys) =
->   case qualLookupKind tc kEnv of
->     []
->       | not (isQualified tc) && null tys -> VariableType (unqualify tc)
->       | otherwise -> errorAt' (undefinedType tc)
->     [n]
->       | n == n' -> ConstructorType tc (map (checkType m kEnv ) tys)
->       | otherwise -> errorAt' (wrongArity tc n n')
->     _ -> case (qualLookupKind (qualQualify m tc) kEnv) of
->            [n] 
->               | n == n' -> ConstructorType tc (map (checkType m kEnv ) tys)
->               | otherwise -> errorAt' (wrongArity tc n n')
->            _ -> errorAt' (ambiguousType tc)
->  where n' = length tys 
-> checkType m kEnv  (VariableType tv)
->   | tv == anonId = VariableType tv
->   | otherwise = checkType m kEnv  (ConstructorType (qualify tv) [])
-> checkType m kEnv  (TupleType tys) =
->   TupleType (map (checkType m kEnv ) tys)
-> checkType m kEnv  (ListType ty) =
->   ListType (checkType m kEnv  ty)
-> checkType m kEnv  (ArrowType ty1 ty2) =
->   ArrowType (checkType m kEnv  ty1) (checkType m kEnv  ty2)
-> checkType m kEnv  (RecordType fs r) =
->   RecordType (map (\ (ls,ty) -> (ls, checkType m kEnv  ty)) fs)
->	       (maybe Nothing (Just . checkType m kEnv ) r)
-
-> checkClosed :: [Ident] -> TypeExpr -> TypeExpr
-> checkClosed tvs (ConstructorType tc tys) =
->   ConstructorType tc (map (checkClosed tvs) tys)
-> checkClosed tvs (VariableType tv)
->   | tv == anonId || tv `notElem` tvs = errorAt' (unboundVariable tv)
->   | otherwise = VariableType tv
-> checkClosed tvs (TupleType tys) =
->   TupleType (map (checkClosed tvs) tys)
-> checkClosed tvs (ListType ty) =
->   ListType (checkClosed tvs ty)
-> checkClosed tvs (ArrowType ty1 ty2) =
->   ArrowType (checkClosed tvs ty1) (checkClosed tvs ty2)
-> checkClosed tvs (RecordType fs r) =
->   RecordType (map (\ (ls,ty) -> (ls, checkClosed tvs ty)) fs)
->	       (maybe Nothing (Just . checkClosed tvs) r)
->       
-
-\end{verbatim}
-Auxiliary definitions
-\begin{verbatim}
-
-> tconstr :: Decl -> Ident
-> tconstr (DataDecl p tc _ _) = tc
-> tconstr (NewtypeDecl p tc _ _) = tc
-> tconstr (TypeDecl p tc _ _) = tc
-> tconstr _ = internalError "tconstr"
-
-\end{verbatim}
-Error messages:
-\begin{verbatim}
-
-> undefinedType :: QualIdent -> (Position,String)
-> undefinedType tc = 
->     (positionOfQualIdent tc,
->      "Undefined type " ++ qualName tc)
-
-> ambiguousType :: QualIdent -> (Position,String)
-> ambiguousType tc = 
->     (positionOfQualIdent tc,
->      "Ambiguous type " ++ qualName tc)
-
-> duplicateType :: Ident -> (Position,String)
-> duplicateType tc = 
->     (positionOfIdent tc,
->      "More than one definition for type " ++ name tc)
-
-> nonLinear :: Ident -> (Position,String)
-> nonLinear tv =
->  (positionOfIdent tv,      
->   "Type variable " ++ name tv ++
->   " occurs more than once on left hand side of type declaration")
-
-> noVariable :: Ident -> (Position,String)
-> noVariable tv =
->  (positionOfIdent tv,      
->   "Type constructor " ++ name tv ++
->   " used in left hand side of type declaration")
-
-> wrongArity :: QualIdent -> Int -> Int -> (Position,String)
-> wrongArity tc arity argc =
->  (positionOfQualIdent tc,      
->   "Type constructor " ++ qualName tc ++ " expects " ++ arguments arity ++
->   " but is applied to " ++ show argc)
->   where arguments 0 = "no arguments"
->         arguments 1 = "1 argument"
->         arguments n = show n ++ " arguments"
-
-> unboundVariable :: Ident -> (Position,String)
-> unboundVariable tv = 
->     (positionOfIdent tv,
->      "Unbound type variable " ++ name tv)
-
-\end{verbatim}
diff --git a/src/Lift.lhs b/src/Lift.lhs
deleted file mode 100644
--- a/src/Lift.lhs
+++ /dev/null
@@ -1,307 +0,0 @@
-
-% $Id: Lift.lhs,v 1.23 2004/02/13 14:02:54 wlux Exp $
-%
-% Copyright (c) 2001-2003, Wolfgang Lux
-% See LICENSE for the full license.
-%
-\nwfilename{Lift.lhs}
-\section{Lifting Declarations}
-After desugaring and simplifying the code, the compiler lifts all
-local function declarations to the top-level keeping only local
-variable declarations. The algorithm used here is similar to
-Johnsson's~\cite{Johnsson87:Thesis} (see also chapter 6
-of~\cite{PeytonJonesLester92:Book}). It consists of two phases, first
-we abstract each local function declaration, adding its free variables
-as initial parameters and update all calls to take these variables
-into account. Then all local function declarations are collected and
-lifted to the top-level.
-\begin{verbatim}
-
-> module Lift(lift) where
-
-> import Control.Monad
-> import qualified Control.Monad.State as S
-> import Data.List
-> import qualified Data.Map as Map
-> import qualified Data.Set as Set
-
-> import Curry.Syntax
-> import Curry.Syntax.Utils
-> import Types
-> import Curry.Base.Ident
-> import Base
-> import TopEnv
-> import SCC
-
-> lift :: ValueEnv -> EvalEnv -> Module -> (Module,ValueEnv,EvalEnv)
-> lift tyEnv evEnv (Module m es ds) =
->   (Module m es (concatMap liftFunDecl ds'),tyEnv',evEnv')
->   where (ds',tyEnv',evEnv') =
->           S.evalState (S.evalStateT (abstractModule m ds) tyEnv) evEnv
-
-\end{verbatim}
-\paragraph{Abstraction}
-Besides adding the free variables to every (local) function, the
-abstraction pass also has to update the type environment in order to
-reflect the new types of the expanded functions. As usual we use a
-state monad transformer in order to pass the type environment
-through. The environment constructed in the abstraction phase maps
-each local function declaration onto its replacement expression,
-i.e. the function applied to its free variables.
-\begin{verbatim}
-
-> type AbstractState a = S.StateT ValueEnv (S.State EvalEnv) a
-> type AbstractEnv = Map.Map Ident Expression
-
-> abstractModule :: ModuleIdent -> [Decl]
->                -> AbstractState ([Decl],ValueEnv,EvalEnv)
-> abstractModule m ds =
->   do
->     ds' <- mapM (abstractDecl m "" [] Map.empty) ds
->     tyEnv' <- S.get
->     evEnv' <- S.lift S.get
->     return (ds',tyEnv',evEnv')
-
-> abstractDecl :: ModuleIdent -> String -> [Ident] -> AbstractEnv -> Decl
->              -> AbstractState Decl
-> abstractDecl m _ lvs env (FunctionDecl p f eqs) =
->   liftM (FunctionDecl p f) (mapM (abstractEquation m lvs env) eqs)
-> abstractDecl m pre lvs env (PatternDecl p t rhs) =
->   liftM (PatternDecl p t) (abstractRhs m pre lvs env rhs)
-> abstractDecl _ _ _ _ d = return d
-
-> abstractEquation :: ModuleIdent -> [Ident] -> AbstractEnv -> Equation
->                  -> AbstractState Equation
-> abstractEquation m lvs env (Equation p lhs@(FunLhs f ts) rhs) =
->   liftM (Equation p lhs)
->         (abstractRhs m (name f ++ ".") (lvs ++ bv ts) env rhs)
-
-> abstractRhs :: ModuleIdent -> String -> [Ident] -> AbstractEnv -> Rhs
->             -> AbstractState Rhs
-> abstractRhs m pre lvs env (SimpleRhs p e _) =
->   liftM (flip (SimpleRhs p) []) (abstractExpr m pre lvs env e)
-
-\end{verbatim}
-Within a declaration group we have to split the list of declarations
-into the function and value declarations. Only the function
-declarations are affected by the abstraction algorithm; the value
-declarations are left unchanged except for abstracting their right
-hand sides.
-
-The abstraction of a recursive declaration group is complicated by the
-fact that not all functions need to call each in a recursive
-declaration group. E.g., in the following example neither g nor h
-call each other.
-\begin{verbatim}
-  f = g True
-    where x = f 1
-          f z = y + z
-          y = g False
-          g z = if z then x else 0
-\end{verbatim}
-Because of this fact, f and g can be abstracted separately by adding
-only \texttt{y} to \texttt{f} and \texttt{x} to \texttt{g}. On the
-other hand, in the following example
-\begin{verbatim}
-  f x y = g 4
-    where g p = h p + x
-          h q = k + y + q
-          k = g x
-\end{verbatim}
-the local function \texttt{g} uses \texttt{h}, so the free variables
-of \texttt{h} have to be added to \texttt{g} as well. However, because
-\texttt{h} does not call \texttt{g} it is sufficient to add only
-\texttt{k} and \texttt{y} (and not \texttt{x}) to its definition. We
-handle this by computing the dependency graph between the functions
-and splitting this graph into its strongly connected components. Each
-component is then processed separately, adding the free variables in
-the group to its functions.
-
-We have to be careful with local declarations within desugared case
-expressions. If some of the cases have guards, e.g.,
-\begin{verbatim}
-  case e of
-    x | x < 1 -> 1
-    x -> let double y = y * y in double x
-\end{verbatim}
-the desugarer at present may duplicate code. While there is no problem
-with local variable declaration being duplicated, we must avoid to
-lift local function declarations more than once. Therefore
-\texttt{abstractFunDecls} transforms only those function declarations
-that have not been lifted and discards the other declarations. Note
-that it is easy to check whether a function has been lifted by
-checking whether an entry for its untransformed name is still present
-in the type environment.
-\begin{verbatim}
-
-> abstractDeclGroup :: ModuleIdent -> String -> [Ident] -> AbstractEnv
->                   -> [Decl] -> Expression -> AbstractState Expression
-> abstractDeclGroup m pre lvs env ds e =
->   abstractFunDecls m pre (lvs ++ bv vds) env (scc bv (qfv m) fds) vds e
->   where (fds,vds) = partition isFunDecl ds
-
-> abstractFunDecls :: ModuleIdent -> String -> [Ident] -> AbstractEnv
->                  -> [[Decl]] -> [Decl] -> Expression
->                  -> AbstractState Expression
-> abstractFunDecls m pre lvs env [] vds e =
->   do
->     vds' <- mapM (abstractDecl m pre lvs env) vds
->     e' <- abstractExpr m pre lvs env e
->     return (Let vds' e')
-> abstractFunDecls m pre lvs env (fds:fdss) vds e =
->   do
->     fs' <- liftM (\tyEnv -> filter (not . isLifted tyEnv) fs) S.get
->     S.modify (abstractFunTypes m pre fvs fs')
->     S.lift (S.modify (abstractFunAnnots m pre fs'))
->     fds' <- mapM (abstractFunDecl m pre fvs lvs env')
->                  [d | d <- fds, any (`elem` fs') (bv d)]
->     e' <- abstractFunDecls m pre lvs env' fdss vds e
->     return (Let fds' e')
->   where fs = bv fds
->         fvs = filter (`elem` lvs) (Set.toList fvsRhs)
->         env' = foldr (bindF (map mkVar fvs)) env fs
->         fvsRhs = Set.unions
->           [Set.fromList (maybe [v] (qfv m) (Map.lookup v env)) | v <- qfv m fds]
->         bindF fvs f = Map.insert f (apply (mkFun m pre f) fvs)
->         isLifted tyEnv f = null (lookupValue f tyEnv)
-
-> abstractFunTypes :: ModuleIdent -> String -> [Ident] -> [Ident]
->                  -> ValueEnv -> ValueEnv
-> abstractFunTypes m pre fvs fs tyEnv = foldr abstractFunType tyEnv fs
->   where tys = map (varType tyEnv) fvs
->         abstractFunType f tyEnv =
->           qualBindFun m (liftIdent pre f)
->                         (foldr TypeArrow (varType tyEnv f) tys)
->                         (unbindFun f tyEnv)
-
-> abstractFunAnnots :: ModuleIdent -> String -> [Ident] -> EvalEnv -> EvalEnv
-> abstractFunAnnots m pre fs evEnv = foldr abstractFunAnnot evEnv fs
->   where abstractFunAnnot f evEnv =
->           case Map.lookup f evEnv of
->             Just ev -> Map.insert (liftIdent pre f) ev (Map.delete f evEnv)
->             Nothing -> evEnv
-
-> abstractFunDecl :: ModuleIdent -> String -> [Ident] -> [Ident]
->                 -> AbstractEnv -> Decl -> AbstractState Decl
-> abstractFunDecl m pre fvs lvs env (FunctionDecl p f eqs) =
->   abstractDecl m pre lvs env (FunctionDecl p f' (map (addVars f') eqs))
->   where f' = liftIdent pre f
->         addVars f (Equation p (FunLhs _ ts) rhs) =
->           Equation p (FunLhs f (map VariablePattern fvs ++ ts)) rhs
-> abstractFunDecl m pre _ lvs env (ExternalDecl p cc ie f ty) =
->   return (ExternalDecl p cc ie (liftIdent pre f) ty)
-
-> abstractExpr :: ModuleIdent -> String -> [Ident] -> AbstractEnv
->              -> Expression -> AbstractState Expression
-> abstractExpr _ _ _ _ (Literal l) = return (Literal l)
-> abstractExpr m pre lvs env (Variable v)
->   | isQualified v = return (Variable v)
->   | otherwise = maybe (return (Variable v)) (abstractExpr m pre lvs env)
->                       (Map.lookup (unqualify v) env)
-> abstractExpr _ _ _ _ (Constructor c) = return (Constructor c)
-> abstractExpr m pre lvs env (Apply e1 e2) =
->   do
->     e1' <- abstractExpr m pre lvs env e1
->     e2' <- abstractExpr m pre lvs env e2
->     return (Apply e1' e2')
-> abstractExpr m pre lvs env (Let ds e) = abstractDeclGroup m pre lvs env ds e
-> abstractExpr m pre lvs env (Case r e alts) =
->   do
->     e' <- abstractExpr m pre lvs env e
->     alts' <- mapM (abstractAlt m pre lvs env) alts
->     return (Case r e' alts')
-> abstractExpr m _ _ _ _ = internalError "abstractExpr"
-
-> abstractAlt :: ModuleIdent -> String -> [Ident] -> AbstractEnv -> Alt
->             -> AbstractState Alt
-> abstractAlt m pre lvs env (Alt p t rhs) =
->   liftM (Alt p t) (abstractRhs m pre (lvs ++ bv t) env rhs)
-
-\end{verbatim}
-\paragraph{Lifting}
-After the abstraction pass, all local function declarations are lifted
-to the top-level.
-\begin{verbatim}
-
-> liftFunDecl :: Decl -> [Decl]
-> liftFunDecl (FunctionDecl p f eqs) = (FunctionDecl p f eqs' : concat dss')
->   where (eqs',dss') = unzip (map liftEquation eqs)
-> liftFunDecl d = [d]
-
-> liftVarDecl :: Decl -> (Decl,[Decl])
-> liftVarDecl (PatternDecl p t rhs) = (PatternDecl p t rhs',ds')
->   where (rhs',ds') = liftRhs rhs
-> liftVarDecl (ExtraVariables p vs) = (ExtraVariables p vs,[])
-
-> liftEquation :: Equation -> (Equation,[Decl])
-> liftEquation (Equation p lhs rhs) = (Equation p lhs rhs',ds')
->   where (rhs',ds') = liftRhs rhs
-
-> liftRhs :: Rhs -> (Rhs,[Decl])
-> liftRhs (SimpleRhs p e _) = (SimpleRhs p e' [],ds')
->   where (e',ds') = liftExpr e
-
-> liftDeclGroup :: [Decl] -> ([Decl],[Decl])
-> liftDeclGroup ds = (vds',concat (map liftFunDecl fds ++ dss'))
->   where (fds,vds) = partition isFunDecl ds
->         (vds',dss') = unzip (map liftVarDecl vds)
-
-> liftExpr :: Expression -> (Expression,[Decl])
-> liftExpr (Literal l) = (Literal l,[])
-> liftExpr (Variable v) = (Variable v,[])
-> liftExpr (Constructor c) = (Constructor c,[])
-> liftExpr (Apply e1 e2) = (Apply e1' e2',ds' ++ ds'')
->   where (e1',ds') = liftExpr e1
->         (e2',ds'') = liftExpr e2
-> liftExpr (Let ds e) = (mkLet ds' e',ds'' ++ ds''')
->   where (ds',ds'') = liftDeclGroup ds
->         (e',ds''') = liftExpr e
->         mkLet ds e = if null ds then e else Let ds e
-> liftExpr (Case r e alts) = (Case r e' alts',concat (ds':dss'))
->   where (e',ds') = liftExpr e
->         (alts',dss') = unzip (map liftAlt alts)
-> liftExpr _ = internalError "liftExpr"
-
-> liftAlt :: Alt -> (Alt,[Decl])
-> liftAlt (Alt p t rhs) = (Alt p t rhs',ds')
->   where (rhs',ds') = liftRhs rhs
-
-
-\end{verbatim}
-\paragraph{Auxiliary definitions}
-\begin{verbatim}
-
-> isFunDecl :: Decl -> Bool
-> isFunDecl (FunctionDecl _ _ _) = True
-> isFunDecl (ExternalDecl _ _ _ _ _) = True
-> isFunDecl _ = False
-
-> mkFun :: ModuleIdent -> String -> Ident -> Expression
-> mkFun m pre f = Variable (qualifyWith m (liftIdent pre f))
-
-> mkVar :: Ident -> Expression
-> mkVar v = Variable (qualify v)
-
-> apply :: Expression -> [Expression] -> Expression
-> apply = foldl Apply
-
-> qualBindFun :: ModuleIdent -> Ident -> Type -> ValueEnv -> ValueEnv
-> qualBindFun m f ty 
->   = qualBindTopEnv "Lift.qualBindFun" f' (Value f' (polyType ty))
->   where f' = qualifyWith m f
-
-> unbindFun :: Ident -> ValueEnv -> ValueEnv
-> unbindFun = unbindTopEnv
-
-> varType :: ValueEnv -> Ident -> Type
-> varType tyEnv v =
->   case lookupValue v tyEnv of
->     [Value _ (ForAll _ ty)] -> ty
->     _ -> internalError ("varType " ++ show v)
-
-> liftIdent :: String -> Ident -> Ident
-> liftIdent prefix x =
->     renameIdent (mkIdent (prefix ++ (show x))) (uniqueId x)
->    --renameIdent (mkIdent (prefix ++ name x ++ show (uniqueId x))) (uniqueId x)
-
-\end{verbatim}
diff --git a/src/Modules.hs b/src/Modules.hs
new file mode 100644
--- /dev/null
+++ b/src/Modules.hs
@@ -0,0 +1,453 @@
+{- |
+    Module      :  $Header$
+    Description :  Compilation of a single module
+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux
+                       2005        Martin Engelke
+                       2007        Sebastian Fischer
+                       2011 - 2015 Björn Peemöller
+                       2016        Jan Tikovsky
+                       2016 - 2017 Finn Teegen
+                       2018        Kai-Oliver Prott
+    License     :  BSD-3-clause
+
+    Maintainer  :  fte@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module controls the compilation of modules.
+-}
+
+module Modules
+  ( compileModule, loadAndCheckModule, loadModule, checkModule
+  , parseModule, checkModuleHeader
+  ) where
+
+import qualified Control.Exception as C   (catch, IOException)
+import           Control.Monad            (liftM, unless, when)
+import           Data.Char                (toUpper)
+import qualified Data.Map          as Map (elems, lookup)
+import           Data.Maybe               (fromMaybe)
+import           System.Directory         (getTemporaryDirectory, removeFile)
+import           System.Exit              (ExitCode (..))
+import           System.FilePath          (normalise)
+import           System.IO
+   (IOMode (ReadMode), Handle, hClose, hGetContents, hPutStr, openFile
+  , openTempFile)
+import           System.Process           (system)
+
+import Curry.Base.Ident
+import Curry.Base.Monad
+import Curry.Base.SpanInfo
+import Curry.Base.Pretty
+import Curry.Base.Span
+import Curry.FlatCurry.InterfaceEquivalence (eqInterface)
+import Curry.Files.Filenames
+import Curry.Files.PathUtils
+import Curry.Syntax.InterfaceEquivalence
+import Curry.Syntax.Utils (shortenModuleAST)
+
+import Base.Messages
+import Base.Types
+
+import Env.Interface
+
+-- source representations
+import qualified Curry.AbstractCurry as AC
+import qualified Curry.FlatCurry     as FC
+import qualified Curry.Syntax        as CS
+import qualified IL
+
+import Checks
+import CompilerEnv
+import CompilerOpts
+import CondCompile (condCompile)
+import Exports
+import Generators
+import Html.CurryHtml (source2html)
+import Imports
+import Interfaces (loadInterfaces)
+import TokenStream (showTokenStream, showCommentTokenStream)
+import Transformations
+
+-- The function 'compileModule' is the main entry-point of this
+-- module for compiling a Curry source module. Depending on the command
+-- line options, it will emit either FlatCurry code or AbstractCurry code
+-- (typed, untyped or with type signatures) for the module.
+-- Usually, the first step is to check the module.
+-- Then the code is translated into the intermediate
+-- language. If necessary, this phase will also update the module's
+-- interface file. The resulting code then is written out
+-- to the corresponding file.
+-- The untyped  AbstractCurry representation is written
+-- out directly after parsing and simple checking the source file.
+-- The typed AbstractCurry code is written out after checking the module.
+--
+-- The compiler automatically loads the prelude when compiling any
+-- module, except for the prelude itself, by adding an appropriate import
+-- declaration to the module.
+compileModule :: Options -> ModuleIdent -> FilePath -> CYIO ()
+compileModule opts m fn = do
+  mdl <- loadAndCheckModule opts m fn
+  writeTokens   opts (fst mdl)
+  writeComments opts (fst mdl)
+  writeParsed   opts mdl
+  let qmdl = qual mdl
+  writeHtml     opts qmdl
+  writeAST      opts (fst  mdl, fmap (const ()) (snd  mdl))
+  writeShortAST opts (fst qmdl, fmap (const ()) (snd qmdl))
+  mdl' <- expandExports opts mdl
+  qmdl' <- dumpWith opts CS.showModule pPrint DumpQualified $ qual mdl'
+  writeAbstractCurry opts qmdl'
+  -- generate interface file
+  let intf = uncurry exportInterface qmdl'
+  writeInterface opts (fst mdl') intf
+  when withFlat $ do
+    ((env, il), mdl'') <- transModule opts qmdl'
+    writeFlat opts env (snd mdl'') il
+  where
+  withFlat = any (`elem` optTargetTypes opts) [ AnnotatedFlatCurry
+                                              , TypedFlatCurry
+                                              , FlatCurry
+                                              ]
+
+loadAndCheckModule :: Options -> ModuleIdent -> FilePath
+                   -> CYIO (CompEnv (CS.Module PredType))
+loadAndCheckModule opts m fn = do
+  ce <- loadModule opts m fn >>= checkModule opts
+  warnMessages $ uncurry (warnCheck opts) ce
+  return ce
+
+-- ---------------------------------------------------------------------------
+-- Loading a module
+-- ---------------------------------------------------------------------------
+
+loadModule :: Options -> ModuleIdent -> FilePath
+           -> CYIO (CompEnv (CS.Module ()))
+loadModule opts m fn = do
+  -- parse and check module header
+  (toks, mdl) <- parseModule opts m fn
+  -- load the imported interfaces into an InterfaceEnv
+  let paths = map (addOutDir (optUseOutDir opts) (optOutDir opts))
+                  ("." : optImportPaths opts)
+  let withPrel = importPrelude opts mdl
+  iEnv   <- loadInterfaces paths withPrel
+  checkInterfaces opts iEnv
+  is     <- importSyntaxCheck iEnv withPrel
+  -- add information of imported modules
+  cEnv   <- importModules withPrel iEnv is
+  return (cEnv { filePath = fn, tokens = toks }, mdl)
+
+parseModule :: Options -> ModuleIdent -> FilePath
+            -> CYIO ([(Span, CS.Token)], CS.Module ())
+parseModule opts m fn = do
+  mbSrc <- liftIO $ readModule fn
+  case mbSrc of
+    Nothing  -> failMessages [message $ text $ "Missing file: " ++ fn]
+    Just src -> do
+      ul      <- liftCYM $ CS.unlit fn src
+      prepd   <- preprocess (optPrepOpts opts) fn ul
+      condC   <- condCompile (optCppOpts opts) fn prepd
+      doDump ((optDebugOpts opts) { dbDumpEnv = False })
+             (DumpCondCompiled, undefined, condC)
+      -- We ignore the warnings issued by the lexer because
+      -- they will be issued a second time during parsing.
+      spanToks <- liftCYM $ silent $ CS.lexSource fn condC
+      ast      <- liftCYM $ CS.parseModule fn condC
+      checked  <- checkModuleHeader m fn ast
+      return (spanToks, checked)
+
+preprocess :: PrepOpts -> FilePath -> String -> CYIO String
+preprocess opts fn src
+  | not (ppPreprocess opts) = return src
+  | otherwise               = do
+    res <- liftIO $ withTempFile $ \ inFn inHdl -> do
+      hPutStr inHdl src
+      hClose inHdl
+      withTempFile $ \ outFn outHdl -> do
+        hClose outHdl
+        ec <- system $ unwords $
+          [ppCmd opts, normalise fn, inFn, outFn] ++ ppOpts opts
+        case ec of
+          ExitFailure x -> return $ Left [message $ text $
+              "Preprocessor exited with exit code " ++ show x]
+          ExitSuccess   -> Right `liftM` readFile outFn
+    either failMessages ok res
+
+withTempFile :: (FilePath -> Handle -> IO a) -> IO a
+withTempFile act = do
+  tmp       <- getTemporaryDirectory
+  (fn, hdl) <- openTempFile tmp "cymake.curry"
+  res       <- act fn hdl
+  hClose hdl
+  removeFile fn
+  return res
+
+checkModuleHeader :: Monad m => ModuleIdent -> FilePath
+                  -> CS.Module () -> CYT m (CS.Module ())
+checkModuleHeader m fn = checkModuleId m
+                       . CS.patchModuleId fn
+
+-- |Check whether the 'ModuleIdent' and the 'FilePath' fit together
+checkModuleId :: Monad m => ModuleIdent -> CS.Module () -> CYT m (CS.Module ())
+checkModuleId mid m@(CS.Module _ _ _ mid' _ _ _)
+  | mid == mid' = ok m
+  | otherwise   = failMessages [errModuleFileMismatch mid']
+
+-- An implicit import of the prelude is temporariliy added to the declarations
+-- of every module, except for the prelude itself, or when the import is
+-- disabled by a compiler option. If no explicit import for the prelude is
+-- present, the prelude is imported unqualified,
+-- otherwise a qualified import is added.
+
+importPrelude :: Options -> CS.Module () -> CS.Module ()
+importPrelude opts m@(CS.Module spi li ps mid es is ds)
+    -- the Prelude itself
+  | mid == preludeMIdent         = m
+    -- disabled by compiler option
+  | noImpPrelude                 = m
+    -- already imported
+  | preludeMIdent `elem` imports = m
+    -- let's add it!
+  | otherwise                    = CS.Module spi li ps mid es (preludeImp:is) ds
+  where
+  noImpPrelude = NoImplicitPrelude `elem` optExtensions opts
+                 || m `CS.hasLanguageExtension` NoImplicitPrelude
+  preludeImp   = CS.ImportDecl NoSpanInfo preludeMIdent
+                  False   -- qualified?
+                  Nothing -- no alias
+                  Nothing -- no selection of types, functions, etc.
+  imports      = [imp | (CS.ImportDecl _ imp _ _ _) <- is]
+
+checkInterfaces :: Monad m => Options -> InterfaceEnv -> CYT m ()
+checkInterfaces opts iEnv = mapM_ checkInterface (Map.elems iEnv)
+  where
+  checkInterface intf = do
+    let env = importInterfaces intf iEnv
+    interfaceCheck opts (env, intf)
+
+importSyntaxCheck :: Monad m => InterfaceEnv -> CS.Module a -> CYT m [CS.ImportDecl]
+importSyntaxCheck iEnv (CS.Module _ _ _ _ _ imps _) = mapM checkImportDecl imps
+  where
+  checkImportDecl (CS.ImportDecl p m q asM is) = case Map.lookup m iEnv of
+    Just intf -> CS.ImportDecl p m q asM `liftM` importCheck intf is
+    Nothing   -> internalError $ "Modules.importModules: no interface for "
+                                    ++ show m
+
+-- ---------------------------------------------------------------------------
+-- Checking a module
+-- ---------------------------------------------------------------------------
+
+-- TODO: The order of the checks should be improved!
+checkModule :: Options -> CompEnv (CS.Module ())
+            -> CYIO (CompEnv (CS.Module PredType))
+checkModule opts mdl = do
+  _   <- dumpCS DumpParsed mdl
+  exc <- extensionCheck  opts mdl >>= dumpCS DumpExtensionChecked
+  tsc <- typeSyntaxCheck opts exc >>= dumpCS DumpTypeSyntaxChecked
+  kc  <- kindCheck       opts tsc >>= dumpCS DumpKindChecked
+  sc  <- syntaxCheck     opts kc  >>= dumpCS DumpSyntaxChecked
+  pc  <- precCheck       opts sc  >>= dumpCS DumpPrecChecked
+  dc  <- deriveCheck     opts pc  >>= dumpCS DumpDeriveChecked
+  inc <- instanceCheck   opts dc  >>= dumpCS DumpInstanceChecked
+  tc  <- typeCheck       opts inc >>= dumpCS DumpTypeChecked
+  ec  <- exportCheck     opts tc  >>= dumpCS DumpExportChecked
+  return ec
+  where
+  dumpCS :: (MonadIO m, Show a) => DumpLevel -> CompEnv (CS.Module a)
+         -> m (CompEnv (CS.Module a))
+  dumpCS = dumpWith opts CS.showModule pPrint
+
+-- ---------------------------------------------------------------------------
+-- Translating a module
+-- ---------------------------------------------------------------------------
+
+transModule :: Options -> CompEnv (CS.Module PredType)
+            -> CYIO (CompEnv IL.Module, CompEnv (CS.Module Type))
+transModule opts mdl = do
+  derived    <- dumpCS DumpDerived       $ derive               mdl
+  desugared  <- dumpCS DumpDesugared     $ desugar              derived
+  dicts      <- dumpCS DumpDictionaries  $ insertDicts    inlDi desugared
+  newtypes   <- dumpCS DumpNewtypes      $ removeNewtypes remNT dicts
+  simplified <- dumpCS DumpSimplified    $ simplify             newtypes
+  lifted     <- dumpCS DumpLifted        $ lift                 simplified
+  il         <- dumpIL DumpTranslated    $ ilTrans        remIm lifted
+  ilCaseComp <- dumpIL DumpCaseCompleted $ completeCase         il
+  return (ilCaseComp, newtypes)
+  where
+  optOpts = optOptimizations opts
+  inlDi = optInlineDictionaries  optOpts
+  remIm = optRemoveUnusedImports optOpts
+  remNT = optDesugarNewtypes     optOpts
+  dumpCS :: Show a => DumpLevel -> CompEnv (CS.Module a)
+         -> CYIO (CompEnv (CS.Module a))
+  dumpCS = dumpWith opts CS.showModule pPrint
+  dumpIL = dumpWith opts IL.showModule IL.ppModule
+
+-- ---------------------------------------------------------------------------
+-- Writing output
+-- ---------------------------------------------------------------------------
+
+-- The functions \texttt{genFlat} and \texttt{genAbstract} generate
+-- flat and abstract curry representations depending on the specified option.
+-- If the interface of a modified Curry module did not change, the
+-- corresponding file name will be returned within the result of 'genFlat'
+-- (depending on the compiler flag "force") and other modules importing this
+-- module won't be dependent on it any longer.
+
+writeTokens :: Options -> CompilerEnv -> CYIO ()
+writeTokens opts env = when tokTarget $ liftIO $
+  writeModule (useSubDir $ tokensName (filePath env))
+              (showTokenStream (tokens env))
+  where
+  tokTarget  = Tokens `elem` optTargetTypes opts
+  useSubDir  = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)
+
+writeComments :: Options -> CompilerEnv -> CYIO ()
+writeComments opts env = when tokTarget $ liftIO $
+  writeModule (useSubDir $ commentsName (filePath env))
+              (showCommentTokenStream $ tokens env)
+  where
+  tokTarget  = Comments `elem` optTargetTypes opts
+  useSubDir  = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)
+
+-- |Output the parsed 'Module' on request
+writeParsed :: Show a => Options -> CompEnv (CS.Module a) -> CYIO ()
+writeParsed opts (env, mdl) = when srcTarget $ liftIO $
+  writeModule (useSubDir $ sourceRepName (filePath env)) (CS.showModule mdl)
+  where
+  srcTarget  = Parsed `elem` optTargetTypes opts
+  useSubDir  = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)
+
+writeHtml :: Options -> CompEnv (CS.Module a) -> CYIO ()
+writeHtml opts (env, mdl) = when htmlTarget $
+  source2html opts (moduleIdent env) (map (\(sp, tok) -> (span2Pos sp, tok)) (tokens env)) mdl
+  where htmlTarget = Html `elem` optTargetTypes opts
+
+writeInterface :: Options -> CompilerEnv -> CS.Interface -> CYIO ()
+writeInterface opts env intf@(CS.Interface m _ _)
+  | optForce opts = outputInterface
+  | otherwise     = do
+      equal <- liftIO $ C.catch (matchInterface interfaceFile intf)
+                        ignoreIOException
+      unless equal outputInterface
+  where
+  ignoreIOException :: C.IOException -> IO Bool
+  ignoreIOException _ = return False
+
+  interfaceFile   = interfName (filePath env)
+  outputInterface = liftIO $ writeModule
+                    (addOutDirModule (optUseOutDir opts) (optOutDir opts) m interfaceFile)
+                    (show $ pPrint intf)
+
+matchInterface :: FilePath -> CS.Interface -> IO Bool
+matchInterface ifn i = do
+  hdl <- openFile ifn ReadMode
+  src <- hGetContents hdl
+  case runCYMIgnWarn (CS.parseInterface ifn src) of
+    Left  _  -> hClose hdl >> return False
+    Right i' -> return (i `intfEquiv` fixInterface i')
+
+writeFlat :: Options -> CompilerEnv -> CS.Module Type -> IL.Module -> CYIO ()
+writeFlat opts env mdl il = do
+  _ <- dumpWith opts show (pPrint . genFlatCurry) DumpTypedFlatCurry (env, afcy)
+  when afcyTarget $ liftIO $ FC.writeFlatCurry (useSubDir afcyName) afcy
+  when tfcyTarget  $ liftIO $ FC.writeFlatCurry (useSubDir tfcyName)  tfcy
+  when fcyTarget $ do
+    _ <- dumpWith opts show pPrint DumpFlatCurry (env, fcy)
+    liftIO $ FC.writeFlatCurry (useSubDir fcyName) fcy
+  writeFlatIntf opts env fcy
+  where
+  afcy       = genAnnotatedFlatCurry env mdl il
+  afcyName   = annotatedFlatName (filePath env)
+  afcyTarget = AnnotatedFlatCurry `elem` optTargetTypes opts
+  tfcy       = genTypedFlatCurry afcy
+  tfcyName   = typedFlatName (filePath env)
+  tfcyTarget = TypedFlatCurry `elem` optTargetTypes opts
+  fcy        = genFlatCurry afcy
+  fcyName    = flatName (filePath env)
+  fcyTarget  = FlatCurry `elem` optTargetTypes opts
+  useSubDir  = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)
+
+writeFlatIntf :: Options -> CompilerEnv -> FC.Prog -> CYIO ()
+writeFlatIntf opts env prog
+  | not (optInterface opts) = return ()
+  | optForce opts           = outputInterface
+  | otherwise               = do
+      mfint <- liftIO $ FC.readFlatInterface targetFile
+      let oldInterface = fromMaybe emptyIntf mfint
+      when (mfint == mfint) $ return () -- necessary to close file -- TODO
+      unless (oldInterface `eqInterface` fint) outputInterface
+  where
+  targetFile      = flatIntName (filePath env)
+  emptyIntf       = FC.Prog "" [] [] [] []
+  fint            = genFlatInterface prog
+  useSubDir       = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)
+  outputInterface = liftIO $ FC.writeFlatCurry (useSubDir targetFile) fint
+
+writeAbstractCurry :: Options -> CompEnv (CS.Module PredType) -> CYIO ()
+writeAbstractCurry opts (env, mdl) = do
+  when acyTarget  $ liftIO
+                  $ AC.writeCurry (useSubDir $ acyName (filePath env))
+                  $ genTypedAbstractCurry env mdl
+  when uacyTarget $ liftIO
+                  $ AC.writeCurry (useSubDir $ uacyName (filePath env))
+                  $ genUntypedAbstractCurry env mdl
+  where
+  acyTarget  = AbstractCurry        `elem` optTargetTypes opts
+  uacyTarget = UntypedAbstractCurry `elem` optTargetTypes opts
+  useSubDir  = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)
+
+
+writeAST :: Options -> CompEnv (CS.Module ()) -> CYIO ()
+writeAST opts (env, mdl) = when astTarget $ liftIO $
+  writeModule (useSubDir $ astName (filePath env)) (CS.showModule mdl)
+  where
+  astTarget  = AST `elem` optTargetTypes opts
+  useSubDir  = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)
+
+
+writeShortAST :: Options -> CompEnv (CS.Module ()) -> CYIO ()
+writeShortAST opts (env, mdl) = when astTarget $ liftIO $
+  writeModule (useSubDir $ shortASTName (filePath env))
+              (CS.showModule $ shortenModuleAST mdl)
+  where
+  astTarget  = ShortAST `elem` optTargetTypes opts
+  useSubDir  = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)
+
+
+type Dump = (DumpLevel, CompilerEnv, String)
+
+dumpWith :: MonadIO m
+         => Options -> (a -> String) -> (a -> Doc) -> DumpLevel
+         -> CompEnv a -> m (CompEnv a)
+dumpWith opts rawView view lvl res@(env, mdl) = do
+  let str = if dbDumpRaw (optDebugOpts opts) then rawView mdl
+                                             else show (view mdl)
+  doDump (optDebugOpts opts) (lvl, env, str)
+  return res
+
+-- |Translate FlatCurry into the intermediate language 'IL'
+-- |The 'dump' function writes the selected information to standard output.
+doDump :: MonadIO m => DebugOpts -> Dump -> m ()
+doDump opts (level, env, dump)
+  = when (level `elem` dbDumpLevels opts) $ liftIO $ do
+      putStrLn (heading (capitalize $ lookupHeader dumpLevel) '=')
+      when (dbDumpEnv opts) $ do
+        putStrLn (heading "Environment" '-')
+        putStrLn (showCompilerEnv env (dbDumpAllBindings opts) (dbDumpSimple opts))
+      putStrLn (heading "Source Code" '-')
+      putStrLn dump
+  where
+  heading h s = '\n' : h ++ '\n' : replicate (length h) s
+  lookupHeader []            = "Unknown dump level " ++ show level
+  lookupHeader ((l,_,h):lhs)
+    | level == l = h
+    | otherwise  = lookupHeader lhs
+  capitalize = unwords . map firstUpper . words
+  firstUpper ""     = ""
+  firstUpper (c:cs) = toUpper c : cs
+
+errModuleFileMismatch :: ModuleIdent -> Message
+errModuleFileMismatch mid = posMessage mid $ hsep $ map text
+  [ "Module", moduleName mid, "must be in a file"
+  , moduleName mid ++ ".(l)curry" ]
diff --git a/src/Modules.lhs b/src/Modules.lhs
deleted file mode 100644
--- a/src/Modules.lhs
+++ /dev/null
@@ -1,700 +0,0 @@
-
-% $Id: Modules.lhs,v 1.84 2004/02/10 17:46:07 wlux Exp $
-%
-% Copyright (c) 1999-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-% March 2007, extensions by Sebastian Fischer (sebf@informatik.uni-kiel.de)
-%
-\nwfilename{Modules.lhs}
-\section{Modules}
-This module controls the compilation of modules.
-
-Since this version is only used as a frontend for PAKCS, some of the following 
-import declarations are commented out
-\begin{verbatim}
-
-> module Modules(compileModule,
->                importPrelude, patchModuleId,
->	         loadInterfaces, transModule,
->	         simpleCheckModule, checkModule
->	        ) where
-
-> import Text.PrettyPrint.HughesPJ
-> import Data.List
-> import qualified Data.Map as Map
-> import System.IO
-> import Data.Maybe
-> import Control.Monad
-
-> import Curry.Base.MessageMonad
-> import Curry.Base.Position as P
-> import Curry.Base.Ident
-
-> import Curry.Files.Filenames
-> import Curry.Files.PathUtils
-
-> import Curry.Syntax
-> import Curry.Syntax.Utils(isImportDecl)
-> import Curry.Syntax.Pretty(ppModule,ppIDecl)
-> import Curry.Syntax.ShowModule(showModule)
-
-> import Curry.ExtendedFlat.Type
-> import qualified Curry.ExtendedFlat.Type as EF 
-
-> import qualified IL.Type as IL
-> import IL.CurryToIL(ilTrans)
-> import qualified IL.Pretty(ppModule)
-> import IL.XML(xmlModule)
-
-> import Base
-> import Types
-> import KindCheck(kindCheck)
-> import SyntaxCheck(syntaxCheck)
-> import PrecCheck(precCheck)
-> import TypeCheck(typeCheck)
-> import WarnCheck(warnCheck)
-> import Arity
-> import Imports(importInterface,importInterfaceIntf,importUnifyData)
-> import Exports(expandInterface,exportInterface)
-> import Eval(evalEnv)
-> import Qual(qual)
-> import Desugar(desugar)
-> import Simplify(simplify)
-> import Lift(lift)
-
-> import GenFlatCurry (genFlatCurry,genFlatInterface)
-> import qualified Curry.AbstractCurry as AC
-> import GenAbstractCurry
-> import InterfaceCheck
-> import CurryEnv
-
-> import CurryCompilerOpts(Options(..),Dump(..))
-> import CaseCompletion
-
-
-> import TypeSubst
-> import TopEnv
-
-
-\end{verbatim}
-The function \texttt{compileModule} is the main entry-point of this
-module for compiling a Curry source module. Depending on the command
-line options it will emit either C code or FlatCurry code (standard 
-or in XML
-representation) or AbtractCurry code (typed, untyped or with type
-signatures) for the module. Usually the first step is to
-check the module. Then the code is translated into the intermediate
-language. If necessary, this phase will also update the module's
-interface file. The resulting code then is either written out (in
-FlatCurry or XML format) or translated further into C code.
-The untyped  AbstractCurry representation is written
-out directly after parsing and simple checking the source file. 
-The typed AbstractCurry code is written out after checking the module.
-
-The compiler automatically loads the prelude when compiling any
-module, except for the prelude itself, by adding an appropriate import
-declaration to the module. 
-
-Since this modified version of the Muenster Curry Compiler is used
-as a frontend for PAKCS, all functions for evaluating goals and generating C 
-code are obsolete and commented out.
-\begin{verbatim}
-
-> compileModule :: Options -> FilePath -> IO (Maybe FilePath)
-> compileModule opts fn =
->   do
->     mod <- liftM (importPrelude fn . ok . parseModule likeFlat fn) (readModule fn)
->     let m = patchModuleId fn mod
->     checkModuleId fn m
->     mEnv <- loadInterfaces (importPaths opts) m
->     if uacy || src
->        then 
->          do (tyEnv, tcEnv, aEnv, m', intf, _) <- simpleCheckModule opts mEnv m
->             if uacy then genAbstract opts fn tyEnv tcEnv m'
->                     else do
->                       let outputFile = maybe (sourceRepName fn)
->                                              id 
->                                              (output opts)
->                           outputMod = showModule m'
->                       writeModule (writeToSubdir opts) outputFile outputMod
->                       return Nothing
->        else
->          do -- checkModule checks types, and then transModule introduces new
->             -- functions (by lambda lifting in 'desugar'). Consequence: The
->             -- type of the newly introduced functions are not inferred (hsi)
->             (tyEnv, tcEnv, aEnv, m', intf, _) <- checkModule opts mEnv m
->             let (il,aEnv',dumps) = transModule fcy False False 
->			                         mEnv tyEnv tcEnv aEnv m'
->             mapM_ (doDump opts) dumps
->	      genCode opts fn mEnv tyEnv tcEnv aEnv' intf m' il
->   where acy      = abstract opts
->         uacy     = untypedAbstract opts
->         fcy      = flat opts
->         xml      = flatXml opts
->         src      = parseOnly opts
->         likeFlat = fcy || xml || acy || uacy || src
->	  
->         genCode opts fn mEnv tyEnv tcEnv aEnv intf m il
->            | fcy || xml = genFlat opts fn mEnv tyEnv tcEnv aEnv intf m il
->            | acy        = genAbstract opts fn tyEnv tcEnv m
->            | otherwise  = return Nothing
-
-> loadInterfaces :: [FilePath] -> Module -> IO ModuleEnv
-> loadInterfaces paths (Module m _ ds) =
->   foldM (loadInterface paths [m]) Map.empty
->         [(p,m) | ImportDecl p m _ _ _ <- ds]
-
-> checkModuleId :: Monad m => FilePath -> Module -> m ()
-> checkModuleId fn (Module mid _ _)
->    | last (moduleQualifiers mid) == takeBaseName fn
->      = return ()
->    | otherwise
->      = error ("module \"" ++ moduleName mid 
->	        ++ "\" must be in a file \"" ++ moduleName mid
->	        ++ ".curry\"")
-
-> simpleCheckModule :: Options -> ModuleEnv -> Module 
->	    -> IO (ValueEnv,TCEnv,ArityEnv,Module,Interface,[WarnMsg])
-> simpleCheckModule opts mEnv (Module m es ds) =
->   do unless (noWarn opts) (printMessages msgs)
->      return (tyEnv'', tcEnv, aEnv'', modul, intf, msgs)
->   where (impDs,topDs) = partition isImportDecl ds
->         iEnv = foldr bindAlias initIEnv impDs
->         (pEnv,tcEnv,tyEnv,aEnv) = importModules mEnv impDs
->         msgs = warnCheck m tyEnv impDs topDs
->	  withExt = withExtensions opts
->         (pEnv',topDs') = precCheck m pEnv 
->		           $ syntaxCheck withExt m iEnv aEnv tyEnv tcEnv
->			   $ kindCheck m tcEnv topDs
->         ds' = impDs ++ qual m tyEnv topDs'
->         modul = (Module m es ds') --expandInterface (Module m es ds') tcEnv tyEnv
->         (_,tcEnv'',tyEnv'',aEnv'') 
->            = qualifyEnv mEnv pEnv' tcEnv tyEnv aEnv
->         intf = exportInterface modul pEnv' tcEnv'' tyEnv''
-
-> checkModule :: Options -> ModuleEnv -> Module 
->      -> IO (ValueEnv,TCEnv,ArityEnv,Module,Interface,[WarnMsg])
-> checkModule opts mEnv (Module m es ds) =
->   do unless (noWarn opts) (printMessages msgs)
->      when (m == mkMIdent ["field114..."])
->           (error (show es))
->      return (tyEnv''', tcEnv', aEnv'', modul, intf, msgs)
->   where (impDs,topDs) = partition isImportDecl ds
->         iEnv = foldr bindAlias initIEnv impDs
->         (pEnv,tcEnvI,tyEnvI,aEnv) = importModules mEnv impDs
->         tcEnv = if withExtensions opts
->	             then fmap (expandRecordTC tcEnvI) tcEnvI
->		     else tcEnvI
->         lEnv = importLabels mEnv impDs
->	  tyEnvL = addImportedLabels m lEnv tyEnvI
->	  tyEnv = if withExtensions opts
->	             then fmap (expandRecordTypes tcEnv) tyEnvL
->		     else tyEnvI
->         msgs = warnCheck m tyEnv impDs topDs
->	  withExt = withExtensions opts
->         -- fre: replaced the argument aEnv by aEnv'' in the
->         --      expression below. This fixed a bug that occured
->         --      when one imported a module qualified that
->         --      exported a function from another module.
->         --      However, there is now a cyclic dependecy 
->         --      but tests didn't show any problems.
->         (pEnv',topDs') = precCheck m pEnv 
->		           $ syntaxCheck withExt m iEnv aEnv'' tyEnv tcEnv
->			   $ kindCheck m tcEnv topDs
->         (tcEnv',tyEnv') = typeCheck m tcEnv tyEnv topDs'
->         ds' = impDs ++ qual m tyEnv' topDs'
->         modul = expandInterface (Module m es ds') tcEnv' tyEnv'
->         (pEnv'',tcEnv'',tyEnv'',aEnv'') 
->            = qualifyEnv mEnv pEnv' tcEnv' tyEnv' aEnv
->         tyEnvL' = addImportedLabels m lEnv tyEnv''
->	  tyEnv''' = if withExtensions opts
->	                then fmap (expandRecordTypes tcEnv'') tyEnvL'
->		        else tyEnv''
->         --tyEnv''' = addImportedLabels m lEnv tyEnv''
->         intf = exportInterface modul pEnv'' tcEnv'' tyEnv'''
-
-> transModule :: Bool -> Bool -> Bool -> ModuleEnv -> ValueEnv -> TCEnv
->      -> ArityEnv -> Module -> (IL.Module,ArityEnv,[(Dump,Doc)])
-> transModule flat debug trusted mEnv tyEnv tcEnv aEnv (Module m es ds) =
->     (il',aEnv',dumps)
->   where topDs = filter (not . isImportDecl) ds
->         evEnv = evalEnv topDs
->         (desugared,tyEnv') = desugar tyEnv tcEnv (Module m es topDs)
->         (simplified,tyEnv'') = simplify flat tyEnv' evEnv desugared
->         (lifted,tyEnv''',evEnv') = lift tyEnv'' evEnv simplified
->         aEnv' = bindArities aEnv lifted
->         il = ilTrans flat tyEnv''' tcEnv evEnv' lifted
->         il' = completeCase mEnv il
->         dumps = [(DumpRenamed,ppModule (Module m es ds)),
->	           (DumpTypes,ppTypes m (localBindings tyEnv)),
->	           (DumpDesugared,ppModule desugared),
->                  (DumpSimplified,ppModule simplified),
->                  (DumpLifted,ppModule lifted),
->                  (DumpIL,IL.Pretty.ppModule il),
->	           (DumpCase,IL.Pretty.ppModule il')
->	          ]
-
-> qualifyEnv :: ModuleEnv -> PEnv -> TCEnv -> ValueEnv -> ArityEnv
->     -> (PEnv,TCEnv,ValueEnv,ArityEnv)
-> qualifyEnv mEnv pEnv tcEnv tyEnv aEnv =
->   (foldr bindQual pEnv' (localBindings pEnv),
->    foldr bindQual tcEnv' (localBindings tcEnv),
->    foldr bindGlobal tyEnv' (localBindings tyEnv),
->    foldr bindQual aEnv' (localBindings aEnv))
->   where (pEnv',tcEnv',tyEnv',aEnv') =
->           foldl importInterface initEnvs (Map.toList mEnv)
->         importInterface (pEnv,tcEnv,tyEnv,aEnv) (m,ds) =
->           importInterfaceIntf (Interface m ds) pEnv tcEnv tyEnv aEnv
->         bindQual (_,y) = qualBindTopEnv "Modules.qualifyEnv" (origName y) y
->         bindGlobal (x,y)
->           | uniqueId x == 0 = bindQual (x,y)
->           | otherwise = bindTopEnv "Modules.qualifyEnv" x y
-
-> writeXML :: Bool -> Maybe FilePath -> FilePath -> CurryEnv -> IL.Module -> IO ()
-> writeXML sub tfn sfn cEnv il = writeModule sub ofn (showln code)
->   where ofn  = fromMaybe (xmlName sfn) tfn
->         code = (xmlModule cEnv il)
-
-> writeFlat :: Options -> Maybe FilePath -> FilePath -> CurryEnv -> ModuleEnv 
->              -> ValueEnv -> TCEnv -> ArityEnv -> IL.Module -> IO Prog
-> writeFlat opts tfn sfn cEnv mEnv tyEnv tcEnv aEnv il
->   = writeFlatFile opts (genFlatCurry opts cEnv mEnv tyEnv tcEnv aEnv il)
->                        (fromMaybe (flatName sfn) tfn)
-
-> writeFlatFile :: Options -> (Prog, [WarnMsg]) -> String -> IO Prog
-> writeFlatFile opts@Options{extendedFlat=ext,writeToSubdir=sub} (res,msgs) fname = do
->         unless (noWarn opts) (printMessages msgs)
->	  if ext then writeExtendedFlat sub fname res
->                else writeFlatCurry sub fname res
->         return res
-
-
-> writeTypedAbs :: Bool -> Maybe FilePath -> FilePath -> ValueEnv -> TCEnv -> Module
->	           -> IO ()
-> writeTypedAbs sub tfn sfn tyEnv tcEnv mod
->    = AC.writeCurry sub fname (genTypedAbstract tyEnv tcEnv mod)
->  where fname = fromMaybe (acyName sfn) tfn
-
-> writeUntypedAbs :: Bool -> Maybe FilePath -> FilePath -> ValueEnv -> TCEnv  
->	             -> Module -> IO ()
-> writeUntypedAbs sub tfn sfn tyEnv tcEnv mod
->    = AC.writeCurry sub fname (genUntypedAbstract tyEnv tcEnv mod)
->  where fname = fromMaybe (uacyName sfn) tfn
-
-> showln :: Show a => a -> String
-> showln x = shows x "\n"
-
-\end{verbatim}
-
-The function \texttt{importModules} brings the declarations of all
-imported modules into scope for the current module.
-\begin{verbatim}
-
-> importModules :: ModuleEnv -> [Decl] -> (PEnv,TCEnv,ValueEnv,ArityEnv)
-> importModules mEnv ds = (pEnv,importUnifyData tcEnv,tyEnv,aEnv)
->   where (pEnv,tcEnv,tyEnv,aEnv) = foldl importModule initEnvs ds
->         importModule (pEnv,tcEnv,tyEnv,aEnv) (ImportDecl p m q asM is) =
->           case Map.lookup m mEnv of
->             Just ds -> importInterface p (fromMaybe m asM) q is
->                                        (Interface m ds) pEnv tcEnv tyEnv aEnv
->             Nothing -> internalError "importModule"
->         importModule (pEnv,tcEnv,tyEnv,aEnv) _ = (pEnv,tcEnv,tyEnv,aEnv)
-
-> initEnvs :: (PEnv,TCEnv,ValueEnv,ArityEnv)
-> initEnvs = (initPEnv,initTCEnv,initDCEnv,initAEnv)
-
-\end{verbatim}
-Unlike unsual identifiers like in functions, types etc. identifiers
-of labels are always represented unqualified within the whole context
-of compilation. Since the common type environment (type \texttt{ValueEnv})
-has some problems with handling imported unqualified identifiers, it is 
-necessary to add the type information for labels seperately. For this reason
-the function \texttt{importLabels} generates an environment containing
-all imported labels and the function \texttt{addImportedLabels} adds this
-content to a type environment.
-\begin{verbatim}
-
-> importLabels :: ModuleEnv -> [Decl] -> LabelEnv
-> importLabels mEnv ds = foldl importLabelTypes Map.empty ds
->   where
->   importLabelTypes lEnv (ImportDecl p m _ asM is) =
->     case (Map.lookup m mEnv) of
->       Just ds' -> foldl (importLabelType p (fromMaybe m asM) is) lEnv ds'
->       Nothing -> internalError "importLabels"
->   importLabelTypes lEnv _ = lEnv
->		      
->   importLabelType p m is lEnv (ITypeDecl _ r _ (RecordType fs _)) =
->     foldl (insertLabelType p m r' (getImportSpec r' is)) lEnv fs
->     where r' = qualifyWith m (fromRecordExtId (unqualify r))
->   importLabelType _ _ _ lEnv _ = lEnv
->			   
->   insertLabelType p m r (Just (ImportTypeAll _)) lEnv ([l],ty) =
->     bindLabelType l r (toType [] ty) lEnv
->   insertLabelType p m r (Just (ImportTypeWith _ ls)) lEnv ([l],ty)
->     | l `elem` ls = bindLabelType l r (toType [] ty) lEnv
->     | otherwise   = lEnv
->   insertLabelType _ _ _ _ lEnv _ = lEnv
->			     
->   getImportSpec r (Just (Importing _ is')) =
->     find (isImported (unqualify r)) is'
->   getImportSpec r Nothing = Just (ImportTypeAll (unqualify r))
->   getImportSpec r _ = Nothing
->		
->   isImported r (Import r') = r == r'
->   isImported r (ImportTypeWith r' _) = r == r'
->   isImported r (ImportTypeAll r') = r == r'
-
-> addImportedLabels :: ModuleIdent -> LabelEnv -> ValueEnv -> ValueEnv
-> addImportedLabels m lEnv tyEnv = 
->   foldr addLabelType tyEnv (concatMap snd (Map.toList lEnv))
->   where
->   addLabelType (LabelType l r ty) tyEnv = 
->     let m' = fromMaybe m (qualidMod r)
->     in  importTopEnv m' l 
->                      (Label (qualify l) (qualQualify m' r) (polyType ty)) 
->	               tyEnv
-
-\end{verbatim}
-Fully expand all (imported) record types within the type constructor 
-environment and the type environment.
-Note: the record types for the current module are expanded within the
-type check.
-\begin{verbatim}
-
-> expandRecordTC :: TCEnv -> TypeInfo -> TypeInfo
-> expandRecordTC tcEnv (DataType qid n args) =
->   DataType qid n (map (maybe Nothing (Just . (expandData tcEnv))) args)
-> expandRecordTC tcEnv (RenamingType qid n (Data id m ty)) =
->   RenamingType qid n (Data id m (expandRecords tcEnv ty))
-> expandRecordTC tcEnv (AliasType qid n ty) =
->   AliasType qid n (expandRecords tcEnv ty)
-
-> expandData :: TCEnv -> Data [Type] -> Data [Type]
-> expandData tcEnv (Data id n tys) =
->   Data id n (map (expandRecords tcEnv) tys)
-
-> expandRecordTypes :: TCEnv -> ValueInfo -> ValueInfo
-> expandRecordTypes tcEnv (DataConstructor qid (ForAllExist n m ty)) =
->   DataConstructor qid (ForAllExist n m (expandRecords tcEnv ty))
-> expandRecordTypes tcEnv (NewtypeConstructor qid (ForAllExist n m ty)) =
->   NewtypeConstructor qid (ForAllExist n m (expandRecords tcEnv ty))
-> expandRecordTypes tcEnv (Value qid (ForAll n ty)) =
->   Value qid (ForAll n (expandRecords tcEnv ty))
-> expandRecordTypes tcEnv (Label qid r (ForAll n ty)) =
->   Label qid r (ForAll n (expandRecords tcEnv ty))
-
-> expandRecords :: TCEnv -> Type -> Type
-> expandRecords tcEnv (TypeConstructor qid tys) =
->   case (qualLookupTC qid tcEnv) of
->     [AliasType _ _ rty@(TypeRecord _ _)]
->       -> expandRecords tcEnv 
->            (expandAliasType (map (expandRecords tcEnv) tys) rty)
->     _ -> TypeConstructor qid (map (expandRecords tcEnv) tys)
-> expandRecords tcEnv (TypeConstrained tys v) =
->   TypeConstrained (map (expandRecords tcEnv) tys) v
-> expandRecords tcEnv (TypeArrow ty1 ty2) =
->   TypeArrow (expandRecords tcEnv ty1) (expandRecords tcEnv ty2)
-> expandRecords tcEnv (TypeRecord fs rv) =
->   TypeRecord (map (\ (l,ty) -> (l,expandRecords tcEnv ty)) fs) rv
-> expandRecords _ ty = ty
-
-\end{verbatim}
-An implicit import of the prelude is added to the declarations of
-every module, except for the prelude itself. If no explicit import for
-the prelude is present, the prelude is imported unqualified, otherwise
-only a qualified import is added.
-\begin{verbatim}
-
-> importPrelude :: FilePath -> Module -> Module
-> importPrelude fn (Module m es ds) =
->   Module m es (if m == preludeMIdent then ds else ds')
->   where ids = [decl | decl@(ImportDecl _ _ _ _ _) <- ds]
->         ds' = ImportDecl (P.first fn) preludeMIdent
->                          (preludeMIdent `elem` map importedModule ids)
->                          Nothing Nothing : ds
->         importedModule (ImportDecl _ m q asM is) = fromMaybe m asM
-
-\end{verbatim}
-If an import declaration for a module is found, the compiler first
-checks whether an import for the module is already pending. In this
-case the module imports are cyclic which is not allowed in Curry. The
-compilation will therefore be aborted. Next, the compiler checks
-whether the module has been imported already. If so, nothing needs to
-be done, otherwise the interface will be searched in the import paths
-and compiled.
-\begin{verbatim}
-
-> loadInterface :: [FilePath] -> [ModuleIdent] -> ModuleEnv ->
->     (Position,ModuleIdent) -> IO ModuleEnv
-> loadInterface paths ctxt mEnv (p,m)
->   | m `elem` ctxt = errorAt p (cyclicImport m (takeWhile (/= m) ctxt))
->   | isLoaded m mEnv = return mEnv
->   | otherwise =
->       lookupInterface paths m >>=
->       maybe (errorAt p (interfaceNotFound m))
->             (compileInterface paths ctxt mEnv m)
->   where isLoaded m mEnv = maybe False (const True) (Map.lookup m mEnv)
-
-\end{verbatim}
-After reading an interface, all imported interfaces are recursively
-loaded and entered into the interface's environment. There is no need
-to check FlatCurry-Interfaces, since these files contain automaticaly
-generated FlatCurry terms (type \texttt{Prog}).
-\begin{verbatim}
-
-> compileInterface :: [FilePath] -> [ModuleIdent] -> ModuleEnv -> ModuleIdent
->                  -> FilePath -> IO ModuleEnv
-> compileInterface paths ctxt mEnv m fn =
->   do
->     mintf <- readFlatInterface fn
->     let intf = fromMaybe (errorAt (P.first fn) (interfaceNotFound m)) mintf
->         (Prog mod _ _ _ _) = intf
->         m' = mkMIdent [mod]
->     unless (m' == m) (errorAt (P.first fn) (wrongInterface m m'))
->     mEnv' <- loadFlatInterfaces paths ctxt mEnv intf
->     return (bindFlatInterface intf mEnv')
-
-> --loadIntfInterfaces :: [FilePath] -> [ModuleIdent] -> ModuleEnv -> Interface
-> --                   -> IO ModuleEnv
-> --loadIntfInterfaces paths ctxt mEnv (Interface m ds) =
-> --  foldM (loadInterface paths (m:ctxt)) mEnv [(p,m) | IImportDecl p m <- ds]
-
-
-> loadFlatInterfaces :: [FilePath] -> [ModuleIdent] -> ModuleEnv -> Prog
->                    -> IO ModuleEnv
-> loadFlatInterfaces paths ctxt mEnv (Prog m is _ _ _) =
->   foldM (loadInterface paths ((mkMIdent [m]):ctxt)) 
->         mEnv 
->         (map (\i -> (p, mkMIdent [i])) is)
->  where p = P.first m
-
-
-Interface files are updated by the Curry builder when necessary.
-(see module \texttt{CurryBuilder}).
-
-\end{verbatim}
-The \texttt{doDump} function writes the selected information to the
-standard output.
-\begin{verbatim}
-
-> doDump :: Options -> (Dump,Doc) -> IO ()
-> doDump opts (d,x) =
->   when (d `elem` dump opts)
->        (print (text hd $$ text (replicate (length hd) '=') $$ x))
->   where hd = dumpHeader d
-
-> dumpHeader :: Dump -> String
-> dumpHeader DumpRenamed = "Module after renaming"
-> dumpHeader DumpTypes = "Types"
-> dumpHeader DumpDesugared = "Source code after desugaring"
-> dumpHeader DumpSimplified = "Source code after simplification"
-> dumpHeader DumpLifted = "Source code after lifting"
-> dumpHeader DumpIL = "Intermediate code"
-> dumpHeader DumpCase = "Intermediate code after case simplification"
-
-
-\end{verbatim}
-The functions \texttt{genFlat} and \texttt{genAbstract} generate
-flat and abstract curry representations depending on the specified option.
-If the interface of a modified Curry module did not change, the corresponding 
-file name will be returned within the result of \texttt{genFlat} (depending
-on the compiler flag "force") and other modules importing this module won't
-be dependent on it any longer.
-\begin{verbatim}
-
-> genFlat :: Options -> FilePath -> ModuleEnv -> ValueEnv -> TCEnv -> ArityEnv 
->            -> Interface -> Module -> IL.Module -> IO (Maybe FilePath)
-> genFlat opts fname mEnv tyEnv tcEnv aEnv intf mod il
->   | flat opts
->     = do writeFlat opts Nothing fname cEnv mEnv tyEnv tcEnv aEnv il
->          let (flatInterface,intMsgs) = genFlatInterface opts cEnv mEnv tyEnv tcEnv aEnv il
->          if force opts
->            then 
->              do writeInterface flatInterface intMsgs
->                 return Nothing
->            else 
->               do mfint <- readFlatInterface fintName
->                  let flatIntf = fromMaybe emptyIntf mfint
->                  if mfint == mfint  -- necessary to close the file 'fintName'
->                        && not (interfaceCheck flatIntf flatInterface)
->                     then 
->                        do writeInterface flatInterface intMsgs
->                           return Nothing
->                     else return Nothing
->   | flatXml opts
->     = writeXML (writeToSubdir opts) (output opts) fname cEnv il >> 
->       return Nothing
->   | otherwise
->     = internalError "@Modules.genFlat: illegal option"
->  where
->    fintName = flatIntName fname
->    cEnv = curryEnv mEnv tcEnv intf mod
->    emptyIntf = Prog "" [] [] [] []
->    writeInterface intf msgs = do
->          unless (noWarn opts) (printMessages msgs)
->          writeFlatCurry (writeToSubdir opts) fintName intf
-
-
-> genAbstract :: Options -> FilePath  -> ValueEnv -> TCEnv -> Module 
->                -> IO (Maybe FilePath)
-> genAbstract opts@Options{writeToSubdir=sub} fname tyEnv tcEnv mod
->    | abstract opts
->      = do writeTypedAbs sub Nothing fname tyEnv tcEnv mod 
->           return Nothing
->    | untypedAbstract opts
->      = do writeUntypedAbs sub Nothing fname tyEnv tcEnv mod
->           return Nothing
->    | otherwise
->      = internalError "@Modules.genAbstract: illegal option"
-
-> printMessages :: [WarnMsg] -> IO ()
-> printMessages []   = return ()
-> printMessages msgs = hPutStrLn stderr $ unlines $ map showWarning msgs
-
-\end{verbatim}
-The function \texttt{ppTypes} is used for pretty-printing the types
-from the type environment.
-\begin{verbatim}
-
-> ppTypes :: ModuleIdent -> [(Ident,ValueInfo)] -> Doc
-> ppTypes m = vcat . map (ppIDecl . mkDecl) . filter (isValue . snd)
->   where mkDecl (v,Value _ (ForAll _ ty)) =
->           IFunctionDecl undefined (qualify v) (arrowArity ty) 
->		      (fromQualType m ty)
->         isValue (DataConstructor _ _) = False
->         isValue (NewtypeConstructor _ _) = False
->         isValue (Value _ _) = True
->         isValue (Label _ _ _) = False
-
-
-\end{verbatim}
-A module which doesn't contain a \texttt{module ... where} declaration
-obtains its filename as module identifier (unlike the definition in
-Haskell and original MCC where a module obtains \texttt{main}).
-\begin{verbatim}
-
-> patchModuleId :: FilePath -> Module -> Module
-> patchModuleId fn (Module mid mexports decls)
->    | (moduleName mid) == "main"
->      = Module (mkMIdent [takeBaseName fn]) mexports decls
->    | otherwise
->      = Module mid mexports decls
-
-
-\end{verbatim}
-Error functions.
-\begin{verbatim}
-
-> interfaceNotFound :: ModuleIdent -> String
-> interfaceNotFound m = "Interface for module " ++ moduleName m ++ " not found"
-
-> cyclicImport :: ModuleIdent -> [ModuleIdent] -> String
-> cyclicImport m [] = "Recursive import for module " ++ moduleName m
-> cyclicImport m ms =
->   "Cyclic import dependency between modules " ++ moduleName m ++
->     modules "" ms
->   where modules comma [m] = comma ++ " and " ++ moduleName m
->         modules _ (m:ms) = ", " ++ moduleName m ++ modules "," ms
-
-> wrongInterface :: ModuleIdent -> ModuleIdent -> String
-> wrongInterface m m' =
->   "Expected interface for " ++ show m ++ " but found " ++ show m'
-
-\end{verbatim}
-
-
-
-
-> bindFlatInterface :: Prog -> ModuleEnv -> ModuleEnv
-> bindFlatInterface (Prog m imps ts fs os)
->    = Map.insert (mkMIdent [m])
->      ((map genIImportDecl imps)
->       ++ (map genITypeDecl ts')
->       ++ (map genIFuncDecl fs)
->       ++ (map genIOpDecl os))
->  where
->  genIImportDecl :: String -> IDecl
->  genIImportDecl imp = IImportDecl pos (mkMIdent [imp])
->
->  genITypeDecl :: TypeDecl -> IDecl
->  genITypeDecl (Type qn _ is cs)
->     | recordExt `isPrefixOf` localName qn
->       = ITypeDecl pos
->                   (genQualIdent qn)
->	            (map (genVarIndexIdent "a") is)
->	            (RecordType (map genLabeledType cs) Nothing)
->     | otherwise
->       = IDataDecl pos 
->                   (genQualIdent qn) 
->                   (map (genVarIndexIdent "a") is) 
->                   (map (Just . genConstrDecl) cs)
->  genITypeDecl (TypeSyn qn _ is t)
->     = ITypeDecl pos
->                 (genQualIdent qn)
->                 (map (genVarIndexIdent "a") is)
->                 (genTypeExpr t)
->
->  genIFuncDecl :: FuncDecl -> IDecl
->  genIFuncDecl (Func qn a _ t _) 
->     = IFunctionDecl pos (genQualIdent qn) a (genTypeExpr t)
->
->  genIOpDecl :: OpDecl -> IDecl
->  genIOpDecl (Op qn f p) = IInfixDecl pos (genInfix f) p  (genQualIdent qn)
->
->  genConstrDecl :: ConsDecl -> ConstrDecl
->  genConstrDecl (Cons qn _ _ ts)
->     = ConstrDecl pos [] (mkIdent (localName qn)) (map genTypeExpr ts)
->
->  genLabeledType :: EF.ConsDecl -> ([Ident],Curry.Syntax.TypeExpr)
->  genLabeledType (Cons qn _ _ [t])
->     = ([renameLabel (fromLabelExtId (mkIdent $ localName qn))], genTypeExpr t)
->
->  genTypeExpr :: EF.TypeExpr -> Curry.Syntax.TypeExpr
->  genTypeExpr (TVar i)
->     = VariableType (genVarIndexIdent "a" i)
->  genTypeExpr (FuncType t1 t2) 
->     = ArrowType (genTypeExpr t1) (genTypeExpr t2)
->  genTypeExpr (TCons qn ts) 
->     = ConstructorType (genQualIdent qn) (map genTypeExpr ts)
->
->  genInfix :: EF.Fixity -> Infix
->  genInfix EF.InfixOp  = Infix
->  genInfix EF.InfixlOp = InfixL
->  genInfix EF.InfixrOp = InfixR
->
->  genQualIdent :: EF.QName -> QualIdent
->  genQualIdent EF.QName{modName=mod,localName=name} = 
->    qualifyWith (mkMIdent [mod]) (mkIdent name)
->
->  genVarIndexIdent :: String -> Int -> Ident
->  genVarIndexIdent v i = mkIdent (v ++ show i)
->
->  isSpecialPreludeType :: TypeDecl -> Bool
->  isSpecialPreludeType (Type EF.QName{modName=mod,localName=name} _ _ _) 
->     = (name == "[]" || name == "()") && mod == "Prelude"
->  isSpecialPreludeType _ = False
->
->  pos = P.first m
->  ts' = filter (not . isSpecialPreludeType) ts
-
-
-
-
-\end{verbatim}
-The label environment is used to store information of labels.
-Unlike unsual identifiers like in functions, types etc. identifiers
-of labels are always represented unqualified. Since the common type 
-environment (type \texttt{ValueEnv}) has some problems with handling 
-imported unqualified identifiers, it is necessary to process the type 
-information for labels seperately.
-\begin{verbatim}
-
-> data LabelInfo = LabelType Ident QualIdent Type deriving Show
-
-> type LabelEnv = Map.Map Ident [LabelInfo]
-
-> bindLabelType :: Ident -> QualIdent -> Type -> LabelEnv -> LabelEnv
-> bindLabelType l r ty = Map.insertWith (++) l [LabelType l r ty]
-
diff --git a/src/NestEnv.lhs b/src/NestEnv.lhs
deleted file mode 100644
--- a/src/NestEnv.lhs
+++ /dev/null
@@ -1,77 +0,0 @@
-
-% $Id: NestEnv.lhs,v 1.11 2003/10/04 17:04:23 wlux Exp $
-%
-% Copyright (c) 1999-2003, Wolfgang Lux
-% See LICENSE for the full license.
-%
-\nwfilename{NestEnv.lhs}
-\subsection{Nested Environments}
-The \texttt{NestEnv} environment type extends top-level environments
-(see section~\ref{sec:toplevel-env}) to manage nested scopes. Local
-scopes allow only for a single, unambiguous definition.
-
-As a matter of convenience, the module \texttt{TopEnv} is exported by
-the module \texttt{NestEnv}.  Thus, only the latter needs to be
-imported.
-\begin{verbatim}
-
-> module NestEnv(module TopEnv, NestEnv, bindNestEnv,qualBindNestEnv,
->                lookupNestEnv,qualLookupNestEnv,
->                toplevelEnv,globalEnv,nestEnv) where
-
-> import qualified Data.Map as Map
-
-> import Curry.Base.Ident
-
-> import TopEnv
-
-
-> data NestEnv a = GlobalEnv (TopEnv a) | LocalEnv (NestEnv a) (Map.Map Ident a)
-> --                 deriving Show
-
-> instance Functor NestEnv where
->   fmap f (GlobalEnv env) = GlobalEnv (fmap f env)
->   fmap f (LocalEnv genv env) = LocalEnv (fmap f genv) (fmap f env)
-
-> bindNestEnv :: Ident -> a -> NestEnv a -> NestEnv a
-> bindNestEnv x y (GlobalEnv env) 
->   = GlobalEnv (bindTopEnv "NestEnv.bindNestEnv" x y env)
-> bindNestEnv x y (LocalEnv genv env) =
->   case Map.lookup x env of
->     Just _ -> error "internal error: bindNestEnv"
->     Nothing -> LocalEnv genv (Map.insert x y env)
-
-> qualBindNestEnv :: QualIdent -> a -> NestEnv a -> NestEnv a
-> qualBindNestEnv x y (GlobalEnv env) 
->   = GlobalEnv (qualBindTopEnv "NestEnv.qualBindNestEnv" x y env)
-> qualBindNestEnv x y (LocalEnv genv env)
->   | isQualified x = error "internal error: qualBindNestEnv"
->   | otherwise =
->       case Map.lookup x' env of
->         Just _ -> error "internal error: qualBindNestEnv"
->         Nothing -> LocalEnv genv (Map.insert x' y env)
->   where x' = unqualify x
-
-> lookupNestEnv :: Ident -> NestEnv a -> [a]
-> lookupNestEnv x (GlobalEnv env) = lookupTopEnv x env
-> lookupNestEnv x (LocalEnv genv env) =
->   case Map.lookup x env of
->     Just y -> [y]
->     Nothing -> lookupNestEnv x genv
-
-> qualLookupNestEnv :: QualIdent -> NestEnv a -> [a]
-> qualLookupNestEnv x env
->   | isQualified x = qualLookupTopEnv x (toplevelEnv env)
->   | otherwise = lookupNestEnv (unqualify x) env
-
-> toplevelEnv :: NestEnv a -> TopEnv a
-> toplevelEnv (GlobalEnv env) = env
-> toplevelEnv (LocalEnv genv _) = toplevelEnv genv
-
-> globalEnv :: TopEnv a -> NestEnv a
-> globalEnv = GlobalEnv
-
-> nestEnv :: NestEnv a -> NestEnv a
-> nestEnv env = LocalEnv env Map.empty
-
-\end{verbatim}
diff --git a/src/OldScopeEnv.hs b/src/OldScopeEnv.hs
deleted file mode 100644
--- a/src/OldScopeEnv.hs
+++ /dev/null
@@ -1,165 +0,0 @@
-module OldScopeEnv (ScopeEnv,
-		    newScopeEnv,
-		    insertIdent, getIdentLevel,
-		    isVisible, isDeclared,
-		    beginScope, endScope,
-		    getLevel,
-		    genIdent, genIdentList) where
-
-import Data.Maybe
-import qualified Data.Map as Map
-
-import Curry.Base.Ident
-
-
--------------------------------------------------------------------------------
-
--- Type for representing an environment containing identifiers in several
--- scope levels
-type ScopeEnv = (IdEnv, [IdEnv], Int)
-
--------------------------------------------------------------------------------
-
--- Generates a new instance of a scope table
-newScopeEnv :: ScopeEnv
-newScopeEnv = (Map.empty, [], 0)
-
-
--- Inserts an identifier into the current level of the scope environment
-insertIdent :: Ident -> ScopeEnv -> ScopeEnv
-insertIdent ident (topleveltab, leveltabs, level)
-   = case leveltabs of
-       (lt:lts) -> (topleveltab, (insertId level ident lt):lts, level)
-       []       -> ((insertId level ident topleveltab), [], 0)
-
-
--- Returns the declaration level of an identifier if it exists
-getIdentLevel :: Ident -> ScopeEnv -> Maybe Int
-getIdentLevel ident (topleveltab, leveltabs, _)
-   = case leveltabs of
-       (lt:_) -> maybe (getIdLevel ident topleveltab) Just (getIdLevel ident lt)
-       []     -> getIdLevel ident topleveltab
-
-
--- Checks whether the specified identifier is visible in the current scope
--- (i.e. checks whether the identifier occurs in the scope environment)
-isVisible :: Ident -> ScopeEnv -> Bool
-isVisible ident (topleveltab, leveltabs, _)
-   = case leveltabs of
-       (lt:_) -> idExists ident lt || idExists ident topleveltab
-       []     -> idExists ident topleveltab
-
-
--- Checks whether the specified identifier is declared in the
--- current scope (i.e. checks whether the identifier occurs in the
--- current level of the scope environment)
-isDeclared :: Ident -> ScopeEnv -> Bool
-isDeclared ident (topleveltab, leveltabs, level)
-   = case leveltabs of
-       (lt:_) -> maybe False ((==) level) (getIdLevel ident lt)
-       []     -> maybe False ((==) 0) (getIdLevel ident topleveltab)
-
-
--- Increases the level of the scope.
-beginScope :: ScopeEnv -> ScopeEnv
-beginScope (topleveltab, leveltabs, level)
-   = case leveltabs of
-       (lt:lts) -> (topleveltab, (lt:lt:lts), level + 1)
-       []       -> (topleveltab, [Map.empty], 1)
-
-
--- Decreases the level of the scope. Identifier from higher levels
--- will be lost.
-endScope :: ScopeEnv -> ScopeEnv
-endScope (topleveltab, leveltabs, level)
-   = case leveltabs of
-       (_:lts) -> (topleveltab, lts, level - 1)
-       []      -> (topleveltab, [], 0)
-
-
--- Returns the level of the current scope. Top level is 0
-getLevel :: ScopeEnv -> Int
-getLevel (_, _, level) = level
-
-
--- Generates a new identifier for the specified name. The new identifier is 
--- unique within the current scope. If no identifier can be generated for 
--- 'name' then 'Nothing' will be returned
-genIdent :: String -> ScopeEnv -> Maybe Ident
-genIdent name (topleveltab, leveltabs, _)
-   = case leveltabs of
-       (lt:_) -> genId name lt
-       []     -> genId name topleveltab
-
-
--- Generates a list of new identifiers where each identifier has
--- the prefix 'name' followed by  an index (i.e. "var3" if 'name' was "var").
--- All returned identifiers are unique within the current scope.
-genIdentList :: Int -> String -> ScopeEnv -> [Ident]
-genIdentList size name scopeenv = p_genIdentList size name scopeenv 0
- where
-   p_genIdentList s n env i
-      | s == 0 
-	= []
-      | otherwise
-	= maybe (p_genIdentList s n env (i + 1))
-	        (\ident -> ident:(p_genIdentList (s - 1) 
-				                 n 
-				                 (insertIdent ident env) 
-				                 (i + 1)))
-		(genIdent (n ++ (show i)) env)
-
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--- Private declarations...
-
-type IdEnv = Map.Map IdRep Int
-
-data IdRep = Name String | Index Int deriving (Eq, Ord)
-
-
--------------------------------------------------------------------------------
-
-
---
-insertId :: Int -> Ident -> IdEnv -> IdEnv
-insertId level ident env
-   = Map.insert (Name (name ident)) 
-             level 
-	     (Map.insert (Index (uniqueId ident)) level env)
-
-
---
-idExists :: Ident -> IdEnv -> Bool
-idExists ident env = indexExists (uniqueId ident) env
-
-
---
-getIdLevel :: Ident -> IdEnv -> Maybe Int
-getIdLevel ident env = Map.lookup (Index (uniqueId ident)) env
-
-
---
-genId n env
-   | nameExists n env = Nothing
-   | otherwise        = Just (p_genId (mkIdent n) 0)
- where
-   p_genId ident index
-      | indexExists index env = p_genId ident (index + 1)
-      | otherwise             = renameIdent ident index
-
-
---
-nameExists :: String -> IdEnv -> Bool
-nameExists name env = isJust (Map.lookup (Name name) env)
-
-
---
-indexExists :: Int -> IdEnv -> Bool
-indexExists index env = isJust (Map.lookup (Index index) env)
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
diff --git a/src/PatchPrelude.hs b/src/PatchPrelude.hs
deleted file mode 100644
--- a/src/PatchPrelude.hs
+++ /dev/null
@@ -1,40 +0,0 @@
-module PatchPrelude where
-
-
-import Curry.ExtendedFlat.Type
-
-
--- the prelude has to be extended by data declarations for list and tuples
-
-prelude = "Prelude"
-
-patchPreludeFCY :: Prog -> Prog
-patchPreludeFCY (Prog name imports types funcs ops)
-   | name == prelude
-     = Prog name [] (prelude_types_fcy ++ types) funcs ops
-   | otherwise
-     = Prog name imports types funcs ops
-
-prelude_types_fcy :: [TypeDecl]
-prelude_types_fcy =
-  let unit = mkQName (prelude,"()")
-      nil  = mkQName (prelude,"[]") in
-  [Type unit Public [] [(Cons unit 0 Public [])],
-   Type nil Public [0] 
-        [Cons nil 0 Public [],
-         Cons (mkQName (prelude,":")) 2 Public 
-              [TVar 0, TCons nil [TVar 0]]]] ++
-  map tupleType [2..maxTupleArity]
-
-tupleType ar = 
-  let tuplecons = mkQName (prelude,"("++take (ar-1) (repeat ',')++")") in
-  Type tuplecons Public [0..ar-1]
-       [Cons tuplecons ar Public (map TVar [0..ar-1])]
-
--- Maximal arity of tuples:
-maxTupleArity = 15
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
diff --git a/src/PrecCheck.lhs b/src/PrecCheck.lhs
deleted file mode 100644
--- a/src/PrecCheck.lhs
+++ /dev/null
@@ -1,461 +0,0 @@
-
-% $Id: PrecCheck.lhs,v 1.21 2004/02/15 22:10:34 wlux Exp $
-%
-% Copyright (c) 2001-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{PrecCheck.lhs}
-\section{Checking Precedences of Infix Operators}
-The parser does not know the relative precedences of infix operators
-and therefore parses them as if they all associate to the right and
-have the same precedence. After performing the definition checks,
-the compiler is going to process the infix applications in the module
-and rearrange infix applications according to the relative precedences
-of the operators involved.
-\begin{verbatim}
-
-> module PrecCheck(precCheck) where
-
-> import Data.List
-
-> import Curry.Base.Position
-> import Curry.Base.Ident
-> import Curry.Syntax
-> import Curry.Syntax.Utils
-
-> import Base
-
-\end{verbatim}
-For each declaration group, including the module-level, the compiler
-first checks that its fixity declarations contain no duplicates and
-that there is a corresponding value or constructor declaration in that
-group. The fixity declarations are then used for extending the
-imported precedence environment.
-\begin{verbatim}
-
-> bindPrecs :: ModuleIdent -> [Decl] -> PEnv -> PEnv
-> bindPrecs m ds pEnv =
->   case findDouble ops of
->     Nothing ->
->       case [ op | op <- ops, op `notElem` bvs] of
->         [] -> foldr bindPrec pEnv fixDs
->         op : _ -> errorAt' (undefinedOperator op)
->     Just op -> errorAt' (duplicatePrecedence op)
->   where (fixDs,nonFixDs) = partition isInfixDecl ds
->         bvs = concatMap boundValues nonFixDs
->         ops = [ op | InfixDecl p _ _ ops <- fixDs, op <- ops]
->         bindPrec (InfixDecl _ fix pr ops) pEnv
->           | p == defaultP = pEnv
->           | otherwise = foldr (flip (bindP m) p) pEnv ops
->           where p = OpPrec fix pr
-
-> boundValues :: Decl -> [Ident]
-> boundValues (DataDecl _ _ _ cs) = map constr cs
->   where constr (ConstrDecl _ _ c _) = c
->         constr (ConOpDecl _ _ _ op _) = op
-> boundValues (NewtypeDecl _ _ _ (NewConstrDecl _ _ c _)) = [c]
-> boundValues (FunctionDecl _ f _) = [f]
-> boundValues (ExternalDecl _ _ _ f _) = [f]
-> boundValues (FlatExternalDecl _ fs) = fs
-> boundValues (PatternDecl _ t _) = bv t
-> boundValues (ExtraVariables _ vs) = vs
-> boundValues _ = []
-
-\end{verbatim}
-With the help of the precedence environment, the compiler checks all
-infix applications and sections in the program. This pass will modify
-the parse tree such that for a nested infix application the operator
-with the lowest precedence becomes the root and that two adjacent
-operators with the same precedence will not have conflicting
-associativities. Note that the top-level precedence environment has to
-be returned because it is needed for constructing the module's
-interface.
-\begin{verbatim}
-
-> precCheck :: ModuleIdent -> PEnv -> [Decl] -> (PEnv,[Decl])
-> precCheck = checkDecls
-
-> checkDecls :: ModuleIdent -> PEnv -> [Decl] -> (PEnv,[Decl])
-> checkDecls m pEnv ds = pEnv' `seq` (pEnv',ds')
->   where pEnv' = bindPrecs m ds pEnv
->         ds' = map (checkDecl m pEnv') ds
-
-> checkDecl :: ModuleIdent -> PEnv -> Decl -> Decl
-> checkDecl m pEnv (FunctionDecl p f eqs) =
->   FunctionDecl p f (map (checkEqn m pEnv) eqs)
-> checkDecl m pEnv (PatternDecl p t rhs) =
->   PatternDecl p (checkConstrTerm pEnv t) (checkRhs m pEnv rhs)
-> checkDecl _ _ d = d
-
-> checkEqn :: ModuleIdent -> PEnv -> Equation -> Equation
-> checkEqn m pEnv (Equation p lhs rhs) =
->   Equation p (checkLhs pEnv lhs) (checkRhs m pEnv rhs)
-
-> checkLhs :: PEnv -> Lhs -> Lhs
-> checkLhs pEnv (FunLhs f ts) = FunLhs f (map (checkConstrTerm pEnv) ts)
-> checkLhs pEnv (OpLhs t1 op t2) = t1' `seq` t2' `seq` OpLhs t1' op t2'
->   where t1' = checkOpL pEnv op (checkConstrTerm pEnv t1)
->         t2' = checkOpR pEnv op (checkConstrTerm pEnv t2)
-> checkLhs pEnv (ApLhs lhs ts) =
->   ApLhs (checkLhs pEnv lhs) (map (checkConstrTerm pEnv) ts)
-
-> checkConstrTerm :: PEnv -> ConstrTerm -> ConstrTerm
-> checkConstrTerm _ (LiteralPattern l) = LiteralPattern l
-> checkConstrTerm _ (NegativePattern op l) = NegativePattern op l
-> checkConstrTerm _ (VariablePattern v) = VariablePattern v
-> checkConstrTerm pEnv (ConstructorPattern c ts) =
->   ConstructorPattern c (map (checkConstrTerm pEnv) ts)
-> checkConstrTerm pEnv (InfixPattern t1 op t2) =
->   fixPrecT pEnv InfixPattern
->	 (checkConstrTerm pEnv t1) op (checkConstrTerm pEnv t2)
-> checkConstrTerm pEnv (ParenPattern t) =
->   ParenPattern (checkConstrTerm pEnv t)
-> checkConstrTerm pEnv (TuplePattern p ts) =
->   TuplePattern p (map (checkConstrTerm pEnv) ts)
-> checkConstrTerm pEnv (ListPattern p ts) =
->   ListPattern p (map (checkConstrTerm pEnv) ts)
-> checkConstrTerm pEnv (AsPattern v t) =
->   AsPattern v (checkConstrTerm pEnv t)
-> checkConstrTerm pEnv (LazyPattern p t) =
->   LazyPattern p (checkConstrTerm pEnv t)
-> checkConstrTerm pEnv (FunctionPattern f ts) =
->   FunctionPattern f (map (checkConstrTerm pEnv) ts)
-> checkConstrTerm pEnv (InfixFuncPattern t1 op t2) =
->   fixPrecT pEnv InfixFuncPattern 
->	 (checkConstrTerm pEnv t1) op (checkConstrTerm pEnv t2)
-> checkConstrTerm pEnv (RecordPattern fs r) =
->   RecordPattern (map (checkFieldPattern pEnv) fs)
->	          (maybe Nothing (Just . checkConstrTerm pEnv) r)
-
-> checkFieldPattern :: PEnv -> Field ConstrTerm -> Field ConstrTerm
-> checkFieldPattern pEnv (Field p label patt) =
->     Field p label (checkConstrTerm pEnv patt)
-
-> checkRhs :: ModuleIdent -> PEnv -> Rhs -> Rhs
-> checkRhs m pEnv (SimpleRhs p e ds) = SimpleRhs p (checkExpr m pEnv' e) ds'
->   where (pEnv',ds') = checkDecls m pEnv ds
-> checkRhs m pEnv (GuardedRhs es ds) =
->   GuardedRhs (map (checkCondExpr m pEnv') es) ds'
->   where (pEnv',ds') = checkDecls m pEnv ds
-
-> checkCondExpr :: ModuleIdent -> PEnv -> CondExpr -> CondExpr
-> checkCondExpr m pEnv (CondExpr p g e) =
->   CondExpr p (checkExpr m pEnv g) (checkExpr m pEnv e)
-
-> checkExpr :: ModuleIdent -> PEnv -> Expression -> Expression
-> checkExpr _ _ (Literal l) = Literal l
-> checkExpr _ _ (Variable v) = Variable v
-> checkExpr _ _ (Constructor c) = Constructor c
-> checkExpr m pEnv (Paren e) = Paren (checkExpr m  pEnv e)
-> checkExpr m pEnv (Typed e ty) = Typed (checkExpr m  pEnv e) ty
-> checkExpr m pEnv (Tuple p es) = Tuple p (map (checkExpr m  pEnv) es)
-> checkExpr m pEnv (List p es) = List p (map (checkExpr m  pEnv) es)
-> checkExpr m pEnv (ListCompr p e qs) = ListCompr p (checkExpr m  pEnv' e) qs'
->   where (pEnv',qs') = mapAccumL (checkStmt m ) pEnv qs
-> checkExpr m pEnv (EnumFrom e) = EnumFrom (checkExpr m pEnv e)
-> checkExpr m pEnv (EnumFromThen e1 e2) =
->   EnumFromThen (checkExpr m pEnv e1) (checkExpr m pEnv e2)
-> checkExpr m pEnv (EnumFromTo e1 e2) =
->   EnumFromTo (checkExpr m pEnv e1) (checkExpr m pEnv e2)
-> checkExpr m pEnv (EnumFromThenTo e1 e2 e3) =
->   EnumFromThenTo (checkExpr m pEnv e1)
->                  (checkExpr m pEnv e2)
->                  (checkExpr m pEnv e3)
-> checkExpr m pEnv (UnaryMinus op e) = UnaryMinus op (checkExpr m pEnv e)
-> checkExpr m pEnv (Apply e1 e2) =
->   Apply (checkExpr m pEnv e1) (checkExpr m pEnv e2)
-> checkExpr m pEnv (InfixApply e1 op e2) =
->   fixPrec pEnv (checkExpr m pEnv e1) op (checkExpr m pEnv e2)
-> checkExpr m pEnv (LeftSection e op) =
->   checkLSection pEnv op (checkExpr m pEnv e)
-> checkExpr m pEnv (RightSection op e) =
->   checkRSection pEnv op (checkExpr m pEnv e)
-> checkExpr m pEnv (Lambda r ts e) =
->   Lambda r (map (checkConstrTerm pEnv) ts) (checkExpr m pEnv e)
-> checkExpr m pEnv (Let ds e) = Let ds' (checkExpr m pEnv' e)
->   where (pEnv',ds') = checkDecls m pEnv ds
-> checkExpr m pEnv (Do sts e) = Do sts' (checkExpr m pEnv' e)
->   where (pEnv',sts') = mapAccumL (checkStmt m ) pEnv sts
-> checkExpr m pEnv (IfThenElse r e1 e2 e3) =
->   IfThenElse r (checkExpr m pEnv e1)
->              (checkExpr m pEnv e2)
->              (checkExpr m pEnv e3)
-> checkExpr m pEnv (Case r e alts) =
->   Case r (checkExpr m pEnv e) (map (checkAlt m pEnv) alts)
-> checkExpr m pEnv (RecordConstr fs) =
->   RecordConstr (map (checkFieldExpr m pEnv) fs)
-> checkExpr m pEnv (RecordSelection e label) =
->   RecordSelection (checkExpr m pEnv e) label
-> checkExpr m pEnv (RecordUpdate fs e) =
->   RecordUpdate (map (checkFieldExpr m pEnv) fs) (checkExpr m pEnv e)
-
-> checkFieldExpr :: ModuleIdent -> PEnv -> Field Expression -> Field Expression
-> checkFieldExpr m pEnv (Field p label e) =
->   Field p label (checkExpr m  pEnv e)
-
-> checkStmt :: ModuleIdent -> PEnv -> Statement -> (PEnv,Statement)
-> checkStmt m pEnv (StmtExpr p e) = (pEnv,StmtExpr p (checkExpr m pEnv e))
-> checkStmt m pEnv (StmtDecl ds) = pEnv' `seq` (pEnv',StmtDecl ds')
->   where (pEnv',ds') = checkDecls m pEnv ds
-> checkStmt m pEnv (StmtBind p t e) =
->   (pEnv,StmtBind p (checkConstrTerm pEnv t) (checkExpr m pEnv e))
-
-> checkAlt :: ModuleIdent -> PEnv -> Alt -> Alt
-> checkAlt m pEnv (Alt p t rhs) =
->   Alt p (checkConstrTerm pEnv t) (checkRhs m pEnv rhs)
-
-\end{verbatim}
-The functions \texttt{fixPrec}, \texttt{fixUPrec}, and
-\texttt{fixRPrec} check the relative precedences of adjacent infix
-operators in nested infix applications and unary negations. The
-expressions will be reordered such that the infix operator with the
-lowest precedence becomes the root of the expression. \emph{The
-functions rely on the fact that the parser constructs infix
-applications in a right-associative fashion}, i.e., the left argument
-of an infix application will never be an infix application. In
-addition, a unary negation will never have an infix application as
-its argument.
-
-The function \texttt{fixPrec} checks whether the left argument of an
-infix application is a unary negation and eventually reorders the
-expression if the precedence of the infix operator is higher than that
-of the negation. This will be done with the help of the function
-\texttt{fixUPrec}. In any case, the function \texttt{fixRPrec} is used
-for fixing the precedence of the infix operator and that of its right
-argument. Note that both arguments already have been checked before
-\texttt{fixPrec} is called.
-\begin{verbatim}
-
-> fixPrec :: PEnv -> Expression -> InfixOp -> Expression
->         -> Expression
-> fixPrec pEnv (UnaryMinus uop e1) op e2
->   | pr < 6 || pr == 6 && fix == InfixL =
->       fixRPrec pEnv (UnaryMinus uop e1) op e2
->   | pr > 6 = fixUPrec pEnv uop e1 op e2
->   | otherwise = errorAt' $ ambiguousParse "unary" (qualify uop) (opName op)
->   where OpPrec fix pr = opPrec op pEnv
-> fixPrec pEnv e1 op e2 = fixRPrec pEnv e1 op e2
-
-> fixUPrec :: PEnv -> Ident -> Expression -> InfixOp -> Expression
->          -> Expression
-> fixUPrec pEnv uop  _ op (UnaryMinus _ _) =
->   errorAt' $ ambiguousParse "operator" (opName op) (qualify uop)
-> fixUPrec pEnv uop e1 op1 (InfixApply e2 op2 e3)
->   | pr2 < 6 || pr2 == 6 && fix2 == InfixL =
->       InfixApply (fixUPrec pEnv uop e1 op1 e2) op2 e3
->   | pr2 > 6 = UnaryMinus uop (fixRPrec pEnv e1 op1 (InfixApply e2 op2 e3))
->   | otherwise = errorAt' $ ambiguousParse "unary" (qualify uop) (opName op2)
->   where OpPrec fix2 pr2 = opPrec op2 pEnv
-> fixUPrec _ uop e1 op e2 = UnaryMinus uop (InfixApply e1 op e2)
-
-> fixRPrec :: PEnv -> Expression -> InfixOp -> Expression
->          -> Expression
-> fixRPrec pEnv e1 op (UnaryMinus uop e2)
->   | pr < 6 = InfixApply e1 op (UnaryMinus uop e2)
->   | otherwise =
->       errorAt' $ ambiguousParse "operator" (opName op) (qualify uop)
->   where OpPrec _ pr = opPrec op pEnv
-> fixRPrec pEnv e1 op1 (InfixApply e2 op2 e3)
->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR =
->       InfixApply e1 op1 (InfixApply e2 op2 e3)
->   | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL =
->       InfixApply (fixPrec pEnv e1 op1 e2) op2 e3
->   | otherwise =
->       errorAt' $ ambiguousParse "operator" (opName op1) (opName op2)
->   where OpPrec fix1 pr1 = opPrec op1 pEnv
->         OpPrec fix2 pr2 = opPrec op2 pEnv
-> fixRPrec _ e1 op e2 = InfixApply e1 op e2
-
-\end{verbatim}
-The functions \texttt{checkLSection} and \texttt{checkRSection} are
-used for handling the precedences inside left and right sections.
-These functions only need to check that an infix operator occurring in
-the section has either a higher precedence than the section operator
-or both operators have the same precedence and are both left
-associative for a left section and right associative for a right
-section, respectively.
-\begin{verbatim}
-
-> checkLSection :: PEnv -> InfixOp -> Expression -> Expression
-> checkLSection pEnv op e@(UnaryMinus uop _)
->   | pr < 6 || pr == 6 && fix == InfixL = LeftSection e op
->   | otherwise = errorAt' $ ambiguousParse "unary" (qualify uop) (opName op)
->   where OpPrec fix pr = opPrec op pEnv
-> checkLSection pEnv op1 e@(InfixApply _ op2 _)
->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL =
->       LeftSection e op1
->   | otherwise =
->       errorAt' $ ambiguousParse "operator" (opName op1) (opName op2)
->   where OpPrec fix1 pr1 = opPrec op1 pEnv
->         OpPrec fix2 pr2 = opPrec op2 pEnv
-> checkLSection _ op e = LeftSection e op
-
-> checkRSection :: PEnv -> InfixOp -> Expression -> Expression
-> checkRSection pEnv op e@(UnaryMinus uop _)
->   | pr < 6 = RightSection op e
->   | otherwise = errorAt' $ ambiguousParse "unary" (qualify uop) (opName op)
->   where OpPrec _ pr = opPrec op pEnv
-> checkRSection pEnv op1 e@(InfixApply _ op2 _)
->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR =
->       RightSection op1 e
->   | otherwise =
->       errorAt' $ ambiguousParse "operator" (opName op1) (opName op2)
->   where OpPrec fix1 pr1 = opPrec op1 pEnv
->         OpPrec fix2 pr2 = opPrec op2 pEnv
-> checkRSection _ op e = RightSection op e
-
-\end{verbatim}
-The functions \texttt{fixPrecT} and \texttt{fixRPrecT} check the
-relative precedences of adjacent infix operators in patterns. The
-patterns will be reordered such that the infix operator with the
-lowest precedence becomes the root of the term. \emph{The functions
-rely on the fact that the parser constructs infix patterns in a
-right-associative fashion}, i.e., the left argument of an infix pattern
-will never be an infix pattern. The functions also check whether the
-left and right arguments of an infix pattern are negative literals. In
-this case, the negation must bind more tightly than the operator for
-the pattern to be accepted.
-\begin{verbatim}
-
-> fixPrecT ::  PEnv 
->             -> (ConstrTerm -> QualIdent -> ConstrTerm -> ConstrTerm)
->	      -> ConstrTerm -> QualIdent -> ConstrTerm  
->             -> ConstrTerm
-> fixPrecT pEnv infixpatt t1@(NegativePattern uop l) op t2
->   | pr < 6 || pr == 6 && fix == InfixL 
->     = fixRPrecT pEnv infixpatt t1 op t2
->   | otherwise 
->     = errorAt' $ invalidParse "unary" uop op
->   where OpPrec fix pr = prec op pEnv
-> fixPrecT pEnv infixpatt t1 op t2 
->   = fixRPrecT pEnv infixpatt t1 op t2
-
-> fixRPrecT :: PEnv 
->              -> (ConstrTerm -> QualIdent -> ConstrTerm -> ConstrTerm)
->              -> ConstrTerm  -> QualIdent -> ConstrTerm
->              -> ConstrTerm
-> fixRPrecT pEnv infixpatt t1 op t2@(NegativePattern uop l)
->   | pr < 6    = infixpatt t1 op t2
->   | otherwise = errorAt' $ invalidParse "unary" uop op
->   where OpPrec _ pr = prec op pEnv
-> fixRPrecT pEnv infixpatt t1 op1 (InfixPattern t2 op2 t3)
->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR
->     = infixpatt t1 op1 (InfixPattern t2 op2 t3)
->   | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL
->     = InfixPattern (fixPrecT pEnv infixpatt t1 op1 t2) op2 t3
->   | otherwise 
->     = errorAt' $ ambiguousParse "operator" op1 op2
->   where OpPrec fix1 pr1 = prec op1 pEnv
->         OpPrec fix2 pr2 = prec op2 pEnv
-> fixRPrecT pEnv infixpatt t1 op1 (InfixFuncPattern t2 op2 t3)
->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR
->     = infixpatt t1 op1 (InfixFuncPattern t2 op2 t3)
->   | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL
->     = InfixFuncPattern (fixPrecT pEnv infixpatt t1 op1 t2) op2 t3
->   | otherwise 
->     = errorAt' $ ambiguousParse "operator" op1 op2
->   where OpPrec fix1 pr1 = prec op1 pEnv
->         OpPrec fix2 pr2 = prec op2 pEnv
-> fixRPrecT _ infixpatt t1 op t2 = infixpatt t1 op t2
-
-> {-fixPrecT :: Position -> PEnv -> ConstrTerm -> QualIdent -> ConstrTerm
->          -> ConstrTerm
-> fixPrecT p pEnv t1@(NegativePattern uop l) op t2
->   | pr < 6 || pr == 6 && fix == InfixL = fixRPrecT p pEnv t1 op t2
->   | otherwise = errorAt p $ invalidParse "unary" uop op
->   where OpPrec fix pr = prec op pEnv
-> fixPrecT p pEnv t1 op t2 = fixRPrecT p pEnv t1 op t2-}
-
-> {-fixRPrecT :: Position -> PEnv -> ConstrTerm -> QualIdent -> ConstrTerm
->           -> ConstrTerm
-> fixRPrecT p pEnv t1 op t2@(NegativePattern uop l)
->   | pr < 6 = InfixPattern t1 op t2
->   | otherwise = errorAt p $ invalidParse "unary" uop op
->   where OpPrec _ pr = prec op pEnv
-> fixRPrecT p pEnv t1 op1 (InfixPattern t2 op2 t3)
->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR =
->       InfixPattern t1 op1 (InfixPattern t2 op2 t3)
->   | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL =
->       InfixPattern (fixPrecT p pEnv t1 op1 t2) op2 t3
->   | otherwise = errorAt p $ ambiguousParse "operator" op1 op2
->   where OpPrec fix1 pr1 = prec op1 pEnv
->         OpPrec fix2 pr2 = prec op2 pEnv
-> fixRPrecT _ _ t1 op t2 = InfixPattern t1 op t2-}
-
-\end{verbatim}
-The functions \texttt{checkOpL} and \texttt{checkOpR} check the left
-and right arguments of an operator declaration. If they are infix
-patterns they must bind more tightly than the operator, otherwise the
-left-hand side of the declaration is invalid.
-\begin{verbatim}
-
-> checkOpL :: PEnv -> Ident -> ConstrTerm -> ConstrTerm
-> checkOpL pEnv op t@(NegativePattern uop l)
->   | pr < 6 || pr == 6 && fix == InfixL = t
->   | otherwise = errorAt' $ invalidParse "unary" uop (qualify op)
->   where OpPrec fix pr = prec (qualify op) pEnv
-> checkOpL pEnv op1 t@(InfixPattern _ op2 _)
->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL = t
->   | otherwise = errorAt' $ invalidParse "operator" op1 op2
->   where OpPrec fix1 pr1 = prec (qualify op1) pEnv
->         OpPrec fix2 pr2 = prec op2 pEnv
-> checkOpL _ _ t = t
-
-> checkOpR :: PEnv -> Ident -> ConstrTerm -> ConstrTerm
-> checkOpR pEnv op t@(NegativePattern uop l)
->   | pr < 6 = t
->   | otherwise = errorAt' $ invalidParse "unary" uop (qualify op)
->   where OpPrec _ pr = prec (qualify op) pEnv
-> checkOpR pEnv op1 t@(InfixPattern _ op2 _)
->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR = t
->   | otherwise = errorAt' $ invalidParse "operator" op1 op2
->   where OpPrec fix1 pr1 = prec (qualify op1) pEnv
->         OpPrec fix2 pr2 = prec op2 pEnv
-> checkOpR _ _ t = t
-
-\end{verbatim}
-The functions \texttt{opPrec} and \texttt{prec} return the fixity and
-operator precedence of an entity. Even though precedence checking is
-performed after the renaming phase, we have to be prepared to see
-ambiguous identifiers here. This may happen while checking the root of
-an operator definition that shadows an imported definition.
-\begin{verbatim}
-
-> opPrec :: InfixOp -> PEnv -> OpPrec
-> opPrec op = prec (opName op)
-
-> prec :: QualIdent -> PEnv -> OpPrec
-> prec op env =
->   case qualLookupP op env of
->     [] -> defaultP
->     PrecInfo _ p : _ -> p
-
-\end{verbatim}
-Error messages.
-\begin{verbatim}
-
-> undefinedOperator :: Ident -> (Position,String)
-> undefinedOperator op = 
->  (positionOfIdent op,
->   "no definition for " ++ name op ++ " in this scope")
-
-> duplicatePrecedence :: Ident -> (Position,String)
-> duplicatePrecedence op = 
->  (positionOfIdent op,
->   "More than one fixity declaration for " ++ name op)
-
-> invalidParse :: String -> Ident -> QualIdent -> (Position,String)
-> invalidParse what op1 op2 =
->  (positionOfIdent op1,
->   "Invalid use of " ++ what ++ " " ++ name op1 ++ " with " ++ qualName op2 ++
->   (showLine $ positionOfQualIdent op2))
-
-> ambiguousParse :: String -> QualIdent -> QualIdent -> (Position,String)
-> ambiguousParse what op1 op2 =
->  (positionOfQualIdent op1,
->   "Ambiguous use of " ++ what ++ " " ++ qualName op1 ++
->   " with " ++ qualName op2 ++ (showLine $ positionOfQualIdent op2))
-
-\end{verbatim}
diff --git a/src/Qual.lhs b/src/Qual.lhs
deleted file mode 100644
--- a/src/Qual.lhs
+++ /dev/null
@@ -1,165 +0,0 @@
-
-% $Id: Qual.lhs,v 1.18 2004/02/15 22:10:36 wlux Exp $
-%
-% Copyright (c) 2001-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{Qual.lhs}
-\section{Proper Qualification}
-After checking the module and before starting the translation into the
-intermediate language, the compiler properly qualifies all
-constructors and (global) functions occurring in a pattern or
-expression such that their module prefix matches the module of their
-definition. This is done also for functions and constructors declared
-in the current module. Only functions and variables declared in local
-declarations groups as well as function arguments remain unchanged.
-
-\em{Note:} The modified version also qualifies type constructors
-\begin{verbatim}
-
-> module Qual(qual) where
-
-> import Curry.Base.Ident
-> import Curry.Syntax
-
-> import Base
-> import TopEnv
-
-> qual :: ModuleIdent -> ValueEnv -> [Decl] -> [Decl]
-> qual m tyEnv ds = map (qualDecl m tyEnv) ds
-
-> qualDecl :: ModuleIdent -> ValueEnv -> Decl -> Decl
-> qualDecl m tyEnv (FunctionDecl p f eqs) =
->   FunctionDecl p f (map (qualEqn m tyEnv) eqs)
-> qualDecl m tyEnv (PatternDecl p t rhs) =
->   PatternDecl p (qualTerm m tyEnv t) (qualRhs m tyEnv rhs)
-> qualDecl _ _ d = d
-
-> qualEqn :: ModuleIdent -> ValueEnv -> Equation -> Equation
-> qualEqn m tyEnv (Equation p lhs rhs) =
->   Equation p (qualLhs m tyEnv lhs) (qualRhs m tyEnv rhs)
-
-> qualLhs :: ModuleIdent -> ValueEnv -> Lhs -> Lhs
-> qualLhs m tyEnv (FunLhs f ts) = FunLhs f (map (qualTerm m tyEnv) ts)
-> qualLhs m tyEnv (OpLhs t1 op t2) =
->   OpLhs (qualTerm m tyEnv t1) op (qualTerm m tyEnv t2)
-> qualLhs m tyEnv (ApLhs lhs ts) =
->   ApLhs (qualLhs m tyEnv lhs) (map (qualTerm m tyEnv) ts)
-
-> qualTerm :: ModuleIdent -> ValueEnv -> ConstrTerm -> ConstrTerm
-> qualTerm _ _ (LiteralPattern l) = LiteralPattern l
-> qualTerm _ _ (NegativePattern op l) = NegativePattern op l
-> qualTerm _ _ (VariablePattern v) = VariablePattern v
-> qualTerm m tyEnv (ConstructorPattern c ts) =
->   ConstructorPattern (qualIdent m tyEnv c) (map (qualTerm m tyEnv) ts)
-> qualTerm m tyEnv (InfixPattern t1 op t2) =
->   InfixPattern (qualTerm m tyEnv t1) 
->                (qualIdent m tyEnv op) 
->                (qualTerm m tyEnv t2)
-> qualTerm m tyEnv (ParenPattern t) = ParenPattern (qualTerm m tyEnv t)
-> qualTerm m tyEnv (TuplePattern p ts) = TuplePattern p (map (qualTerm m tyEnv) ts)
-> qualTerm m tyEnv (ListPattern p ts) = ListPattern p (map (qualTerm m tyEnv) ts)
-> qualTerm m tyEnv (AsPattern v t) = AsPattern v (qualTerm m tyEnv t)
-> qualTerm m tyEnv (LazyPattern p t) = LazyPattern p (qualTerm m tyEnv t)
-> qualTerm m tyEnv (FunctionPattern f ts) =
->   FunctionPattern (qualIdent m tyEnv f) (map (qualTerm m tyEnv) ts)
-> qualTerm m tyEnv (InfixFuncPattern t1 op t2) =
->   InfixFuncPattern (qualTerm m tyEnv t1) 
->		     (qualIdent m tyEnv op) 
->	             (qualTerm m tyEnv t2)
-> qualTerm m tyEnv (RecordPattern fs rt) =
->   RecordPattern (map (qualFieldPattern m tyEnv) fs)
->	          (maybe Nothing (Just . qualTerm m tyEnv) rt)
-
-> qualFieldPattern :: ModuleIdent -> ValueEnv -> Field ConstrTerm
->	           -> Field ConstrTerm
-> qualFieldPattern m tyEnv (Field p l t) = Field p l (qualTerm m tyEnv t)
-
-> qualRhs :: ModuleIdent -> ValueEnv -> Rhs -> Rhs
-> qualRhs m tyEnv (SimpleRhs p e ds) =
->   SimpleRhs p (qualExpr m tyEnv e) (map (qualDecl m tyEnv) ds) 
-> qualRhs m tyEnv (GuardedRhs es ds) =
->   GuardedRhs (map (qualCondExpr m tyEnv) es) (map (qualDecl m tyEnv) ds)
-
-> qualCondExpr :: ModuleIdent -> ValueEnv -> CondExpr -> CondExpr
-> qualCondExpr m tyEnv (CondExpr p g e) =
->   CondExpr p (qualExpr m tyEnv g) (qualExpr m tyEnv e)
-
-> qualExpr :: ModuleIdent -> ValueEnv -> Expression -> Expression
-> qualExpr _ _ (Literal l) = Literal l
-> qualExpr m tyEnv (Variable v) = Variable (qualIdent m tyEnv v)
-> qualExpr m tyEnv (Constructor c) = Constructor (qualIdent m tyEnv c)
-> qualExpr m tyEnv (Paren e) = Paren (qualExpr m tyEnv e)
-> qualExpr m tyEnv (Typed e ty) = Typed (qualExpr m tyEnv e) ty
-> qualExpr m tyEnv (Tuple p es) = Tuple p (map (qualExpr m tyEnv) es)
-> qualExpr m tyEnv (List p es) = List p (map (qualExpr m tyEnv) es)
-> qualExpr m tyEnv (ListCompr p e qs) =
->   ListCompr p (qualExpr m tyEnv e) (map (qualStmt m tyEnv) qs)
-> qualExpr m tyEnv (EnumFrom e) = EnumFrom (qualExpr m tyEnv e)
-> qualExpr m tyEnv (EnumFromThen e1 e2) =
->   EnumFromThen (qualExpr m tyEnv e1) (qualExpr m tyEnv e2)
-> qualExpr m tyEnv (EnumFromTo e1 e2) =
->   EnumFromTo (qualExpr m tyEnv e1) (qualExpr m tyEnv e2)
-> qualExpr m tyEnv (EnumFromThenTo e1 e2 e3) =
->   EnumFromThenTo (qualExpr m tyEnv e1) 
->                  (qualExpr m tyEnv e2) 
->                  (qualExpr m tyEnv e3)
-> qualExpr m tyEnv (UnaryMinus op e) = UnaryMinus op (qualExpr m tyEnv e)
-> qualExpr m tyEnv (Apply e1 e2) = 
->   Apply (qualExpr m tyEnv e1) (qualExpr m tyEnv e2)
-> qualExpr m tyEnv (InfixApply e1 op e2) =
->   InfixApply (qualExpr m tyEnv e1) (qualOp m tyEnv op) (qualExpr m tyEnv e2)
-> qualExpr m tyEnv (LeftSection e op) =
->   LeftSection (qualExpr m tyEnv e) (qualOp m tyEnv op)
-> qualExpr m tyEnv (RightSection op e) =
->   RightSection (qualOp m tyEnv op) (qualExpr m tyEnv e)
-> qualExpr m tyEnv (Lambda r ts e) =
->   Lambda r (map (qualTerm m tyEnv) ts) (qualExpr m tyEnv e)
-> qualExpr m tyEnv (Let ds e) = 
->   Let (map (qualDecl m tyEnv) ds) (qualExpr m tyEnv e)
-> qualExpr m tyEnv (Do sts e) = 
->   Do (map (qualStmt m tyEnv) sts) (qualExpr m tyEnv e)
-> qualExpr m tyEnv (IfThenElse r e1 e2 e3) =
->   IfThenElse r (qualExpr m tyEnv e1) 
->              (qualExpr m tyEnv e2) 
->              (qualExpr m tyEnv e3)
-> qualExpr m tyEnv (Case r e alts) =
->   Case r (qualExpr m tyEnv e) (map (qualAlt m tyEnv) alts)
-> qualExpr m tyEnv (RecordConstr fs) =
->   RecordConstr (map (qualFieldExpr m tyEnv) fs)
-> qualExpr m tyEnv (RecordSelection e l) =
->   RecordSelection (qualExpr m tyEnv e) l
-> qualExpr m tyEnv (RecordUpdate fs e) =
->   RecordUpdate (map (qualFieldExpr m tyEnv) fs) (qualExpr m tyEnv e)
-
-> qualStmt :: ModuleIdent -> ValueEnv -> Statement -> Statement
-> qualStmt m tyEnv (StmtExpr p e) = StmtExpr p (qualExpr m tyEnv e)
-> qualStmt m tyEnv (StmtBind p t e) =
->   StmtBind p (qualTerm m tyEnv t) (qualExpr m tyEnv e)
-> qualStmt m tyEnv (StmtDecl ds) = StmtDecl (map (qualDecl m tyEnv) ds)
-
-> qualAlt :: ModuleIdent -> ValueEnv -> Alt -> Alt
-> qualAlt m tyEnv (Alt p t rhs) = 
->   Alt p (qualTerm m tyEnv t) (qualRhs m tyEnv rhs)
-
-> qualFieldExpr :: ModuleIdent -> ValueEnv -> Field Expression
->	        -> Field Expression
-> qualFieldExpr m tyEnv (Field p l e) = Field p l (qualExpr m tyEnv e)
-
-> qualOp :: ModuleIdent -> ValueEnv -> InfixOp -> InfixOp
-> qualOp m tyEnv (InfixOp op) = InfixOp (qualIdent m tyEnv op)
-> qualOp m tyEnv (InfixConstr op) = InfixConstr (qualIdent m tyEnv op)
-
-> qualIdent :: ModuleIdent -> ValueEnv -> QualIdent -> QualIdent
-> qualIdent m tyEnv x
->   | not (isQualified x) && uniqueId (unqualify x) /= 0 = x
->   | otherwise =
->       case (qualLookupValue x tyEnv) of
->         [y] -> origName y
->         vs  -> case (qualLookupValue (qualQualify m x) tyEnv) of
->                  [y] -> origName y
->                  _ -> qualQualify m x -- internalError ("qualIdent: " ++ show x)
-
-\end{verbatim}
diff --git a/src/SCC.lhs b/src/SCC.lhs
deleted file mode 100644
--- a/src/SCC.lhs
+++ /dev/null
@@ -1,60 +0,0 @@
-
-% $Id: SCC.lhs,v 1.3 2003/04/30 21:29:06 wlux Exp $
-%
-% Copyright (c) 2000,2002-2003, Wolfgang Lux
-% See LICENSE for the full license.
-%
-\nwfilename{SCC.lhs}
-\section{Computing strongly connected components}
-At various places in the compiler we had to partition a list of
-declarations into strongly connected components. The function
-\texttt{scc} computes this relation in two steps. First, the list is
-topologically sorted ``downwards'' using the \emph{defs} relation.
-Then the resulting list is sorted ``upwards'' using the \emph{uses}
-relation and partitioned into the connected components. Both relations
-are computed within this module using the bound and free names of each
-declaration.
-
-In order to avoid useless recomputations, the code in the module first
-decorates the declarations with their bound and free names and a
-unique number. The latter is only used to provide a trivial ordering
-so that the declarations can be used as set elements.
-\begin{verbatim}
-
-> module SCC(scc) where
-
-> import qualified Data.Set as Set
-
-> data Node a b = Node{ key::Int, bvs::[b], fvs::[b], node::a }
-
-> instance Eq (Node a b) where
->   n1 == n2 = key n1 == key n2
-> instance Ord (Node b a) where
->   n1 `compare` n2 = key n1 `compare` key n2
-
-> scc :: Eq b => (a -> [b])              -- entities defined by node
->             -> (a -> [b])              -- entities used by node
->             -> [a]                     -- list of nodes
->             -> [[a]]                   -- strongly connected components
-> scc bvs fvs = map (map node) . tsort' . tsort . zipWith wrap [0..]
->   where wrap i n = Node i (bvs n) (fvs n) n
-
-> tsort :: Eq b => [Node a b] -> [Node a b]
-> tsort xs = snd (dfs xs Set.empty [])
->   where dfs [] marks stack = (marks,stack)
->         dfs (x:xs) marks stack
->           | x `Set.member` marks = dfs xs marks stack
->           | otherwise = dfs xs marks' (x:stack')
->           where (marks',stack') = dfs (defs x) (x `Set.insert` marks) stack
->         defs x = filter (any (`elem` fvs x) . bvs) xs
-
-> tsort' :: Eq b => [Node a b] -> [[Node a b]]
-> tsort' xs = snd (dfs xs Set.empty [])
->   where dfs [] marks stack = (marks,stack)
->         dfs (x:xs) marks stack
->           | x `Set.member` marks = dfs xs marks stack
->           | otherwise = dfs xs marks' ((x:concat stack'):stack)
->           where (marks',stack') = dfs (uses x) (x `Set.insert` marks) []
->         uses x = filter (any (`elem` bvs x) . fvs) xs
-
-\end{verbatim}
diff --git a/src/ScopeEnv.hs b/src/ScopeEnv.hs
deleted file mode 100644
--- a/src/ScopeEnv.hs
+++ /dev/null
@@ -1,175 +0,0 @@
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---
--- ScopeEnv - provides functions and data types for dealing with nested
---            scope environments to store data from nested scopes
---
--- This module should be imported using "import qualified" to avoid name
--- clashes
---
--- November 2005,
--- Martin Engelke (men@informatik.uni-kiel.de)
---
-module ScopeEnv (ScopeEnv,
-		 new, insert, update, modify, lookup, sureLookup,
-		 level, exists, beginScope, endScope, endScopeUp,
-		 toList, toLevelList, currentLevel) where
-
-import qualified Data.Map as Map
-import Prelude hiding (lookup)
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
--- Data type for representing information in nested scopes.
-data ScopeEnv a b = ScopeEnv Int (Map.Map a (b,Int)) [Map.Map a (b,Int)]
-		    deriving Show
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--- Returns an empty scope environment
-new :: Ord a => ScopeEnv a b
-new = ScopeEnv 0 Map.empty []
-
-
--- Inserts a value under a key into the environment of the current scope
-insert :: Ord a => a -> b -> ScopeEnv a b -> ScopeEnv a b
-insert key val env = modifySE insertLev env
- where
- insertLev lev local = Map.insert key (val,lev) local
-
-
--- Updates the value stored under an existing key in the environment of 
--- the current scope
-update :: Ord a => a -> b -> ScopeEnv a b -> ScopeEnv a b
-update key val env = modifySE updateLev env
- where
- updateLev lev local = maybe local 
-		             (\ (_,lev') ->  Map.insert key (val,lev') local)
-			     (Map.lookup key local)
-
--- Modifies the value of an existing key by applying the function 'fun'
--- in the environment of the current scope
-modify :: Ord a => (b -> b) -> a -> ScopeEnv a b -> ScopeEnv a b
-modify fun key env = modifySE modifyLev env
- where
- modifyLev lev local 
-    = maybe local
-            (\ (val',lev') -> Map.insert key (fun val', lev') local)
-	    (Map.lookup key local)
-
-
--- Looks up the value which is stored under a key from the environment of
--- the current scope
-lookup :: Ord a => a -> ScopeEnv a b -> Maybe b
-lookup key env = selectSE lookupLev env
- where
- lookupLev lev local = maybe Nothing (Just . fst) (Map.lookup key local)
-
-
--- Similar to 'lookup', but returns an alternative value, if the key
--- doesn't exist in the environment of the current scope
-sureLookup :: Ord a => a -> b -> ScopeEnv a b -> b
-sureLookup key alt env = maybe alt id (lookup key env)
-
-
--- Returns the level of the last insertion of a key
-level :: Ord a => a -> ScopeEnv a b -> Int
-level key env = selectSE levelLev env
- where
- levelLev lev local = maybe (-1) snd (Map.lookup key local)
-
-
--- Checks, whether a key exists in the environment of the current scope
-exists :: Ord a => a -> ScopeEnv a b -> Bool
-exists key env = selectSE existsLev env
- where
- existsLev lev local = maybe False (const True) (Map.lookup key local)
-
-
--- Switches to the next scope (i.e. pushes the environment of the current
--- scope onto the top of an scope stack and increments the level counter)
-beginScope :: Ord a => ScopeEnv a b -> ScopeEnv a b
-beginScope (ScopeEnv lev top [])
-   = ScopeEnv (lev + 1) top [top]
-beginScope (ScopeEnv lev top (local:locals))
-   = ScopeEnv (lev + 1) top (local:local:locals)
-
-
--- Switches to the previous scope (i.e. pops the environment from the top
--- of the scope stack and decrements the level counter)
-endScope :: Ord a => ScopeEnv a b -> ScopeEnv a b
-endScope (ScopeEnv _ top [])
-   = ScopeEnv 0 top []
-endScope (ScopeEnv lev top (_:locals))
-   = ScopeEnv (lev - 1) top locals
-
-
--- Behaves like 'endScope' but additionally updates the environment of
--- the previous scope by updating all keys with the corresponding values
--- from the poped environment
-endScopeUp :: Ord a => ScopeEnv a b -> ScopeEnv a b
-endScopeUp (ScopeEnv _ top [])
-   = ScopeEnv 0 top []
-endScopeUp (ScopeEnv lev top (local:[]))
-   = ScopeEnv 0 (foldr (updateSE local) top (Map.toList top)) []
-endScopeUp (ScopeEnv lev top (local:local':locals))
-   = ScopeEnv (lev - 1) 
-              top 
-	      ((foldr (updateSE local) local' (Map.toList local')):locals)
-
-
--- Returns the environment of current scope as a (key,value) list
-toList :: Ord a => ScopeEnv a b -> [(a,b)]
-toList env = selectSE toListLev env
- where
- toListLev lev local = map (\ (key,(val,_)) -> (key,val)) (Map.toList local)
-
-
--- Returns all (key,value) pairs from the environment of the current scope 
--- which has been inserted in the current level
-toLevelList :: Ord a => ScopeEnv a b -> [(a,b)]
-toLevelList env = selectSE toLevelListLev env
- where
- toLevelListLev lev local
-    = map (\ (key,(val,_)) -> (key,val))
-          (filter (\ (_,(_,lev')) -> lev' == lev) (Map.toList local))
-
-
--- Returns the current level
-currentLevel :: Ord a => ScopeEnv a b -> Int
-currentLevel env = selectSE const env
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--- Privates...
-
---
-modifySE :: (Int -> Map.Map a (b,Int) -> Map.Map a (b,Int)) -> ScopeEnv a b 
-          -> ScopeEnv a b
-modifySE f (ScopeEnv _ top []) 
-   = ScopeEnv 0 (f 0 top) []
-modifySE f (ScopeEnv lev top (local:locals))
-   = ScopeEnv lev top ((f lev local):locals)
-
---
-selectSE :: (Int -> Map.Map a (b,Int) -> c) -> ScopeEnv a b -> c
-selectSE f (ScopeEnv _ top [])        = f 0 top
-selectSE f (ScopeEnv lev _ (local:_)) = f lev local
-
---
-updateSE :: Ord a => Map.Map a (b,Int) -> (a,(b,Int)) ->  Map.Map a (b,Int) 
-          -> Map.Map a (b,Int)
-updateSE local (key,(_,lev)) local'
-   = maybe local' 
-           (\ (val',lev') 
-	    -> if lev == lev' then Map.insert key (val',lev) local' 
-                              else local')
-	   (Map.lookup key local)
-
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
diff --git a/src/Simplify.lhs b/src/Simplify.lhs
deleted file mode 100644
--- a/src/Simplify.lhs
+++ /dev/null
@@ -1,475 +0,0 @@
-% $Id: Simplify.lhs,v 1.10 2004/02/13 14:02:58 wlux Exp $
-%
-% Copyright (c) 2003, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{Simplify.lhs}
-\section{Optimizing the Desugared Code}\label{sec:simplify}
-After desugaring the source code, but before lifting local
-declarations, the compiler performs a few simple optimizations to
-improve the efficiency of the generated code. In addition, the
-optimizer replaces pattern bindings with simple variable bindings and
-selector functions.
-
-Currently, the following optimizations are implemented:
-\begin{itemize}
-\item Remove unused declarations.
-\item Inline simple constants.
-\item Compute minimal binding groups.
-\item Under certain conditions, inline local function definitions.
-\end{itemize}
-\begin{verbatim}
-
-> module Simplify(simplify) where
-
-> import Control.Monad.Reader as R
-> import Control.Monad.State as S
-> import qualified Data.Map as Map
-
-> import Curry.Base.Position
-> import Curry.Base.Ident
-> import Curry.Syntax
-> import Curry.Syntax.Utils
-
-> import Types
-> import Base
-> import SCC
-> import Typing
-
-
-> type SimplifyState a = S.StateT ValueEnv (ReaderT EvalEnv (S.State Int)) a
-> type InlineEnv = Map.Map Ident Expression
-> type SimplifyFlags = Bool
- 
-> flatFlag :: SimplifyFlags -> Bool
-> flatFlag   x = x
-
-> simplify :: SimplifyFlags -> ValueEnv -> EvalEnv -> Module -> (Module,ValueEnv)
-> simplify flags tyEnv evEnv m 
->   = S.evalState (R.runReaderT (S.evalStateT (simplifyModule flags m) tyEnv) evEnv) 1
-
-> simplifyModule :: SimplifyFlags -> Module -> SimplifyState (Module,ValueEnv)
-> simplifyModule flat (Module m es ds) =
->   do
->     ds' <- mapM (simplifyDecl flat m Map.empty) ds
->     tyEnv <- S.get
->     return (Module m es ds',tyEnv)
-
-> simplifyDecl :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Decl -> SimplifyState Decl
-> simplifyDecl flat m env (FunctionDecl p f eqs) =
->   liftM (FunctionDecl p f . concat) (mapM (simplifyEquation flat m env) eqs)
-> simplifyDecl flat m env (PatternDecl p t rhs) =
->   liftM (PatternDecl p t) (simplifyRhs flat m env rhs)
-> simplifyDecl _ _ _ d = return d
-
-\end{verbatim}
-After simplifying the right hand side of an equation, the compiler
-transforms declarations of the form
-\begin{quote}\tt
-  $f\;t_1\dots t_{k-k'}\;x_{k-k'+1}\dots x_{k}$ =
-    let $f'\;t'_1\dots t'_{k'}$ = $e$ in
-    $f'\;x_1\dots x_{k'}$
-\end{quote}
-into the equivalent definition
-\begin{quote}\tt
-  $f\;t_1\dots t_{k-k'}\;(x_{k-k'+1}$@$t'_1)\dots(x_k$@$t'_{k'})$ = $e$
-\end{quote}
-where the arities of $f$ and $f'$ are $k$ and $k'$, respectively, and
-$x_{k-k'+1},\dots,x_{k}$ are variables. This optimization was
-introduced in order to avoid an auxiliary function being generated for
-definitions whose right-hand side is a $\lambda$-expression, e.g.,
-\verb|f . g = \x -> f (g x)|. This declaration is transformed into
-\verb|(.) f g x = let lambda x = f (g x) in lambda x| by desugaring
-and in turn is optimized into \verb|(.) f g x = f (g x)|, here. The
-transformation can obviously be generalized to the case where $f'$ is
-defined by more than one equation. However, we must be careful not to
-change the evaluation mode of arguments. Therefore, the transformation
-is applied only if $f$ and $f'$ use them same evaluation mode or all
-of the arguments $t'_1,\dots,t'_k$ are variables. Actually, the
-transformation could be applied to the case where the arguments
-$t_1,\dots,t_{k-k'}$ are all variables as well, but in this case the
-evaluation mode of $f$ may have to be changed to match that of $f'$.
-
-We have to be careful with this optimization in conjunction with
-newtype constructors. It is possible that the local function is
-applied only partially, e.g., for
-\begin{verbatim}
-  newtype ST s a = ST (s -> (a,s))
-  returnST x = ST (\s -> (x,s))
-\end{verbatim}
-the desugared code is equivalent to
-\begin{verbatim}
-  returnST x = let lambda1 s = (x,s) in lambda1
-\end{verbatim}
-We must not ``optimize'' this into \texttt{returnST x s = (x,s)}
-because the compiler assumes that \texttt{returnST} is a unary
-function.
-
-Note that this transformation is not strictly semantic preserving as
-the evaluation order of arguments can be changed. This happens if $f$
-is defined by more than one rule with overlapping patterns and the
-local functions of each rule have disjoint patterns. As an example,
-consider the function
-\begin{verbatim}
-  f (Just x) _ = let g (Left z)  = x + z in g
-  f _ (Just y) = let h (Right z) = y + z in h
-\end{verbatim}
-The definition of \texttt{f} is non-deterministic because of the
-overlapping patterns in the first and second argument. However, the
-optimized definition
-\begin{verbatim}
-  f (Just x) _ (Left z)  = x + z
-  f _ (Just y) (Right z) = y + z
-\end{verbatim}
-is deterministic. It will evaluate and match the third argument first,
-whereas the original definition is going to evaluate the first or the
-second argument first, depending on the non-deterministic branch
-chosen. As such definitions are presumably rare, and the optimization
-avoids a non-deterministic split of the computation, we put up with
-the change of evaluation order.
-
-This transformation is actually just a special case of inlining a
-(local) function definition. We are unable to handle the general case
-because it would require to represent the pattern matching code
-explicitly in a Curry expression.
-\begin{verbatim}
-
-> simplifyEquation :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Equation
->                  -> SimplifyState [Equation]
-> simplifyEquation flat m env (Equation p lhs rhs) =
->   do
->     rhs' <- simplifyRhs flat m env rhs
->     tyEnv <- S.get
->     evEnv <- S.lift R.ask
->     return (inlineFun flat m tyEnv evEnv p lhs rhs')
-
-> inlineFun :: SimplifyFlags -> ModuleIdent -> ValueEnv -> EvalEnv -> Position -> Lhs -> Rhs
->           -> [Equation]
-> inlineFun flags m tyEnv evEnv p (FunLhs f ts)
->           (SimpleRhs _ (Let [FunctionDecl _ f' eqs'] e) _)
->   | True -- False -- inlining of functions is deactivated (hsi)
->    && f' `notElem` qfv m eqs' && e' == Variable (qualify f') &&
->     n == arrowArity (funType m tyEnv (qualify f')) &&
->     (evMode evEnv f == evMode evEnv f' ||
->      and [all isVarPattern ts | Equation _ (FunLhs _ ts) _ <- eqs']) =
->     map (mergeEqns p f ts' vs') eqs'
->   where n :: Int                      -- type signature necessary for nhc
->         (n,vs',ts',e') = etaReduce 0 [] (reverse ts) e
->         mergeEqns p f ts vs (Equation _ (FunLhs _ ts') rhs) =
->           Equation p (FunLhs f (ts ++ zipWith AsPattern vs ts')) rhs
->         etaReduce n vs (VariablePattern v : ts) (Apply e (Variable v'))
->           | qualify v == v' = etaReduce (n+1) (v:vs) ts e
->         etaReduce n vs ts e = (n,vs,reverse ts,e)
-> inlineFun _ _ _ _ p lhs rhs = [Equation p lhs rhs]
-
-> simplifyRhs :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Rhs -> SimplifyState Rhs
-> simplifyRhs flat m env (SimpleRhs p e _) =
->   do
->     e' <- simplifyExpr flat m env e
->     return (SimpleRhs p e' [])
-
-\end{verbatim}
-Variables that are bound to (simple) constants and aliases to other
-variables are substituted. In terms of conventional compiler
-technology these optimizations correspond to constant folding and copy
-propagation, respectively. The transformation is applied recursively
-to a substituted variable in order to handle chains of variable
-definitions.
-
-The bindings of a let expression are sorted topologically in
-order to split them into minimal binding groups. In addition,
-local declarations occurring on the right hand side of a pattern
-declaration are lifted into the enclosing binding group using the
-equivalence (modulo $\alpha$-conversion) of \texttt{let}
-$x$~=~\texttt{let} \emph{decls} \texttt{in} $e_1$ \texttt{in} $e_2$
-and \texttt{let} \emph{decls}\texttt{;} $x$~=~$e_1$ \texttt{in} $e_2$.
-This transformation avoids the creation of some redundant lifted
-functions in later phases of the compiler.
-\begin{verbatim}
-
-> simplifyExpr :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Expression
->              -> SimplifyState Expression
-> simplifyExpr _ _ _ (Literal l) = return (Literal l)
-> simplifyExpr flat m env (Variable v)
->   | isQualified v = return (Variable v)
->   | otherwise = maybe (return (Variable v)) (simplifyExpr flat m env)
->                       (Map.lookup (unqualify v) env)
-> simplifyExpr _ _ _ (Constructor c) = return (Constructor c)
-> simplifyExpr flags m env (Apply (Let ds e1) e2) 
->   = simplifyExpr flags m env (Let ds (Apply e1 e2))
-> simplifyExpr flags m env (Apply (Case r e1 alts) e2) 
->   = simplifyExpr flags m env (Case r e1 (map (applyToAlt e2) alts))
->   where applyToAlt e (Alt p t rhs) = Alt p t (applyRhs rhs e)
->         applyRhs (SimpleRhs p e1 _) e2 = SimpleRhs p (Apply e1 e2) []
-> simplifyExpr flat m env (Apply e1 e2) =
->   do
->     e1' <- simplifyExpr flat m env e1
->     e2' <- simplifyExpr flat m env e2
->     return (Apply e1' e2')
-> simplifyExpr flags m env (Let ds e) =
->   do
->     tyEnv <- S.get
->     dss' <- mapM (sharePatternRhs m tyEnv) ds
->     simplifyLet flags m env
->       (scc bv (qfv m) (foldr (hoistDecls flags) [] (concat dss'))) e
-> simplifyExpr flat m env (Case r e alts) =
->   do
->     e' <- simplifyExpr flat m env e
->     alts' <- mapM (simplifyAlt flat m env) alts
->     return (Case r e' alts')
-> 
-
-> simplifyAlt :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Alt -> SimplifyState Alt
-> simplifyAlt flat m env (Alt p t rhs) =
->   liftM (Alt p t) (simplifyRhs flat m env rhs)
-
-> hoistDecls :: SimplifyFlags -> Decl -> [Decl] -> [Decl]
-> hoistDecls flags (PatternDecl p t (SimpleRhs p' (Let ds e) _)) ds' 
->  = foldr (hoistDecls flags) ds' (PatternDecl p t (SimpleRhs p' e []) : ds)
-> hoistDecls _ d ds = d : ds
-
-\end{verbatim}
-The declaration groups of a let expression are first processed from
-outside to inside, simplifying the right hand sides and collecting
-inlineable expressions on the fly. At present, only simple constants
-and aliases to other variables are inlined. A constant is considered
-simple if it is either a literal, a constructor, or a non-nullary
-function. Note that it is not possible to define nullary functions in
-local declarations in Curry. Thus, an unqualified name always refers
-to either a variable or a non-nullary function.  Applications of
-constructors and partial applications of functions to at least one
-argument are not inlined because the compiler has to allocate space
-for them, anyway. In order to prevent non-termination, recursive
-binding groups are not processed.
-
-With the list of inlineable expressions, the body of the let is
-simplified and then the declaration groups are processed from inside
-to outside to construct the simplified, nested let expression. In
-doing so unused bindings are discarded. In addition, all pattern
-bindings are replaced by simple variable declarations using selector
-functions to access the pattern variables.
-\begin{verbatim}
-
-> simplifyLet :: SimplifyFlags -> ModuleIdent -> InlineEnv -> [[Decl]] -> Expression
->             -> SimplifyState Expression
-> simplifyLet flat m env [] e = simplifyExpr flat m env e
-> simplifyLet flags m env (ds:dss) e =
->   do
->     ds' <- mapM (simplifyDecl flags m env) ds
->     tyEnv <- S.get
->     e' <- simplifyLet flags m (inlineVars flags m tyEnv ds' env) dss e
->     dss'' <-
->       mapM (expandPatternBindings flags m tyEnv (qfv m ds' ++ qfv m e')) ds'
->     return (foldr (mkLet flags m) e' 
->                   (scc bv (qfv m) (concat dss'')))
-
-> inlineVars :: SimplifyFlags -> ModuleIdent -> ValueEnv -> [Decl] -> InlineEnv -> InlineEnv
-> inlineVars flags m tyEnv [PatternDecl _ (VariablePattern v) (SimpleRhs _ e _)] env
->   | canInline e = Map.insert v e env
->   where
->   canInline (Literal _) = True
->   canInline (Constructor _) = True
->   canInline _ = False -- inlining of variables is deactivated (hsi)
->   canInline (Variable v')
->       | isQualified v' = arrowArity (funType m tyEnv v') > 0
->       | otherwise = v /= unqualify v'
->   canInline _ = False
-> inlineVars _ _ _ _ env = env
-
-> mkLet :: SimplifyFlags -> ModuleIdent -> [Decl] -> Expression -> Expression
-> mkLet flags m [ExtraVariables p vs] e
->   | null vs' = e
->   | otherwise = Let [ExtraVariables p vs'] e
->   where vs' = filter (`elem` qfv m e) vs
-> mkLet flags m [PatternDecl _ (VariablePattern v) (SimpleRhs _ e _)] (Variable v')
->   | v' == qualify v && v `notElem` qfv m e = e
-> mkLet flags m ds e
->   | null (filter (`elem` qfv m e) (bv ds)) = e
->   | otherwise = Let ds e
-
-\end{verbatim}
-\label{pattern-binding}
-In order to implement lazy pattern matching in local declarations,
-pattern declarations $t$~\texttt{=}~$e$ where $t$ is not a variable
-are transformed into a list of declarations
-$v_0$~\texttt{=}~$e$\texttt{;} $v_1$~\texttt{=}~$f_1$~$v_0$\texttt{;}
-\dots{} $v_n$~\texttt{=}~$f_n$~$v_0$ where $v_0$ is a fresh variable,
-$v_1,\dots,v_n$ are the variables occurring in $t$ and the auxiliary
-functions $f_i$ are defined by $f_i$~$t$~\texttt{=}~$v_i$ (see also
-appendix D.8 of the Curry report~\cite{Hanus:Report}). The bindings
-$v_0$~\texttt{=}~$e$ are introduced before splitting the declaration
-groups of the enclosing let expression (cf. the \texttt{Let} case in
-\texttt{simplifyExpr} above) so that they are placed in their own
-declaration group whenever possible. In particular, this ensures that
-the new binding is discarded when the expression $e$ is itself a
-variable.
-
-Unfortunately, this transformation introduces a well-known space
-leak~\cite{Wadler87:Leaks,Sparud93:Leaks} because the matched
-expression cannot be garbage collected until all of the matched
-variables have been evaluated. Consider the following function:
-\begin{verbatim}
-  f x | all (' ' ==) cs = c where (c:cs) = x
-\end{verbatim}
-One might expect the call \verb|f (replicate 10000 ' ')| to execute in
-constant space because (the tail of) the long list of blanks is
-consumed and discarded immediately by \texttt{all}. However, the
-application of the selector function that extracts the head of the
-list is not evaluated until after the guard has succeeded and thus
-prevents the list from being garbage collected.
-
-In order to avoid this space leak we use the approach
-from~\cite{Sparud93:Leaks} and update all pattern variables when one
-of the selector functions has been evaluated. Therefore all pattern
-variables except for the matched one are passed as additional
-arguments to each of the selector functions. Thus, each of these
-variables occurs twice in the argument list of a selector function,
-once in the first argument and also as one of the remaining arguments.
-This duplication of names is used by the compiler to insert the code
-that updates the variables when generating abstract machine code.
-
-By its very nature, this transformation introduces cyclic variable
-bindings. Since cyclic bindings are not supported by PAKCS, we revert
-to a simpler translation when generating FlatCurry output.
-
-We will add only those pattern variables as additional arguments which
-are actually used in the code. This reduces the number of auxiliary
-variables and can prevent the introduction of a recursive binding
-group when only a single variable is used. It is also the reason for
-performing this transformation here instead of in the \texttt{Desugar}
-module. The selector functions are defined in a local declaration on
-the right hand side of a projection declaration so that there is
-exactly one declaration for each used variable.
-
-Another problem of the translation scheme is the handling of pattern
-variables with higher-order types, e.g.,
-\begin{verbatim}
-  strange :: [a->a] -> Maybe (a->a)
-  strange xs = Just x
-    where (x:_) = xs
-\end{verbatim}
-By reusing the types of the pattern variables, the selector function
-\verb|f (x:_) = x| has type \texttt{[a->a] -> a -> a} and therefore
-seems to be binary function. Thus, in the goal \verb|strange []| the
-selector is only applied partially and not evaluated. Note that this
-goal will fail without the type annotation. In order to ensure that a
-selector function is always evaluated when the corresponding variable
-is used, we assume that the projection declarations -- ignoring the
-additional arguments to prevent the space leak -- are actually defined
-by $f_i$~$t$~\texttt{= I}~$v_i$, using a private renaming type
-\begin{verbatim}
-  newtype Identity a = I a
-\end{verbatim}
-As newtype constructors are completely transparent to the compiler,
-this does not change the generated code, but only the types of the
-selector functions.
-\begin{verbatim}
-
-> sharePatternRhs :: ModuleIdent -> ValueEnv -> Decl -> SimplifyState [Decl]
-> sharePatternRhs m tyEnv (PatternDecl p t rhs) =
->   case t of
->     VariablePattern _ -> return [PatternDecl p t rhs]
->     _ -> 
->       do
->         v0 <- freshIdent m patternId (monoType (typeOf tyEnv t))
->         let v = addRefId (srcRefOf p) v0
->         return [PatternDecl p t (SimpleRhs p (mkVar v) []),
->                 PatternDecl p (VariablePattern v) rhs]
->   where patternId n = mkIdent ("_#pat" ++ show n)
-> sharePatternRhs _ _ d = return [d]
-
-> expandPatternBindings :: SimplifyFlags -> ModuleIdent -> ValueEnv -> [Ident] 
->    -> Decl -> SimplifyState [Decl]
->
-> expandPatternBindings flags m tyEnv fvs (PatternDecl p t (SimpleRhs p' e _)) =
->   case t of
->     VariablePattern _ -> return [PatternDecl p t (SimpleRhs p' e [])]
->     _
->       | flatFlag flags ->
->           do
->             fs <- sequence (zipWith getId tys vs)
->             return (zipWith (flatProjectionDecl p t e) fs vs)
->       | otherwise ->
->           do
->             fs <- mapM (freshIdent m fpSelectorId . selectorType ty)
->                        (shuffle tys)
->             return (zipWith (projectionDecl p t e) fs (shuffle vs))
->
->       where getId t v = freshIdent m 
->                            (\ i -> updIdentName ( ++'#':name v) (fpSelectorId i))
->                            (flatSelectorType ty t)
->             
->             vs = filter (`elem` fvs) (bv t)
->             ty = typeOf tyEnv t
->             tys = map (typeOf tyEnv) vs
->             selectorType ty0 (ty:tys) =
->               polyType (foldr TypeArrow (identityType ty) (ty0:tys))
->
->             selectorDecl p f t (v:vs) =
->               funDecl p f (t:map VariablePattern vs) (mkVar v)
->             projectionDecl p t e f (v:vs) =
->               varDecl p v (Let [selectorDecl p f t (v:vs)]
->                                (foldl applyVar (Apply (mkVar f) e) vs))
->
->             flatSelectorType ty0 ty =
->               polyType (TypeArrow ty0 (identityType ty))
->             flatSelectorDecl p f t v = funDecl p f [t] (mkVar v)
->             flatProjectionDecl p t e f v =
->               varDecl p v (Let [flatSelectorDecl p f t v] (Apply (mkVar f) e))
->
-> expandPatternBindings _ _ _ _ d = return [d]
-
-\end{verbatim}
-Auxiliary functions
-\begin{verbatim}
-
-> isVarPattern :: ConstrTerm -> Bool
-> isVarPattern (VariablePattern _) = True
-> isVarPattern (AsPattern _ t) = isVarPattern t
-> isVarPattern (ConstructorPattern _ _) = False
-> isVarPattern (LiteralPattern _) = False
-
-> funType :: ModuleIdent -> ValueEnv -> QualIdent -> Type
-> funType m tyEnv f =
->   case (qualLookupValue f tyEnv) of
->     [Value _ (ForAll _ ty)] -> ty
->     vs -> case (qualLookupValue (qualQualify m f) tyEnv) of
->             [Value _ (ForAll _ ty)] -> ty
->             _ -> internalError ("funType " ++ show f)
-
-> evMode :: EvalEnv -> Ident -> Maybe EvalAnnotation
-> evMode evEnv f = Map.lookup f evEnv
-
-> freshIdent :: ModuleIdent -> (Int -> Ident) -> TypeScheme
->            -> SimplifyState Ident
-> freshIdent m f ty =
->   do
->     x <- liftM f (S.lift (R.lift ( S.modify succ >> S.get)))
->     S.modify (bindFun m x ty)
->     return x
-
-> shuffle :: [a] -> [[a]]
-> shuffle xs = shuffle id xs
->   where shuffle _ [] = []
->         shuffle f (x:xs) = (x : f xs) : shuffle (f . (x:)) xs
-
-> mkVar :: Ident -> Expression
-> mkVar = Variable . qualify
-
-> applyVar :: Expression -> Ident -> Expression
-> applyVar e v = Apply e (mkVar v)
-
-> varDecl :: Position -> Ident -> Expression -> Decl
-> varDecl p v e = PatternDecl p (VariablePattern v) (SimpleRhs p e [])
-
-> funDecl :: Position -> Ident -> [ConstrTerm] -> Expression -> Decl
-> funDecl p f ts e =
->   FunctionDecl p f [Equation p (FunLhs f ts) (SimpleRhs p e [])]
-
-> identityType :: Type -> Type
-> identityType = TypeConstructor qIdentityId . return
->   where qIdentityId = qualify (mkIdent "Identity")
-
-\end{verbatim}
diff --git a/src/Subst.lhs b/src/Subst.lhs
deleted file mode 100644
--- a/src/Subst.lhs
+++ /dev/null
@@ -1,124 +0,0 @@
-% Copyright (c) 2002, Wolfgang Lux
-% See LICENSE for the full license.
-%
-\nwfilename{Subst.lhs}
-\section{Substitutions}
-The module {\tt Subst} implements substitutions. A substitution
-$\sigma = \left\{x_1\mapsto t_1,\dots,x_n\mapsto t_n\right\}$ is a
-finite mapping from (finitely many) variables $x_1,\dots,x_n$ to
-some kind of expression or term.
-
-In order to implement substitutions efficiently composed
-substitutions are marked with a boolean flag (see below).
-\begin{verbatim}
-
-> module Subst where
-
-> import qualified Data.Map as Map
-
-> data Subst a b = Subst Bool (Map.Map a b) deriving Show
-
-> idSubst :: Ord a => Subst a b
-> idSubst = Subst False Map.empty
-
-> substToList :: Ord v => Subst v e -> [(v,e)]
-> substToList (Subst _ sigma) = Map.toList sigma
-
-> bindSubst :: Ord v => v -> e -> Subst v e -> Subst v e
-> bindSubst v e (Subst comp sigma) = Subst comp (Map.insert v e sigma)
-
-> unbindSubst :: Ord v => v -> Subst v e -> Subst v e
-> unbindSubst v (Subst comp sigma) = Subst comp (Map.delete v sigma)
-
-\end{verbatim}
-For any substitution we have the following definitions:
-\begin{displaymath}
-  \begin{array}{l}
-    \sigma(x) = \left\{\begin{array}{ll}
-        t_i&\mbox{if $x=x_i$}\\
-        x&\mbox{otherwise}\end{array}\right. \\
-    \mathop{{\mathcal D}om}(\sigma) = \left\{x_1,\dots,x_n\right\} \\
-    \mathop{{\mathcal C}odom}(\sigma) = \left\{t_1,\dots,t_n\right\}
-  \end{array}  
-\end{displaymath}
-Note that obviously the set of variables must be a subset of the set
-of expressions. Also it is usually possible to extend the substitution
-to a homomorphism on the codomain of the substitution. This is
-captured by the following class declaration:
-\begin{verbatim}
-
-class Ord v => Subst v e where
-  var :: v -> e
-  subst :: Subst v e -> e -> e
-
-\end{verbatim}
-With the help of the injection \texttt{var}, we can then compute the
-substitution for a variable $\sigma(v)$ and also the composition of
-two substitutions
-$(\sigma_1 \circ \sigma_2)(e) \mathop{:=} \sigma_1(\sigma_2(e))$. A
-naive implementation of the composition were
-\begin{verbatim}
-  compose sigma sigma' =
-    foldr (uncurry bindSubst) sigma (substToList (fmap (subst sigma) sigma'))
-\end{verbatim}
-However, such an implementation is very inefficient because the
-number of substiutions applied to a variable increases in
-$\mathcal{O}(n)$ of the number of compositions.
-
-A more efficient implementation is to apply \texttt{subst} again to
-the value substituted for a variable in
-$\mathop{{\mathcal D}om}(\sigma)$. However, this is correct only as
-long as the result of the substitution does not include any variables
-which are in $\mathop{{\mathcal D}om}(\sigma)$. For instance, it is
-impossible to implement simple variable renamings in this way.
-
-Therefore we use the simple strategy to apply \texttt{subst} again
-only in case of a substitution which was returned from \texttt{compose}.
-\begin{verbatim}
-
-substVar :: Subst v e => Subst v e -> v -> e
-substVar (Subst comp sigma) v = maybe (var v) subst' (Map.lookup v sigma)
-  where subst' = if comp then subst (Subst comp sigma) else id
-
-> compose :: (Show v,Ord v,Show e) => Subst v e -> Subst v e -> Subst v e
-> compose sigma sigma' =
->   composed (foldr (uncurry bindSubst) sigma' (substToList sigma))
->   where dom = domain sigma
->         dom' = domain sigma'
->         domain = map fst . substToList
->         composed (Subst _ sigma) = Subst True sigma
-
-\end{verbatim}
-Unfortunately Haskell does not (yet) support multi-parameter type
-classes. For that reason we have to define a separate class for each
-kind of variable type for these functions. We implement
-\texttt{substVar} as a function that takes the class functions as an
-additional parameters. As an example for the use of this function the
-module includes a class \texttt{IntSubst} for substitution whose
-domain are integer numbers.
-\begin{verbatim}
-
-> substVar' :: Ord v => (v -> e) -> (Subst v e -> e -> e)
->           -> Subst v e -> v -> e
-> substVar' var subst (Subst comp sigma) v =
->   maybe (var v) subst' (Map.lookup v sigma)
->   where subst' = if comp then subst (Subst comp sigma) else id
-
-> class IntSubst e where
->   ivar :: Int -> e
->   isubst :: Subst Int e -> e -> e
-
-> isubstVar :: IntSubst e => Subst Int e -> Int -> e
-> isubstVar = substVar' ivar isubst
-
-\end{verbatim}
-The function \texttt{restrictSubstTo} implements the restriction of a
-substitution to a given subset of its domain.
-\begin{verbatim}
-
-> restrictSubstTo :: Ord v => [v] -> Subst v e -> Subst v e
-> restrictSubstTo vs (Subst comp sigma) =
->   foldr (uncurry bindSubst) (Subst comp Map.empty)
->         (filter ((`elem` vs) . fst) (Map.toList sigma))
-
-\end{verbatim}
diff --git a/src/SyntaxCheck.lhs b/src/SyntaxCheck.lhs
deleted file mode 100644
--- a/src/SyntaxCheck.lhs
+++ /dev/null
@@ -1,1149 +0,0 @@
-
-% $Id: SyntaxCheck.lhs,v 1.53 2004/02/15 22:10:37 wlux Exp $
-%
-% Copyright (c) 1999-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{SyntaxCheck.lhs}
-\section{Syntax Checks}
-After the type declarations have been checked, the compiler performs a
-syntax check on the remaining declarations. This check disambiguates
-nullary data constructors and variables which -- in contrast to
-Haskell -- is not possible on purely syntactic criteria. In addition,
-this pass checks for undefined as well as ambiguous variables and
-constructors. In order to allow lifting of local definitions in
-later phases, all local variables are renamed by adding a unique
-key.\footnote{Actually, all variables defined in the same scope share
-the same key.} Finally, all (adjacent) equations of a function are
-merged into a single definition.
-\begin{verbatim}
-
-> module SyntaxCheck(syntaxCheck) where
-
-> import Data.Maybe
-> import Data.List
-> import qualified Data.Map as Map
-> import Control.Monad.State as S
-
-> import Curry.Syntax
-> import Curry.Syntax.Utils
-> import Types
-> import Curry.Base.Position
-> import Curry.Base.Ident
-> import Base
-> import NestEnv
-> import Utils
-
-\end{verbatim}
-The syntax checking proceeds as follows. First, the compiler extracts
-information about all imported values and data constructors from the
-imported (type) environments. Next, the data constructors defined in
-the current module are entered into this environment. After this
-all record labels are entered into the environment too. If a record
-identifier is already assigned to a constructor, then an error will be
-generated. Finally, all
-declarations are checked within the resulting environment. In
-addition, this process will also rename the local variables.
-\begin{verbatim}
-
-> syntaxCheck :: Bool -> ModuleIdent -> ImportEnv -> ArityEnv -> ValueEnv -> TCEnv -> [Decl] -> [Decl]
-> syntaxCheck withExt m iEnv aEnv tyEnv tcEnv ds =
->   case findDouble (concatMap constrs tds) of
->     --Nothing -> tds ++ run (checkModule withExt m env vds)
->     Nothing -> map (checkTypeDecl withExt m) tds
->	        ++ run (checkModule withExt m env2 vds)
->     Just c -> errorAt' (duplicateData c)
->   where (tds,vds) = partition isTypeDecl ds
->	  (rs, tds') = partition isRecordDecl tds
->         env1 = foldr (bindTypes m) -- (bindConstrs m) 
->	               (globalEnv (fmap (renameInfo tcEnv iEnv aEnv) tyEnv)) 
->	               tds'
->	  env2 = foldr (bindTypes m) env1 rs
-
-\end{verbatim}
-A global state transformer is used for generating fresh integer keys
-by which the variables get renamed.
-\begin{verbatim}
-
-> type RenameState a = S.State Int a
-
-> run :: RenameState a -> a
-> run m = S.evalState m (globalKey + 1)
-
-> newId :: RenameState Int
-> newId = S.modify succ >> S.get
-
-\end{verbatim}
-\ToDo{Probably the state transformer should use an \texttt{Integer} 
-counter.}
-
-A nested environment is used for recording information about the data
-constructors and variables in the module. For every data constructor
-its arity is saved. This is used for checking that all constructor
-applications in patterns are saturated. For local variables the
-environment records the new name of the variable after renaming.
-Global variables are recorded with qualified identifiers in order
-to distinguish multiply declared entities.
-
-Currently records must explicitly be declared together with their labels.
-When constructing or updating a record, it is necessary to compute 
-all its labels using just one of them. Thus for each label 
-the record identifier and all its labels are entered into the environment
-
-\em{Note:} the function \texttt{qualLookupVar} has been extended to
-allow the usage of the qualified list constructor \texttt{(prelude.:)}.
-\begin{verbatim}
-
-> type RenameEnv = NestEnv RenameInfo
-> data RenameInfo = Constr Int 
->                 | GlobalVar Int QualIdent 
->                 | LocalVar Int Ident
->	          | RecordLabel QualIdent [Ident]
->	    deriving (Eq,Show)
-
-> globalKey :: Int
-> globalKey = uniqueId (mkIdent "")
-
-> renameInfo :: TCEnv -> ImportEnv -> ArityEnv -> ValueInfo -> RenameInfo
-> renameInfo tcEnv iEnv aEnv (DataConstructor _ (ForAllExist _ _ ty)) 
->    = Constr (arrowArity ty)
-> renameInfo tcEnv iEnv aEnv (NewtypeConstructor _ _) 
->    = Constr 1
-> renameInfo tcEnv iEnv aEnv (Value qid _)
->    = let (mmid, id) = (qualidMod qid, qualidId qid)
->          qid' = maybe qid 
->	                (\mid -> maybe qid 
->		                       (\mid' -> qualifyWith mid' id)
->				       (lookupAlias mid iEnv))
->		        mmid
->      in case (lookupArity id aEnv) of
->	    [ArityInfo _ arity] -> GlobalVar arity qid
->           rs -> case (qualLookupArity qid' aEnv) of
->	            [ArityInfo _ arity] -> GlobalVar arity qid
->	            _ -> maybe (internalError "renameInfo: missing arity")
->	                       (\ (ArityInfo _ arity) -> GlobalVar arity qid)
->		               (find (\ (ArityInfo qid'' _) 
->			              -> qid'' == qid) rs)
-> renameInfo tcEnv iEnv aEnv (Label l r _)
->    = case (qualLookupTC r tcEnv) of
->        [AliasType _ _ (TypeRecord fs _)] ->
->          RecordLabel r (map fst fs)
->        _ -> internalError "renameInfo: no record"
-
-\end{verbatim}
-Since record types are currently translated into data types, it is
-necessary to ensure that all identifiers for records and constructors
-are different. Furthermore it is not allowed to declare a label more
-than once.
-\begin{verbatim}
-
-> bindTypes :: ModuleIdent -> Decl -> RenameEnv -> RenameEnv
-> bindTypes m (DataDecl _ tc _ cs) env = foldr (bindConstr m) env cs
-> bindTypes m (NewtypeDecl _ tc _ nc) env = bindNewConstr m nc env
-> bindTypes m (TypeDecl _ t _ (RecordType fs r)) env =
->    -- - | isJust r = internalError "bindTypes: illegal record declaration"
->    -- - | null fs = errorAt (positionOfIdent t) emptyRecord
->    -- - | otherwise =
->      case (qualLookupVar (qualifyWith m t) env) of
->        [] -> foldr (bindRecordLabel m t (concatMap fst fs)) env fs
->        rs | any isConstr rs -> errorAt' (illegalRecordId t)
->           | otherwise
->             -> foldr (bindRecordLabel m t (concatMap fst fs)) env fs
-> bindTypes _ _ env = env
-
-> bindRecordLabel :: ModuleIdent -> Ident -> [Ident] 
->	             -> ([Ident],TypeExpr) -> RenameEnv -> RenameEnv
-> bindRecordLabel m t labels (ls,_) env = 
->     foldr (\l -> case (lookupVar l env) of
->                    [] -> bindGlobal m l
->                             (RecordLabel (qualifyWith m t) labels)
->                    _  -> errorAt' (duplicateDefinition l)
->	    ) env ls
-
-> --bindConstrs :: ModuleIdent -> Decl -> RenameEnv -> RenameEnv
-> --bindConstrs m (DataDecl _ tc _ cs) env = foldr (bindConstr m) env cs
-> --bindConstrs m (NewtypeDecl _ tc _ nc) env = bindNewConstr m nc env
-> --bindConstrs _ _ env = env
-
-> bindConstr :: ModuleIdent -> ConstrDecl -> RenameEnv -> RenameEnv
-> bindConstr m (ConstrDecl _ _ c tys) = bindGlobal m c (Constr (length tys))
-> bindConstr m (ConOpDecl _ _ _ op _) = bindGlobal m op (Constr 2)
-
-> bindNewConstr :: ModuleIdent -> NewConstrDecl -> RenameEnv -> RenameEnv
-> bindNewConstr m (NewConstrDecl _ _ c _) = bindGlobal m c (Constr 1)
-
-> bindFuncDecl :: ModuleIdent -> Decl -> RenameEnv -> RenameEnv
-> bindFuncDecl m (FunctionDecl _ id equs) env
->    | null equs = internalError "bindFuncDecl: missing equations"
->    | otherwise = let (_,ts) = getFlatLhs (head equs)
->		   in  bindGlobal m 
->	                          id 
->			          (GlobalVar (length ts) (qualifyWith m id))
->	                          env
-> bindFuncDecl m (ExternalDecl _ _ _ id texpr) env
->    = bindGlobal m id (GlobalVar (typeArity texpr) (qualifyWith m id)) env
-> bindFuncDecl m (TypeSig _ ids texpr) env
->    = foldr bindTS env (map (qualifyWith m) ids)
->  where
->  bindTS qid env 
->     | null (qualLookupVar qid env)
->       = bindGlobal m (unqualify qid) (GlobalVar (typeArity texpr) qid) env
->     | otherwise
->       = env
-> bindFuncDecl _ _ env = env
-
-> bindVarDecl :: Decl -> RenameEnv -> RenameEnv
-> bindVarDecl (FunctionDecl _ id equs) env
->    | null equs 
->      = internalError "bindFuncDecl: missing equations"
->    | otherwise 
->      = let (_,ts) = getFlatLhs (head equs)
->	 in  bindLocal (unRenameIdent id) (LocalVar (length ts) id) env
-> bindVarDecl (PatternDecl p t _) env
->    = foldr bindVar env (bv t)
-> bindVarDecl (ExtraVariables p vs) env
->    = foldr bindVar env vs 
-> bindVarDecl _ env = env
-
-> bindVar :: Ident -> RenameEnv -> RenameEnv
-> bindVar v env
->   | v' == anonId = env
->   | otherwise = bindLocal v' (LocalVar 0 v) env
->   where v' = unRenameIdent v
-
-> bindGlobal :: ModuleIdent -> Ident -> RenameInfo -> RenameEnv -> RenameEnv
-> bindGlobal m c r = bindNestEnv c r . qualBindNestEnv (qualifyWith m c) r
-
-> bindLocal :: Ident -> RenameInfo -> RenameEnv -> RenameEnv
-> bindLocal f r = bindNestEnv f r
-
-> lookupVar :: Ident -> RenameEnv -> [RenameInfo]
-> lookupVar v env = lookupNestEnv v env ++! lookupTupleConstr v
-
-> qualLookupVar :: QualIdent -> RenameEnv -> [RenameInfo]
-> qualLookupVar v env =
->   qualLookupNestEnv v env
->   ++! qualLookupListCons v env
->   ++! lookupTupleConstr (unqualify v)
-
-> qualLookupListCons :: QualIdent -> RenameEnv -> [RenameInfo]
-> qualLookupListCons v env
->    | (isJust mmid) && ((fromJust mmid) == preludeMIdent) && (ident == consId)
->       = qualLookupNestEnv (qualify ident) env
->    | otherwise = []
->  where (mmid, ident) = (qualidMod v, qualidId v)
-
-> lookupTupleConstr :: Ident -> [RenameInfo]
-> lookupTupleConstr v
->   | isTupleId v = [Constr (tupleArity v)]
->   | otherwise = []
-
-\end{verbatim}
-When a module is checked, the global declaration group is checked. The
-resulting renaming environment can be discarded. The same is true for
-a goal. Note that all declarations in the goal must be considered as
-local declarations.
-\begin{verbatim}
-
-> checkModule :: Bool -> ModuleIdent -> RenameEnv -> [Decl] -> RenameState [Decl]
-> checkModule withExt m env ds = liftM snd (checkTopDecls withExt m env ds)
-
-> checkTopDecls :: Bool -> ModuleIdent -> RenameEnv -> [Decl]
->               -> RenameState (RenameEnv,[Decl])
-> checkTopDecls withExt m env ds = 
->   checkDeclGroup (bindFuncDecl m) withExt m globalKey env ds
-
-> checkTypeDecl :: Bool -> ModuleIdent -> Decl -> Decl
-> checkTypeDecl withExt m d@(TypeDecl p r tvs (RecordType fs rty))
->   | not withExt = errorAt (positionOfIdent r) noRecordExt
->   | isJust rty = internalError "checkTypeDecl - illegal record type"
->   | null fs = errorAt (positionOfIdent r) emptyRecord
->   | otherwise = TypeDecl p r tvs (RecordType fs Nothing)
-> checkTypeDecl _ _ d = d
-
-\end{verbatim}
-Each declaration group opens a new scope and uses a distinct key
-for renaming the variables in this scope. In a declaration group,
-first the left hand sides of all declarations are checked, next the
-compiler checks that there is a definition for every type signature
-and evaluation annotation in this group. Finally, the right hand sides
-are checked and adjacent equations for the same function are merged
-into a single definition.
-
-The function \texttt{checkDeclLhs} also handles the case where a
-pattern declaration is recognized as a function declaration by the
-parser. This happens, e.g., for the declaration \verb|where Just x = y|
-because the parser cannot distinguish nullary constructors and
-functions. Note that pattern declarations are not allowed on the
-top-level.
-\begin{verbatim}
-
-> checkLocalDecls :: Bool -> ModuleIdent -> RenameEnv -> [Decl] 
->                  -> RenameState (RenameEnv,[Decl])
-> checkLocalDecls withExt m env ds =
->   newId >>= \k -> checkDeclGroup bindVarDecl withExt m k (nestEnv env) ds
-
-> checkDeclGroup :: (Decl -> RenameEnv -> RenameEnv) -> Bool -> ModuleIdent
->                 -> Int -> RenameEnv -> [Decl] 
->                 -> RenameState (RenameEnv,[Decl])
-> checkDeclGroup bindDecl withExt m k env ds =
->   mapM (checkDeclLhs withExt k m env) ds' >>=
->   checkDecls bindDecl withExt m env . joinEquations
->  where ds' = sortFuncDecls ds
-
-> checkDeclLhs :: Bool -> Int -> ModuleIdent -> RenameEnv -> Decl -> RenameState Decl
-> checkDeclLhs withExt k _ _ (InfixDecl p fix pr ops) =
->   return (InfixDecl p fix pr (map (flip renameIdent k) ops))
-> checkDeclLhs withExt k _ env (TypeSig p vs ty) =
->   return (TypeSig p (map (checkVar "type signature" k env) vs) ty)
-> checkDeclLhs withExt k _ env (EvalAnnot p fs ev) =
->   return (EvalAnnot p (map (checkVar "evaluation annotation" k env) fs) ev)
-> checkDeclLhs withExt k m env (FunctionDecl p _ eqs) = 
->   checkEquationLhs withExt k m env p eqs
-> checkDeclLhs withExt k _ env (ExternalDecl p cc ie f ty) =
->   return (ExternalDecl p cc ie (checkVar "external declaration" k env f) ty)
-> checkDeclLhs withExt k _ env (FlatExternalDecl p fs) =
->   return (FlatExternalDecl p
->             (map (checkVar "external declaration" k env) fs))
-> checkDeclLhs withExt k m env (PatternDecl p t rhs) =
->   do
->     t' <- checkConstrTerm withExt k p m env t
->     return (PatternDecl p t' rhs)
-> checkDeclLhs withExt k _ env (ExtraVariables p vs) =
->   return (ExtraVariables p
->             (map (checkVar "free variables declaration" k env) vs))
-> checkDeclLhs _ _ _ _ d = return d
-
-> checkEquationLhs :: Bool -> Int -> ModuleIdent -> RenameEnv -> Position 
->	           -> [Equation] -> RenameState Decl
-> checkEquationLhs withExt k m env p [Equation p' lhs rhs] =
->   either (return . funDecl) (checkDeclLhs withExt k m env . patDecl)
->          (checkEqLhs m k env p' lhs)
->   where funDecl (f,lhs) = FunctionDecl p f [Equation p' lhs rhs]
->         patDecl t
->           | k == globalKey = errorAt p noToplevelPattern
->           | otherwise = PatternDecl p' t rhs
-> checkEquationLhs _ _ _ _ _ _ = internalError "checkEquationLhs"
-
-> checkEqLhs :: ModuleIdent -> Int -> RenameEnv -> Position -> Lhs
->            -> Either (Ident,Lhs) ConstrTerm
-> checkEqLhs m k env _ (FunLhs f ts)
->   | isDataConstr f env
->     = if k /= globalKey
->       then Right (ConstructorPattern (qualify f) ts)
->       else if null (qualLookupVar (qualifyWith m f) env)
->            then Left (f',FunLhs f' ts)
->	     else errorAt (positionOfIdent f) noToplevelPattern
->   | otherwise = Left (f',FunLhs f' ts)
->   where f' = renameIdent f k
-> checkEqLhs m k env p (OpLhs t1 op t2)
->   | isDataConstr op env 
->     = if k /= globalKey
->       then checkOpLhs k env (infixPattern t1 (qualify op)) t2
->       else if null (qualLookupVar (qualifyWith m op) env)
->            then Left (op',OpLhs t1 op' t2)
->	     else errorAt p noToplevelPattern
->   | otherwise = Left (op',OpLhs t1 op' t2)
->   where op' = renameIdent op k
->         infixPattern (InfixPattern t1 op1 t2) op2 t3 =
->           InfixPattern t1 op1 (infixPattern t2 op2 t3)
->         infixPattern t1 op t2 = InfixPattern t1 op t2
-> checkEqLhs m k env p (ApLhs lhs ts) =
->   case checkEqLhs m k env p lhs of
->     Left (f',lhs') -> Left (f',ApLhs lhs' ts)
->     Right _ -> errorAt' $ nonVariable "curried definition" f
->   where (f,_) = flatLhs lhs
-
-> checkOpLhs :: Int -> RenameEnv -> (ConstrTerm -> ConstrTerm) -> ConstrTerm
->            -> Either (Ident,Lhs) ConstrTerm
-> checkOpLhs k env f (InfixPattern t1 op t2)
->   | isJust m || isDataConstr op' env =
->       checkOpLhs k env (f . InfixPattern t1 op) t2
->   | otherwise = Left (op'',OpLhs (f t1) op'' t2)
->   where (m,op') = (qualidMod op, qualidId op)
->         op'' = renameIdent op' k
-> checkOpLhs _ _ f t = Right (f t)
-
-> checkVar :: String -> Int -> RenameEnv -> Ident -> Ident
-> checkVar what k env v 
->   | False && isDataConstr v env = errorAt' (nonVariable what v)---------------
->   | otherwise = renameIdent v k
-
-
-> checkDecls :: (Decl -> RenameEnv -> RenameEnv) -> Bool -> ModuleIdent
->	        -> RenameEnv -> [Decl] -> RenameState (RenameEnv,[Decl])
-> checkDecls bindDecl withExt m env ds = 
->   case findDouble bvs of
->     Nothing ->
->       case findDouble tys of
->         Nothing ->
->           case findDouble evs of
->             Nothing ->
->               case filter (`notElem` tys) fs' of
->                 [] -> liftM ((,) env') 
->		              (mapM (checkDeclRhs withExt bvs m env'') ds)
->                 f : _ -> errorAt' (noTypeSig f)
->             Just v -> errorAt' (duplicateEvalAnnot v)
->         Just v -> errorAt' (duplicateTypeSig v)
->     Just v -> errorAt' (duplicateDefinition v)
->   where vds = filter isValueDecl ds
->	  tds = filter isTypeSig ds
->         bvs = concat (map vars vds)
->         tys = concat (map vars tds)
->         evs = concat (map vars (filter isEvalAnnot ds))
->         fs' = [f | FlatExternalDecl _ fs <- ds, f <- fs]
->         env' = foldr bindDecl env vds
->         env'' = foldr bindDecl env' tds
-
-> checkDeclRhs :: Bool -> [Ident] -> ModuleIdent -> RenameEnv -> Decl 
->              -> RenameState Decl
-> checkDeclRhs withExt bvs _ _ (TypeSig p vs ty) =
->   return (TypeSig p (map (checkLocalVar bvs ) vs) ty)
-> checkDeclRhs withExt bvs _ _ (EvalAnnot p vs ev) =
->   return (EvalAnnot p (map (checkLocalVar bvs ) vs) ev)
-> checkDeclRhs withExt _ m env (FunctionDecl p f eqs) =
->   liftM (FunctionDecl p f) (mapM (checkEquation withExt m env) eqs)
-> checkDeclRhs withExt _ m env (PatternDecl p t rhs) =
->   liftM (PatternDecl p t) (checkRhs withExt m env rhs)
-> checkDeclRhs _ _ _ _ d = return d
-
-> checkLocalVar :: [Ident] -> Ident -> Ident
-> checkLocalVar bvs v
->   | v `elem` bvs = v
->   | otherwise = errorAt' (noBody v)
-
-> joinEquations :: [Decl] -> [Decl]
-> joinEquations [] = []
-> joinEquations (FunctionDecl p f eqs : FunctionDecl p' f' [eq] : ds)
->   | f == f' =
->       if arity (head eqs) == arity eq then
->         joinEquations (FunctionDecl p f (eqs ++ [eq]) : ds)
->       else
->         errorAt' (differentArity f)
->   where arity (Equation _ lhs _) = length $ snd $ flatLhs lhs
-> joinEquations (d : ds) = d : joinEquations ds
-
-> checkEquation :: Bool -> ModuleIdent -> RenameEnv -> Equation -> RenameState Equation
-> checkEquation withExt m env (Equation p lhs rhs) =
->   do
->     (env',lhs') <- checkLhs withExt p m env lhs
->     rhs' <- checkRhs withExt m env' rhs
->     return (Equation p lhs' rhs')
-
-> checkLhs :: Bool -> Position -> ModuleIdent -> RenameEnv -> Lhs 
->             -> RenameState (RenameEnv,Lhs)
-> checkLhs withExt p m env lhs =
->   newId >>= \k ->
->   checkLhsTerm withExt k p m env lhs >>=
->   return . checkConstrTerms withExt (nestEnv env)
-
-> checkLhsTerm :: Bool -> Int -> Position -> ModuleIdent -> RenameEnv -> Lhs 
->                 -> RenameState Lhs
-> checkLhsTerm withExt k p m env (FunLhs f ts) =
->   do
->     ts' <- mapM (checkConstrTerm withExt k p m env) ts
->     return (FunLhs f ts')
-> checkLhsTerm withExt k p m env (OpLhs t1 op t2) =
->   let wrongCalls = concatMap (checkParenConstrTerm (Just (qualify op)))
->                               [t1,t2] in
->   if not (null wrongCalls)
->     then errorAt (positionOfIdent op) 
->                  (infixWithoutParens wrongCalls)
->     else  do
->       t1' <- checkConstrTerm withExt k p m env t1
->       t2' <- checkConstrTerm withExt k p m env t2 
->       return (OpLhs t1' op t2')
->
-> checkLhsTerm withExt k p m env (ApLhs lhs ts) =
->   do
->     lhs' <- checkLhsTerm withExt k p m env lhs
->     ts' <- mapM (checkConstrTerm withExt k p m env) ts
->     return (ApLhs lhs' ts')
-
-> checkArgs :: Bool -> Position -> ModuleIdent -> RenameEnv -> [ConstrTerm]
->           -> RenameState (RenameEnv,[ConstrTerm])
-> checkArgs withExt p m env ts =
->   newId >>= \k ->
->   mapM (checkConstrTerm withExt k p m env) ts >>=
->   return . checkConstrTerms withExt (nestEnv env)
-
-> checkConstrTerms :: QuantExpr t => Bool -> RenameEnv -> t
->                  -> (RenameEnv,t)
-> checkConstrTerms withExt env ts =
->   case findDouble bvs of
->     Nothing -> (foldr bindVar env bvs,ts)
->     Just v -> errorAt' (duplicateVariable v)
->   where bvs = bv ts
-
-> checkConstrTerm :: Bool -> Int -> Position -> ModuleIdent -> RenameEnv
->	             -> ConstrTerm -> RenameState ConstrTerm
-> checkConstrTerm _ _ _ _ _ (LiteralPattern l) =
->   liftM LiteralPattern (renameLiteral l)
-> checkConstrTerm _ _ _ _ _ (NegativePattern op l) =
->   liftM (NegativePattern op) (renameLiteral l)
-> checkConstrTerm withExt k p m env (VariablePattern v)
->   | v == anonId 
->     = liftM (VariablePattern . renameIdent anonId) newId
->   | otherwise 
->     = checkConstrTerm withExt k p m env (ConstructorPattern (qualify v) [])
-> checkConstrTerm withExt k p m env (ConstructorPattern c ts) =
->   case qualLookupVar c env of
->     [Constr n]
->       | n == n' ->
->           liftM (ConstructorPattern c) 
->	          (mapM (checkConstrTerm withExt k p m env) ts)
->       | otherwise -> errorAt' (wrongArity c n n')
->       where n' = length ts
->     [r]
->       | null ts && not (isQualified c) ->
->	    return (VariablePattern (renameIdent (varIdent r) k))
->       | withExt ->
->           do ts' <- mapM (checkConstrTerm withExt k p m env) ts
->	       if n' > n
->	          then let (ts1,ts2) = splitAt n ts'
->	               in  return (genFuncPattAppl 
->			             (FunctionPattern (qualVarIdent r) 
->				                      ts1) 
->	                             ts2)
->	          else return (FunctionPattern (qualVarIdent r) ts')
->       | otherwise -> errorAt (positionOfQualIdent c) noFuncPattExt  
->	where n = arity r
->	      n' = length ts
->     rs -> case (qualLookupVar (qualQualify m c) env) of
->             []
->               | null ts && not (isQualified c) ->
->	            return (VariablePattern (renameIdent (unqualify c) k))
->	        | null rs -> errorAt' (undefinedData c)
->		| otherwise -> errorAt' (ambiguousData c)
->             [Constr n]
->               | n == n' ->
->                   liftM (ConstructorPattern (qualQualify m c)) 
->                         (mapM (checkConstrTerm withExt k p m env) ts)
->               | otherwise -> errorAt' (wrongArity c n n')
->               where n' = length ts
->	      [r]
->	        | null ts && not (isQualified c) ->
->                   return (VariablePattern (renameIdent (varIdent r) k))
->               | withExt ->
->	            do ts' <- mapM (checkConstrTerm withExt k p m env) ts
->	               if n' > n
->	                  then let (ts1,ts2) = splitAt n ts'
->	                       in  return 
->			             (genFuncPattAppl 
->			                (FunctionPattern (qualVarIdent r) ts1) 
->	                                ts2)
->	                  else return (FunctionPattern (qualVarIdent r) ts')
->	        | otherwise -> errorAt (positionOfQualIdent c) noFuncPattExt
->               where n = arity r
->		      n' = length ts
->             _ -> errorAt' (ambiguousData c)
-> checkConstrTerm withExt k p m env (InfixPattern t1 op t2) =
->   case (qualLookupVar op env) of
->     [Constr n]
->       | n == 2 ->
->           do t1' <- checkConstrTerm withExt k p m env t1
->	       t2' <- checkConstrTerm withExt k p m env t2
->              return (InfixPattern t1' op t2') 
->       | otherwise -> errorAt' (wrongArity op n 2)
->     [r]
->       | withExt ->
->           do t1' <- checkConstrTerm withExt k p m env t1
->	       t2' <- checkConstrTerm withExt k p m env t2
->              return (InfixFuncPattern t1' op t2')
->       | otherwise -> errorAt p noFuncPattExt    
->     rs -> case (qualLookupVar (qualQualify m op) env) of
->             [] | null rs -> errorAt' (undefinedData op)
->                | otherwise -> errorAt' (ambiguousData op)
->             [Constr n]
->               | n == 2 ->
->                   do t1' <- checkConstrTerm withExt k p m env t1
->	               t2' <- checkConstrTerm withExt k p m env t2
->                      return (InfixPattern t1' (qualQualify m op) t2') 
->               | otherwise -> errorAt' (wrongArity op n 2)
->	      [r]
->               | withExt ->
->	            do t1' <- checkConstrTerm withExt k p m env t1
->	               t2' <- checkConstrTerm withExt k p m env t2
->		       return (InfixFuncPattern t1' (qualQualify m op) t2')
->	        | otherwise -> errorAt p noFuncPattExt
->             _ -> errorAt' (ambiguousData op)
-> checkConstrTerm withExt k p m env (ParenPattern t) =
->   liftM ParenPattern (checkConstrTerm withExt k p m env t)
-> checkConstrTerm withExt k p m env (TuplePattern pos ts) =
->   liftM (TuplePattern pos) (mapM (checkConstrTerm withExt k p m env) ts)
-> checkConstrTerm withExt k p m env (ListPattern pos ts) =
->   liftM (ListPattern pos) (mapM (checkConstrTerm withExt k p m env) ts)
-> checkConstrTerm withExt k p m env (AsPattern v t) =
->   liftM (AsPattern (checkVar "@ pattern" k env v))
->         (checkConstrTerm withExt k p m env t)
-> checkConstrTerm withExt k p m env (LazyPattern pos t) =
->   liftM (LazyPattern pos) (checkConstrTerm withExt k p m env t)
-> checkConstrTerm withExt k p m env (RecordPattern fs t)
->   | not withExt = errorAt p noRecordExt
->   | not (null fs) =
->     let (Field _ label _) = head fs
->     in  case (lookupVar label env) of
->           [] -> errorAt' (undefinedLabel label)
->           [RecordLabel r ls]
->             | not (null duplicates) ->
->	        errorAt' (duplicateLabel (head duplicates))
->	      | isNothing t && not (null missings) ->
->	        errorAt (positionOfIdent label) 
->                       (missingLabel (head missings) r "record pattern")
->             | maybe True ((==) (VariablePattern anonId)) t ->
->	        do fs' <- mapM (checkFieldPatt withExt k m r env) fs
->	           t'  <- maybe (return Nothing)
->	                        (\t' -> checkConstrTerm withExt k p m env t'
->			                >>= return . Just)
->			        t
->	           return (RecordPattern fs' t')
->	      | otherwise -> errorAt p illegalRecordPatt
->            where ls' = map fieldLabel fs
->                  duplicates = maybeToList (dup ls')
->		   missings = ls \\ ls'
->	    [_] -> errorAt' (notALabel label)
->	    _ -> errorAt' (duplicateDefinition label)
->   | otherwise = errorAt p emptyRecord
-
-> checkFieldPatt :: Bool -> Int -> ModuleIdent -> QualIdent -> RenameEnv
->	            -> Field ConstrTerm -> RenameState (Field ConstrTerm)
-> checkFieldPatt withExt k m r env (Field p l t)
->    = case (lookupVar l env) of
->        [] -> errorAt' (undefinedLabel l)
->        [RecordLabel r' _]
->          | r == r' -> do t' <- checkConstrTerm withExt k 
->                                   (positionOfIdent l) m env t
->		           return (Field p l t')
->          | otherwise -> errorAt' (illegalLabel l r)
->        [_] -> errorAt' (notALabel l)
->	 _ -> errorAt' (duplicateDefinition l)
-
-> checkRhs :: Bool -> ModuleIdent -> RenameEnv -> Rhs -> RenameState Rhs
-> checkRhs withExt m env (SimpleRhs p e ds) =
->   do
->     (env',ds') <- checkLocalDecls withExt m env ds
->     e' <- checkExpr withExt p m env' e
->     return (SimpleRhs p e' ds')
-> checkRhs withExt m env (GuardedRhs es ds) =
->   do
->     (env',ds') <- checkLocalDecls withExt m env ds
->     es' <- mapM (checkCondExpr withExt m env') es
->     return (GuardedRhs es' ds')
-
-> checkCondExpr :: Bool -> ModuleIdent -> RenameEnv -> CondExpr -> RenameState CondExpr
-> checkCondExpr withExt m env (CondExpr p g e) =
->   do
->     g' <- checkExpr withExt p m env g
->     e' <- checkExpr withExt p m env e
->     return (CondExpr p g' e')
-
-> checkExpr :: Bool -> Position -> ModuleIdent -> RenameEnv -> Expression 
->           -> RenameState Expression
-> checkExpr _ _ _ _ (Literal l) = liftM Literal (renameLiteral l)
-> checkExpr withExt _ m env (Variable v) =
->   case (qualLookupVar v env) of
->     [] ->  errorAt' (undefinedVariable v)
->     [Constr _] -> return (Constructor v)
->     [GlobalVar _ _] -> return (Variable v)
->     [LocalVar _ v'] -> return (Variable (qualify v'))
->     rs -> case (qualLookupVar (qualQualify m v) env) of
->             [] -> errorAt' (ambiguousIdent rs v)
->             [Constr _] -> return (Constructor v)
->             [GlobalVar _ _] -> return (Variable v)
->             [LocalVar _ v'] -> return (Variable (qualify v'))
->             rs' -> errorAt' (ambiguousIdent rs' v)
-> checkExpr withExt p m env (Constructor c) = 
->   checkExpr withExt p m env (Variable c)
-> checkExpr withExt p m env (Paren e) = 
->   liftM Paren (checkExpr withExt p m env e)
-> checkExpr withExt p m env (Typed e ty) = 
->   liftM (flip Typed ty) (checkExpr withExt p m env e)
-> checkExpr withExt p m env (Tuple pos es) = 
->   liftM (Tuple pos) (mapM (checkExpr withExt p m env) es)
-> checkExpr withExt p m env (List pos es) = 
->   liftM (List pos) (mapM (checkExpr withExt p m env) es)
-> checkExpr withExt p m env (ListCompr pos e qs) =
->   do
->     (env',qs') <- mapAccumM (checkStatement withExt p m) env qs
->     e' <- checkExpr withExt p m env' e
->     return (ListCompr pos e' qs')
-> checkExpr withExt p m env (EnumFrom e) = 
->   liftM EnumFrom (checkExpr withExt p m env e)
-> checkExpr withExt p m env (EnumFromThen e1 e2) =
->   do
->     e1' <- checkExpr withExt p m env e1
->     e2' <- checkExpr withExt p m env e2
->     return (EnumFromThen e1' e2')
-> checkExpr withExt p m env (EnumFromTo e1 e2) =
->   do
->     e1' <- checkExpr withExt p m env e1
->     e2' <- checkExpr withExt p m env e2
->     return (EnumFromTo e1' e2')
-> checkExpr withExt p m env (EnumFromThenTo e1 e2 e3) =
->   do
->     e1' <- checkExpr withExt p m env e1
->     e2' <- checkExpr withExt p m env e2
->     e3' <- checkExpr withExt p m env e3
->     return (EnumFromThenTo e1' e2' e3')
-> checkExpr withExt p m env (UnaryMinus op e) = 
->   liftM (UnaryMinus op) (checkExpr withExt p m env e)
-> checkExpr withExt p m env (Apply e1 e2) =
->   do
->     e1' <- checkExpr withExt p m env e1
->     e2' <- checkExpr withExt p m env e2
->     return (Apply e1' e2')
-> checkExpr withExt p m env (InfixApply e1 op e2) =
->   do
->     e1' <- checkExpr withExt p m env e1
->     e2' <- checkExpr withExt p m env e2
->     return (InfixApply e1' (checkOp m env op) e2')
-> checkExpr withExt p m env (LeftSection e op) =
->   liftM (flip LeftSection (checkOp m env op)) (checkExpr withExt p m env e)
-> checkExpr withExt p m env (RightSection op e) =
->   liftM (RightSection (checkOp m env op)) (checkExpr withExt p m env e)
-> checkExpr withExt p m env (Lambda r ts e) =
->   do
->     (env',ts') <- checkArgs withExt p m env ts
->     e' <- checkExpr withExt p m env' e
->     return (Lambda r ts' e')
-> checkExpr withExt p m env (Let ds e) =
->   do
->     (env',ds') <- checkLocalDecls withExt m env ds
->     e' <- checkExpr withExt p m env' e
->     return (Let ds' e')
-> checkExpr withExt p m env (Do sts e) =
->   do
->     (env',sts') <- mapAccumM (checkStatement withExt p m) env sts
->     e' <- checkExpr withExt p m env' e
->     return (Do sts' e')
-> checkExpr withExt p m env (IfThenElse r e1 e2 e3) =
->   do
->     e1' <- checkExpr withExt p m env e1
->     e2' <- checkExpr withExt p m env e2
->     e3' <- checkExpr withExt p m env e3
->     return (IfThenElse r e1' e2' e3')
-> checkExpr withExt p m env (Case r e alts) =
->   do
->     e' <- checkExpr withExt p m env e
->     alts' <- mapM (checkAlt withExt m env) alts
->     return (Case r e' alts')
-> checkExpr withExt p m env (RecordConstr fs)
->   | not withExt = errorAt p noRecordExt
->   | not (null fs) = 
->     let (Field _ label _) = head fs
->     in  case (lookupVar label env) of
->           [] -> errorAt' (undefinedLabel label)
->	    [RecordLabel r ls]
->              | not (null duplicates) ->
->                errorAt' (duplicateLabel (head duplicates))
->              | not (null missings) ->
->	         errorAt (positionOfIdent label) 
->                        (missingLabel (head missings) r "record construction")
->	       | otherwise ->
->	         do fs' <- mapM (checkFieldExpr withExt m r env) fs
->	            return (RecordConstr fs')
->	      where ls' = map fieldLabel fs
->	            duplicates = maybeToList (dup ls')
->		    missings = ls \\ ls'
->           [_] -> errorAt' (notALabel label)
->	    _ -> errorAt' (duplicateDefinition label)
->   | otherwise = errorAt p emptyRecord
-> checkExpr withExt p m env (RecordSelection e l)
->   | not withExt = errorAt p noRecordExt
->   | otherwise =
->     case (lookupVar l env) of
->       [] -> errorAt' (undefinedLabel l)
->       [RecordLabel r ls] ->
->         do e' <- checkExpr withExt p m env e
->            return (RecordSelection e' l)
->       [_] -> errorAt' (notALabel l)
->       _ -> errorAt' (duplicateDefinition l)
-> checkExpr withExt p m env (RecordUpdate fs e)
->   | not withExt = errorAt p noRecordExt
->   | not (null fs) =
->     let (Field _ label _) = head fs
->     in  case (lookupVar label env) of
->           [] -> errorAt' (undefinedLabel label)
->	    [RecordLabel r ls]
->             | not (null duplicates) ->
->	        errorAt' (duplicateLabel (head duplicates))
->	      | otherwise ->
->	        do fs' <- mapM (checkFieldExpr withExt m r env) fs
->	           e' <- checkExpr withExt (positionOfIdent label) m env e
->	           return (RecordUpdate fs' e')
->	      where duplicates = maybeToList (dup (map fieldLabel fs))
->	    [_] -> errorAt' (notALabel label)
->	    _ -> errorAt' (duplicateDefinition label)
->   | otherwise = errorAt p emptyRecord
-
-> checkStatement :: Bool -> Position -> ModuleIdent -> RenameEnv -> Statement
->                -> RenameState (RenameEnv,Statement)
-> checkStatement withExt p m env (StmtExpr pos e) =
->   do
->     e' <- checkExpr withExt p m env e
->     return (env,StmtExpr pos e')
-> checkStatement withExt p m env (StmtBind pos t e) =
->   do
->     e' <- checkExpr withExt p m env e
->     (env',[t']) <- checkArgs withExt p m env [t]
->     return (env',StmtBind pos t' e')
-> checkStatement withExt _ m env (StmtDecl ds) =
->   do
->     (env',ds') <- checkLocalDecls withExt m env ds
->     return (env',StmtDecl ds')
-
-> checkAlt :: Bool -> ModuleIdent -> RenameEnv -> Alt -> RenameState Alt
-> checkAlt withExt m env (Alt p t rhs) =
->   do
->     (env',[t']) <- checkArgs withExt p m env [t]
->     rhs' <- checkRhs withExt m env' rhs
->     return (Alt p t' rhs')
-
-> checkFieldExpr :: Bool -> ModuleIdent -> QualIdent -> RenameEnv 
->	            -> Field Expression -> RenameState (Field Expression)
-> checkFieldExpr withExt m r env (Field p l e)
->    = case (lookupVar l env) of
->        [] -> errorAt' (undefinedLabel l)
->        [RecordLabel r' _]
->          | r == r' -> do e' <- checkExpr withExt (positionOfIdent l) m env e
->		           return (Field p l e')
->          | otherwise -> errorAt' (illegalLabel l r)
->        [_] -> errorAt' (notALabel l)
->	 _ -> errorAt' (duplicateDefinition l)
-
-
-> checkOp :: ModuleIdent -> RenameEnv -> InfixOp -> InfixOp
-> checkOp m env op =
->   case (qualLookupVar v env) of
->     [] -> errorAt' (undefinedVariable v)
->     [Constr _] -> InfixConstr v
->     [GlobalVar _ _] -> InfixOp v
->     [LocalVar _ v'] -> InfixOp (qualify v')
->     rs -> case (qualLookupVar (qualQualify m v) env) of
->             [] -> errorAt' (ambiguousIdent rs v)
->             [Constr _] -> InfixConstr v
->             [GlobalVar _ _] -> InfixOp v
->             [LocalVar _ v'] -> InfixOp (qualify v')
->             rs' -> errorAt' (ambiguousIdent rs' v)
->   where v = opName op
-
-\end{verbatim}
-Auxiliary definitions.
-\begin{verbatim}
-
-> constrs :: Decl -> [Ident]
-> constrs (DataDecl _ _ _ cs) = map constr cs
->   where constr (ConstrDecl _ _ c _) = c
->         constr (ConOpDecl _ _ _ op _) = op
-> constrs (NewtypeDecl _ _ _ (NewConstrDecl _ _ c _)) = [c]
-> constrs _ = []
-
-> vars :: Decl -> [Ident]
-> vars (TypeSig p fs _) = fs
-> vars (EvalAnnot p fs _) = fs
-> vars (FunctionDecl p f _) = [f]
-> vars (ExternalDecl p _ _ f _) = [f]
-> vars (FlatExternalDecl p fs) = fs
-> vars (PatternDecl p t _) = (bv t)
-> vars (ExtraVariables p vs) = vs
-> vars _ = []
-
-> renameLiteral :: Literal -> RenameState Literal
-> renameLiteral (Int v i) = liftM (flip Int i . renameIdent v) newId
-> renameLiteral l = return l
-
-
-Since the compiler expects all rules of the same function to be together,
-it is necessary to sort the list of declarations.
-
-> sortFuncDecls :: [Decl] -> [Decl]
-> sortFuncDecls decls = sortFD Map.empty [] decls
->  where
->  sortFD env res [] = reverse res
->  sortFD env res (decl:decls)
->     = case decl of
->	  FunctionDecl _ ident _
->	     | isJust (Map.lookup ident env)
->	       -> sortFD env (insertBy cmpFuncDecl decl res) decls
->	     | otherwise
->              -> sortFD (Map.insert ident () env) (decl:res) decls
->	  _    -> sortFD env (decl:res) decls
-
-> cmpFuncDecl :: Decl -> Decl -> Ordering
-> cmpFuncDecl (FunctionDecl _ id1 _) (FunctionDecl _ id2 _)
->    | id1 == id2 = EQ
->    | otherwise  = GT
-> cmpFuncDecl decl1 decl2 = GT
-
-cmpPos :: Position -> Position -> Ordering
-cmpPos p1 p2 | lp1 < lp2  = LT
-             | lp1 == lp2 = EQ
-             | otherwise  = GT
- where lp1 = line p1
-       lp2 = line p2
-
-
-\end{verbatim}
-Due to the lack of a capitalization convention in Curry, it is
-possible that an identifier may ambiguously refer to a data
-constructor and a function provided that both are imported from some
-other module. When checking whether an identifier denotes a
-constructor there are two options with regard to ambiguous
-identifiers:
-\begin{enumerate}
-\item Handle the identifier as a data constructor if at least one of
-  the imported names is a data constructor.
-\item Handle the identifier as a data constructor only if all imported
-  entities are data constructors.
-\end{enumerate}
-We choose the first possibility here because in the second case a
-redefinition of a constructor can magically become possible if a
-function with the same name is imported. It seems better to warn
-the user about the fact that the identifier is ambiguous.
-\begin{verbatim}
-
-> isDataConstr :: Ident -> RenameEnv -> Bool
-> isDataConstr v = any isConstr . lookupVar v . globalEnv . toplevelEnv
-
-> isConstr :: RenameInfo -> Bool
-> isConstr (Constr _) = True
-> isConstr (GlobalVar _ _) = False
-> isConstr (LocalVar _ _) = False
-> isConstr (RecordLabel _ _) = False
-
-> varIdent :: RenameInfo -> Ident
-> varIdent (GlobalVar _ v) = unqualify v
-> varIdent (LocalVar _ v) =  v
-> varIdent _ = internalError "not a variable"
-
-> qualVarIdent :: RenameInfo -> QualIdent
-> qualVarIdent (GlobalVar _ v) = v
-> qualVarIdent (LocalVar _ v) = qualify v
-> qualVarIdent _ = internalError "not a qualified variable"
-
-> arity :: RenameInfo -> Int
-> arity (Constr n) = n
-> arity (GlobalVar n _) = n
-> arity (LocalVar n _) = n
-> arity (RecordLabel _ ls) = length ls
-
-\end{verbatim}
-Unlike expressions, constructor terms have no possibility to represent
-over-applications in function patterns. Therefore it is necessary to
-transform them to nested
-function patterns using the prelude function \texttt{apply}. E.g. the
-the function pattern \texttt{(id id 10)} is transformed to
-\texttt{(apply (id id) 10)}
-\begin{verbatim}
-
-> genFuncPattAppl :: ConstrTerm -> [ConstrTerm] -> ConstrTerm
-> genFuncPattAppl term [] = term
-> genFuncPattAppl term (t:ts) 
->    = FunctionPattern qApplyId [genFuncPattAppl term ts, t]
->  where
->  qApplyId = qualifyWith preludeMIdent (mkIdent "apply")
-
-\end{verbatim}
-Miscellaneous functions.
-\begin{verbatim}
-
-> typeArity :: TypeExpr -> Int
-> typeArity (ArrowType _ t2) = 1 + typeArity t2
-> typeArity _                = 0
-
-> getFlatLhs :: Equation -> (Ident,[ConstrTerm])
-> getFlatLhs (Equation  _ lhs _) = flatLhs lhs
-
-> dup :: Eq a => [a] -> Maybe a
-> dup [] = Nothing
-> dup (x:xs) | elem x xs = Just x
->            | otherwise = dup xs
-
-\end{verbatim}
-Error messages.
-\begin{verbatim}
-
-> undefinedVariable :: QualIdent -> (Position,String)
-> undefinedVariable v = 
->     (positionOfQualIdent v,
->      qualName v ++ " is undefined")
-
-> undefinedData :: QualIdent -> (Position,String)
-> undefinedData c =  
->     (positionOfQualIdent c,
->      "Undefined data constructor " ++ qualName c)
-
-> undefinedLabel :: Ident -> (Position,String)
-> undefinedLabel l =   
->     (positionOfIdent l,
->      "Undefined record label `" ++ name l ++ "`")
-
-> ambiguousIdent :: [RenameInfo] -> QualIdent -> (Position,String)
-> ambiguousIdent rs
->   | any isConstr rs = ambiguousData
->   | otherwise = ambiguousVariable
-
-> ambiguousVariable :: QualIdent -> (Position,String)
-> ambiguousVariable v =  
->     (positionOfQualIdent v,
->      "Ambiguous variable " ++ qualName v)
-
-> ambiguousData :: QualIdent -> (Position,String)
-> ambiguousData c =  
->     (positionOfQualIdent c,
->      "Ambiguous data constructor " ++ qualName c)
-
-> duplicateDefinition :: Ident -> (Position,String)
-> duplicateDefinition v =
->     (positionOfIdent v,
->      "More than one definition for `" ++ name v ++ "`")
-
-> duplicateVariable :: Ident -> (Position,String)
-> duplicateVariable v = 
->     (positionOfIdent v,
->      name v ++ " occurs more than once in pattern")
-
-> duplicateData :: Ident -> (Position,String)
-> duplicateData c = 
->     (positionOfIdent c,
->      "More than one definition for data constructor `"
->	            ++ name c ++ "`")
-
-> duplicateTypeSig :: Ident -> (Position,String)
-> duplicateTypeSig v =  
->     (positionOfIdent v,
->      "More than one type signature for `" ++ name v ++ "`")
-
-> duplicateEvalAnnot :: Ident -> (Position,String)
-> duplicateEvalAnnot v =   
->     (positionOfIdent v,
->      "More than one eval annotation for `" ++ name v ++ "`")
-
-> duplicateLabel :: Ident -> (Position,String)
-> duplicateLabel l =   
->     (positionOfIdent l,
->      "Multiple occurrence of record label `" ++ name l ++ "`")
-
-> missingLabel :: Ident -> QualIdent -> String -> String 
-> missingLabel l r what = 
->     "Missing label `" ++ name l 
->     ++ "` in the " ++ what ++ " of `" 
->     ++ name (unqualify r) ++ "`" --qualName r
-
-
-> illegalLabel :: Ident -> QualIdent -> (Position,String)
-> illegalLabel l r =   
->     (positionOfIdent l,
->      "Label `" ++ name l ++ "` is not defined in record `" 
->	     ++ name (unqualify r) ++ "`") --qualName r
-
-> illegalRecordId :: Ident -> (Position,String)
-> illegalRecordId r = 
->    (positionOfIdent r,
->     "Record identifier `" ++ name r 
->	      ++ "` already assigned to a data constructor")
-
-> nonVariable :: String -> Ident -> (Position,String)
-> nonVariable what c = 
->  (positionOfIdent c,     
->   "Data constructor `" ++ name c ++ "` in left hand side of " ++ what)
-
-> noBody :: Ident -> (Position,String)
-> noBody v = 
->  (positionOfIdent v,     
->   "No body for `" ++ name v ++ "`")
-
-> noTypeSig :: Ident -> (Position,String)
-> noTypeSig f = 
->  (positionOfIdent f,     
->   "No type signature for external function `" ++ name f ++ "`")
-
-> noToplevelPattern :: String
-> noToplevelPattern = "Pattern declaration not allowed at top-level"
-
-> notALabel :: Ident -> (Position,String)
-> notALabel l =  
->  (positionOfIdent l,     
->   "`" ++ name l ++ "` is not a record label")
-
-> emptyRecord :: String
-> emptyRecord = "empty records are not allowed"
-
-> differentArity :: Ident -> (Position,String)
-> differentArity f =   
->  (positionOfIdent f,     
->   "Equations for `" ++ name f ++ "` have different arities")
-
-> wrongArity :: QualIdent -> Int -> Int -> (Position,String)
-> wrongArity c arity argc =  
->  (positionOfQualIdent c,    
->   "Data constructor " ++ qualName c ++ " expects " ++ arguments arity ++
->   " but is applied to " ++ show argc)
->   where arguments 0 = "no arguments"
->         arguments 1 = "1 argument"
->         arguments n = show n ++ " arguments"
-
-> illegalRecordPatt :: String
-> illegalRecordPatt = "Expexting `_` after `|` in the record pattern"
-
-> noFuncPattExt :: String
-> noFuncPattExt = "function patterns are not supported in standard curry"
->	        ++ extMessage
-
-> noRecordExt :: String
-> noRecordExt = "records are not supported in standard curry"
->             ++ extMessage
-
-> extMessage :: String
-> extMessage = "\n(Use flag -e to enable extended curry)"
-
-> infixWithoutParens :: [(QualIdent,QualIdent)] -> String
-> infixWithoutParens calls =
->     "Missing parens in infix patterns: \n" ++
->     unlines (map (\(q1,q2) -> show q1 ++ " " ++ 
->                               showLine (positionOfQualIdent q1) ++ 
->                               "calls " ++ show q2 ++ " " ++ 
->                               showLine (positionOfQualIdent q2)) calls)
-
-\end{verbatim}
-
-checkParen 
-@param Aufrufende InfixFunktion
-@param ConstrTerm
-@return Liste mit fehlerhaften Funktionsaufrufen
-\begin{verbatim}
-
-> checkParenConstrTerm :: (Maybe QualIdent) -> ConstrTerm -> [(QualIdent,QualIdent)]
-> checkParenConstrTerm _ (LiteralPattern _) = []
-> checkParenConstrTerm _ (NegativePattern _ _) = []
-> checkParenConstrTerm _ (VariablePattern _) = []
-> checkParenConstrTerm _ (ConstructorPattern qualIdent constrTerms) =
->     concatMap (checkParenConstrTerm Nothing) constrTerms
-> checkParenConstrTerm mCaller (InfixPattern constrTerm1 qualIdent constrTerm2) =
->     maybe [] (\c -> [(c,qualIdent)]) mCaller ++
->     checkParenConstrTerm Nothing constrTerm1 ++
->     checkParenConstrTerm Nothing constrTerm2
-> checkParenConstrTerm _ (ParenPattern constrTerm) =
->     checkParenConstrTerm Nothing constrTerm
-> checkParenConstrTerm _ (TuplePattern _ constrTerms) =
->     concatMap (checkParenConstrTerm Nothing) constrTerms
-> checkParenConstrTerm _ (ListPattern _ constrTerms) =
->     concatMap (checkParenConstrTerm Nothing) constrTerms
-> checkParenConstrTerm mCaller (AsPattern _ constrTerm) =
->     checkParenConstrTerm mCaller constrTerm
-> checkParenConstrTerm mCaller (LazyPattern _ constrTerm) =
->     checkParenConstrTerm mCaller constrTerm
-> checkParenConstrTerm _ (FunctionPattern _ constrTerms) =
->     concatMap (checkParenConstrTerm Nothing) constrTerms
-> checkParenConstrTerm mCaller (InfixFuncPattern constrTerm1 qualIdent constrTerm2) =
->     maybe [] (\c -> [(c,qualIdent)]) mCaller ++
->     checkParenConstrTerm Nothing constrTerm1 ++
->     checkParenConstrTerm Nothing constrTerm2
-> checkParenConstrTerm _ (RecordPattern fieldConstrTerms mConstrTerm) =  
->     maybe [] (checkParenConstrTerm Nothing) mConstrTerm ++
->     concatMap (\(Field _ _ constrTerm) -> checkParenConstrTerm Nothing constrTerm) 
->               fieldConstrTerms
-
-\end{verbatim}
diff --git a/src/SyntaxColoring.hs b/src/SyntaxColoring.hs
deleted file mode 100644
--- a/src/SyntaxColoring.hs
+++ /dev/null
@@ -1,800 +0,0 @@
-module SyntaxColoring (Program,Code(..),TypeKind(..),ConstructorKind(..),
-                       IdentifierKind(..),FunctionKind(..), genProgram,
-                       code2string,getQualIdent, position2code,
-                       area2codes) where
-
-import Debug.Trace
-import Data.Function(on)
-
-import Data.Maybe
-import Data.Either
-import Data.List
-import Data.Char hiding(Space)
-
-import Curry.Base.Position
-import Curry.Base.Ident
-import Curry.Base.MessageMonad
-import Curry.Syntax 
-import Curry.Syntax.Lexer
-
-
-
-debug = False -- mergen von Token und Codes
-
-trace' s x = if debug then trace s x else x
-
-
-debug' = False -- messages
-
-trace'' s x = if debug' then trace s x else x
-
-type Program = [(Int,Int,Code)] 
-
-data Code =  Keyword String
-           | Space Int
-           | NewLine
-           | ConstructorName  ConstructorKind QualIdent
-           | TypeConstructor  TypeKind QualIdent
-           | Function FunctionKind QualIdent
-           | ModuleName ModuleIdent
-           | Commentary String
-           | NumberCode String
-           | StringCode String
-           | CharCode String
-           | Symbol String
-           | Identifier IdentifierKind QualIdent
-           | CodeWarning [WarnMsg] Code
-           | NotParsed String
-             deriving Show
-           
-data TypeKind = TypeDecla
-              | TypeUse
-              | TypeExport deriving Show          
-
-data ConstructorKind = ConstrPattern
-                     | ConstrCall
-                     | ConstrDecla
-                     | OtherConstrKind deriving Show
-                     
-data IdentifierKind = IdDecl
-                    | IdOccur
-                    | UnknownId  deriving Show         
-                      
-data FunctionKind = InfixFunction
-                  | TypSig
-                  | FunDecl
-                  | FunctionCall
-                  | OtherFunctionKind deriving Show      
-                  
-                  
-     
-        
---- @param plaintext
---- @param list with parse-Results with descending quality  e.g. [typingParse,fullParse,parse]                                        
---- @param lex-Result
---- @return program
-genProgram :: String -> [MsgMonad Module] -> MsgMonad [(Position,Token)] -> Program       
-genProgram plainText parseResults m
-    = case runMsg m of
-        (Left e, msgs) -> buildMessagesIntoPlainText (e : msgs) plainText
-        (Right posNtokList, mess) 
-            -> let messages = (prepareMessages (concatMap getMessages parseResults ++ mess))
-                   mergedMessages = (mergeMessages' (trace' ("Messages: " ++ show messages) messages) posNtokList)
-                   (nameList,codes) = catIdentifiers parseResults
-               in tokenNcodes2codes nameList 1 1 mergedMessages codes
-
-    
---- @param Program
---- @param line
---- @param col
---- @return Code at this Position                  
-position2code :: Program -> Int -> Int -> Maybe Code                 
-position2code []  _ _ = Nothing
-position2code [_] _ _ = Nothing
-position2code ((l,c,code):xs@((_,c2,_):_)) line col
-     | line == l && col >= c && col < c2 = Just code
-     | l > line = Nothing
-     | otherwise = position2code xs line col
-     
-area2codes :: Program -> Position -> Position -> [Code]     
-area2codes [] _ _ = []
-area2codes xxs@((l,c,code):xs) p1@Position{file=file} p2 
-     | p1 > p2 = area2codes xxs p2 p1
-     | posEnd >= p1 && posBegin <= p2  = code : area2codes xs p1 p2
-     | posBegin > p2 = []
-     | otherwise = area2codes xs p1 p2
-   where
-      posBegin = Position file l c noRef
-      posEnd   = Position file l (c + length (code2string code)) noRef
-                  
-  
---- @param code
---- @return qualIdent if available                   
-getQualIdent :: Code -> Maybe QualIdent
-getQualIdent (ConstructorName _ qualIdent) = Just qualIdent
-getQualIdent (Function _ qualIdent) = Just qualIdent
-getQualIdent (Identifier _ qualIdent) = Just qualIdent                      
-getQualIdent (TypeConstructor _ qualIdent) = Just qualIdent
-getQualIdent  _ = Nothing                  
-                  
-                    
--- DEBUGGING----------- wird bald nicht mehr gebraucht
-
-setMessagePosition :: WarnMsg -> WarnMsg
-setMessagePosition m@(WarnMsg (Just p) _) = trace'' ("pos:" ++ show p ++ ":" ++ show m) m
-setMessagePosition (WarnMsg _ m) = 
-        let mes@(WarnMsg pos _) =  (WarnMsg (getPositionFromString m) m) in
-        trace'' ("pos:" ++ show pos ++ ":" ++ show mes) mes
-
-getPositionFromString :: String -> Maybe Position
-getPositionFromString message =
-     if line > 0 && col > 0 
-          then Just Position{file=file,line=line,column=col,astRef=noRef}
-          else Nothing
-  where
-      file = takeWhile (/= '"') (tail (dropWhile (/= '"') message))
-      line = readInt (takeWhile (/= '.') (drop 7 (dropWhile (/= ',') message)))
-      col = readInt (takeWhile (/= ':') (tail (dropWhile (/= '.') (drop 7 (dropWhile (/= ',') message)))))
-      
-     
-readInt :: String -> Int 
-readInt s = 
-      let onlyNum = filter isDigit s in
-      if null onlyNum
-         then 0
-         else read onlyNum :: Int
-
--- -------------------------
-
-  
-
--- -------------------------
-
-
-flatCode :: Code -> Code
-flatCode (CodeWarning _ code) = code
-flatCode code = code
-             
-
-                 
--- ----------Message---------------------------------------                  
-                  
-
-getMessages :: MsgMonad a -> [WarnMsg]
-getMessages = snd . runMsg --(Result mess _) = mess
--- getMessages (Failure mess) = mess
-
-lessMessage :: WarnMsg -> WarnMsg -> Bool
-lessMessage (WarnMsg mPos1 _) (WarnMsg mPos2 _) = mPos1 < mPos2
-
-nubMessages :: [WarnMsg] -> [WarnMsg] 
-nubMessages = nubBy eqMessage
-
-eqMessage :: WarnMsg -> WarnMsg -> Bool
-eqMessage (WarnMsg p1 s1) (WarnMsg p2 s2) = (p1 == p2) && (s1 == s2)
-
-prepareMessages :: [WarnMsg] -> [WarnMsg]   
-prepareMessages = qsort lessMessage . map setMessagePosition . nubMessages
-
-
-buildMessagesIntoPlainText :: [WarnMsg] -> String -> Program
-buildMessagesIntoPlainText messages text = 
-    buildMessagesIntoPlainText' messages (lines text) [] 1
- where
-    buildMessagesIntoPlainText' :: [WarnMsg] -> [String] -> [String] -> Int -> Program
-    buildMessagesIntoPlainText' _ [] [] _ = 
-          []
-    buildMessagesIntoPlainText' _ [] postStrs line = 
-          [(line,1,NotParsed (unlines postStrs))]    
-    buildMessagesIntoPlainText' [] preStrs postStrs line = 
-          [(line,1,NotParsed (unlines (preStrs ++ postStrs)))]  
-            
-    buildMessagesIntoPlainText' messages (str:preStrs) postStrs ln = 
-          let (pre,post) = partition isLeq messages in
-          if null pre 
-             then buildMessagesIntoPlainText' post preStrs (postStrs ++ [str]) (ln + 1)
-             else (ln,1,NotParsed (unlines postStrs)) : 
-                  (ln,1,CodeWarning pre (NotParsed str)) :
-                  (ln,1,NewLine) :
-                  buildMessagesIntoPlainText' post preStrs [] (ln + 1)
-      where 
-         isLeq (WarnMsg (Just p) _) = line p <= ln 
-         isLeq _ = True
-                
-        
-        
-
-     
---- @param parse-Modules  [typingParse,fullParse,parse] 
-catIdentifiers :: [MsgMonad Module] -> ([(ModuleIdent,ModuleIdent)],[Code])
-catIdentifiers = catIds . rights_sc . map (fst . runMsg)
-    where 
-      catIds [] = ([],[])
-      catIds [m] =
-          catIdentifiers' m Nothing
-      catIds rs@(m:y:ys) =  
-          catIdentifiers' (last rs) (Just m)
-    
--- not in base befoer base4
-
-rights_sc  xs = [ x | Right x <- xs]
-
---- @param parse-Module
---- @param Maybe betterParse-Module    
-catIdentifiers' :: Module -> Maybe Module -> ([(ModuleIdent,ModuleIdent)],[Code])
-catIdentifiers' (Module moduleIdent maybeExportSpec decls)
-                Nothing =
-      let codes = (concatMap decl2codes (qsort lessDecl decls)) in
-      (concatMap renamedImports decls,      
-      ModuleName moduleIdent :
-       maybe [] exportSpec2codes maybeExportSpec ++ codes)
-catIdentifiers' (Module moduleIdent maybeExportSpec1 _)
-                (Just (Module _ maybeExportSpec2 decls)) =
-      let codes = (concatMap decl2codes (qsort lessDecl decls)) in
-      (concatMap renamedImports decls,
-      replaceFunctionCalls $ 
-        map (addModuleIdent moduleIdent)
-          ([ModuleName moduleIdent] ++
-           mergeExports2codes  
-              (maybe [] (\(Exporting _ i) -> i)  maybeExportSpec1)
-              (maybe [] (\(Exporting _ i) -> i)  maybeExportSpec2) ++
-           codes))     
-  
-     
-renamedImports :: Decl -> [(ModuleIdent,ModuleIdent)]
-renamedImports decl =
-    case decl of
-        (ImportDecl _ oldName _ (Just newName) _) -> [(oldName,newName)]
-        _ -> []
-   
-                      
-replaceFunctionCalls :: [Code] -> [Code]                  
-replaceFunctionCalls codes = map (idOccur2functionCall qualIdents) codes
-   where
-      qualIdents = findFunctionDecls codes
-                                              
-
-findFunctionDecls :: [Code] -> [QualIdent]
-findFunctionDecls  =  mapMaybe getQualIdent . 
-                      filter isFunctionDecl .                       
-                      map flatCode                   
-
-isFunctionDecl  :: Code -> Bool
-isFunctionDecl  (Function FunDecl _)  = True
-isFunctionDecl  _ = False  
-
-idOccur2functionCall :: [QualIdent] -> Code -> Code
-idOccur2functionCall qualIdents ide@(Identifier IdOccur qualIdent)  
-   | isQualified qualIdent = Function FunctionCall qualIdent
-   | elem qualIdent qualIdents = Function FunctionCall qualIdent
-   | otherwise = ide
-idOccur2functionCall qualIdents (CodeWarning mess code) =
-       CodeWarning mess (idOccur2functionCall qualIdents code)
-idOccur2functionCall _ code = code
-  
-
-addModuleIdent :: ModuleIdent -> Code -> Code
-addModuleIdent moduleIdent c@(Function x qualIdent) 
-    | uniqueId (unqualify qualIdent) == 0 =
-        Function x (qualQualify moduleIdent qualIdent)
-    | otherwise = c
-addModuleIdent moduleIdent cn@(ConstructorName x qualIdent) 
-    | not $ isQualified qualIdent =
-        ConstructorName x (qualQualify moduleIdent qualIdent)
-    | otherwise = cn       
-addModuleIdent moduleIdent tc@(TypeConstructor TypeDecla qualIdent) 
-    | not $ isQualified qualIdent =
-        TypeConstructor TypeDecla (qualQualify moduleIdent qualIdent)
-    | otherwise = tc         
-addModuleIdent moduleIdent (CodeWarning mess code) =
-    CodeWarning mess (addModuleIdent moduleIdent code)
-addModuleIdent _ c = c
-                        
--- ----------------------------------------
-
-mergeMessages' :: [WarnMsg] -> [(Position,Token)] -> [([WarnMsg],Position,Token)]
-mergeMessages' _ [] = []
-mergeMessages' [] ((p,t):ps) = ([],p,t) : mergeMessages' [] ps
-mergeMessages' mss@(m@(WarnMsg mPos x):ms) ((p,t):ps)  
-    | mPos <= Just p = trace' (show mPos ++ " <= " ++ show (Just p) ++ " Message: " ++ x) ([m],p,t) : mergeMessages' ms ps 
-    | otherwise = ([],p,t) : mergeMessages' mss ps
-
-
-tokenNcodes2codes :: [(ModuleIdent,ModuleIdent)] -> Int -> Int -> [([WarnMsg],Position,Token)] -> [Code] -> [(Int,Int,Code)]
-tokenNcodes2codes _ _ _ [] _ = []          
-tokenNcodes2codes nameList currLine currCol toks@((messages,pos@Position{line=line,column=col},token):ts) codes 
-    | currLine < line = 
-           trace' " NewLine: "
-           ((currLine,currCol,NewLine) :
-           tokenNcodes2codes nameList (currLine + 1) 1 toks codes)
-    | currCol < col =  
-           trace' (" Space " ++ show (col - currCol))
-           ((currLine,currCol,Space (col - currCol)) :         
-           tokenNcodes2codes nameList currLine col toks codes)
-    | isTokenIdentifier token && null codes =    
-           trace' ("empty Code-List, Token: " ++ show (line,col) ++ show token)
-           (addMessage [(currLine,currCol,NotParsed tokenStr)] ++ tokenNcodes2codes nameList newLine newCol ts codes)
-    | not (isTokenIdentifier token) = 
-           trace' (" Token ist kein Identifier: " ++ tokenStr ) 
-           (addMessage [(currLine,currCol,token2code token)] ++ tokenNcodes2codes nameList newLine newCol ts codes) 
-    | tokenStr == code2string (head codes) =
-           trace' (" Code wird genommen: " ++ show (head codes) )
-           (addMessage [(currLine,currCol,head codes)] ++ tokenNcodes2codes nameList newLine newCol ts (tail codes)) 
-    | tokenStr == code2qualString (renameModuleIdents nameList (head codes)) =
-           let mIdent = maybe Nothing rename (getModuleIdent (head codes)) 
-               lenMod = maybe 0 (length . moduleName) mIdent
-               startPos = maybe currCol (const (currCol + lenMod + 1)) mIdent
-               symbol = [(currLine,currCol + lenMod,Symbol ".")]               
-               prefix = maybe [] 
-                              ( (: symbol) . 
-                                ( \i -> (currLine,
-                                         currCol,
-                                         ModuleName i))) 
-                              mIdent in
-           trace' (" Code wird genommen: " ++ show (head codes) )
-           (addMessage (prefix ++ [(currCol,startPos,head codes)]) ++ tokenNcodes2codes nameList newLine newCol ts (tail codes))           
-    | elem tokenStr (codeQualifiers (head codes)) =
-           trace' (" Token: "++ tokenStr ++" ist Modulname von: " ++ show (head codes) )
-           (addMessage [(currLine,currCol,ModuleName (mkMIdent [tokenStr]))] ++ 
-                    tokenNcodes2codes nameList newLine newCol ts codes)                  
-    | otherwise = 
-           trace' (" Token: "++ 
-                   tokenStr ++
-                   ",Code faellt weg:" ++ 
-                   code2string (head codes) ++ 
-                   "|" ++ 
-                   code2qualString (head codes))
-           (tokenNcodes2codes nameList currLine currCol toks (tail codes))
-  where
-      tokenStr = token2string token            
-      newLine  = (currLine + length (lines tokenStr)) - 1 
-      newCol   = currCol + length tokenStr   
-
-      rename mid = Just $ fromMaybe mid (lookup mid nameList)
-
-      addMessage [] = []
-      addMessage ((l,c,code):cs)
-         | null messages = (l,c,code):cs
-         | otherwise = trace' ("Warning bei code: " ++ show codes ++ ":" ++ show messages) 
-                              ((l,c,CodeWarning messages code): addMessage cs)
-      
-      
-renameModuleIdents :: [(ModuleIdent,ModuleIdent)] -> Code -> Code
-renameModuleIdents nameList c =
-    case c of
-        Function x qualIdent -> Function x (rename qualIdent (qualidMod qualIdent))
-        Identifier x qualIdent -> Identifier x (rename qualIdent (qualidMod qualIdent))
-        _ -> c
-  where
-    rename x (Nothing) = x
-    rename x (Just m) = maybe x (\ m' -> qualifyWith m' (qualidId x)) (lookup m nameList)
-           
-{-
-codeWithoutUniqueID ::  Code -> String
-codeWithoutUniqueID code = maybe (code2string code) (name . unqualify) $ getQualIdent code
-     
-
-codeUnqualify :: Code -> Code
-codeUnqualify code = maybe code (setQualIdent code . qualify . unqualify)  $ getQualIdent code  
--}  
-          
-codeQualifiers :: Code -> [String]
-codeQualifiers = maybe [] moduleQualifiers . getModuleIdent
-
-getModuleIdent :: Code -> Maybe ModuleIdent
-getModuleIdent (ConstructorName _ qualIdent) = qualidMod qualIdent
-getModuleIdent (Function _ qualIdent) = qualidMod qualIdent
-getModuleIdent (ModuleName moduleIdent) = Just moduleIdent
-getModuleIdent (Identifier _ qualIdent) = qualidMod qualIdent                     
-getModuleIdent (TypeConstructor _ qualIdent) = qualidMod qualIdent
-getModuleIdent _ = Nothing
-
-
-  
-{-
-setQualIdent :: Code -> QualIdent -> Code
-setQualIdent (Keyword str) _ = (Keyword str)
-setQualIdent (Space i) _ = (Space i)
-setQualIdent NewLine _ = NewLine
-setQualIdent (ConstructorName kind _) qualIdent = (ConstructorName kind qualIdent)
-setQualIdent (Function kind _) qualIdent = (Function kind qualIdent)
-setQualIdent (ModuleName moduleIdent) _ = (ModuleName moduleIdent)
-setQualIdent (Commentary str) _ = (Commentary str)
-setQualIdent (NumberCode str) _ = (NumberCode str)
-setQualIdent (Symbol str) _ = (Symbol str)
-setQualIdent (Identifier kind _) qualIdent = (Identifier kind qualIdent)                      
-setQualIdent (TypeConstructor kind _) qualIdent = (TypeConstructor kind qualIdent)
-setQualIdent (StringCode str) _ = (StringCode str)                                 
-setQualIdent (CharCode str) _ = (CharCode str)             
--}
-                  
-code2string (Keyword str) = str
-code2string (Space i)= concat (replicate i " ")
-code2string NewLine = "\n"
-code2string (ConstructorName _ qualIdent) = name $ unqualify qualIdent
-code2string (Function _ qualIdent) = name $ unqualify qualIdent
-code2string (ModuleName moduleIdent) = moduleName moduleIdent
-code2string (Commentary str) = str
-code2string (NumberCode str) = str
-code2string (Symbol str) = str
-code2string (Identifier _ qualIdent) = name $ unqualify qualIdent                      
-code2string (TypeConstructor _ qualIdent) = name $ unqualify qualIdent
-code2string (StringCode str) = str                                 
-code2string (CharCode str) = str
-code2string (NotParsed str) = str
-code2string _ = "" -- error / warning
- 
-code2qualString (ConstructorName _ qualIdent) = qualName qualIdent
-code2qualString (Function _ qualIdent) = qualName qualIdent
-code2qualString (Identifier _ qualIdent) = qualName qualIdent                      
-code2qualString (TypeConstructor _ qualIdent) = qualName qualIdent
-code2qualString x = code2string x
-
-
-
-token2code :: Token -> Code
-token2code tok@(Token cat _)
-    | elem cat [IntTok,FloatTok,IntegerTok]
-         = NumberCode (token2string tok)
-    | elem cat [KW_case,KW_choice,KW_data,KW_do,KW_else,KW_eval,KW_external,
-                KW_free,KW_if,KW_import,KW_in,KW_infix,KW_infixl,KW_infixr,
-                KW_let,KW_module,KW_newtype,KW_of,KW_rigid,KW_then,KW_type,
-                KW_where,Id_as,Id_ccall,Id_forall,Id_hiding,Id_interface,Id_primitive,
-                Id_qualified]
-         =  Keyword (token2string tok)
-    | elem cat [LeftParen,RightParen,Semicolon,LeftBrace,RightBrace,LeftBracket,
-                RightBracket,Comma,Underscore,Backquote,
-                At,Colon,DotDot,DoubleColon,Equals,Backslash,Bar,LeftArrow,RightArrow,
-                Tilde]
-         = Symbol (token2string tok)
-    | elem cat [LineComment, NestedComment]
-         = Commentary (token2string tok)
-    | isTokenIdentifier tok
-         = Identifier UnknownId $ qualify $ mkIdent $ token2string tok
-    | cat == StringTok 
-         = StringCode (token2string tok)
-    | cat == CharTok
-         = CharCode (token2string tok)          
-    | elem cat [EOF,VSemicolon,VRightBrace] = Space 0 
-    
-isTokenIdentifier :: Token -> Bool
-isTokenIdentifier (Token cat _) = 
-  elem cat [Id,QId,Sym,QSym,Sym_Dot,Sym_Minus,Sym_MinusDot]
-    
--- DECL Position
-
-getPosition :: Decl -> Position
-getPosition (ImportDecl pos _ _ _ _) = pos     
-getPosition (InfixDecl pos _ _ _) = pos     
-getPosition (DataDecl pos _ _ _) = pos     
-getPosition (NewtypeDecl pos _ _ _) = pos
-getPosition (TypeDecl pos _ _ _) = pos   
-getPosition (TypeSig pos _ _) = pos    
-getPosition (EvalAnnot pos _ _) = pos
-getPosition (FunctionDecl pos _ _) = pos    
-getPosition (ExternalDecl pos _ _ _ _) = pos
-getPosition (FlatExternalDecl pos _) = pos    
-getPosition (PatternDecl pos _ _) = pos    
-getPosition (ExtraVariables pos _) = pos
-             
-
-lessDecl :: Decl -> Decl -> Bool
-lessDecl = (<) `on` getPosition
-
-qsort _ []     = []
-qsort less (x:xs) = qsort less [y | y <- xs, less y x] ++ [x] ++ qsort less [y | y <- xs, not $ less y x]
-
-
-
--- DECL TO CODE -------------------------------------------------------------------- 
-
-
-
-exportSpec2codes ::  ExportSpec -> [Code]
-exportSpec2codes (Exporting _ exports) = concatMap (export2codes [])  exports
-
---- @param parse-Exports
---- @param betterParse-Exports
-mergeExports2codes :: [Export] -> [Export]  -> [Code]
-mergeExports2codes [] _ = []
-mergeExports2codes (e:es) xs = concatMap (export2codes xs)  (e:es)
-
-
-export2codes :: [Export] -> Export -> [Code]
-export2codes exports e@(Export qualIdent) 
-    | length (filter checkDouble exports) /= 1 =      
-       [Identifier UnknownId qualIdent]
-    | otherwise =
-       let [export] = (filter checkDouble exports) in
-       export2c export     
-  where    
-    checkDouble (ExportTypeWith q _) = eqQualIdent qualIdent q
-    checkDouble (Export q) = eqQualIdent qualIdent q
-    checkDouble _ = False
-    
-    eqQualIdent q1 q2 
-      | q1 == q2 = True
-      | not (isQualified q1) = unqualify q1 == unqualify q2
-      | otherwise = False
-      
-    export2c (Export qualIdent) = 
-         [Function OtherFunctionKind qualIdent]
-    export2c _ = 
-         [TypeConstructor TypeExport qualIdent]
-         
-    
-    
-       
-export2codes _ (ExportTypeWith qualIdent idents) = 
-     TypeConstructor TypeExport qualIdent : map (Function OtherFunctionKind . qualify) idents
-export2codes _ (ExportTypeAll  qualIdent) = 
-     [TypeConstructor TypeExport qualIdent]  
-export2codes _ (ExportModule moduleIdent) = 
-     [ModuleName moduleIdent]
-
-decl2codes :: Decl -> [Code]            
-decl2codes (ImportDecl _ moduleIdent xQualified mModuleIdent importSpec) = 
-     [ModuleName moduleIdent] ++
-     maybe [] ((:[]) . ModuleName) mModuleIdent ++
-     maybe [] (importSpec2codes moduleIdent)  importSpec
-decl2codes (InfixDecl _ _ _ idents) =
-     map (Function InfixFunction . qualify) idents
-decl2codes (DataDecl _ ident idents constrDecls) =
-     TypeConstructor TypeDecla (qualify ident) : 
-     map (Identifier UnknownId . qualify) idents ++
-     concatMap constrDecl2codes constrDecls
-decl2codes (NewtypeDecl xPosition xIdent yIdents xNewConstrDecl) =
-     []
-decl2codes (TypeDecl _ ident idents typeExpr) =
-     TypeConstructor TypeDecla (qualify ident) : 
-     map (Identifier UnknownId . qualify) idents ++ 
-     typeExpr2codes typeExpr
-decl2codes (TypeSig _ idents typeExpr) =
-     map (Function TypSig . qualify) idents ++ typeExpr2codes typeExpr   
-decl2codes (EvalAnnot xPosition idents xEvalAnnotation) =
-     map (Function FunDecl . qualify) idents
-decl2codes (FunctionDecl _ _ equations) =
-     concatMap equation2codes equations  
-decl2codes (ExternalDecl xPosition xCallConv xString xIdent xTypeExpr) =
-     []
-decl2codes (FlatExternalDecl _ idents) =
-     map (Function FunDecl . qualify) idents   
-decl2codes (PatternDecl xPosition constrTerm rhs) =
-     constrTerm2codes constrTerm ++ rhs2codes rhs
-decl2codes (ExtraVariables _ idents) =
-     map (Identifier IdDecl . qualify) idents
-  
-equation2codes :: Equation -> [Code]
-equation2codes (Equation _ lhs rhs) =
-     lhs2codes lhs ++ rhs2codes rhs
-     
-lhs2codes :: Lhs -> [Code]
-lhs2codes (FunLhs ident constrTerms) =
-    Function FunDecl (qualify ident) : concatMap constrTerm2codes constrTerms
-lhs2codes (OpLhs constrTerm1 ident constrTerm2) =
-    constrTerm2codes constrTerm1 ++ [Function FunDecl $ qualify ident] ++ constrTerm2codes constrTerm2
-lhs2codes (ApLhs lhs constrTerms) =
-    lhs2codes lhs ++ concatMap constrTerm2codes constrTerms     
-
-rhs2codes :: Rhs -> [Code]
-rhs2codes (SimpleRhs _ expression decls) =
-    expression2codes expression ++ concatMap decl2codes decls
-rhs2codes (GuardedRhs condExprs decls) =
-    concatMap condExpr2codes condExprs ++ concatMap decl2codes decls
-    
-condExpr2codes :: CondExpr -> [Code]
-condExpr2codes (CondExpr _ expression1 expression2) =   
-   expression2codes expression1 ++ expression2codes expression2    
-    
-constrTerm2codes :: ConstrTerm -> [Code]
-constrTerm2codes (LiteralPattern literal) = []
-constrTerm2codes (NegativePattern ident literal) = []
-constrTerm2codes (VariablePattern ident) = [Identifier IdDecl (qualify ident)]
-constrTerm2codes (ConstructorPattern qualIdent constrTerms) =
-    ConstructorName ConstrPattern qualIdent : concatMap constrTerm2codes constrTerms
-constrTerm2codes (InfixPattern constrTerm1 qualIdent constrTerm2) =
-    constrTerm2codes constrTerm1 ++ [ConstructorName ConstrPattern qualIdent] ++ constrTerm2codes constrTerm2
-constrTerm2codes (ParenPattern constrTerm) = constrTerm2codes constrTerm
-constrTerm2codes (TuplePattern _ constrTerms) = concatMap constrTerm2codes constrTerms
-constrTerm2codes (ListPattern _ constrTerms) = concatMap constrTerm2codes constrTerms
-constrTerm2codes (AsPattern ident constrTerm) =
-    Function OtherFunctionKind (qualify ident) : constrTerm2codes constrTerm
-constrTerm2codes (LazyPattern _ constrTerm) = constrTerm2codes constrTerm
-constrTerm2codes (FunctionPattern qualIdent constrTerms) = 
-    Function OtherFunctionKind qualIdent : concatMap constrTerm2codes constrTerms
-constrTerm2codes (InfixFuncPattern constrTerm1 qualIdent constrTerm2) =
-    constrTerm2codes constrTerm1 ++ [Function InfixFunction qualIdent] ++ constrTerm2codes constrTerm2
-   
-expression2codes :: Expression -> [Code]
-expression2codes (Literal literal) = []
-expression2codes (Variable qualIdent) = 
-    [Identifier IdOccur qualIdent]
-expression2codes (Constructor qualIdent) = 
-    [ConstructorName ConstrCall qualIdent]
-expression2codes (Paren expression) = 
-    expression2codes expression
-expression2codes (Typed expression typeExpr) = 
-    expression2codes expression ++ typeExpr2codes typeExpr
-expression2codes (Tuple _ expressions) = 
-    concatMap expression2codes expressions
-expression2codes (List _ expressions) = 
-    concatMap expression2codes expressions
-expression2codes (ListCompr _ expression statements) = 
-    expression2codes expression ++ concatMap statement2codes statements
-expression2codes (EnumFrom expression) = 
-    expression2codes expression
-expression2codes (EnumFromThen expression1 expression2) = 
-    expression2codes expression1 ++ expression2codes expression2
-expression2codes (EnumFromTo expression1 expression2) = 
-    expression2codes expression1 ++ expression2codes expression2
-expression2codes (EnumFromThenTo expression1 expression2 expression3) = 
-    expression2codes expression1 ++ 
-    expression2codes expression2 ++ 
-    expression2codes expression3
-expression2codes (UnaryMinus ident expression) = 
-    Symbol (name ident) : expression2codes expression 
-expression2codes (Apply expression1 expression2) = 
-    expression2codes expression1 ++ expression2codes expression2
-expression2codes (InfixApply expression1 infixOp expression2) = 
-    expression2codes expression1 ++ infixOp2codes infixOp ++ expression2codes expression2
-expression2codes (LeftSection expression infixOp) = 
-    expression2codes expression ++ infixOp2codes infixOp
-expression2codes (RightSection infixOp expression) = 
-    infixOp2codes infixOp ++ expression2codes expression
-expression2codes (Lambda _ constrTerms expression) = 
-    concatMap constrTerm2codes constrTerms ++ expression2codes expression
-expression2codes (Let decls expression) = 
-    concatMap decl2codes decls ++ expression2codes expression
-expression2codes (Do statements expression) = 
-    concatMap statement2codes statements ++ expression2codes expression
-expression2codes (IfThenElse _ expression1 expression2 expression3) = 
-    expression2codes expression1 ++ expression2codes expression2 ++ expression2codes expression3
-expression2codes (Case _ expression alts) = 
-    expression2codes expression ++ concatMap alt2codes alts
-    
-infixOp2codes :: InfixOp -> [Code]
-infixOp2codes (InfixOp qualIdent) = [Function InfixFunction qualIdent]
-infixOp2codes (InfixConstr qualIdent) = [ConstructorName OtherConstrKind qualIdent]
-
-
-statement2codes :: Statement -> [Code] 
-statement2codes (StmtExpr _ expression) =
-    expression2codes expression
-statement2codes (StmtDecl decls) =
-    concatMap decl2codes decls
-statement2codes (StmtBind _ constrTerm expression) =
-     constrTerm2codes constrTerm ++ expression2codes expression
-
-
-alt2codes :: Alt -> [Code]
-alt2codes (Alt _ constrTerm rhs) =
-    constrTerm2codes constrTerm ++ rhs2codes rhs
-         
-constrDecl2codes :: ConstrDecl -> [Code]
-constrDecl2codes (ConstrDecl _ idents ident typeExprs) =
-    ConstructorName ConstrDecla (qualify ident) : concatMap typeExpr2codes typeExprs
-constrDecl2codes (ConOpDecl _ idents typeExpr1 ident typeExpr2) =   
-    typeExpr2codes typeExpr1 ++ [ConstructorName ConstrDecla $ qualify ident] ++ typeExpr2codes typeExpr2
-
-         
-importSpec2codes :: ModuleIdent -> ImportSpec -> [Code]
-importSpec2codes moduleIdent (Importing _ imports) = concatMap (import2codes moduleIdent) imports
-importSpec2codes moduleIdent (Hiding _ imports) = concatMap (import2codes moduleIdent) imports
-
-import2codes :: ModuleIdent -> Import -> [Code]
-import2codes moduleIdent (Import ident) =
-     [Function OtherFunctionKind $ qualifyWith moduleIdent ident]  
-import2codes moduleIdent (ImportTypeWith ident idents) = 
-     ConstructorName OtherConstrKind (qualifyWith moduleIdent ident) :
-     map (Function OtherFunctionKind . qualifyWith moduleIdent) idents
-import2codes moduleIdent (ImportTypeAll  ident) = 
-     [ConstructorName OtherConstrKind $ qualifyWith moduleIdent ident]  
-     
-typeExpr2codes :: TypeExpr -> [Code]     
-typeExpr2codes (ConstructorType qualIdent typeExprs) = 
-    TypeConstructor TypeUse qualIdent : concatMap typeExpr2codes typeExprs
-typeExpr2codes (VariableType ident) = 
-    [Identifier IdOccur (qualify ident)]
-typeExpr2codes (TupleType typeExprs) = 
-    concatMap typeExpr2codes typeExprs
-typeExpr2codes (ListType typeExpr) = 
-    typeExpr2codes typeExpr
-typeExpr2codes (ArrowType typeExpr1 typeExpr2) = 
-    typeExpr2codes typeExpr1 ++ typeExpr2codes typeExpr2
-
--- TOKEN TO STRING ------------------------------------------------------------
-
-token2string (Token Id a) = attributes2string a
-token2string (Token QId a) = attributes2string a
-token2string (Token Sym a) = attributes2string a
-token2string (Token QSym a) = attributes2string a
-token2string (Token IntTok a) = attributes2string a
-token2string (Token FloatTok a) = attributes2string a
-token2string (Token CharTok a) = attributes2string a
-token2string (Token IntegerTok a) = attributes2string a
-token2string (Token StringTok a) = attributes2string a
-token2string (Token LeftParen _) = "("
-token2string (Token RightParen _) = ")"
-token2string (Token Semicolon _) = ";"
-token2string (Token LeftBrace _) = "{"
-token2string (Token RightBrace _) = "}"
-token2string (Token LeftBracket _) = "["
-token2string (Token RightBracket _) = "]"
-token2string (Token Comma _) = ","
-token2string (Token Underscore _) = "_"
-token2string (Token Backquote _) = "`"
-token2string (Token VSemicolon _) = ""
-token2string (Token VRightBrace _) = ""
-token2string (Token At _) = "@"
-token2string (Token Colon _) = ":"
-token2string (Token DotDot _) = ".."
-token2string (Token DoubleColon _) = "::"
-token2string (Token Equals _) = "="
-token2string (Token Backslash _) = "\\"
-token2string (Token Bar _) = "|"
-token2string (Token LeftArrow _) = "<-"
-token2string (Token RightArrow _) = "->"
-token2string (Token Tilde _) = "~"
-token2string (Token Sym_Dot _) = "."
-token2string (Token Sym_Minus _) = "-"
-token2string (Token Sym_MinusDot _) = "-."
-token2string (Token KW_case _) = "case"
-token2string (Token KW_choice _) = "choice"
-token2string (Token KW_data _) = "data"
-token2string (Token KW_do _) = "do"
-token2string (Token KW_else _) = "else"
-token2string (Token KW_eval _) = "eval"
-token2string (Token KW_external _) = "external"
-token2string (Token KW_free _) = "free"
-token2string (Token KW_if _) = "if"
-token2string (Token KW_import _) = "import"
-token2string (Token KW_in _) = "in"
-token2string (Token KW_infix _) = "infix"
-token2string (Token KW_infixl _) = "infixl"
-token2string (Token KW_infixr _) = "infixr"
-token2string (Token KW_let _) = "let"
-token2string (Token KW_module _) = "module"
-token2string (Token KW_newtype _) = "newtype"
-token2string (Token KW_of _) = "of"
-token2string (Token KW_rigid _) = "rigid"
-token2string (Token KW_then _) = "then"
-token2string (Token KW_type _) = "type"
-token2string (Token KW_where _) = "where"
-token2string (Token Id_as _) = "as"
-token2string (Token Id_ccall _) = "ccall"
-token2string (Token Id_forall _) = "forall"
-token2string (Token Id_hiding _) = "hiding"
-token2string (Token Id_interface _) = "interface"
-token2string (Token Id_primitive _) = "primitive"
-token2string (Token Id_qualified _) = "qualified"
-token2string (Token EOF _) = ""
-token2string (Token LineComment (StringAttributes sval _)) = sval
-token2string (Token NestedComment (StringAttributes sval _)) = sval
-
-attributes2string NoAttributes = ""
-attributes2string (CharAttributes cval _) = showCh cval 
-attributes2string (IntAttributes ival _) = show ival
-attributes2string (FloatAttributes fval _) = show fval
-attributes2string (IntegerAttributes intval _) = show intval
-attributes2string (StringAttributes sval _) = showSt sval 
-attributes2string (IdentAttributes mIdent ident) =concat (intersperse "." (mIdent ++ [ident])) 
-
-
-showCh c    
-   | c == '\\' = "'\\\\'"
-   | elem c ('\127' : ['\001' .. '\031']) = show c
-   | otherwise = toString c
-  where
-    toString c = '\'' : c : "'"
-
-showSt = addQuotes . concatMap toGoodChar 
-   where
-      addQuotes x = "\"" ++ x ++ "\""
-
-toGoodChar c     
-   | c == '\\' = "\\\\"
-   | elem c ('\127' : ['\001' .. '\031']) = justShow c
-   | c == '"' = "\\\""
-   | otherwise = c : "" 
- where
-     justShow = init . tail . show
diff --git a/src/TokenStream.hs b/src/TokenStream.hs
new file mode 100644
--- /dev/null
+++ b/src/TokenStream.hs
@@ -0,0 +1,168 @@
+{- |
+    Module      :  $Header$
+    Description :  Generating List of Tokens and Spans
+    Copyright   :  (c) 2015 - 2016, Katharina Rahf
+                       2015 - 2016, Björn Peemöller
+                       2015 - 2016, Jan Tikovsky
+
+    This module defines a function for writing the list of tokens
+    and spans of a Curry source module into a separate file.
+-}
+
+module TokenStream (showTokenStream, showCommentTokenStream) where
+
+import Data.List             (intercalate)
+
+import Curry.Base.Position   (Position (..))
+import Curry.Base.Span       (Span (..))
+import Curry.Syntax          (Token (..), Category (..), Attributes (..))
+
+-- |Show a list of 'Span' and 'Token' tuples.
+-- The list is split into one tuple on each line to increase readability.
+showTokenStream :: [(Span, Token)] -> String
+showTokenStream [] = "[]\n"
+showTokenStream ts =
+  "[ " ++ intercalate "\n, " (map showST filteredTs) ++ "\n]\n"
+  where filteredTs     = filter (not . isVirtual) ts
+        showST (sp, t) = "(" ++ showSpanAsPair sp ++ ", " ++ showToken t ++ ")"
+
+-- |Show a list of 'Span' and 'Token' tuples filtered by CommentTokens.
+-- The list is split into one tuple on each line to increase readability.
+showCommentTokenStream :: [(Span, Token)] -> String
+showCommentTokenStream [] = "[]\n"
+showCommentTokenStream ts =
+  "[ " ++ intercalate "\n, " (map showST filteredTs) ++ "\n]\n"
+  where filteredTs     = filter isComment ts
+        showST (sp, t) = "(" ++ showSpan sp ++ ", " ++ showToken t ++ ")"
+
+isVirtual :: (Span, Token) -> Bool
+isVirtual (_, Token cat _) = cat `elem` [EOF, VRightBrace, VSemicolon]
+
+isComment :: (Span, Token) -> Bool
+isComment (_, Token cat _) = cat `elem` [LineComment, NestedComment]
+
+-- show 'span' as "((startLine, startColumn), (endLine, endColumn))"
+showSpanAsPair :: Span -> String
+showSpanAsPair sp =
+  "(" ++ showPosAsPair (start sp) ++ ", " ++ showPos (end sp) ++ ")"
+
+-- show 'span' as "(Span startPos endPos)"
+showSpan :: Span -> String
+showSpan NoSpan = "NoSpan"
+showSpan Span { start = s, end = e } =
+   "(Span " ++ showPos s ++ " " ++ showPos e ++ ")"
+
+-- show 'position' as "(Position line column)"
+showPos :: Position -> String
+showPos NoPos = "NoPos"
+showPos Position { line = l, column = c } =
+  "(Position " ++ show l++ " " ++ show c ++ ")"
+
+-- show 'Position' as "(line, column)"
+showPosAsPair :: Position -> String
+showPosAsPair p = "(" ++ show (line p) ++ ", " ++ show (column p) ++ ")"
+
+-- |Show tokens and their value if needed
+showToken :: Token -> String
+-- literals
+showToken (Token CharTok        a) = "CharTok"   +++ showAttributes a
+showToken (Token IntTok         a) = "IntTok"    +++ showAttributes a
+showToken (Token FloatTok       a) = "FloatTok"  +++ showAttributes a
+showToken (Token StringTok      a) = "StringTok" +++ showAttributes a
+-- identifiers
+showToken (Token Id             a) = "Id"        +++ showAttributes a
+showToken (Token QId            a) = "QId"       +++ showAttributes a
+showToken (Token Sym            a) = "Sym"       +++ showAttributes a
+showToken (Token QSym           a) = "QSym"      +++ showAttributes a
+-- punctuation symbols
+showToken (Token LeftParen      _) = "LeftParen"
+showToken (Token RightParen     _) = "RightParen"
+showToken (Token Semicolon      _) = "Semicolon"
+showToken (Token LeftBrace      _) = "LeftBrace"
+showToken (Token RightBrace     _) = "RightBrace"
+showToken (Token LeftBracket    _) = "LeftBracket"
+showToken (Token RightBracket   _) = "RightBracket"
+showToken (Token Comma          _) = "Comma"
+showToken (Token Underscore     _) = "Underscore"
+showToken (Token Backquote      _) = "Backquote"
+-- layout
+showToken (Token VSemicolon     _) = "VSemicolon"
+showToken (Token VRightBrace    _) = "VRightBrace"
+-- reserved keywords
+showToken (Token KW_case        _) = "KW_case"
+showToken (Token KW_class       _) = "KW_class"
+showToken (Token KW_data        _) = "KW_data"
+showToken (Token KW_default     _) = "KW_default"
+showToken (Token KW_deriving    _) = "KW_deriving"
+showToken (Token KW_do          _) = "KW_do"
+showToken (Token KW_else        _) = "KW_else"
+showToken (Token KW_external    _) = "KW_external"
+showToken (Token KW_fcase       _) = "KW_fcase"
+showToken (Token KW_free        _) = "KW_free"
+showToken (Token KW_if          _) = "KW_if"
+showToken (Token KW_import      _) = "KW_import"
+showToken (Token KW_in          _) = "KW_in"
+showToken (Token KW_infix       _) = "KW_infix"
+showToken (Token KW_infixl      _) = "KW_infixl"
+showToken (Token KW_infixr      _) = "KW_infixr"
+showToken (Token KW_instance    _) = "KW_instance"
+showToken (Token KW_let         _) = "KW_let"
+showToken (Token KW_module      _) = "KW_module"
+showToken (Token KW_newtype     _) = "KW_newtype"
+showToken (Token KW_of          _) = "KW_of"
+showToken (Token KW_then        _) = "KW_then"
+showToken (Token KW_type        _) = "KW_type"
+showToken (Token KW_where       _) = "KW_where"
+-- reserved operators
+showToken (Token At             _) = "At"
+showToken (Token Colon          _) = "Colon"
+showToken (Token DotDot         _) = "DotDot"
+showToken (Token DoubleColon    _) = "DoubleColon"
+showToken (Token Equals         _) = "Equals"
+showToken (Token Backslash      _) = "Backslash"
+showToken (Token Bar            _) = "Bar"
+showToken (Token LeftArrow      _) = "LeftArrow"
+showToken (Token RightArrow     _) = "RightArrow"
+showToken (Token Tilde          _) = "Tilde"
+showToken (Token DoubleArrow    _) = "DoubleArrow"
+-- special identifiers
+showToken (Token Id_as          _) = "Id_as"
+showToken (Token Id_ccall       _) = "Id_ccall"
+showToken (Token Id_forall      _) = "Id_forall"
+showToken (Token Id_hiding      _) = "Id_hiding"
+showToken (Token Id_interface   _) = "Id_interface"
+showToken (Token Id_primitive   _) = "Id_primitive"
+showToken (Token Id_qualified   _) = "Id_qualified"
+-- special operators
+showToken (Token SymDot         _) = "SymDot"
+showToken (Token SymMinus       _) = "SymMinus"
+-- special symbols
+showToken (Token SymStar        _) = "SymStar"
+-- pragmas
+showToken (Token PragmaLanguage _) = "PragmaLanguage"
+showToken (Token PragmaOptions  a) = "PragmaOptions" +++ showAttributes a
+showToken (Token PragmaHiding   _) = "PragmaHiding"
+showToken (Token PragmaMethod   _) = "PragmaMethod"
+showToken (Token PragmaModule   _) = "PragmaModule"
+showToken (Token PragmaEnd      _) = "PragmaEnd"
+-- comments
+showToken (Token LineComment    a) = "LineComment"   +++ showAttributes a
+showToken (Token NestedComment  a) = "NestedComment" +++ showAttributes a
+-- end-of-file token
+showToken (Token EOF            _) = "EOF"
+
+showAttributes :: Attributes -> String
+showAttributes NoAttributes            = ""
+showAttributes (CharAttributes    c _) = show c
+showAttributes (IntAttributes     i _) = show i
+showAttributes (FloatAttributes   f _) = show f
+showAttributes (StringAttributes  s _) = show s
+showAttributes (IdentAttributes   m i) = show $ intercalate "." (m ++ [i])
+showAttributes (OptionsAttributes t a) = "(" ++ show t ++ ")" ++ ' ' : show a
+
+-- Concatenate two 'String's with a smart space in between,
+-- which is only added if both 'String's are non-empty
+(+++) :: String -> String -> String
+[] +++ t  = t
+s  +++ [] = s
+s  +++ t  = s ++ ' ' : t
diff --git a/src/TopEnv.lhs b/src/TopEnv.lhs
deleted file mode 100644
--- a/src/TopEnv.lhs
+++ /dev/null
@@ -1,148 +0,0 @@
-
-% $Id: TopEnv.lhs,v 1.20 2003/10/04 17:04:32 wlux Exp $
-%
-% Copyright (c) 1999-2003, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{TopEnv.lhs}
-\subsection{Top-Level Environments}\label{sec:toplevel-env}
-The module \texttt{TopEnv} implements environments for qualified and
-possibly ambiguous identifiers. An identifier is ambiguous if two
-different entities are imported under the same name or if a local
-definition uses the same name as an imported entity. Following an idea
-presented in \cite{DiatchkiJonesHallgren02:ModuleSystem}, an
-identifier is associated with a list of entities in order to handle
-ambiguous names properly.
-
-In general, two entities are considered equal if the names of their
-original definitions match.  However, in the case of algebraic data
-types it is possible to hide some or all of their data constructors on
-import and export, respectively. In this case we have to merge both
-imports such that all data constructors which are visible through any
-import path are visible in the current module. The class
-\texttt{Entity} is used to handle this merge.
-
-The code in this module ensures that the list of entities returned by
-the functions \texttt{lookupTopEnv} and \texttt{qualLookupTopEnv}
-contains exactly one element for each imported entity regardless of
-how many times and from which module(s) it was imported. Thus, the
-result of these function is a list with exactly one element if and
-only if the identifier is unambiguous. The module names associated
-with an imported entity identify the modules from which the entity was
-imported.
-\begin{verbatim}
-
-> module TopEnv(TopEnv(..), Entity(..), emptyTopEnv,
->               predefTopEnv,qualImportTopEnv,importTopEnv,
->               bindTopEnv,qualBindTopEnv,rebindTopEnv,qualRebindTopEnv,
->               unbindTopEnv,lookupTopEnv,qualLookupTopEnv,
->               allImports,moduleImports,localBindings
->              ) where
-
-> import Data.Maybe
-> import qualified Data.Map as Map
-> import Control.Arrow(second)
-> import Curry.Base.Ident
-
-
-> data Source = Local | Import [ModuleIdent] deriving (Eq,Show)
-
-> class Entity a where
->  origName :: a -> QualIdent
->  merge    :: a -> a -> Maybe a
->  merge x y
->    | origName x == origName y = Just x
->    | otherwise = Nothing
-
-> newtype TopEnv a = TopEnv { topEnvMap :: Map.Map QualIdent [(Source,a)] 
->                           } deriving Show
-
-> instance Functor TopEnv where
->   fmap f (TopEnv env) = TopEnv (fmap (map (second f)) env)
-
-> entities :: QualIdent -> Map.Map QualIdent [(Source,a)] -> [(Source,a)]
-> entities x env = fromMaybe [] (Map.lookup x env)
-
-> emptyTopEnv :: TopEnv a
-> emptyTopEnv = TopEnv Map.empty
-
-> predefTopEnv :: Entity a => QualIdent -> a -> TopEnv a -> TopEnv a
-> predefTopEnv x y (TopEnv env) =
->   case Map.lookup x env of
->     Just _ -> error "internal error: predefTopEnv"
->     Nothing -> TopEnv (Map.insert x [(Import [],y)] env)
-
-> importTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a -> TopEnv a
-> importTopEnv m x y (TopEnv env) =
->   TopEnv (Map.insert x' (mergeImport m y (entities x' env)) env)
->   where x' = qualify x
-
-> qualImportTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a
->                  -> TopEnv a
-> qualImportTopEnv m x y (TopEnv env) =
->   TopEnv (Map.insert x' (mergeImport m y (entities x' env)) env)
->   where x' = qualifyWith m x
-
-> mergeImport :: Entity a => ModuleIdent -> a -> [(Source,a)] -> [(Source,a)]
-> mergeImport m x [] = [(Import [m],x)]
-> mergeImport m x ((Local,x') : xs) = (Local,x') : mergeImport m x xs
-> mergeImport m x ((Import ms,x') : xs) =
->   case merge x x' of
->     Just x'' -> (Import (m:ms),x'') : xs
->     Nothing -> (Import ms,x') : mergeImport m x xs
-
-> bindTopEnv :: String -> Ident -> a -> TopEnv a -> TopEnv a
-> bindTopEnv fun x y env = qualBindTopEnv fun (qualify x) y env
-
-> qualBindTopEnv :: String -> QualIdent -> a -> TopEnv a -> TopEnv a
-> qualBindTopEnv fun x y (TopEnv env) =
->   TopEnv (Map.insert x (bindLocal y (entities x env)) env)
->   where bindLocal y ys
->           | null [y' | (Local,y') <- ys] = (Local,y) : ys
->           | otherwise = error ("internal error: \"qualBindTopEnv " 
->		                 ++ show x ++ "\" failed in function \""
->			         ++ fun ++ "\"")
-
-> rebindTopEnv :: Ident -> a -> TopEnv a -> TopEnv a
-> rebindTopEnv = qualRebindTopEnv . qualify
-
-> qualRebindTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a
-> qualRebindTopEnv x y (TopEnv env) =
->   TopEnv (Map.insert x (rebindLocal (entities x env)) env)
->   where rebindLocal [] = error "internal error: qualRebindTopEnv"
->         rebindLocal ((Local,_) : ys) = (Local,y) : ys
->         rebindLocal ((Import ms,y) : ys) = (Import ms,y) : rebindLocal ys
-
-> unbindTopEnv :: Ident -> TopEnv a -> TopEnv a
-> unbindTopEnv x (TopEnv env) =
->   TopEnv (Map.insert x' (unbindLocal (entities x' env)) env)
->   where x' = qualify x
->         unbindLocal [] = error "internal error: unbindTopEnv"
->         unbindLocal ((Local,_) : ys) = ys
->         unbindLocal ((Import ms,y) : ys) = (Import ms,y) : unbindLocal ys
-
-> lookupTopEnv :: Ident -> TopEnv a -> [a]
-> lookupTopEnv = qualLookupTopEnv . qualify
-
-> qualLookupTopEnv :: QualIdent -> TopEnv a -> [a]
-> qualLookupTopEnv x (TopEnv env) = map snd (entities x env)
-
-> allImports :: TopEnv a -> [(QualIdent,a)]
-> allImports (TopEnv env) =
->   [(x,y) | (x,ys) <- Map.toList env, (Import _,y) <- ys]
-
-> unqualBindings :: TopEnv a -> [(Ident,(Source,a))]
-> unqualBindings (TopEnv env) =
->   [(x',y) | (x,ys) <- takeWhile (not . isQualified . fst) (Map.toList env),
->             let x' = unqualify x, y <- ys]
-
-> moduleImports :: ModuleIdent -> TopEnv a -> [(Ident,a)]
-> moduleImports m env =
->   [(x,y) | (x,(Import ms,y)) <- unqualBindings env, m `elem` ms]
-
-> localBindings :: TopEnv a -> [(Ident,a)]
-> localBindings env = [(x,y) | (x,(Local,y)) <- unqualBindings env]
-
-\end{verbatim}
diff --git a/src/Transformations.hs b/src/Transformations.hs
new file mode 100644
--- /dev/null
+++ b/src/Transformations.hs
@@ -0,0 +1,89 @@
+{- |
+    Module      :  $Header$
+    Description :  Code transformations
+    Copyright   :  (c) 2011, Björn Peemöller (bjp@informatik.uni-kiel.de)
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module subsumes the different transformations of the source code.
+-}
+module Transformations where
+
+import Curry.Syntax
+
+import Base.Types
+
+import Transformations.CaseCompletion as CC (completeCase)
+import Transformations.CurryToIL      as IL (ilTrans, transType)
+import Transformations.Derive         as DV (derive)
+import Transformations.Desugar        as DS (desugar)
+import Transformations.Dictionary     as DI (insertDicts)
+import Transformations.Lift           as L  (lift)
+import Transformations.Newtypes       as NT (removeNewtypes)
+import Transformations.Qual           as Q  (qual)
+import Transformations.Simplify       as S  (simplify)
+
+import Env.TypeConstructor
+
+import CompilerEnv
+import Imports (qualifyEnv)
+import qualified IL
+
+-- |Fully qualify used constructors and functions.
+qual :: CompEnv (Module a) -> CompEnv (Module a)
+qual (env, mdl) = (qualifyEnv env, mdl')
+  where mdl' = Q.qual (moduleIdent env) (tyConsEnv env) (valueEnv env) mdl
+
+-- |Automatically derive instances.
+derive :: CompEnv (Module PredType) -> CompEnv (Module PredType)
+derive (env, mdl) = (env, mdl')
+  where mdl' = DV.derive (tyConsEnv env) (valueEnv env) (instEnv env)
+                         (opPrecEnv env) mdl
+
+-- |Remove any syntactic sugar, changes the value environment.
+desugar :: CompEnv (Module PredType) -> CompEnv (Module PredType)
+desugar (env, mdl) = (env { valueEnv = tyEnv' }, mdl')
+  where (mdl', tyEnv') = DS.desugar (extensions env) (valueEnv env)
+                                    (tyConsEnv env) mdl
+
+-- |Insert dictionaries, changes the type constructor and value environments.
+insertDicts :: Bool -> CompEnv (Module PredType) -> CompEnv (Module Type)
+insertDicts inlDi (env, mdl) = (env { interfaceEnv = intfEnv'
+                                    , tyConsEnv = tcEnv'
+                                    , valueEnv = vEnv'
+                                    , opPrecEnv = pEnv' }, mdl')
+  where (mdl', intfEnv', tcEnv', vEnv', pEnv') =
+          DI.insertDicts inlDi (interfaceEnv env) (tyConsEnv env)
+                         (valueEnv env) (classEnv env) (instEnv env)
+                         (opPrecEnv env) mdl
+
+-- |Remove newtype constructors.
+removeNewtypes :: Bool -> CompEnv (Module Type) -> CompEnv (Module Type)
+removeNewtypes remNT (env, mdl) = (env, mdl')
+  where mdl' = NT.removeNewtypes remNT (valueEnv env) mdl
+
+-- |Simplify the source code, changes the value environment.
+simplify :: CompEnv (Module Type) -> CompEnv (Module Type)
+simplify (env, mdl) = (env { valueEnv = tyEnv' }, mdl')
+  where (mdl', tyEnv') = S.simplify (valueEnv env) mdl
+
+-- |Lift local declarations, changes the value environment.
+lift :: CompEnv (Module Type) -> CompEnv (Module Type)
+lift (env, mdl) = (env { valueEnv = tyEnv' }, mdl')
+  where (mdl', tyEnv') = L.lift (valueEnv env) mdl
+
+-- |Translate into the intermediate language
+ilTrans :: Bool -> CompEnv (Module Type) -> CompEnv IL.Module
+ilTrans remIm (env, mdl) = (env, il)
+  where il = IL.ilTrans remIm (valueEnv env) (tyConsEnv env) mdl
+
+transType :: TCEnv -> Type -> IL.Type
+transType = IL.transType
+
+-- |Add missing case branches
+completeCase :: CompEnv IL.Module -> CompEnv IL.Module
+completeCase (env, mdl) =
+  (env, CC.completeCase (interfaceEnv env) (tyConsEnv env) mdl)
diff --git a/src/Transformations/CaseCompletion.hs b/src/Transformations/CaseCompletion.hs
new file mode 100644
--- /dev/null
+++ b/src/Transformations/CaseCompletion.hs
@@ -0,0 +1,479 @@
+{- |
+    Module      :  $Header$
+    Description :  CaseCompletion
+    Copyright   :  (c) 2005        Martin Engelke
+                       2011 - 2015 Björn Peemöller
+                       2016        Jan Tikovsky
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    This module expands case branches with missing constructors.
+
+    The MCC translates case expressions into the intermediate language
+    representation (IL) without completing them (i.e. without generating
+    case branches for missing contructors), because the intermediate language
+    supports variable patterns for the fallback case.
+    In contrast, the FlatCurry representation of patterns only allows
+    literal and constructor patterns, which requires the expansion
+    default branches to all missing constructors.
+
+    This is only necessary for *rigid* case expressions, because any
+    *flexible* case expression with more than one branch and a variable
+    pattern is non-deterministic. In consequence, these overlapping patterns
+    have already been eliminated in the pattern matching compilation
+    process (see module CurryToIL).
+
+    To summarize, this module expands all rigid case expressions.
+-}
+{-# LANGUAGE CPP #-}
+module Transformations.CaseCompletion (completeCase) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative        ((<$>), (<*>))
+#endif
+import qualified Control.Monad.State as S   (State, evalState, gets, modify)
+import           Data.List                  (find)
+import           Data.Maybe                 (fromMaybe, listToMaybe)
+
+import           Curry.Base.Ident
+import qualified Curry.Syntax        as CS
+
+import Base.CurryTypes                      (toType)
+import Base.Expr
+import Base.Messages                        (internalError)
+import Base.Types                           ( boolType, charType, floatType
+                                            , intType, listType
+                                            )
+import Base.Subst
+
+import Env.TypeConstructor
+import Env.Interface                        (InterfaceEnv, lookupInterface)
+
+import Transformations.CurryToIL            (transType)
+import Transformations.Dictionary           (qImplMethodId)
+
+import IL
+
+-- Completes case expressions by adding branches for missing constructors.
+-- The interface environment 'iEnv' is needed to compute these constructors.
+completeCase :: InterfaceEnv -> TCEnv -> Module -> Module
+completeCase iEnv tcEnv mdl@(Module mid is ds) = Module mid is ds'
+ where ds'= S.evalState (mapM ccDecl ds) (CCState mdl iEnv 0 tcEnv )
+
+-- -----------------------------------------------------------------------------
+-- Internally used state monad
+-- -----------------------------------------------------------------------------
+
+data CCState = CCState
+  { modul        :: Module
+  , interfaceEnv :: InterfaceEnv
+  , nextId       :: Int
+  , tyconEnv     :: TCEnv
+  }
+
+type CCM a = S.State CCState a
+
+getModule :: CCM Module
+getModule = S.gets modul
+
+getTCEnv :: CCM TCEnv
+getTCEnv = S.gets tyconEnv
+
+getInterfaceEnv :: CCM InterfaceEnv
+getInterfaceEnv = S.gets interfaceEnv
+
+-- Create a fresh identifier
+freshIdent :: CCM Ident
+freshIdent = do
+  nid <- S.gets nextId
+  S.modify $ \s -> s { nextId = succ nid }
+  return $ mkIdent $ "_#comp" ++ show nid
+
+-- -----------------------------------------------------------------------------
+-- The following functions traverse an IL term searching for case expressions
+-- -----------------------------------------------------------------------------
+
+ccDecl :: Decl -> CCM Decl
+ccDecl dd@(DataDecl        _ _ _) = return dd
+ccDecl edd@(ExternalDataDecl _ _) = return edd
+ccDecl (FunctionDecl qid vs ty e) = FunctionDecl qid vs ty <$> ccExpr e
+ccDecl ed@(ExternalDecl    _ _ _) = return ed
+ccDecl nd@(NewtypeDecl     _ _ _) = return nd
+
+ccExpr :: Expression -> CCM Expression
+ccExpr l@(Literal       _ _) = return l
+ccExpr v@(Variable      _ _) = return v
+ccExpr f@(Function    _ _ _) = return f
+ccExpr c@(Constructor _ _ _) = return c
+ccExpr (Apply         e1 e2) = Apply <$> ccExpr e1 <*> ccExpr e2
+ccExpr (Case        ea e bs) = do
+  e'  <- ccExpr e
+  bs' <- mapM ccAlt bs
+  ccCase ea e' bs'
+ccExpr (Or            e1 e2) = Or <$> ccExpr e1 <*> ccExpr e2
+ccExpr (Exist        v ty e) = Exist v ty <$> ccExpr e
+ccExpr (Let             b e) = Let <$> ccBinding b <*> ccExpr e
+ccExpr (Letrec         bs e) = Letrec <$> mapM ccBinding bs <*> ccExpr e
+ccExpr (Typed          e ty) = flip Typed ty <$> ccExpr e
+
+ccAlt :: Alt -> CCM Alt
+ccAlt (Alt p e) = Alt p <$> ccExpr e
+
+ccBinding :: Binding -> CCM Binding
+ccBinding (Binding v e) = Binding v <$> ccExpr e
+
+-- ---------------------------------------------------------------------------
+-- Functions for completing case alternatives
+-- ---------------------------------------------------------------------------
+ccCase :: Eval -> Expression -> [Alt] -> CCM Expression
+-- flexible cases are not completed
+ccCase Flex  e alts     = return $ Case Flex e alts
+ccCase Rigid _ []       = internalError $ "CaseCompletion.ccCase: "
+                                       ++ "empty alternative list"
+ccCase Rigid e as@(Alt p _:_) = case p of
+  ConstructorPattern _ _ _ -> completeConsAlts Rigid e as
+  LiteralPattern     _ _   -> completeLitAlts  Rigid e as
+  VariablePattern    _ _   -> completeVarAlts        e as
+
+-- Completes a case alternative list which branches via constructor patterns
+-- by adding alternatives. Thus, case expressions of the form
+--     case <ce> of
+--       <C_1> -> <expr_1>
+--              :
+--       <C_n> -> <expr_n>
+--      [<var> -> <default_expr>]
+-- are in general extended to
+--     let x = <ce> in
+--     let y = <default_expr>[<var>/x] in
+--     case x of
+--       <C_1>  -> <expr_1>
+--               :
+--       <C_n>  -> <expr_n>
+--       <C'_1> -> y
+--               :
+--       <C'_m> -> y
+-- where the C'_j are the complementary constructor patterns of the C_i,
+-- @x@ and @y@ are fresh variables, and "default_expr" is the expression
+-- from the first alternative containing a variable pattern. If there is no such
+-- alternative, the default expression is set to the prelude function 'failed'.
+-- In addition, there are a few optimizations performed to avoid the
+-- construction of unnecessary let-bindings:
+--   - If there are no complementary patterns, the expression remains unchanged.
+--   - If there is only one complementary pattern,
+--     the binding for @y@ is avoided (see @bindDefVar@).
+--   - If the variable @<var>@ does not occur in the default expression,
+--     the binding for @x@ is avoided (see @mkCase@).
+completeConsAlts :: Eval -> Expression -> [Alt] -> CCM Expression
+completeConsAlts ea ce alts = do
+  mdl       <- getModule
+  menv      <- getInterfaceEnv
+  tcEnv     <- getTCEnv
+  -- complementary constructor patterns
+  complPats <- mapM genPat $ getComplConstrs mdl menv tcEnv
+               [ c | (Alt (ConstructorPattern _ c _) _) <- consAlts ]
+  v <- freshIdent
+  w <- freshIdent
+  return $ case (complPats, defaultAlt v) of
+            (_:_, Just e') -> bindDefVar v ce w e' complPats
+            _              -> Case ea ce consAlts
+  where
+  -- existing contructor pattern alternatives
+  consAlts = [ a | a@(Alt (ConstructorPattern _ _ _) _) <- alts ]
+
+  -- unifier for data type and concrete pattern type
+  dataTy  = let TypeConstructor qid tys = patTy
+            in TypeConstructor qid $ map TypeVariable [0 .. length tys - 1]
+  patTy   = let Alt pat _ = head consAlts in typeOf pat
+  tySubst = matchType dataTy patTy idSubst
+
+  -- generate a new constructor pattern
+  genPat (qid, tys) = ConstructorPattern patTy qid <$>
+    mapM (\ty' -> freshIdent >>= \v -> return (ty', v)) (subst tySubst tys)
+
+  -- default alternative, if there is one
+  defaultAlt v = listToMaybe [ replaceVar x (Variable ty v) e
+                             | Alt (VariablePattern ty x) e <- alts ]
+
+  -- create a binding for @v = e@ if needed
+  bindDefVar v e w e' ps
+    | v `elem` fv e' = mkBinding v e $ mkCase (Variable (typeOf e) v) w e' ps
+    | otherwise      = mkCase e w e' ps
+
+  -- create a binding for @w = e'@ if needed, and a case expression
+  -- @case e of { consAlts ++ (ps -> w) }@
+  mkCase e w e' ps = case ps of
+    [p] -> Case ea e (consAlts ++ [Alt p e'])
+    _   -> mkBinding w e'
+         $ Case ea e (consAlts ++ [Alt p (Variable (typeOf e') w) | p <- ps])
+
+-- If the alternatives' branches contain literal patterns, a complementary
+-- constructor list cannot be generated because it would become potentially
+-- infinite. Thus, function 'completeLitAlts' transforms case expressions like
+--     case <ce> of
+--       <lit_1> -> <expr_1>
+--       <lit_2> -> <expr_2>
+--                   :
+--       <lit_n> -> <expr_n>
+--      [<var>   -> <default_expr>]
+-- to
+--     let x = <ce> in
+--     case (v == <lit_1>) of
+--       True  -> <expr_1>
+--       False -> case (x == <lit_2>) of
+--                  True  -> <expr_2>
+--                  False -> case ...
+--                                 :
+--                               -> case (x == <lit_n>) of
+--                                    True  -> <expr_n>
+--                                    False -> <default_expr>
+-- If the default expression is missing, @failed@ is used instead.
+completeLitAlts :: Eval -> Expression -> [Alt] -> CCM Expression
+completeLitAlts ea ce alts = do
+  x <- freshIdent
+  return $ mkBinding x ce $ nestedCases x alts
+  where
+  nestedCases _ []              = failedExpr (typeOf $ head alts)
+  nestedCases x (Alt p ae : as) = case p of
+    LiteralPattern ty l  -> Case ea (Variable ty x `eqExpr` Literal ty l)
+                          [ Alt truePatt  ae
+                          , Alt falsePatt (nestedCases x as)
+                          ]
+    VariablePattern ty v -> replaceVar v (Variable ty x) ae
+    _ -> internalError "CaseCompletion.completeLitAlts: illegal alternative"
+
+-- For the unusual case of only one alternative containing a variable pattern,
+-- it is necessary to tranform it to a 'let' term because FlatCurry does not
+-- support variable patterns in case alternatives. So the case expression
+--    case <ce> of
+--      x -> <ae>
+-- is transformed to
+--      let x = <ce> in <ae>
+completeVarAlts :: Expression -> [Alt] -> CCM Expression
+completeVarAlts _  []             = internalError $
+  "CaseCompletion.completeVarAlts: empty alternative list"
+completeVarAlts ce (Alt p ae : _) = case p of
+  VariablePattern _ x -> return $ mkBinding x ce ae
+  _                   -> internalError $
+    "CaseCompletion.completeVarAlts: variable pattern expected"
+
+-- Smart constructor for non-recursive let-binding. @mkBinding v e e'@
+-- evaluates to @e'[v/e]@ if @e@ is a variable, or @let v = e in e'@ otherwise.
+mkBinding :: Ident -> Expression -> Expression -> Expression
+mkBinding v e e' = case e of
+  Variable _ _ -> replaceVar v e e'
+  _            -> Let (Binding v e) e'
+
+-- ---------------------------------------------------------------------------
+-- This part of the module contains functions for replacing variables
+-- with expressions. This is necessary in the case of having a default
+-- alternative like
+--      v -> <expr>
+-- where the variable v occurs in the default expression <expr>. When
+-- building additional alternatives for this default expression, the variable
+-- must be replaced with the newly generated constructors.
+replaceVar :: Ident -> Expression -> Expression -> Expression
+replaceVar v e x@(Variable  _ w)
+  | v == w    = e
+  | otherwise = x
+replaceVar v e (Apply     e1 e2)
+  = Apply (replaceVar v e e1) (replaceVar v e e2)
+replaceVar v e (Case   ev e' bs)
+  = Case ev (replaceVar v e e') (map (replaceVarInAlt v e) bs)
+replaceVar v e (Or        e1 e2)
+  = Or (replaceVar v e e1) (replaceVar v e e2)
+replaceVar v e (Exist   w ty e')
+   | v == w                     = Exist w ty e'
+   | otherwise                  = Exist w ty (replaceVar v e e')
+replaceVar v e (Let        b e')
+   | v `occursInBinding` b      = Let b e'
+   | otherwise                  = Let (replaceVarInBinding v e b)
+                                      (replaceVar v e e')
+replaceVar v e (Letrec    bs e')
+   | any (occursInBinding v) bs = Letrec bs e'
+   | otherwise                  = Letrec (map (replaceVarInBinding v e) bs)
+                                         (replaceVar v e e')
+replaceVar _ _ e'               = e'
+
+replaceVarInAlt :: Ident -> Expression -> Alt -> Alt
+replaceVarInAlt v e (Alt p e')
+  | v `occursInPattern` p = Alt p e'
+  | otherwise             = Alt p (replaceVar v e e')
+
+replaceVarInBinding :: Ident -> Expression -> Binding -> Binding
+replaceVarInBinding v e (Binding w e')
+  | v == w    = Binding w e'
+  | otherwise = Binding w (replaceVar v e e')
+
+occursInPattern :: Ident -> ConstrTerm -> Bool
+occursInPattern v (VariablePattern       _ w) = v == w
+occursInPattern v (ConstructorPattern _ _ vs) = v `elem` map snd vs
+occursInPattern _ _                           = False
+
+occursInBinding :: Ident -> Binding -> Bool
+occursInBinding v (Binding w _) = v == w
+
+-- ---------------------------------------------------------------------------
+-- The following functions generate several IL expressions and patterns
+
+failedExpr :: Type -> Expression
+failedExpr ty = Function ty (qualifyWith preludeMIdent (mkIdent "failed")) 0
+
+--TODO: Add note about arity of 0 because of the predefined functions in the Prelude
+eqExpr :: Expression -> Expression -> Expression
+eqExpr e1 e2 = Apply (Apply (Function eqTy eq 0) e1) e2
+  where eq   = qImplMethodId preludeMIdent qDataId ty $ mkIdent "==="
+        ty   = case e2 of
+                 Literal _ l -> case l of
+                                  Char  _ -> charType
+                                  Int   _ -> intType
+                                  Float _ -> floatType
+                 _ -> internalError "CaseCompletion.eqExpr: no literal"
+        ty'  = case e2 of
+                 Literal _ l -> case l of
+                                  Char  _ -> charType'
+                                  Int   _ -> intType'
+                                  Float _ -> floatType'
+                 _ -> internalError "CaseCompletion.eqExpr: no literal"
+        eqTy = TypeArrow ty' (TypeArrow ty' boolType')
+
+truePatt :: ConstrTerm
+truePatt = ConstructorPattern boolType' qTrueId []
+
+falsePatt :: ConstrTerm
+falsePatt = ConstructorPattern boolType' qFalseId []
+
+boolType' :: Type
+boolType' = IL.TypeConstructor qBoolId []
+
+charType' :: Type
+charType' = IL.TypeConstructor qCharId []
+
+intType' :: Type
+intType' = IL.TypeConstructor qIntId []
+
+floatType' :: Type
+floatType' = IL.TypeConstructor qFloatId []
+
+-- ---------------------------------------------------------------------------
+-- The following functions compute the missing constructors for generating
+-- missing case alternatives
+
+-- Computes the complementary constructors for a given list of constructors.
+-- All specified constructors must be of the same type.
+-- This functions uses the module environment 'menv', which contains all
+-- imported constructors, except for the built-in list constructors.
+-- TODO: Check if the list constructors are in the menv.
+getComplConstrs :: Module -> InterfaceEnv -> TCEnv
+                -> [QualIdent] -> [(QualIdent, [Type])]
+getComplConstrs _                 _    _     []
+  = internalError "CaseCompletion.getComplConstrs: empty constructor list"
+getComplConstrs (Module mid _ ds) menv tcEnv cs@(c:_)
+  -- built-in lists
+  | c `elem` [qNilId, qConsId] = complementary cs
+    [ (qNilId, [])
+    , (qConsId, [TypeVariable 0, transType tcEnv (listType boolType)])
+    ]
+  -- current module
+  | mid' == mid                = getCCFromDecls cs ds
+  -- imported module
+  | otherwise                  = maybe [] (getCCFromIDecls mid' cs tcEnv)
+                                          (lookupInterface mid' menv)
+  where mid' = fromMaybe mid (qidModule c)
+
+-- Find complementary constructors within the declarations of the
+-- current module
+getCCFromDecls :: [QualIdent] -> [Decl] -> [(QualIdent, [Type])]
+getCCFromDecls cs ds = complementary cs cinfos
+  where
+  cinfos = map constrInfo
+         $ maybe [] extractConstrDecls (find (`declares` head cs) ds)
+
+  decl `declares` qid = case decl of
+    DataDecl    _ _ cs' -> any (`declaresConstr` qid) cs'
+    _                   -> False
+
+  declaresConstr (ConstrDecl cid _) qid = cid == qid
+
+  extractConstrDecls (DataDecl _ _ cs') = cs'
+  extractConstrDecls _                  = []
+
+  constrInfo (ConstrDecl cid tys) = (cid, tys)
+
+-- Find complementary constructors within the module environment
+getCCFromIDecls :: ModuleIdent -> [QualIdent] -> TCEnv-> CS.Interface
+                -> [(QualIdent, [Type])]
+getCCFromIDecls mid cs tcEnv (CS.Interface _ _ ds) = complementary cs cinfos
+  where
+  cinfos = map (uncurry constrInfo)
+         $ maybe [] extractConstrDecls (find (`declares` head cs) ds)
+
+  decl `declares` qid = case decl of
+    CS.IDataDecl    _ _ _ _ cs' _ -> any (`declaresConstr` qid) cs'
+    CS.INewtypeDecl _ _ _ _ nc  _ -> isNewConstrDecl qid nc
+    _                             -> False
+
+  declaresConstr (CS.ConstrDecl   _ cid _) qid = unqualify qid == cid
+  declaresConstr (CS.ConOpDecl _ _ oid _) qid = unqualify qid == oid
+  declaresConstr (CS.RecordDecl  _ cid _) qid = unqualify qid == cid
+
+  isNewConstrDecl qid (CS.NewConstrDecl _ cid _) = unqualify qid == cid
+  isNewConstrDecl qid (CS.NewRecordDecl _ cid _) = unqualify qid == cid
+
+  extractConstrDecls (CS.IDataDecl _ _ _ vs cs' _) = zip (repeat vs) cs'
+  extractConstrDecls _                             = []
+
+  constrInfo vs (CS.ConstrDecl _ cid tys)     =
+    (qualifyWith mid cid, map (transType' vs) tys)
+  constrInfo vs (CS.ConOpDecl  _ ty1 oid ty2) =
+    (qualifyWith mid oid, map (transType' vs) [ty1, ty2])
+  constrInfo vs (CS.RecordDecl _ cid  fs)     =
+    ( qualifyWith mid cid
+    , [transType' vs ty | CS.FieldDecl _ ls ty <- fs, _ <- ls]
+    )
+
+  transType' vs = transType tcEnv . toType vs
+
+-- Compute complementary constructors
+complementary :: [QualIdent] -> [(QualIdent, [Type])] -> [(QualIdent, [Type])]
+complementary known others = filter ((`notElem` known) . fst) others
+
+-- ---------------------------------------------------------------------------
+-- The following section contains defintions to compute a type substitution
+-- for generating the type annotations for missing case alternatives
+
+type TypeSubst = Subst Int Type
+
+class SubstType a where
+  subst :: TypeSubst -> a -> a
+
+instance SubstType a => SubstType [a] where
+  subst sigma = map (subst sigma)
+
+instance SubstType Type where
+  subst sigma (TypeConstructor q tys) = TypeConstructor q $ subst sigma tys
+  subst sigma (TypeVariable tv)       = substVar' TypeVariable subst sigma tv
+  subst sigma (TypeArrow ty1 ty2)
+    = TypeArrow (subst sigma ty1) (subst sigma ty2)
+  subst sigma (TypeForall tvs ty)
+    = TypeForall tvs (subst (foldr (unbindSubst . fst) sigma tvs) ty)
+
+matchType :: Type -> Type -> TypeSubst -> TypeSubst
+matchType ty1 ty2 = fromMaybe noMatch (matchType' ty1 ty2)
+  where
+    noMatch = internalError $ "Transformations.CaseCompletion.matchType: " ++
+                                showsPrec 11 ty1 " " ++ showsPrec 11 ty2 ""
+
+matchType' :: Type -> Type -> Maybe (TypeSubst -> TypeSubst)
+matchType' (TypeVariable tv) ty
+  | ty == TypeVariable tv = Just id
+  | otherwise = Just (bindSubst tv ty)
+matchType' (TypeConstructor tc1 tys1) (TypeConstructor tc2 tys2)
+  | tc1 == tc2 = Just $ foldr (\(ty1, ty2) -> (matchType ty1 ty2 .)) id $ tys
+  where tys = zip tys1 tys2
+matchType' (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) =
+  Just (matchType ty11 ty21 . matchType ty12 ty22)
+matchType' _ _ = Nothing
diff --git a/src/Transformations/CurryToIL.hs b/src/Transformations/CurryToIL.hs
new file mode 100644
--- /dev/null
+++ b/src/Transformations/CurryToIL.hs
@@ -0,0 +1,704 @@
+{- |
+    Module      :  $Header$
+    Description :  Translation of Curry into IL
+    Copyright   :  (c) 1999 - 2003 Wolfgang Lux
+                                   Martin Engelke
+                       2011 - 2015 Björn Peemöller
+                       2015        Jan Tikovsky
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   After desugaring and lifting have been performed, the source code is
+   translated into the intermediate language. Besides translating from
+   source terms and expressions into intermediate language terms and
+   expressions, this phase in particular has to implement the pattern
+   matching algorithm for equations and case expressions.
+
+   Because of name conflicts between the source and intermediate language
+   data structures, we can use only a qualified import for the 'IL' module.
+-}
+{-# LANGUAGE CPP #-}
+module Transformations.CurryToIL (ilTrans, transType) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative        ((<$>), (<*>))
+#endif
+
+import           Control.Monad.Extra         (concatMapM)
+import qualified Control.Monad.Reader as R
+import qualified Control.Monad.State  as S
+import           Data.List                   (nub, partition)
+import           Data.Maybe                  (fromJust)
+import qualified Data.Map             as Map
+import qualified Data.Set             as Set (Set, empty, insert, delete, toList)
+
+import Curry.Base.Ident
+import Curry.Syntax hiding (caseAlt)
+
+import Base.Expr
+import Base.Messages (internalError)
+import Base.Types hiding (polyType)
+import Base.Kinds
+import Base.Typing
+import Base.Utils (foldr2)
+
+import Env.TypeConstructor
+import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)
+
+import qualified IL as IL
+
+ilTrans :: Bool -> ValueEnv -> TCEnv -> Module Type -> IL.Module
+ilTrans remIm vEnv tcEnv (Module _ _ _ m _ im ds) = IL.Module m im' ds'
+  where ds' = R.runReader (concatMapM trDecl ds) (TransEnv m vEnv tcEnv)
+        im' = preludeMIdent : if remIm then imports m ds' else map moduleImport im
+        moduleImport (ImportDecl _ mdl _ _ _) = mdl
+
+
+-- -----------------------------------------------------------------------------
+-- Computation of necessary imports
+-- -----------------------------------------------------------------------------
+
+-- The list of import declarations in the intermediate language code is
+-- determined by collecting all module qualifiers used in the current module.
+
+imports :: ModuleIdent -> [IL.Decl] -> [ModuleIdent]
+imports m = Set.toList . Set.delete m . foldr mdlsDecl Set.empty
+
+mdlsDecl :: IL.Decl -> Set.Set ModuleIdent -> Set.Set ModuleIdent
+mdlsDecl (IL.DataDecl       _ _ cs) ms = foldr mdlsConstrsDecl ms cs
+  where mdlsConstrsDecl (IL.ConstrDecl _ tys) ms' = foldr mdlsType ms' tys
+mdlsDecl (IL.NewtypeDecl    _ _ nc) ms = mdlsNewConstrDecl nc
+  where mdlsNewConstrDecl (IL.NewConstrDecl _ ty) = mdlsType ty ms
+mdlsDecl (IL.ExternalDataDecl  _ _) ms = ms
+mdlsDecl (IL.FunctionDecl _ _ ty e) ms = mdlsType ty (mdlsExpr e ms)
+mdlsDecl (IL.ExternalDecl   _ _ ty) ms = mdlsType ty ms
+
+mdlsType :: IL.Type -> Set.Set ModuleIdent -> Set.Set ModuleIdent
+mdlsType (IL.TypeConstructor tc tys) ms = modules tc (foldr mdlsType ms tys)
+mdlsType (IL.TypeVariable         _) ms = ms
+mdlsType (IL.TypeArrow      ty1 ty2) ms = mdlsType ty1 (mdlsType ty2 ms)
+mdlsType (IL.TypeForall        _ ty) ms = mdlsType ty ms
+
+mdlsExpr :: IL.Expression -> Set.Set ModuleIdent -> Set.Set ModuleIdent
+mdlsExpr (IL.Function    _ f _) ms = modules f ms
+mdlsExpr (IL.Constructor _ c _) ms = modules c ms
+mdlsExpr (IL.Apply       e1 e2) ms = mdlsExpr e1 (mdlsExpr e2 ms)
+mdlsExpr (IL.Case       _ e as) ms = mdlsExpr e (foldr mdlsAlt ms as)
+  where
+  mdlsAlt     (IL.Alt                 t e') = mdlsPattern t . mdlsExpr e'
+  mdlsPattern (IL.ConstructorPattern _ c _) = modules c
+  mdlsPattern _                             = id
+mdlsExpr (IL.Or          e1 e2) ms = mdlsExpr e1 (mdlsExpr e2 ms)
+mdlsExpr (IL.Exist       _ _ e) ms = mdlsExpr e ms
+mdlsExpr (IL.Let           b e) ms = mdlsBinding b (mdlsExpr e ms)
+mdlsExpr (IL.Letrec       bs e) ms = foldr mdlsBinding (mdlsExpr e ms) bs
+mdlsExpr _                      ms = ms
+
+mdlsBinding :: IL.Binding -> Set.Set ModuleIdent -> Set.Set ModuleIdent
+mdlsBinding (IL.Binding _ e) = mdlsExpr e
+
+modules :: QualIdent -> Set.Set ModuleIdent -> Set.Set ModuleIdent
+modules x ms = maybe ms (`Set.insert` ms) (qidModule x)
+
+-- -----------------------------------------------------------------------------
+-- Internal reader monad
+-- -----------------------------------------------------------------------------
+
+data TransEnv = TransEnv
+  { moduleIdent :: ModuleIdent
+  , valueEnv    :: ValueEnv
+  , tyconEnv    :: TCEnv
+  }
+
+type TransM a = R.Reader TransEnv a
+
+getValueEnv :: TransM ValueEnv
+getValueEnv = R.asks valueEnv
+
+getTCEnv :: TransM TCEnv
+getTCEnv = R.asks tyconEnv
+
+trQualify :: Ident -> TransM QualIdent
+trQualify i = flip qualifyWith i <$> R.asks moduleIdent
+
+getArity :: QualIdent -> TransM Int
+getArity qid = do
+    vEnv <- getValueEnv
+    return $ case qualLookupValue qid vEnv of
+      [DataConstructor  _ a _ _] -> a
+      [NewtypeConstructor _ _ _] -> 1
+      [Value            _ _ a _] -> a
+      [Label              _ _ _] -> 1
+      _                          ->
+        internalError $ "CurryToIL.getArity: " ++ show qid
+
+-- Return the type of a constructor
+constrType :: QualIdent -> TransM Type
+constrType c = do
+  vEnv <- getValueEnv
+  case qualLookupValue c vEnv of
+    [DataConstructor  _ _ _ (ForAll _ (PredType _ ty))] -> return ty
+    [NewtypeConstructor _ _ (ForAll _ (PredType _ ty))] -> return ty
+    _ -> internalError $ "CurryToIL.constrType: " ++ show c
+
+-- Return the kinds of a type constructor's type variables
+tcTVarKinds :: QualIdent -> TransM [Kind]
+tcTVarKinds qid = do
+  tcEnv <- getTCEnv
+  let mid = fromJust $ qidModule qid
+      kind = tcKind mid qid tcEnv
+  return $ kindArgs kind
+
+-- -----------------------------------------------------------------------------
+-- Translation
+-- -----------------------------------------------------------------------------
+
+-- At the top-level, the compiler has to translate data type, newtype,
+-- function, and external declarations. When translating a data type or
+-- newtype declaration, we ignore the types in the declaration and lookup
+-- the types of the constructors in the type environment instead because
+-- these types are already fully expanded, i.e., they do not include any
+-- alias types.
+
+trDecl :: Decl Type -> TransM [IL.Decl]
+trDecl (DataDecl     _ tc tvs cs _) = (:[]) <$> trData tc tvs cs
+trDecl (NewtypeDecl  _ tc tvs nc _) = (:[]) <$> trNewtype tc tvs nc
+trDecl (ExternalDataDecl  _ tc tvs) = (:[]) <$> trExternalData tc tvs
+trDecl (FunctionDecl    _ _ f  eqs) = (:[]) <$> trFunction f eqs
+trDecl (ExternalDecl          _ vs) = mapM trExternal vs
+trDecl _                            = return []
+
+trData :: Ident -> [Ident] -> [ConstrDecl] -> TransM IL.Decl
+trData tc tvs cs = do
+  tc' <- trQualify tc
+  ks <- tcTVarKinds tc'
+  IL.DataDecl tc' (transKind <$> ks) <$> mapM trConstrDecl cs
+
+trNewtype :: Ident -> [Ident] -> NewConstrDecl -> TransM IL.Decl
+trNewtype tc tvs nc = do
+  tc' <- trQualify tc
+  ks <- tcTVarKinds tc'
+  IL.NewtypeDecl tc' (transKind <$> ks) <$> trNewConstrDecl nc
+
+trConstrDecl :: ConstrDecl -> TransM IL.ConstrDecl
+trConstrDecl d = do
+  c' <- trQualify (constr d)
+  ty' <- arrowArgs <$> constrType c'
+  tcEnv <- getTCEnv
+  return $ IL.ConstrDecl c' (map (transType tcEnv) ty')
+  where
+  constr (ConstrDecl    _ c _) = c
+  constr (ConOpDecl  _ _ op _) = op
+  constr (RecordDecl    _ c _) = c
+
+trNewConstrDecl :: NewConstrDecl -> TransM IL.NewConstrDecl
+trNewConstrDecl d = do
+  c' <- trQualify (constr d)
+  ty' <- arrowArgs <$> constrType c'
+  tcEnv <- getTCEnv
+  case ty' of
+    [ty] -> return $ IL.NewConstrDecl c' (transType tcEnv ty)
+    _    -> internalError "CurryToIL.trNewConstrDecl: invalid constructor type"
+  where
+  constr (NewConstrDecl    _ c _) = c
+  constr (NewRecordDecl    _ c _) = c
+
+trExternalData :: Ident -> [Ident] -> TransM IL.Decl
+trExternalData tc tvs = do
+  tc' <- trQualify tc
+  ks <- tcTVarKinds tc'
+  return $ IL.ExternalDataDecl tc' (transKind <$> ks)
+
+trExternal :: Var Type -> TransM IL.Decl
+trExternal (Var ty f) = do
+  tcEnv <- getTCEnv
+  f' <- trQualify f
+  a <- getArity f'
+  return $ IL.ExternalDecl f' a (transType tcEnv $ polyType ty)
+
+-- The type representation in the intermediate language does not support
+-- types with higher order kinds. Therefore, the type transformations has
+-- to transform all types to first order terms. To that end, we assume the
+-- existence of a type synonym 'type Apply f a = f a'. In addition, the type
+-- representation of the intermediate language does not support constrained
+-- type variables and skolem types. The former are fixed and the later are
+-- replaced by fresh type constructors.
+
+transType :: TCEnv -> Type -> IL.Type
+transType tcEnv ty' = transType' ty' []
+  where
+    ks = transTVars tcEnv ty'
+    transType' (TypeConstructor    tc) = IL.TypeConstructor tc
+    transType' (TypeApply     ty1 ty2) = transType' ty1 . (transType' ty2 [] :)
+    transType' (TypeVariable       tv) = foldl applyType' (IL.TypeVariable tv)
+    transType' (TypeConstrained tys _) = transType' (head tys)
+    transType' (TypeArrow     ty1 ty2) =
+      foldl applyType' (IL.TypeArrow (transType' ty1 []) (transType' ty2 []))
+    transType' (TypeForall     tvs ty) =
+      foldl applyType' (IL.TypeForall tvs' (transType' ty []))
+      where tvs' = filter ((`elem` tvs) . fst) ks
+
+applyType' :: IL.Type -> IL.Type -> IL.Type
+applyType' ty1 ty2 =
+  IL.TypeConstructor (qualifyWith preludeMIdent (mkIdent "Apply")) [ty1, ty2]
+
+-- We need to existentially quantify all variables in some types
+polyType :: Type -> Type
+polyType (TypeForall _ ty) = polyType ty
+polyType ty                =
+  let vs = nub $ typeVars ty
+  in if null vs then ty else TypeForall vs ty
+
+-- We need to infer kinds for the quantified variables.
+-- We already checked the correctness of all Kinds earlier,
+-- thus we know that we will be able to unify all the inferred equations.
+-- We can also keep a flat environment,
+-- as all variables have already been renamed.
+
+data KIS = KIS
+  { _nextId :: Int
+  , kinds  :: Map.Map Int IL.Kind
+  }
+
+freshId :: S.State KIS Int
+freshId = do
+  KIS i ks <- S.get
+  S.put (KIS (i+1) ks)
+  return i
+
+transTVars :: TCEnv -> Type -> [(Int, IL.Kind)]
+transTVars tcEnv ty' =
+  Map.toList $ kinds $ S.execState (build ty' IL.KindStar) (KIS 0 Map.empty)
+  where
+    build :: Type -> IL.Kind -> S.State KIS ()
+    build (TypeArrow     ty1 ty2) _ =
+      build ty1 IL.KindStar >> build ty2 IL.KindStar
+    build (TypeConstrained tys _) k =
+      build (head tys) k
+    build (TypeForall       _ ty) k =
+      build ty k
+    build (TypeVariable       tv) k = do
+      KIS i ks <- S.get
+      -- get current kind
+      let k' = Map.findWithDefault k tv ks
+      -- unify it
+      let s = unifyKind k k'
+      -- apply substitution
+      let ks' = fmap (applyKindSubst s) $ Map.insert tv k' ks
+      S.put (KIS i ks')
+    build (TypeConstructor     _) _ = return ()
+    build ta@(TypeApply       _ _) k =
+      let (ty, tys) = unapplyType True ta
+      in case ty of
+        TypeConstructor tc -> do
+          let k' = tcKind (fromJust $ qidModule tc) tc tcEnv
+          mapM_ (uncurry build) (zip tys $ unarrowKind $ transKind k')
+        _ -> do -- var of forall
+          -- construct new kind vars
+          ks <- mapM (const (freshId >>= return . IL.KindVariable)) tys
+          -- infer kind for v
+          build ty (foldr IL.KindArrow k ks)
+          -- infer kinds for args
+          mapM_ (uncurry build) (zip tys ks)
+
+type KindSubst = Map.Map Int IL.Kind
+
+transKind :: Kind -> IL.Kind
+transKind KindStar          = IL.KindStar
+transKind (KindVariable  _) = IL.KindStar
+transKind (KindArrow k1 k2) = IL.KindArrow (transKind k1) (transKind k2)
+
+unarrowKind :: IL.Kind -> [IL.Kind]
+unarrowKind (IL.KindArrow k1 k2) = k1 : unarrowKind k2
+unarrowKind k                    = [k]
+
+applyKindSubst :: KindSubst -> IL.Kind -> IL.Kind
+applyKindSubst _ IL.KindStar =
+  IL.KindStar
+applyKindSubst s (IL.KindArrow k1 k2) =
+  IL.KindArrow (applyKindSubst s k1) (applyKindSubst s k2)
+applyKindSubst s v@(IL.KindVariable i) =
+  Map.findWithDefault v i s
+
+composeKindSubst :: KindSubst -> KindSubst -> KindSubst
+composeKindSubst s1 s2 = Map.map (applyKindSubst s1) s2 `Map.union` s1
+
+unifyKind :: IL.Kind -> IL.Kind -> KindSubst
+unifyKind IL.KindStar          IL.KindStar            = Map.empty
+unifyKind (IL.KindVariable i)  k                      = Map.singleton i k
+unifyKind k                    (IL.KindVariable i)    = Map.singleton i k
+unifyKind (IL.KindArrow k1 k2) (IL.KindArrow k1' k2') =
+  let s1 = unifyKind k1 k1'
+      s2 = unifyKind (applyKindSubst s1 k2) (applyKindSubst s1 k2')
+  in s1 `composeKindSubst` s2
+unifyKind k1 k2 = error $ "Transformation.CurryToIL.unifyKind: " ++ show k1 ++ ", " ++ show k2
+
+-- Each function in the program is translated into a function of the
+-- intermediate language. The arguments of the function are renamed such
+-- that all variables occurring in the same position (in different
+-- equations) have the same name. This is necessary in order to
+-- facilitate the translation of pattern matching into a 'case' expression.
+-- We use the following simple convention here: The top-level
+-- arguments of the function are named from left to right '_1', '_2',
+-- and so on. The names of nested arguments are constructed by appending
+-- '_1', '_2', etc. from left to right to the name that were assigned
+-- to a variable occurring at the position of the constructor term.
+
+-- Some special care is needed for the selector functions introduced by
+-- the compiler in place of pattern bindings. In order to generate the
+-- code for updating all pattern variables, the equality of names between
+-- the pattern variables in the first argument of the selector function
+-- and their repeated occurrences in the remaining arguments must be
+-- preserved. This means that the second and following arguments of a
+-- selector function have to be renamed according to the name mapping
+-- computed for its first argument.
+
+trFunction :: Ident -> [Equation Type] -> TransM IL.Decl
+trFunction f eqs = do
+  f' <- trQualify f
+  tcEnv <- getTCEnv
+  let tys = map typeOf ts
+      ty' = transType tcEnv $ polyType $ foldr TypeArrow (typeOf rhs) tys
+      vs' = zip (map (transType tcEnv) tys) vs
+  alts <- mapM (trEquation vs ws) eqs
+  return $ IL.FunctionDecl f' vs' ty' (flexMatch vs' alts)
+  where
+  -- vs are the variables needed for the function: _1, _2, etc.
+  -- ws is an infinite list for introducing additional variables later
+  Equation _ lhs rhs = head eqs
+  (_, ts) = flatLhs lhs
+  (vs, ws) = splitAt (length ts) (argNames (mkIdent ""))
+
+trEquation :: [Ident]       -- identifiers for the function's parameters
+           -> [Ident]       -- infinite list of additional identifiers
+           -> Equation Type -- equation to be translated
+           -> TransM Match  -- nested constructor terms + translated RHS
+trEquation vs vs' (Equation _ (FunLhs _ _ ts) rhs) = do
+  -- construct renaming of variables inside constructor terms
+  let patternRenaming = foldr2 bindRenameEnv Map.empty vs ts
+  -- translate right-hand-side
+  rhs' <- trRhs vs' patternRenaming rhs
+  -- convert patterns
+  tcEnv <- getTCEnv
+  return (zipWith (trPattern tcEnv) vs ts, rhs')
+trEquation _  _    _
+  = internalError "Translation of non-FunLhs euqation not defined"
+
+type RenameEnv = Map.Map Ident Ident
+
+-- Construct a renaming of all variables inside the pattern to fresh identifiers
+bindRenameEnv :: Ident -> Pattern a -> RenameEnv -> RenameEnv
+bindRenameEnv _ (LiteralPattern        _ _ _) env = env
+bindRenameEnv v (VariablePattern      _ _ v') env = Map.insert v' v env
+bindRenameEnv v (ConstructorPattern _ _ _ ts) env
+  = foldr2 bindRenameEnv env (argNames v) ts
+bindRenameEnv v (AsPattern            _ v' t) env
+  = Map.insert v' v (bindRenameEnv v t env)
+bindRenameEnv _ _                           _
+  = internalError "CurryToIL.bindRenameEnv"
+
+trRhs :: [Ident] -> RenameEnv -> Rhs Type -> TransM IL.Expression
+trRhs vs env (SimpleRhs _ _ e _) = trExpr vs env e
+trRhs _  _   (GuardedRhs _ _ _ _) = internalError "CurryToIL.trRhs: GuardedRhs"
+
+-- Note that the case matching algorithm assumes that the matched
+-- expression is accessible through a variable. The translation of case
+-- expressions therefore introduces a let binding for the scrutinized
+-- expression and immediately throws it away after the matching -- except
+-- if the matching algorithm has decided to use that variable in the
+-- right hand sides of the case expression. This may happen, for
+-- instance, if one of the alternatives contains an as-pattern.
+
+trExpr :: [Ident] -> RenameEnv -> Expression Type -> TransM IL.Expression
+trExpr _  _   (Literal     _ ty l) = do
+  tcEnv <- getTCEnv
+  return $ IL.Literal (transType tcEnv ty) (trLiteral l)
+trExpr _  env (Variable    _ ty v)
+  | isQualified v = getTCEnv >>= fun
+  | otherwise     = do
+    tcEnv <- getTCEnv
+    case Map.lookup (unqualify v) env of
+      Nothing -> error $ "unexpected variable" ++ show v --TODO: Replace case by fromJust?
+      Just v' -> return $ IL.Variable (transType tcEnv ty) v' -- apply renaming
+  where
+    fun tcEnv = IL.Function (transType tcEnv ty) v <$> getArity v
+trExpr _  _   (Constructor _ ty c) = do
+  tcEnv <- getTCEnv
+  IL.Constructor (transType tcEnv ty) c <$> getArity c
+trExpr vs env (Apply     _ e1 e2)
+  = IL.Apply <$> trExpr vs env e1 <*> trExpr vs env e2
+trExpr vs env (Let      _ _ ds e) = do
+  e' <- trExpr vs env' e
+  case ds of
+    [FreeDecl _ vs']
+       -> do tcEnv <- getTCEnv
+             return $
+               foldr (\ (Var ty v) -> IL.Exist v (transType tcEnv ty)) e' vs'
+    [d] | all (`notElem` bv d) (qfv emptyMIdent d)
+      -> flip IL.Let    e' <$>      trBinding d
+    _ -> flip IL.Letrec e' <$> mapM trBinding ds
+  where
+  env' = foldr2 Map.insert env bvs bvs
+  bvs  = bv ds
+  trBinding (PatternDecl _ (VariablePattern _ _ v) rhs)
+    = IL.Binding v <$> trRhs vs env' rhs
+  trBinding p = error $ "unexpected binding: " ++ show p
+trExpr (v:vs) env (Case _ _ ct e alts) = do
+  -- the ident v is used for the case expression subject, as this could
+  -- be referenced in the case alternatives by a variable pattern
+  e' <- trExpr vs env e
+  tcEnv <- getTCEnv
+  let matcher = if ct == Flex then flexMatch else rigidMatch
+      ty'     = transType tcEnv $ typeOf e
+  expr <- matcher [(ty', v)] <$> mapM (trAlt (v:vs) env) alts
+  return $ case expr of
+    IL.Case mode (IL.Variable _ v') alts'
+        -- subject is not referenced -> forget v and insert subject
+      | v == v' && v `notElem` fv alts' -> IL.Case mode e' alts'
+    _
+        -- subject is referenced -> introduce binding for v as subject
+      | v `elem` fv expr                -> IL.Let (IL.Binding v e') expr
+      | otherwise                       -> expr
+trExpr vs env (Typed _ e _) = do
+  tcEnv <- getTCEnv
+  e' <- trExpr vs env e
+  return $ IL.Typed e' (transType tcEnv $ typeOf e)
+trExpr _ _ _ = internalError "CurryToIL.trExpr"
+
+trAlt :: [Ident] -> RenameEnv -> Alt Type -> TransM Match
+trAlt ~(v:vs) env (Alt _ t rhs) = do
+  tcEnv <- getTCEnv
+  rhs' <- trRhs vs (bindRenameEnv v t env) rhs
+  return ([trPattern tcEnv v t], rhs')
+
+trLiteral :: Literal -> IL.Literal
+trLiteral (Char  c) = IL.Char c
+trLiteral (Int   i) = IL.Int i
+trLiteral (Float f) = IL.Float f
+trLiteral _         = internalError "CurryToIL.trLiteral"
+
+-- -----------------------------------------------------------------------------
+-- Translation of Patterns
+-- -----------------------------------------------------------------------------
+
+data NestedTerm = NestedTerm IL.ConstrTerm [NestedTerm] deriving Show
+
+pattern :: NestedTerm -> IL.ConstrTerm
+pattern (NestedTerm t _) = t
+
+arguments :: NestedTerm -> [NestedTerm]
+arguments (NestedTerm _ ts) = ts
+
+trPattern :: TCEnv -> Ident -> Pattern Type -> NestedTerm
+trPattern tcEnv _ (LiteralPattern        _ ty l)
+  = NestedTerm (IL.LiteralPattern (transType tcEnv ty) $ trLiteral l) []
+trPattern tcEnv v (VariablePattern       _ ty _)
+  = NestedTerm (IL.VariablePattern (transType tcEnv ty) v) []
+trPattern tcEnv v (ConstructorPattern _ ty c ts)
+  = NestedTerm (IL.ConstructorPattern (transType tcEnv ty) c vs')
+               (zipWith (trPattern tcEnv) vs ts)
+  where vs  = argNames v
+        vs' = zip (map (transType tcEnv . typeOf) ts) vs
+trPattern tcEnv v (AsPattern              _ _ t)
+  = trPattern tcEnv v t
+trPattern _ _ _
+  = internalError "CurryToIL.trPattern"
+
+argNames :: Ident -> [Ident]
+argNames v = [mkIdent (prefix ++ show i) | i <- [1 :: Integer ..] ]
+  where prefix = idName v ++ "_"
+
+-- -----------------------------------------------------------------------------
+-- Flexible Pattern Matching Algorithm
+-- -----------------------------------------------------------------------------
+
+-- The pattern matching code searches for the left-most inductive
+-- argument position in the left hand sides of all rules defining an
+-- equation. An inductive position is a position where all rules have a
+-- constructor rooted term. If such a position is found, a flexible 'case'
+-- expression is generated for the argument at that position. The
+-- matching code is then computed recursively for all of the alternatives
+-- independently. If no inductive position is found, the algorithm looks
+-- for the left-most demanded argument position, i.e., a position where
+-- at least one of the rules has a constructor rooted term. If such a
+-- position is found, an 'or' expression is generated with those
+-- cases that have a variable at the argument position in one branch and
+-- all other rules in the other branch. If there is no demanded position,
+-- the pattern matching is finished and the compiler translates the right
+-- hand sides of the remaining rules, eventually combining them using
+-- 'or' expressions.
+
+-- Actually, the algorithm below combines the search for inductive and
+-- demanded positions. The function 'flexMatch' scans the argument
+-- lists for the left-most demanded position. If this turns out to be
+-- also an inductive position, the function 'flexMatchInductive' is
+-- called in order to generate a flexible 'case' expression. Otherwise, the
+-- function 'optFlexMatch' is called that tries to find an inductive
+-- position in the remaining arguments. If one is found,
+-- 'flexMatchInductive' is called, otherwise the function
+-- 'optFlexMatch' uses the demanded argument position found by 'flexMatch'.
+
+-- a @Match@ is a list of patterns and the respective expression.
+type Match  = ([NestedTerm], IL.Expression)
+-- a @Match'@ is a @Match@ with skipped patterns during the search for an
+-- inductive position.
+type Match' = (FunList NestedTerm, [NestedTerm], IL.Expression)
+-- Functional lists
+type FunList a = [a] -> [a]
+
+flexMatch :: [(IL.Type, Ident)] -- variables to be matched
+          -> [Match]            -- alternatives
+          -> IL.Expression      -- result expression
+flexMatch []     alts = foldl1 IL.Or (map snd alts)
+flexMatch (v:vs) alts
+  | notDemanded = varExp
+  | isInductive = conExp
+  | otherwise   = optFlexMatch (IL.Or conExp varExp) (v:) vs (map skipPat alts)
+  where
+  isInductive        = null varAlts
+  notDemanded        = null conAlts
+  -- separate variable and constructor patterns
+  (varAlts, conAlts) = partition isVarMatch (map tagAlt alts)
+  -- match variables
+  varExp             = flexMatch               vs (map snd  varAlts)
+  -- match constructors
+  conExp             = flexMatchInductive id v vs (map prep conAlts)
+  prep (p, (ts, e))  = (p, (id, ts, e))
+
+-- Search for the next inductive position
+optFlexMatch :: IL.Expression            -- default expression
+             -> FunList (IL.Type, Ident) -- skipped variables
+             -> [(IL.Type, Ident)]       -- next variables
+             -> [Match']                 -- alternatives
+             -> IL.Expression
+optFlexMatch def _      []     _    = def
+optFlexMatch def prefix (v:vs) alts
+  | isInductive = flexMatchInductive prefix v vs alts'
+  | otherwise   = optFlexMatch def (prefix . (v:)) vs (map skipPat' alts)
+  where
+  isInductive   = not (any isVarMatch alts')
+  alts'         = map tagAlt' alts
+
+-- Generate a case expression matching the inductive position
+flexMatchInductive :: FunList (IL.Type, Ident)  -- skipped variables
+                   -> (IL.Type, Ident)          -- current variable
+                   -> [(IL.Type, Ident)]        -- next variables
+                   -> [(IL.ConstrTerm, Match')] -- alternatives
+                   -> IL.Expression
+flexMatchInductive prefix v vs as
+  = IL.Case IL.Flex (uncurry IL.Variable v) (flexMatchAlts as)
+  where
+  -- create alternatives for the different constructors
+  flexMatchAlts []              = []
+  flexMatchAlts ((t, e) : alts) = IL.Alt t expr : flexMatchAlts others
+    where
+    -- match nested patterns for same constructors
+    expr = flexMatch (prefix (vars t ++ vs)) (map expandVars (e : map snd same))
+    expandVars (pref, ts1, e') = (pref ts1, e')
+    -- split into same and other constructors
+    (same, others) = partition ((t ==) . fst) alts
+
+-- -----------------------------------------------------------------------------
+-- Rigid Pattern Matching Algorithm
+-- -----------------------------------------------------------------------------
+
+-- Matching in a 'case'-expression works a little bit differently.
+-- In this case, the alternatives are matched from the first to the last
+-- alternative and the first matching alternative is chosen. All
+-- remaining alternatives are discarded.
+
+-- TODO: The case matching algorithm should use type information in order
+-- to detect total matches and immediately discard all alternatives which
+-- cannot be reached.
+
+rigidMatch :: [(IL.Type, Ident)] -> [Match] -> IL.Expression
+rigidMatch vs alts = rigidOptMatch (snd $ head alts) id vs (map prepare alts)
+  where prepare (ts, e) = (id, ts, e)
+
+rigidOptMatch :: IL.Expression            -- default expression
+              -> FunList (IL.Type, Ident) -- variables to be matched next
+              -> [(IL.Type, Ident)]       -- variables to be matched afterwards
+              -> [Match']                 -- translated equations
+              -> IL.Expression
+-- if there are no variables left: return the default expression
+rigidOptMatch def _      []       _    = def
+rigidOptMatch def prefix (v : vs) alts
+  | isDemanded = rigidMatchDemanded prefix v vs alts'
+  | otherwise  = rigidOptMatch def (prefix . (v:)) vs (map skipPat' alts)
+  where
+  isDemanded   = not $ isVarMatch (head alts')
+  alts'        = map tagAlt' alts
+
+-- Generate a case expression matching the demanded position.
+-- This algorithm constructs a branch for all contained patterns, where
+-- the right-hand side then respects the order of the patterns.
+-- Thus, the expression
+--    case x of
+--      []   -> []
+--      ys   -> ys
+--      y:ys -> [y]
+-- gets translated to
+--    case x of
+--      []   -> []
+--      y:ys -> x
+--      x    -> x
+rigidMatchDemanded :: FunList (IL.Type, Ident)  -- skipped variables
+                   -> (IL.Type, Ident)          -- current variable
+                   -> [(IL.Type, Ident)]        -- next variables
+                   -> [(IL.ConstrTerm, Match')] -- alternatives
+                   -> IL.Expression
+rigidMatchDemanded prefix v vs alts = IL.Case IL.Rigid (uncurry IL.Variable v)
+  $ map caseAlt (consPats ++ varPats)
+  where
+  -- N.B.: @varPats@ is either empty or a singleton list due to nub
+  (varPats, consPats) = partition isVarPattern $ nub $ map fst alts
+  caseAlt t           = IL.Alt t expr
+    where
+    expr = rigidMatch (prefix $ vars t ++ vs) (matchingCases alts)
+    -- matchingCases selects the matching alternatives
+    --  and recursively matches the remaining patterns
+    matchingCases a = map (expandVars (vars t)) $ filter (matches . fst) a
+    matches t' = t == t' || isVarPattern t'
+    expandVars vs' (p, (pref, ts1, e)) = (pref ts2, e)
+      where ts2 | isVarPattern p = map var2Pattern vs' ++ ts1
+                | otherwise      = ts1
+            var2Pattern v' = NestedTerm (uncurry IL.VariablePattern v') []
+
+-- -----------------------------------------------------------------------------
+-- Pattern Matching Auxiliaries
+-- -----------------------------------------------------------------------------
+
+isVarPattern :: IL.ConstrTerm -> Bool
+isVarPattern (IL.VariablePattern _ _) = True
+isVarPattern _                        = False
+
+isVarMatch :: (IL.ConstrTerm, a) -> Bool
+isVarMatch = isVarPattern . fst
+
+vars :: IL.ConstrTerm -> [(IL.Type, Ident)]
+vars (IL.ConstructorPattern _ _ vs) = vs
+vars _                              = []
+
+-- tagAlt extracts the structure of the first pattern
+tagAlt :: Match -> (IL.ConstrTerm, Match)
+tagAlt (t:ts, e) = (pattern t, (arguments t ++ ts, e))
+tagAlt ([]  , _) = error "CurryToIL.tagAlt: empty pattern list"
+
+-- skipPat skips the current pattern position for later matching
+skipPat :: Match -> Match'
+skipPat (t:ts, e) = ((t:), ts, e)
+skipPat ([]  , _) = error "CurryToIL.skipPat: empty pattern list"
+
+-- tagAlt' extracts the next pattern
+tagAlt' :: Match' -> (IL.ConstrTerm, Match')
+tagAlt' (pref, t:ts, e') = (pattern t, (pref, arguments t ++ ts, e'))
+tagAlt' (_   , []  , _ ) = error "CurryToIL.tagAlt': empty pattern list"
+
+-- skipPat' skips the current argument for later matching
+skipPat' :: Match' -> Match'
+skipPat' (pref, t:ts, e') = (pref . (t:), ts, e')
+skipPat' (_   , []  , _ ) = error "CurryToIL.skipPat': empty pattern list"
diff --git a/src/Transformations/Derive.hs b/src/Transformations/Derive.hs
new file mode 100644
--- /dev/null
+++ b/src/Transformations/Derive.hs
@@ -0,0 +1,729 @@
+{- |
+  Module      :  $Header$
+  Description :  Deriving instances
+  Copyright   :  (c) 2016        Finn Teegen
+  License     :  BSD-3-clause
+
+  Maintainer  :  bjp@informatik.uni-kiel.de
+  Stability   :  experimental
+  Portability :  portable
+
+  TODO
+-}
+{-# LANGUAGE CPP #-}
+module Transformations.Derive (derive) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative      ((<$>))
+#endif
+import Control.Monad               (replicateM)
+import qualified Control.Monad.State as S (State, evalState, gets, modify)
+import           Data.List         (intercalate, intersperse)
+import           Data.Maybe        (fromJust, isJust)
+import qualified Data.Set   as Set (deleteMin, union)
+
+import Curry.Base.Ident
+import Curry.Base.SpanInfo
+import Curry.Syntax
+
+import Base.CurryTypes (fromPredType)
+import Base.Messages (internalError)
+import Base.Types
+import Base.TypeSubst (instanceType)
+import Base.Typing (typeOf)
+import Base.Utils (snd3, mapAccumM)
+
+import Env.Instance
+import Env.OpPrec
+import Env.TypeConstructor
+import Env.Value
+
+data DVState = DVState
+  { moduleIdent :: ModuleIdent
+  , tyConsEnv   :: TCEnv
+  , valueEnv    :: ValueEnv
+  , instEnv     :: InstEnv
+  , opPrecEnv   :: OpPrecEnv
+  , nextId      :: Integer
+  }
+
+type DVM = S.State DVState
+
+derive :: TCEnv -> ValueEnv -> InstEnv -> OpPrecEnv -> Module PredType
+       -> Module PredType
+derive tcEnv vEnv inEnv pEnv (Module spi li ps m es is ds) = Module spi li ps m es is $
+  ds ++ concat (S.evalState (deriveAllInstances tds) initState)
+  where tds = filter isTypeDecl ds
+        initState = DVState m tcEnv vEnv inEnv pEnv 1
+
+getModuleIdent :: DVM ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+getTyConsEnv :: DVM TCEnv
+getTyConsEnv = S.gets tyConsEnv
+
+getValueEnv :: DVM ValueEnv
+getValueEnv = S.gets valueEnv
+
+getInstEnv :: DVM InstEnv
+getInstEnv = S.gets instEnv
+
+getPrecEnv :: DVM OpPrecEnv
+getPrecEnv = S.gets opPrecEnv
+
+getNextId :: DVM Integer
+getNextId = do
+  nid <- S.gets nextId
+  S.modify $ \s -> s { nextId = succ nid }
+  return nid
+
+-- TODO: Comment (here and below)
+
+type ConstrInfo = (Int, QualIdent, Maybe [Ident], [Type])
+
+deriveAllInstances :: [Decl PredType] -> DVM [[Decl PredType]]
+deriveAllInstances ds = do
+  derived <- mapM deriveInstances ds
+  inst <- getInstEnv
+  mid <- getModuleIdent
+  let dds = filter (hasDataInstance inst mid) ds
+  datains <- mapM deriveDataInstance dds
+  return (datains:derived)
+
+-- If we ever entered a data instance for this datatype into the instance
+-- environment, we can safely derive a data instance
+hasDataInstance :: InstEnv -> ModuleIdent -> Decl PredType -> Bool
+hasDataInstance inst mid (DataDecl    _ tc _ _ _) =
+  maybe False (\(mid', _, _) -> mid == mid') $
+    lookupInstInfo (qDataId, qualifyWith mid tc) inst
+hasDataInstance inst mid (NewtypeDecl _ tc _ _ _) =
+  maybe False (\(mid', _, _) -> mid == mid') $
+    lookupInstInfo (qDataId, qualifyWith mid tc) inst
+hasDataInstance _       _   _                     =
+  False
+
+deriveDataInstance :: Decl PredType -> DVM (Decl PredType)
+deriveDataInstance (DataDecl    p tc tvs _ _) =
+  head <$> deriveInstances (DataDecl p tc tvs [] [qDataId])
+deriveDataInstance (NewtypeDecl p tc tvs _ _) =
+  deriveDataInstance $ DataDecl p tc tvs [] []
+deriveDataInstance _                          =
+  internalError "Derive.deriveDataInstance: No DataDel"
+
+-- An instance declaration is created for each type class of a deriving clause.
+-- Newtype declaration are simply treated as data declarations.
+
+deriveInstances :: Decl PredType -> DVM [Decl PredType]
+deriveInstances (DataDecl    _ tc tvs _ clss) = do
+  m <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  let otc = qualifyWith m tc
+      cis = constructors m otc tcEnv
+  mapM (deriveInstance otc tvs cis) clss
+deriveInstances (NewtypeDecl p tc tvs _ clss) =
+  deriveInstances $ DataDecl p tc tvs [] clss
+deriveInstances _                             = return []
+
+deriveInstance :: QualIdent -> [Ident] -> [ConstrInfo] -> QualIdent
+               -> DVM (Decl PredType)
+deriveInstance tc tvs cis cls = do
+  inEnv <- getInstEnv
+  let ps = snd3 $ fromJust $ lookupInstInfo (cls, tc) inEnv
+      ty = applyType (TypeConstructor tc) $
+             take (length tvs) $ map TypeVariable [0 ..]
+      QualTypeExpr _ cx inst = fromPredType tvs $ PredType ps ty
+  ds <- deriveMethods cls ty cis ps
+  return $ InstanceDecl NoSpanInfo WhitespaceLayout cx cls inst ds
+
+-- Note: The methods and arities of the generated instance declarations have to
+-- correspond to the methods and arities entered previously into the instance
+-- environment (see instance check).
+
+deriveMethods :: QualIdent -> Type -> [ConstrInfo] -> PredSet
+              -> DVM [Decl PredType]
+deriveMethods cls
+  | cls == qEqId      = deriveEqMethods
+  | cls == qOrdId     = deriveOrdMethods
+  | cls == qEnumId    = deriveEnumMethods
+  | cls == qBoundedId = deriveBoundedMethods
+  | cls == qReadId    = deriveReadMethods
+  | cls == qShowId    = deriveShowMethods
+  | cls == qDataId    = deriveDataMethods
+  | otherwise         = internalError $ "Derive.deriveMethods: " ++ show cls
+
+-- Binary Operators:
+
+type BinOpExpr = Int
+              -> [Expression PredType]
+              -> Int
+              -> [Expression PredType]
+              -> Expression PredType
+
+deriveBinOp :: QualIdent -> Ident -> BinOpExpr -> Type -> [ConstrInfo]
+            -> PredSet -> DVM (Decl PredType)
+deriveBinOp cls op expr ty cis ps = do
+  pty <- getInstMethodType ps cls ty op
+  eqs <- mapM (deriveBinOpEquation op expr ty) $ sequence [cis, cis]
+  return $ FunctionDecl NoSpanInfo pty op $
+    if null eqs
+      then [mkEquation NoSpanInfo op [] $
+        preludeFailed $ instType $ unpredType pty]
+      else eqs
+
+deriveBinOpEquation :: Ident -> BinOpExpr -> Type -> [ConstrInfo]
+                    -> DVM (Equation PredType)
+deriveBinOpEquation op expr ty [(i1, c1, _, tys1), (i2, c2, _, tys2)] = do
+  vs1 <- mapM (freshArgument . instType) tys1
+  vs2 <- mapM (freshArgument . instType) tys2
+  let pat1 = constrPattern pty c1 vs1
+      pat2 = constrPattern pty c2 vs2
+      es1 = map (uncurry mkVar) vs1
+      es2 = map (uncurry mkVar) vs2
+  return $ mkEquation NoSpanInfo op [pat1, pat2] $ expr i1 es1 i2 es2
+  where pty = predType $ instType ty
+deriveBinOpEquation _ _ _ _ = internalError "Derive.deriveBinOpEquation"
+
+-- Equality:
+
+deriveEqMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]
+deriveEqMethods ty cis ps = sequence
+  [deriveBinOp qEqId eqOpId eqOpExpr ty cis ps]
+
+eqOpExpr :: BinOpExpr
+eqOpExpr i1 es1 i2 es2
+  | i1 == i2  = if null es1 then prelTrue
+                            else foldl1 prelAnd $ zipWith prelEq es1 es2
+  | otherwise = prelFalse
+
+-- Data:
+
+deriveDataMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]
+deriveDataMethods ty cis ps = sequence
+  [ deriveBinOp qDataId dataEqId dataEqOpExpr ty cis ps
+  , deriveAValue ty cis ps]
+
+dataEqOpExpr :: BinOpExpr
+dataEqOpExpr i1 es1 i2 es2
+  | i1 == i2  = if null es1 then prelTrue
+                            else foldl1 prelAnd $ zipWith prelDataEq es1 es2
+  | otherwise = prelFalse
+
+deriveAValue :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)
+deriveAValue ty cis ps = do
+  pty <- getInstMethodType ps qDataId ty aValueId
+  return $ FunctionDecl NoSpanInfo pty aValueId $
+    if null cis
+      then [mkEquation NoSpanInfo aValueId [] $ preludeFailed $ instType ty]
+      else map (aValueEquation ty) cis
+
+aValueEquation :: Type -> ConstrInfo -> Equation PredType
+aValueEquation ty (arity, cns, _, tys)
+  | arity >= 0 = mkEquation NoSpanInfo aValueId [] $ predType <$>
+                  foldl (Apply NoSpanInfo)
+                    (Constructor NoSpanInfo constrType cns)
+                    (map mkAValue tys')
+  | otherwise  = internalError "Derive.aValueEquation: negative arity"
+  where
+    constrType = foldr TypeArrow (instType ty) tys'
+    mkAValue argTy = Variable NoSpanInfo argTy qAValueId
+    tys' = map instType tys
+
+-- Ordering:
+
+deriveOrdMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]
+deriveOrdMethods ty cis ps = sequence
+  [deriveBinOp qOrdId leqOpId leqOpExpr ty cis ps]
+
+leqOpExpr :: BinOpExpr
+leqOpExpr i1 es1 i2 es2
+  | i1 < i2   = prelTrue
+  | i1 > i2   = prelFalse
+  | otherwise = if null es1 then prelTrue
+                            else foldl1 prelOr $ map innerAnd [0 .. n - 1]
+  where n = length es1
+        innerAnd i = foldl1 prelAnd $ map (innerOp i) [0 .. i]
+        innerOp i j | j == n - 1 = prelLeq (es1 !! j) (es2 !! j)
+                    | j == i     = prelLt  (es1 !! j) (es2 !! j)
+                    | otherwise  = prelEq  (es1 !! j) (es2 !! j)
+
+-- Enumerations:
+
+deriveEnumMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]
+deriveEnumMethods ty cis ps = sequence
+  [ deriveSuccOrPred succId ty cis (tail cis) ps
+  , deriveSuccOrPred predId ty (tail cis) cis ps
+  , deriveToEnum ty cis ps
+  , deriveFromEnum ty cis ps
+  , deriveEnumFrom ty (last cis) ps
+  , deriveEnumFromThen ty (head cis) (last cis) ps
+  ]
+
+deriveSuccOrPred :: Ident -> Type -> [ConstrInfo] -> [ConstrInfo] -> PredSet
+                 -> DVM (Decl PredType)
+deriveSuccOrPred f ty cis1 cis2 ps = do
+  pty <- getInstMethodType ps qEnumId ty f
+  FunctionDecl NoSpanInfo pty f <$>
+    if null eqs
+      then do
+        v <- freshArgument $ instType ty
+        return [mkEquation NoSpanInfo f [uncurry (VariablePattern NoSpanInfo) v] $
+          preludeFailed $ instType ty]
+      else return eqs
+  where eqs = zipWith (succOrPredEquation f ty) cis1 cis2
+
+succOrPredEquation :: Ident -> Type -> ConstrInfo -> ConstrInfo
+                   -> Equation PredType
+succOrPredEquation f ty (_, c1, _, _) (_, c2, _, _) =
+  mkEquation NoSpanInfo f [ConstructorPattern NoSpanInfo pty c1 []] $
+    Constructor NoSpanInfo pty c2
+  where pty = predType $ instType ty
+
+deriveToEnum :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)
+deriveToEnum ty cis ps = do
+  pty <- getInstMethodType ps qEnumId ty toEnumId
+  return $ FunctionDecl NoSpanInfo pty toEnumId eqs
+  where eqs = zipWith (toEnumEquation ty) [0 ..] cis
+
+toEnumEquation :: Type -> Integer -> ConstrInfo -> Equation PredType
+toEnumEquation ty i (_, c, _, _) =
+  mkEquation NoSpanInfo toEnumId
+    [LiteralPattern NoSpanInfo (predType intType) (Int i)] $
+    Constructor NoSpanInfo (predType $ instType ty) c
+
+deriveFromEnum :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)
+deriveFromEnum ty cis ps = do
+  pty <- getInstMethodType ps qEnumId ty fromEnumId
+  return $ FunctionDecl NoSpanInfo pty fromEnumId eqs
+  where eqs = zipWith (fromEnumEquation ty) cis [0 ..]
+
+fromEnumEquation :: Type -> ConstrInfo -> Integer -> Equation PredType
+fromEnumEquation ty (_, c, _, _) i =
+  mkEquation NoSpanInfo fromEnumId [ConstructorPattern NoSpanInfo pty c []] $
+    Literal NoSpanInfo (predType intType) $ Int i
+  where pty = predType $ instType ty
+
+deriveEnumFrom :: Type -> ConstrInfo -> PredSet -> DVM (Decl PredType)
+deriveEnumFrom ty (_, c, _, _) ps = do
+  pty <- getInstMethodType ps qEnumId ty enumFromId
+  v <- freshArgument $ instType ty
+  return $ funDecl NoSpanInfo pty enumFromId
+    [uncurry (VariablePattern NoSpanInfo) v] $
+    enumFromExpr v c
+
+enumFromExpr :: (PredType, Ident) -> QualIdent -> Expression PredType
+enumFromExpr v c = prelEnumFromTo (uncurry mkVar v) $
+  Constructor NoSpanInfo (fst v) c
+
+deriveEnumFromThen :: Type -> ConstrInfo -> ConstrInfo -> PredSet
+                   -> DVM (Decl PredType)
+deriveEnumFromThen ty (_, c1, _, _) (_, c2, _, _) ps = do
+  pty <- getInstMethodType ps qEnumId ty enumFromId
+  vs  <- replicateM 2 ((freshArgument . instType) ty)
+  let [v1, v2] = vs
+  return $ funDecl NoSpanInfo pty enumFromThenId
+    (map (uncurry (VariablePattern NoSpanInfo)) vs) $
+    enumFromThenExpr v1 v2 c1 c2
+
+enumFromThenExpr :: (PredType, Ident) -> (PredType, Ident) -> QualIdent
+                 -> QualIdent -> Expression PredType
+enumFromThenExpr v1 v2 c1 c2 =
+  prelEnumFromThenTo (uncurry mkVar v1) (uncurry mkVar v2) boundedExpr
+  where boundedExpr = IfThenElse NoSpanInfo
+                                 (prelLeq
+                                   (prelFromEnum $ uncurry mkVar v1)
+                                   (prelFromEnum $ uncurry mkVar v2))
+                                 (Constructor NoSpanInfo (fst v1) c2)
+                                 (Constructor NoSpanInfo (fst v1) c1)
+
+-- Upper and Lower Bounds:
+
+deriveBoundedMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]
+deriveBoundedMethods ty cis ps = sequence
+  [ deriveMaxOrMinBound qMinBoundId ty (head cis) ps
+  , deriveMaxOrMinBound qMaxBoundId ty (last cis) ps
+  ]
+
+deriveMaxOrMinBound :: QualIdent -> Type -> ConstrInfo -> PredSet
+                    -> DVM (Decl PredType)
+deriveMaxOrMinBound f ty (_, c, _, tys) ps = do
+  pty <- getInstMethodType ps qBoundedId ty $ unqualify f
+  return $ funDecl NoSpanInfo pty (unqualify f) [] $ maxOrMinBoundExpr f c ty tys
+
+maxOrMinBoundExpr :: QualIdent -> QualIdent -> Type -> [Type]
+                  -> Expression PredType
+maxOrMinBoundExpr f c ty tys =
+  apply (Constructor NoSpanInfo pty c) $
+  map (flip (Variable NoSpanInfo) f . predType) instTys
+  where instTy:instTys = map instType $ ty : tys
+        pty = predType $ foldr TypeArrow instTy instTys
+
+-- Read:
+
+deriveReadMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]
+deriveReadMethods ty cis ps = sequence [deriveReadsPrec ty cis ps]
+
+deriveReadsPrec :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)
+deriveReadsPrec ty cis ps = do
+  pty <- getInstMethodType ps qReadId ty readsPrecId
+  d <- freshArgument intType
+  r <- freshArgument stringType
+  let pats = map (uncurry (VariablePattern NoSpanInfo)) [d, r]
+  funDecl NoSpanInfo pty readsPrecId pats <$>
+    deriveReadsPrecExpr ty cis (uncurry mkVar d) (uncurry mkVar r)
+
+deriveReadsPrecExpr :: Type -> [ConstrInfo] -> Expression PredType
+                    -> Expression PredType -> DVM (Expression PredType)
+deriveReadsPrecExpr ty cis d r = do
+  es <- mapM (deriveReadsPrecReadParenExpr ty d) cis
+  return $ foldr1 prelAppend $ map (flip (Apply NoSpanInfo) r) es
+
+deriveReadsPrecReadParenExpr :: Type -> Expression PredType -> ConstrInfo
+                             -> DVM (Expression PredType)
+deriveReadsPrecReadParenExpr ty d ci@(_, c, _, _) = do
+  pEnv <- getPrecEnv
+  let p = precedence c pEnv
+  e <- deriveReadsPrecLambdaExpr ty ci p
+  return $ prelReadParen (readsPrecReadParenCondExpr ci d p) e
+
+readsPrecReadParenCondExpr :: ConstrInfo -> Expression PredType -> Precedence
+                           -> Expression PredType
+readsPrecReadParenCondExpr (_, c, _, tys) d p
+  | null tys                        = prelFalse
+  | isQInfixOp c && length tys == 2 =
+    prelLt (Literal NoSpanInfo predIntType $ Int p) d
+  | otherwise                       =
+    prelLt (Literal NoSpanInfo predIntType $ Int 10) d
+
+deriveReadsPrecLambdaExpr :: Type -> ConstrInfo -> Precedence
+                      -> DVM (Expression PredType)
+deriveReadsPrecLambdaExpr ty (_, c, ls, tys) p = do
+  r <- freshArgument stringType
+  (stmts, vs, s) <- deriveReadsPrecStmts (unqualify c) (p + 1) r ls tys
+  let pty = predType $ foldr (TypeArrow . instType) (instType ty) tys
+      e = Tuple NoSpanInfo
+                [ apply (Constructor NoSpanInfo pty c) $ map (uncurry mkVar) vs
+                , uncurry mkVar s
+                ]
+  return $ Lambda NoSpanInfo [uncurry (VariablePattern NoSpanInfo) r]
+         $ ListCompr NoSpanInfo e stmts
+
+deriveReadsPrecStmts
+  :: Ident -> Precedence -> (PredType, Ident) -> Maybe [Ident] -> [Type]
+  -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))
+deriveReadsPrecStmts c p r ls tys
+  | null tys                       = deriveReadsPrecNullaryConstrStmts c r
+  | isJust ls                      =
+    deriveReadsPrecRecordConstrStmts c r (fromJust ls) tys
+  | isInfixOp c && length tys == 2 = deriveReadsPrecInfixConstrStmts c p r tys
+  | otherwise                      = deriveReadsPrecConstrStmts c r tys
+
+deriveReadsPrecNullaryConstrStmts
+  :: Ident -> (PredType, Ident)
+  -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))
+deriveReadsPrecNullaryConstrStmts c r = do
+  (s, stmt) <- deriveReadsPrecLexStmt (idName c) r
+  return ([stmt], [], s)
+
+deriveReadsPrecRecordConstrStmts
+  :: Ident -> (PredType, Ident) -> [Ident] -> [Type]
+  -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))
+deriveReadsPrecRecordConstrStmts c r ls tys = do
+  (s, stmt1) <- deriveReadsPrecLexStmt (idName c) r
+  (t, ress) <-
+    mapAccumM deriveReadsPrecFieldStmts s $ zip3 ("{" : repeat ",") ls tys
+  let (stmtss, vs) = unzip ress
+  (u, stmt2) <- deriveReadsPrecLexStmt "}" t
+  return (stmt1 : concat stmtss ++ [stmt2], vs, u)
+
+deriveReadsPrecFieldStmts
+  :: (PredType, Ident) -> (String, Ident, Type)
+  -> DVM ((PredType, Ident), ([Statement PredType], (PredType, Ident)))
+deriveReadsPrecFieldStmts r (pre, l, ty) = do
+  (s, stmt1) <- deriveReadsPrecLexStmt pre r
+  (t, stmt2) <- deriveReadsPrecLexStmt (idName l) s
+  (u, stmt3) <- deriveReadsPrecLexStmt "=" t
+  (w, (stmt4, v)) <- deriveReadsPrecReadsPrecStmt 0 u ty
+  return (w, ([stmt1, stmt2, stmt3, stmt4], v))
+
+deriveReadsPrecInfixConstrStmts
+  :: Ident -> Precedence -> (PredType, Ident) -> [Type]
+  -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))
+deriveReadsPrecInfixConstrStmts c p r tys = do
+  (s, (stmt1, v1)) <- deriveReadsPrecReadsPrecStmt (p + 1) r $ head tys
+  (t, stmt2) <- deriveReadsPrecLexStmt (idName c) s
+  (u, (stmt3, v2)) <- deriveReadsPrecReadsPrecStmt (p + 1) t $ head $ tail tys
+  return ([stmt1, stmt2, stmt3], [v1, v2], u)
+
+deriveReadsPrecConstrStmts
+  :: Ident -> (PredType, Ident) -> [Type]
+  -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))
+deriveReadsPrecConstrStmts c r tys = do
+    (s, stmt) <- deriveReadsPrecLexStmt (idName c) r
+    (t, ress) <- mapAccumM (deriveReadsPrecReadsPrecStmt 11) s tys
+    let (stmts, vs) = unzip ress
+    return (stmt : stmts, vs, t)
+
+deriveReadsPrecLexStmt :: String -> (PredType, Ident)
+                      -> DVM ((PredType, Ident), Statement PredType)
+deriveReadsPrecLexStmt str r = do
+  s <- freshArgument stringType
+  let pat  = TuplePattern NoSpanInfo
+               [ LiteralPattern NoSpanInfo predStringType $ String str
+               , uncurry (VariablePattern NoSpanInfo) s
+               ]
+      stmt = StmtBind NoSpanInfo pat $ preludeLex $ uncurry mkVar r
+  return (s, stmt)
+
+deriveReadsPrecReadsPrecStmt  :: Precedence -> (PredType, Ident) -> Type
+      -> DVM ((PredType, Ident), (Statement PredType, (PredType, Ident)))
+deriveReadsPrecReadsPrecStmt p r ty = do
+  v <- freshArgument $ instType ty
+  s <- freshArgument $ stringType
+  let pat  = TuplePattern NoSpanInfo $
+               map (uncurry (VariablePattern NoSpanInfo)) [v, s]
+      stmt = StmtBind NoSpanInfo pat $ preludeReadsPrec (instType ty) p $
+               uncurry mkVar r
+  return (s, (stmt, v))
+
+-- Show:
+
+deriveShowMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]
+deriveShowMethods ty cis ps = sequence [deriveShowsPrec ty cis ps]
+
+deriveShowsPrec :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)
+deriveShowsPrec ty cis ps = do
+  pty <- getInstMethodType ps qShowId ty showsPrecId
+  eqs <- mapM (deriveShowsPrecEquation ty) cis
+  return $ FunctionDecl NoSpanInfo pty showsPrecId eqs
+
+deriveShowsPrecEquation :: Type -> ConstrInfo -> DVM (Equation PredType)
+deriveShowsPrecEquation ty (_, c, ls, tys) = do
+  d <- freshArgument intType
+  vs <- mapM (freshArgument . instType) tys
+  let pats = [uncurry (VariablePattern NoSpanInfo) d, constrPattern pty c vs]
+  pEnv <- getPrecEnv
+  return $ mkEquation NoSpanInfo showsPrecId pats $ showsPrecExpr (unqualify c)
+    (precedence c pEnv) ls (uncurry mkVar d) $ map (uncurry mkVar) vs
+  where pty = predType $ instType ty
+
+showsPrecExpr :: Ident -> Precedence -> Maybe [Ident] -> Expression PredType
+              -> [Expression PredType] -> Expression PredType
+showsPrecExpr c p ls d vs
+  | null vs                       = showsPrecNullaryConstrExpr c
+  | isJust ls                     = showsPrecShowParenExpr d 10 $
+    showsPrecRecordConstrExpr c (fromJust ls) vs
+  | isInfixOp c && length vs == 2 = showsPrecShowParenExpr d p $
+    showsPrecInfixConstrExpr c p vs
+  | otherwise                     = showsPrecShowParenExpr d 10 $
+    showsPrecConstrExpr c vs
+
+showsPrecNullaryConstrExpr :: Ident -> Expression PredType
+showsPrecNullaryConstrExpr c = preludeShowString $ showsConstr c ""
+
+showsPrecShowParenExpr :: Expression PredType -> Precedence
+                       -> Expression PredType -> Expression PredType
+showsPrecShowParenExpr d p =
+  prelShowParen $ prelLt (Literal NoSpanInfo predIntType $ Int p) d
+
+showsPrecRecordConstrExpr :: Ident -> [Ident] -> [Expression PredType]
+                          -> Expression PredType
+showsPrecRecordConstrExpr c ls vs = foldr prelDot (preludeShowString "}") $
+  (:) (preludeShowString $ showsConstr c " {") $
+    intercalate [preludeShowString ", "] $ zipWith showsPrecFieldExpr ls vs
+
+showsPrecFieldExpr :: Ident -> Expression PredType -> [Expression PredType]
+showsPrecFieldExpr l v =
+  [preludeShowString $ showsConstr l " = ", preludeShowsPrec 0 v]
+
+showsPrecInfixConstrExpr :: Ident -> Precedence -> [Expression PredType]
+                         -> Expression PredType
+showsPrecInfixConstrExpr c p vs = foldr1 prelDot
+  [ preludeShowsPrec (p + 1) $ head vs
+  , preludeShowString $ ' ' : idName c ++ " "
+  , preludeShowsPrec (p + 1) $ head $ tail vs
+  ]
+
+showsPrecConstrExpr :: Ident -> [Expression PredType] -> Expression PredType
+showsPrecConstrExpr c vs = foldr1 prelDot $
+  preludeShowString (showsConstr c " ") :
+    intersperse (preludeShowString " ") (map (preludeShowsPrec 11) vs)
+
+-- -----------------------------------------------------------------------------
+-- Generating variables
+-- -----------------------------------------------------------------------------
+
+freshArgument :: Type -> DVM (PredType, Ident)
+freshArgument = freshVar "_#arg"
+
+freshVar :: String -> Type -> DVM (PredType, Ident)
+freshVar name ty =
+  ((,) (predType ty)) . mkIdent . (name ++) .  show <$> getNextId
+
+-- -----------------------------------------------------------------------------
+-- Auxiliary functions
+-- -----------------------------------------------------------------------------
+
+constructors :: ModuleIdent -> QualIdent -> TCEnv -> [ConstrInfo]
+constructors m tc tcEnv =  zipWith (mkConstrInfo m) [1 ..] $
+  case qualLookupTypeInfo tc tcEnv of
+    [DataType     _ _ cs] -> cs
+    [RenamingType _ _ nc] -> [nc]
+    _                     -> internalError $ "Derive.constructors: " ++ show tc
+
+mkConstrInfo :: ModuleIdent -> Int -> DataConstr -> ConstrInfo
+mkConstrInfo m i (DataConstr   c    tys) =
+  (i, qualifyWith m c, Nothing, tys)
+mkConstrInfo m i (RecordConstr c ls tys) =
+  (i, qualifyWith m c, Just ls, tys)
+
+showsConstr :: Ident -> ShowS
+showsConstr c = showParen (isInfixOp c) $ showString $ idName c
+
+precedence :: QualIdent -> OpPrecEnv -> Precedence
+precedence op pEnv = case qualLookupP op pEnv of
+  [] -> defaultPrecedence
+  PrecInfo _ (OpPrec _ p) : _ -> p
+
+instType :: Type -> Type
+instType (TypeConstructor tc) = TypeConstructor tc
+instType (TypeVariable    tv) = TypeVariable (-1 - tv)
+instType (TypeApply  ty1 ty2) = TypeApply (instType ty1) (instType ty2)
+instType (TypeArrow  ty1 ty2) = TypeArrow (instType ty1) (instType ty2)
+instType ty = ty
+
+-- Returns the type for a given instance's method of a given class. To this
+-- end, the class method's type is stripped of its first predicate (which is
+-- the implicit class constraint) and the class variable is replaced with the
+-- instance's type. The remaining predicate set is then united with the
+-- instance's predicate set.
+
+getInstMethodType :: PredSet -> QualIdent -> Type -> Ident -> DVM PredType
+getInstMethodType ps cls ty f = do
+  vEnv <- getValueEnv
+  return $ instMethodType vEnv ps cls ty f
+
+instMethodType :: ValueEnv -> PredSet -> QualIdent -> Type -> Ident -> PredType
+instMethodType vEnv ps cls ty f = PredType (ps `Set.union` ps'') ty''
+  where PredType ps' ty' = case qualLookupValue (qualifyLike cls f) vEnv of
+          [Value _ _ _ (ForAll _ pty)] -> pty
+          _ -> internalError "Derive.instMethodType"
+        PredType ps'' ty'' = instanceType ty $ PredType (Set.deleteMin ps') ty'
+
+-- -----------------------------------------------------------------------------
+-- Prelude entities
+-- -----------------------------------------------------------------------------
+
+prelTrue :: Expression PredType
+prelTrue = Constructor NoSpanInfo predBoolType qTrueId
+
+prelFalse :: Expression PredType
+prelFalse = Constructor NoSpanInfo predBoolType qFalseId
+
+prelAppend :: Expression PredType -> Expression PredType -> Expression PredType
+prelAppend e1 e2 = foldl1 (Apply NoSpanInfo)
+  [Variable NoSpanInfo pty qAppendOpId, e1, e2]
+  where pty = predType $ foldr1 TypeArrow $ replicate 3 $ typeOf e1
+
+prelDot :: Expression PredType -> Expression PredType -> Expression PredType
+prelDot e1 e2 = foldl1 (Apply NoSpanInfo)
+  [Variable NoSpanInfo pty qDotOpId, e1, e2]
+  where ty1@(TypeArrow _    ty12) = typeOf e1
+        ty2@(TypeArrow ty21 _   ) = typeOf e2
+        pty = predType $ foldr1 TypeArrow [ty1, ty2, ty21, ty12]
+
+prelAnd :: Expression PredType -> Expression PredType -> Expression PredType
+prelAnd e1 e2 = foldl1 (Apply NoSpanInfo)
+  [Variable NoSpanInfo pty qAndOpId, e1, e2]
+  where pty = predType $ foldr1 TypeArrow $ replicate 3 boolType
+
+prelEq :: Expression PredType -> Expression PredType -> Expression PredType
+prelEq e1 e2 = foldl1 (Apply NoSpanInfo)
+  [Variable NoSpanInfo pty qEqOpId, e1, e2]
+  where ty = typeOf e1
+        pty = predType $ foldr1 TypeArrow [ty, ty, boolType]
+
+prelDataEq :: Expression PredType -> Expression PredType -> Expression PredType
+prelDataEq e1 e2 = foldl1 (Apply NoSpanInfo)
+  [Variable NoSpanInfo pty qDataEqId, e1, e2]
+  where ty = typeOf e1
+        pty = predType $ foldr1 TypeArrow [ty, ty, boolType]
+
+prelLeq :: Expression PredType -> Expression PredType -> Expression PredType
+prelLeq e1 e2 = foldl1 (Apply NoSpanInfo)
+  [Variable NoSpanInfo pty qLeqOpId, e1, e2]
+  where ty = typeOf e1
+        pty = predType $ foldr1 TypeArrow [ty, ty, boolType]
+
+prelLt :: Expression PredType -> Expression PredType -> Expression PredType
+prelLt e1 e2 = foldl1 (Apply NoSpanInfo)
+  [Variable NoSpanInfo pty qLtOpId, e1, e2]
+  where ty = typeOf e1
+        pty = predType $ foldr1 TypeArrow [ty, ty, boolType]
+
+prelOr :: Expression PredType -> Expression PredType -> Expression PredType
+prelOr e1 e2 = foldl1 (Apply NoSpanInfo)
+  [Variable NoSpanInfo pty qOrOpId, e1, e2]
+  where pty = predType $ foldr1 TypeArrow $ replicate 3 boolType
+
+prelFromEnum :: Expression PredType -> Expression PredType
+prelFromEnum e = Apply NoSpanInfo (Variable NoSpanInfo pty qFromEnumId) e
+  where pty = predType $ TypeArrow (typeOf e) intType
+
+prelEnumFromTo :: Expression PredType -> Expression PredType
+               -> Expression PredType
+prelEnumFromTo e1 e2 = apply (Variable NoSpanInfo pty qEnumFromToId) [e1, e2]
+  where ty = typeOf e1
+        pty = predType $ foldr1 TypeArrow [ty, ty, listType ty]
+
+prelEnumFromThenTo :: Expression PredType -> Expression PredType
+                   -> Expression PredType -> Expression PredType
+prelEnumFromThenTo e1 e2 e3 =
+  apply (Variable NoSpanInfo pty qEnumFromThenToId) [e1, e2, e3]
+  where ty = typeOf e1
+        pty = predType $ foldr1 TypeArrow [ty, ty, ty, listType ty]
+
+prelReadParen :: Expression PredType -> Expression PredType
+              -> Expression PredType
+prelReadParen e1 e2 = apply (Variable NoSpanInfo pty qReadParenId) [e1, e2]
+  where ty = typeOf e2
+        pty = predType $ foldr1 TypeArrow [boolType, ty, ty]
+
+prelShowParen :: Expression PredType -> Expression PredType
+              -> Expression PredType
+prelShowParen e1 e2 = apply (Variable NoSpanInfo pty qShowParenId) [e1, e2]
+  where pty = predType $ foldr1 TypeArrow [ boolType
+                                          , TypeArrow stringType stringType
+                                          , stringType, stringType
+                                          ]
+
+preludeLex :: Expression PredType -> Expression PredType
+preludeLex = Apply NoSpanInfo (Variable NoSpanInfo pty qLexId)
+  where pty = predType $ TypeArrow stringType $
+                listType $ tupleType [stringType, stringType]
+
+preludeReadsPrec :: Type -> Integer -> Expression PredType
+                 -> Expression PredType
+preludeReadsPrec ty p e = flip (Apply NoSpanInfo) e $
+  Apply NoSpanInfo (Variable NoSpanInfo pty qReadsPrecId) $
+  Literal NoSpanInfo predIntType $ Int p
+  where pty = predType $ foldr1 TypeArrow [ intType, stringType
+                                          , listType $ tupleType [ ty
+                                                                 , stringType
+                                                                 ]
+                                          ]
+
+preludeShowsPrec :: Integer -> Expression PredType -> Expression PredType
+preludeShowsPrec p e = flip (Apply NoSpanInfo) e $
+  Apply NoSpanInfo (Variable NoSpanInfo pty qShowsPrecId) $
+  Literal NoSpanInfo predIntType $ Int p
+  where pty = predType $ foldr1 TypeArrow [ intType, typeOf e
+                                          , stringType, stringType
+                                          ]
+
+preludeShowString :: String -> Expression PredType
+preludeShowString s = Apply NoSpanInfo (Variable NoSpanInfo pty qShowStringId) $
+  Literal NoSpanInfo predStringType $ String s
+  where pty = predType $ foldr1 TypeArrow $ replicate 3 stringType
+
+preludeFailed :: Type -> Expression PredType
+preludeFailed ty = Variable NoSpanInfo (predType ty) qFailedId
diff --git a/src/Transformations/Desugar.hs b/src/Transformations/Desugar.hs
new file mode 100644
--- /dev/null
+++ b/src/Transformations/Desugar.hs
@@ -0,0 +1,1168 @@
+{- |
+  Module      :  $Header$
+  Description :  Desugaring Curry Expressions
+  Copyright   :  (c) 2001 - 2004 Wolfgang Lux
+                                 Martin Engelke
+                     2011 - 2015 Björn Peemöller
+                     2015        Jan Tikovsky
+                     2016 - 2017 Finn Teegen
+  License     :  BSD-3-clause
+
+  Maintainer  :  bjp@informatik.uni-kiel.de
+  Stability   :  experimental
+  Portability :  portable
+
+  The desugaring pass removes all syntactic sugar from the module.
+  In particular, the output of the desugarer will have the following
+  properties.
+
+  * No guarded right hand sides occur in equations, pattern declarations,
+    and case alternatives. In addition, the declaration lists (`where`-blocks)
+    of the right hand sides are empty; local declarations are transformed
+    into let expressions.
+
+  * Patterns in equations and case alternatives are composed only of
+    - literals,
+    - variables,
+    - constructor applications, and
+    - as patterns applied to literals or constructor applications.
+
+  * Expressions are composed only of
+    - literals,
+    - variables,
+    - constructors,
+    - (binary) applications,
+    - case expressions,
+    - let expressions, and
+    - expressions with a type signature.
+
+  * Functional patterns are replaced by variables and are integrated
+    in a guarded right hand side using the (=:<=) operator.
+
+  * Records are transformed into ordinary data types by removing the fields.
+    Record construction and pattern matching are represented using solely the
+    record constructor. Record selections are represented using selector
+    functions which are generated for each record declaration, and record
+    updated are represented using case-expressions that perform the update.
+
+  * The type environment will be extended by new function declarations for:
+    - Record selections, and
+    - Converted lambda expressions.
+
+  As we are going to insert references to real prelude entities,
+  all names must be properly qualified before calling this module.
+-}
+{-# LANGUAGE CPP #-}
+module Transformations.Desugar (desugar) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative        ((<$>), (<*>))
+#endif
+import           Control.Arrow              (first, second)
+import           Control.Monad              (liftM2)
+import           Control.Monad.Extra        (concatMapM)
+import qualified Control.Monad.State as S   (State, runState, gets, modify)
+import           Data.Foldable              (foldrM)
+import           Data.List                  ( (\\), elemIndex, nub, partition
+                                            , tails )
+import           Data.Maybe                 (fromMaybe)
+import qualified Data.Set            as Set (Set, empty, member, insert)
+
+import Curry.Base.Ident
+import Curry.Base.SpanInfo
+import Curry.Syntax
+
+import Base.Expr
+import Base.CurryTypes
+import Base.Messages (internalError)
+import Base.TypeExpansion
+import Base.Types
+import Base.TypeSubst
+import Base.Typing
+import Base.Utils (fst3, mapAccumM)
+
+import Env.TypeConstructor (TCEnv, TypeInfo (..), qualLookupTypeInfo)
+import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)
+
+-- TODO: some types keep their spanInfo, some don't. Probably none of them are needed
+
+-- The desugaring phase keeps only the type, function, and value
+-- declarations of the module, i.e., type signatures are discarded.
+-- While record declarations are transformed into ordinary data/newtype
+-- declarations, the remaining type declarations are not desugared.
+-- Since they cannot occur in local declaration groups, they are filtered
+-- out separately. Actually, the transformation is slightly more general than
+-- necessary as it allows value declarations at the top-level of a module.
+
+desugar :: [KnownExtension] -> ValueEnv -> TCEnv -> Module PredType
+        -> (Module PredType, ValueEnv)
+desugar xs vEnv tcEnv (Module spi li ps m es is ds)
+  = (Module spi li ps m es is ds', valueEnv s')
+  where (ds', s') = S.runState (desugarModuleDecls ds)
+                               (DesugarState m xs tcEnv vEnv 1)
+
+-- ---------------------------------------------------------------------------
+-- Desugaring monad and accessor functions
+-- ---------------------------------------------------------------------------
+
+-- New identifiers may be introduced while desugaring pattern declarations,
+-- case and lambda-expressions, list comprehensions, and record selections
+-- and updates. As usual, we use a state monad transformer for generating
+-- unique names. In addition, the state is also used for passing through the
+-- type environment, which must be augmented with the types of these new
+-- variables.
+
+data DesugarState = DesugarState
+  { moduleIdent :: ModuleIdent      -- read-only
+  , extensions  :: [KnownExtension] -- read-only
+  , tyConsEnv   :: TCEnv            -- read-only
+  , valueEnv    :: ValueEnv         -- will be extended
+  , nextId      :: Integer          -- counter
+  }
+
+type DsM a = S.State DesugarState a
+
+getModuleIdent :: DsM ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+checkNegativeLitsExtension :: DsM Bool
+checkNegativeLitsExtension = S.gets (\s -> NegativeLiterals `elem` extensions s)
+
+getTyConsEnv :: DsM TCEnv
+getTyConsEnv = S.gets tyConsEnv
+
+getValueEnv :: DsM ValueEnv
+getValueEnv = S.gets valueEnv
+
+getNextId :: DsM Integer
+getNextId = do
+  nid <- S.gets nextId
+  S.modify $ \s -> s { nextId = succ nid }
+  return nid
+
+-- ---------------------------------------------------------------------------
+-- Generation of fresh names
+-- ---------------------------------------------------------------------------
+
+-- Create a fresh variable ident for a given prefix with a monomorphic type
+freshVar :: Typeable t => String -> t -> DsM (PredType, Ident)
+freshVar prefix t = do
+  v <- (mkIdent . (prefix ++) . show) <$> getNextId
+  return (predType $ typeOf t, v)
+
+-- ---------------------------------------------------------------------------
+-- Desugaring
+-- ---------------------------------------------------------------------------
+
+desugarModuleDecls :: [Decl PredType] -> DsM [Decl PredType]
+desugarModuleDecls ds = do
+  ds'    <- concatMapM dsRecordDecl ds
+  ds''   <- concatMapM dsTypeDecl ds'
+  ds'''  <- mapM dsClassAndInstanceDecl ds''
+  ds'''' <- dsDeclGroup ds'''
+  return $ filter (not . liftM2 (||) isValueDecl isTypeSig) ds''' ++ ds''''
+
+-- -----------------------------------------------------------------------------
+-- Desugaring of type declarations
+-- -----------------------------------------------------------------------------
+
+dsTypeDecl :: Decl PredType -> DsM [Decl PredType]
+dsTypeDecl (DataDecl si tc tvs cs clss) = do
+  cs' <- mapM dsConstrDecl cs
+  return $ [DataDecl si tc tvs cs' clss]
+dsTypeDecl (NewtypeDecl si tc tvs nc clss) = do
+  nc' <- dsNewConstrDecl nc
+  return $ [NewtypeDecl si tc tvs nc' clss]
+dsTypeDecl (TypeDecl _ _ _ _) = return []
+dsTypeDecl d = return [d]
+
+dsConstrDecl :: ConstrDecl -> DsM ConstrDecl
+dsConstrDecl (ConstrDecl si c tys) = ConstrDecl si c <$> mapM dsTypeExpr tys
+dsConstrDecl (ConOpDecl si ty1 op ty2) =
+  ConstrDecl si op <$> mapM dsTypeExpr [ty1, ty2]
+dsConstrDecl cd = internalError $ "Desugar.dsConstrDecl: " ++ show cd
+
+dsNewConstrDecl :: NewConstrDecl -> DsM NewConstrDecl
+dsNewConstrDecl (NewConstrDecl si c ty) = NewConstrDecl si c <$> dsTypeExpr ty
+dsNewConstrDecl nc = internalError $ "Desugar.dsNewConstrDecl: " ++ show nc
+
+-- -----------------------------------------------------------------------------
+-- Desugaring of class and instance declarations
+-- -----------------------------------------------------------------------------
+
+dsClassAndInstanceDecl :: Decl PredType -> DsM (Decl PredType)
+dsClassAndInstanceDecl (ClassDecl p li cx cls tv ds) = do
+  tds' <- mapM dsTypeSig tds
+  vds' <- dsDeclGroup vds
+  return $ ClassDecl p li cx cls tv $ tds' ++ vds'
+  where (tds, vds) = partition isTypeSig ds
+dsClassAndInstanceDecl (InstanceDecl p li cx cls ty ds) =
+  InstanceDecl p li cx cls ty <$> dsDeclGroup ds
+dsClassAndInstanceDecl d = return d
+
+dsTypeSig :: Decl PredType -> DsM (Decl PredType)
+dsTypeSig (TypeSig s fs qty) = TypeSig s fs <$> dsQualTypeExpr qty
+dsTypeSig d                  = internalError $ "Desugar.dsTypeSig: " ++ show d
+
+-- -----------------------------------------------------------------------------
+-- Desugaring of type declarations: records
+-- -----------------------------------------------------------------------------
+
+-- As an extension to the Curry language, the compiler supports Haskell's
+-- record syntax, which introduces field labels for data and renaming types.
+-- Field labels can be used in constructor declarations, patterns,
+-- and expressions. For further convenience, an implicit selector
+-- function is introduced for each field label.
+
+-- Generate selector functions for record labels and replace record
+-- constructor declarations by ordinary constructor declarations.
+dsRecordDecl :: Decl PredType -> DsM [Decl PredType]
+dsRecordDecl (DataDecl p tc tvs cs clss) = do
+  m <- getModuleIdent
+  let qcs = map (qualifyWith m . constrId) cs
+  selFuns <- mapM (genSelFun p qcs) (nub $ concatMap recordLabels cs)
+  return $ DataDecl p tc tvs (map unlabelConstr cs) clss : selFuns
+dsRecordDecl (NewtypeDecl p tc tvs nc clss) = do
+  m <- getModuleIdent
+  let qc = qualifyWith m (nconstrId nc)
+  selFun <- mapM (genSelFun p [qc]) (nrecordLabels nc)
+  return $ NewtypeDecl p tc tvs (unlabelNewConstr nc) clss : selFun
+dsRecordDecl d = return [d]
+
+-- Generate a selector function for a single record label
+genSelFun :: SpanInfo -> [QualIdent] -> Ident -> DsM (Decl PredType)
+genSelFun p qcs l = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  let ForAll _ pty = varType (qualifyWith m l) vEnv
+  FunctionDecl p pty l <$> concatMapM (genSelEqn p l) qcs
+
+-- Generate a selector equation for a label and a constructor if the label
+-- is applicable, otherwise the empty list is returned.
+genSelEqn :: SpanInfo -> Ident -> QualIdent -> DsM [Equation PredType]
+genSelEqn p l qc = do
+  vEnv <- getValueEnv
+  let (ls, ty) = conType qc vEnv
+      (tys, ty0) = arrowUnapply (instType ty)
+  case elemIndex l ls of
+    Just n  -> do
+      vs <- mapM (freshVar "_#rec") tys
+      let pat = constrPattern (predType ty0) qc vs
+      return [mkEquation p l [pat] (uncurry mkVar (vs !! n))]
+    Nothing -> return []
+
+-- Remove any labels from a data constructor declaration
+unlabelConstr :: ConstrDecl -> ConstrDecl
+unlabelConstr (RecordDecl p c fs) = ConstrDecl p c tys
+  where tys = [ty | FieldDecl _ ls ty <- fs, _ <- ls]
+unlabelConstr c                   = c
+
+-- Remove any labels from a newtype constructor declaration
+unlabelNewConstr :: NewConstrDecl -> NewConstrDecl
+unlabelNewConstr (NewRecordDecl p nc (_, ty)) = NewConstrDecl p nc ty
+unlabelNewConstr c                            = c
+
+-- -----------------------------------------------------------------------------
+-- Desugaring of value declarations
+-- -----------------------------------------------------------------------------
+
+-- Within a declaration group, all type signatures are discarded. First,
+-- the patterns occurring in the left hand sides of pattern declarations
+-- and external declarations are desugared. Due to lazy patterns, the former
+-- may add further declarations to the group that must be desugared as well.
+dsDeclGroup :: [Decl PredType] -> DsM [Decl PredType]
+dsDeclGroup ds = concatMapM dsDeclLhs (filter isValueDecl ds) >>= mapM dsDeclRhs
+
+dsDeclLhs :: Decl PredType -> DsM [Decl PredType]
+dsDeclLhs (PatternDecl p t rhs) = do
+  (ds', t') <- dsPat p [] t
+  dss'      <- mapM dsDeclLhs ds'
+  return $ PatternDecl p t' rhs : concat dss'
+dsDeclLhs d                     = return [d]
+
+-- TODO: Check if obsolete and remove
+-- After desugaring its right hand side, each equation is eta-expanded
+-- by adding as many variables as necessary to the argument list and
+-- applying the right hand side to those variables (Note: eta-expansion
+-- is disabled in the version for PAKCS).
+-- Furthermore every occurrence of a record type within the type of a function
+-- is simplified to the corresponding type constructor from the record
+-- declaration. This is possible because currently records must not be empty
+-- and a record label belongs to only one record declaration.
+
+-- Desugaring of the right-hand-side of declarations
+dsDeclRhs :: Decl PredType -> DsM (Decl PredType)
+dsDeclRhs (FunctionDecl p pty f eqs) =
+  FunctionDecl p pty f <$> mapM dsEquation eqs
+dsDeclRhs (PatternDecl      p t rhs) = PatternDecl p t <$> dsRhs id rhs
+dsDeclRhs d@(FreeDecl           _ _) = return d
+dsDeclRhs d@(ExternalDecl       _ _) = return d
+dsDeclRhs _                          =
+  error "Desugar.dsDeclRhs: no pattern match"
+
+-- Desugaring of an equation
+dsEquation :: Equation PredType -> DsM (Equation PredType)
+dsEquation (Equation p lhs rhs) = do
+  (     cs1, ts1) <- dsNonLinearity         ts
+  (ds1, cs2, ts2) <- dsFunctionalPatterns p ts1
+  (ds2,      ts3) <- mapAccumM (dsPat p) [] ts2
+  rhs'            <- dsRhs (constrain cs2 . constrain cs1)
+                           (addDecls (ds1 ++ ds2) rhs)
+  return $ Equation p (FunLhs NoSpanInfo f ts3) rhs'
+  where (f, ts) = flatLhs lhs
+
+-- Constrain an expression by a list of constraints.
+-- @constrain []  e  ==  e@
+-- @constrain c_n e  ==  (c_1 & ... & c_n) &> e@
+constrain :: [Expression PredType] -> Expression PredType -> Expression PredType
+constrain cs e = if null cs then e else foldr1 (&) cs &> e
+
+-- -----------------------------------------------------------------------------
+-- Desugaring of right-hand sides
+-- -----------------------------------------------------------------------------
+
+-- A list of boolean guards is expanded into a nested if-then-else
+-- expression, whereas a constraint guard is replaced by a case
+-- expression. Note that if the guard type is 'Success' only a
+-- single guard is allowed for each equation (This change was
+-- introduced in version 0.8 of the Curry report.). We check for the
+-- type 'Bool' of the guard because the guard's type defaults to
+-- 'Success' if it is not restricted by the guard expression.
+
+dsRhs :: (Expression PredType -> Expression PredType)
+      -> Rhs PredType -> DsM (Rhs PredType)
+dsRhs f rhs =   expandRhs (prelFailed (typeOf rhs)) f rhs
+            >>= dsExpr (getSpanInfo rhs)
+            >>= return . simpleRhs (getSpanInfo rhs)
+
+expandRhs :: Expression PredType -> (Expression PredType -> Expression PredType)
+          -> Rhs PredType -> DsM (Expression PredType)
+expandRhs _  f (SimpleRhs _ _ e ds) = return $ mkLet ds (f e)
+expandRhs e0 f (GuardedRhs _ _ es ds) = mkLet ds . f
+                                     <$> expandGuards e0 es
+
+expandGuards :: Expression PredType -> [CondExpr PredType]
+             -> DsM (Expression PredType)
+expandGuards e0 es =
+  return $ if boolGuards es then foldr mkIfThenElse e0 es else mkCond es
+  where
+  mkIfThenElse (CondExpr _ g e) = IfThenElse NoSpanInfo g e
+  mkCond [CondExpr _ g e] = g &> e
+  mkCond _                = error "Desugar.expandGuards.mkCond: non-unary list"
+
+boolGuards :: [CondExpr PredType] -> Bool
+boolGuards []                    = False
+boolGuards (CondExpr _ g _ : es) = not (null es) || typeOf g == boolType
+
+-- Add additional declarations to a right-hand side
+addDecls :: [Decl PredType] -> Rhs PredType -> Rhs PredType
+addDecls ds (SimpleRhs p li e ds') = SimpleRhs p li e (ds ++ ds')
+addDecls ds (GuardedRhs spi li es ds') = GuardedRhs spi li es (ds ++ ds')
+
+-- -----------------------------------------------------------------------------
+-- Desugaring of non-linear patterns
+-- -----------------------------------------------------------------------------
+
+-- The desugaring traverses a pattern in depth-first order and collects
+-- all variables. If it encounters a variable which has been previously
+-- introduced, the second occurrence is changed to a fresh variable
+-- and a new pair (newvar, oldvar) is saved to generate constraints later.
+-- Non-linear patterns inside single functional patterns are not desugared,
+-- as this special case is handled later.
+dsNonLinearity :: [Pattern PredType]
+               -> DsM ([Expression PredType], [Pattern PredType])
+dsNonLinearity ts = do
+  ((_, cs), ts') <- mapAccumM dsNonLinear (Set.empty, []) ts
+  return (reverse cs, ts')
+
+type NonLinearEnv = (Set.Set Ident, [Expression PredType])
+
+dsNonLinear :: NonLinearEnv -> Pattern PredType
+            -> DsM (NonLinearEnv, Pattern PredType)
+dsNonLinear env l@(LiteralPattern        _ _ _) = return (env, l)
+dsNonLinear env n@(NegativePattern       _ _ _) = return (env, n)
+dsNonLinear env t@(VariablePattern       _ _ v)
+  | isAnonId v         = return (env, t)
+  | v `Set.member` vis = do
+    v' <- freshVar "_#nonlinear" t
+    return ((vis, mkStrictEquality v v' : eqs),
+             uncurry (VariablePattern NoSpanInfo) v')
+  | otherwise          = return ((Set.insert v vis, eqs), t)
+  where (vis, eqs) = env
+dsNonLinear env (ConstructorPattern _ pty c ts)
+  = second (ConstructorPattern NoSpanInfo pty c) <$> mapAccumM dsNonLinear env ts
+dsNonLinear env (InfixPattern   _ pty t1 op t2) = do
+  (env1, t1') <- dsNonLinear env  t1
+  (env2, t2') <- dsNonLinear env1 t2
+  return (env2, InfixPattern NoSpanInfo pty t1' op t2')
+dsNonLinear env (ParenPattern              _ t) =
+  second (ParenPattern NoSpanInfo) <$> dsNonLinear env t
+dsNonLinear env (RecordPattern      _ pty c fs) =
+  second (RecordPattern NoSpanInfo pty c)
+  <$> mapAccumM (dsField dsNonLinear) env fs
+dsNonLinear env (TuplePattern             _ ts) =
+  second (TuplePattern NoSpanInfo) <$> mapAccumM dsNonLinear env ts
+dsNonLinear env (ListPattern          _ pty ts) =
+  second (ListPattern NoSpanInfo pty) <$> mapAccumM dsNonLinear env ts
+dsNonLinear env (AsPattern               _ v t) = do
+  let pty = predType $ typeOf t
+  (env1, pat) <- dsNonLinear env (VariablePattern NoSpanInfo pty v)
+  let VariablePattern _ _ v' = pat
+  (env2, t') <- dsNonLinear env1 t
+  return (env2, AsPattern NoSpanInfo v' t')
+dsNonLinear env (LazyPattern               _ t) =
+  second (LazyPattern NoSpanInfo) <$> dsNonLinear env t
+dsNonLinear env fp@(FunctionPattern    _ _ _ _) = dsNonLinearFuncPat env fp
+dsNonLinear env fp@(InfixFuncPattern _ _ _ _ _) = dsNonLinearFuncPat env fp
+
+dsNonLinearFuncPat :: NonLinearEnv -> Pattern PredType
+                   -> DsM (NonLinearEnv, Pattern PredType)
+dsNonLinearFuncPat (vis, eqs) fp = do
+  let fpVars = map (\(v, _, pty) -> (pty, v)) $ patternVars fp
+      vs     = filter ((`Set.member` vis) . snd) fpVars
+  vs' <- mapM (freshVar "_#nonlinear" . uncurry (VariablePattern NoSpanInfo)) vs
+  let vis' = foldr (Set.insert . snd) vis fpVars
+      fp'  = substPat (zip (map snd vs) (map snd vs')) fp
+  return ((vis', zipWith mkStrictEquality (map snd vs) vs' ++ eqs), fp')
+
+mkStrictEquality :: Ident -> (PredType, Ident) -> Expression PredType
+mkStrictEquality x (pty, y) = mkVar pty x =:= mkVar pty y
+
+substPat :: [(Ident, Ident)] -> Pattern a -> Pattern a
+substPat _ l@(LiteralPattern        _ _ _) = l
+substPat _ n@(NegativePattern       _ _ _) = n
+substPat s (VariablePattern         _ a v) =
+  VariablePattern NoSpanInfo a $ fromMaybe v (lookup v s)
+
+substPat s (ConstructorPattern   _ a c ps) =
+  ConstructorPattern NoSpanInfo a c $ map (substPat s) ps
+substPat s (InfixPattern     _ a p1 op p2) =
+  InfixPattern NoSpanInfo a (substPat s p1) op (substPat s p2)
+substPat s (ParenPattern              _ p) =
+  ParenPattern NoSpanInfo (substPat s p)
+substPat s (RecordPattern        _ a c fs) =
+  RecordPattern NoSpanInfo a c (map substField fs)
+  where substField (Field pos l pat) = Field pos l (substPat s pat)
+substPat s (TuplePattern             _ ps) =
+  TuplePattern NoSpanInfo $ map (substPat s) ps
+substPat s (ListPattern            _ a ps) =
+  ListPattern NoSpanInfo a $ map (substPat s) ps
+substPat s (AsPattern               _ v p) =
+  AsPattern NoSpanInfo (fromMaybe v (lookup v s)) (substPat s p)
+substPat s (LazyPattern               _ p) =
+  LazyPattern NoSpanInfo (substPat s p)
+substPat s (FunctionPattern      _ a f ps) =
+  FunctionPattern NoSpanInfo a f $ map (substPat s) ps
+substPat s (InfixFuncPattern _ a p1 op p2) =
+  InfixFuncPattern NoSpanInfo a (substPat s p1) op (substPat s p2)
+
+-- -----------------------------------------------------------------------------
+-- Desugaring of functional patterns
+-- -----------------------------------------------------------------------------
+
+-- Desugaring of functional patterns works in the following way:
+--  1. The patterns are recursively traversed from left to right
+--     to extract every functional pattern (note that functional patterns
+--     can not be nested).
+--     Each pattern is replaced by a fresh variable and a pair
+--     (variable, functional pattern) is generated.
+--  2. The variable-pattern pairs of the form @(v, p)@ are collected and
+--     transformed into additional constraints of the form @p =:<= v@,
+--     where the pattern @p@ is converted to the corresponding expression.
+--     In addition, any variable occurring in @p@ is declared as a fresh
+--     free variable.
+--     Multiple constraints will later be combined using the @&>@-operator
+--     such that the patterns are evaluated from left to right.
+
+dsFunctionalPatterns
+  :: SpanInfo -> [Pattern PredType]
+  -> DsM ([Decl PredType], [Expression PredType], [Pattern PredType])
+dsFunctionalPatterns p ts = do
+  -- extract functional patterns
+  (bs, ts') <- mapAccumM elimFP [] ts
+  -- generate declarations of free variables and constraints
+  let (ds, cs) = genFPExpr p (concatMap patternVars ts') (reverse bs)
+  -- return (declarations, constraints, desugared patterns)
+  return (ds, cs, ts')
+
+type LazyBinding = (Pattern PredType, (PredType, Ident))
+
+elimFP :: [LazyBinding] -> Pattern PredType
+       -> DsM ([LazyBinding], Pattern PredType)
+elimFP bs p@(LiteralPattern        _ _ _) = return (bs, p)
+elimFP bs p@(NegativePattern       _ _ _) = return (bs, p)
+elimFP bs p@(VariablePattern       _ _ _) = return (bs, p)
+elimFP bs (ConstructorPattern _ pty c ts) =
+  second (ConstructorPattern NoSpanInfo  pty c) <$> mapAccumM elimFP bs ts
+elimFP bs (InfixPattern   _ pty t1 op t2) = do
+  (bs1, t1') <- elimFP bs  t1
+  (bs2, t2') <- elimFP bs1 t2
+  return (bs2, InfixPattern NoSpanInfo pty t1' op t2')
+elimFP bs (ParenPattern              _ t) =
+  second (ParenPattern NoSpanInfo) <$> elimFP bs t
+elimFP bs (RecordPattern      _ pty c fs) =
+  second (RecordPattern NoSpanInfo pty c) <$> mapAccumM (dsField elimFP) bs fs
+elimFP bs (TuplePattern             _ ts) =
+  second (TuplePattern NoSpanInfo) <$> mapAccumM elimFP bs ts
+elimFP bs (ListPattern          _ pty ts) =
+  second (ListPattern NoSpanInfo pty) <$> mapAccumM elimFP bs ts
+elimFP bs (AsPattern               _ v t) =
+  second (AsPattern NoSpanInfo v) <$> elimFP bs t
+elimFP bs (LazyPattern               _ t) =
+  second (LazyPattern NoSpanInfo) <$> elimFP bs t
+elimFP bs p@(FunctionPattern    _  _ _ _) = do
+ (pty, v) <- freshVar "_#funpatt" p
+ return ((p, (pty, v)) : bs, VariablePattern NoSpanInfo pty v)
+elimFP bs p@(InfixFuncPattern  _ _ _ _ _) = do
+ (pty, v) <- freshVar "_#funpatt" p
+ return ((p, (pty, v)) : bs, VariablePattern NoSpanInfo pty v)
+
+genFPExpr :: SpanInfo -> [(Ident, Int, PredType)] -> [LazyBinding]
+          -> ([Decl PredType], [Expression PredType])
+genFPExpr p vs bs
+  | null bs   = ([]               , [])
+  | null free = ([]               , cs)
+  | otherwise = ([FreeDecl p (map (\(v, _, pty) -> Var pty v) free)], cs)
+  where
+  mkLB (t, (pty, v)) = let (t', es) = fp2Expr t
+                       in  (t' =:<= mkVar pty v) : es
+  cs   = concatMap mkLB bs
+  free = nub $ filter (not . isAnonId . fst3) $
+                 concatMap patternVars (map fst bs) \\ vs
+
+fp2Expr :: Pattern PredType -> (Expression PredType, [Expression PredType])
+fp2Expr (LiteralPattern          _ pty l) = (Literal NoSpanInfo  pty l, [])
+fp2Expr (NegativePattern         _ pty l) =
+  (Literal NoSpanInfo pty (negateLiteral l), [])
+fp2Expr (VariablePattern         _ pty v) = (mkVar pty v, [])
+fp2Expr (ConstructorPattern  _  pty c ts) =
+  let (ts', ess) = unzip $ map fp2Expr ts
+      pty' = predType $ foldr TypeArrow (unpredType pty) $ map typeOf ts
+  in  (apply (Constructor NoSpanInfo pty' c) ts', concat ess)
+fp2Expr (InfixPattern   _ pty t1 op t2) =
+  let (t1', es1) = fp2Expr t1
+      (t2', es2) = fp2Expr t2
+      pty' = predType $ foldr TypeArrow (unpredType pty) [typeOf t1, typeOf t2]
+  in  (InfixApply NoSpanInfo t1' (InfixConstr pty' op) t2', es1 ++ es2)
+fp2Expr (ParenPattern                _ t) = first (Paren NoSpanInfo) (fp2Expr t)
+fp2Expr (TuplePattern               _ ts) =
+  let (ts', ess) = unzip $ map fp2Expr ts
+  in  (Tuple NoSpanInfo ts', concat ess)
+fp2Expr (ListPattern            _ pty ts) =
+  let (ts', ess) = unzip $ map fp2Expr ts
+  in  (List NoSpanInfo pty ts', concat ess)
+fp2Expr (FunctionPattern      _ pty f ts) =
+  let (ts', ess) = unzip $ map fp2Expr ts
+      pty' = predType $ foldr TypeArrow (unpredType pty) $ map typeOf ts
+  in  (apply (Variable NoSpanInfo pty' f) ts', concat ess)
+fp2Expr (InfixFuncPattern _ pty t1 op t2) =
+  let (t1', es1) = fp2Expr t1
+      (t2', es2) = fp2Expr t2
+      pty' = predType $ foldr TypeArrow (unpredType pty) $ map typeOf [t1, t2]
+  in  (InfixApply NoSpanInfo t1' (InfixOp pty' op) t2', es1 ++ es2)
+fp2Expr (AsPattern                 _ v t) =
+  let (t', es) = fp2Expr t
+      pty = predType $ typeOf t
+  in  (mkVar pty v, (t' =:<= mkVar pty v) : es)
+fp2Expr (RecordPattern        _ pty c fs) =
+  let (fs', ess) = unzip [ (Field p f e, es) | Field p f t <- fs
+                                             , let (e, es) = fp2Expr t]
+  in  (Record NoSpanInfo pty c fs', concat ess)
+fp2Expr t                               = internalError $
+  "Desugar.fp2Expr: Unexpected constructor term: " ++ show t
+
+-- -----------------------------------------------------------------------------
+-- Desugaring of ordinary patterns
+-- -----------------------------------------------------------------------------
+
+-- The transformation of patterns is straight forward except for lazy
+-- patterns. A lazy pattern '~t' is replaced by a fresh
+-- variable 'v' and a new local declaration 't = v' in the
+-- scope of the pattern. In addition, as-patterns 'v@t' where
+-- 't' is a variable or an as-pattern are replaced by 't' in combination
+-- with a local declaration for 'v'.
+
+-- Record patterns are transformed into normal constructor patterns by
+-- rearranging fields in the order of the record's declaration, adding
+-- fresh variables in place of omitted fields, and discarding the field
+-- labels.
+
+-- Note: By rearranging fields here we loose the ability to comply
+-- strictly with the Haskell 98 pattern matching semantics, which matches
+-- fields of a record pattern in the order of their occurrence in the
+-- pattern. However, keep in mind that Haskell matches alternatives from
+-- top to bottom and arguments within an equation or alternative from
+-- left to right, which is not the case in Curry except for rigid case
+-- expressions.
+
+dsLiteralPat :: PredType -> Literal
+             -> Either (Pattern PredType) (Pattern PredType)
+dsLiteralPat pty c@(Char _) = Right (LiteralPattern NoSpanInfo pty c)
+dsLiteralPat pty (Int i) =
+  Right (LiteralPattern NoSpanInfo pty (fixLiteral (unpredType pty)))
+  where fixLiteral (TypeConstrained tys _) = fixLiteral (head tys)
+        fixLiteral ty
+          | ty == floatType = Float $ fromInteger i
+          | otherwise = Int i
+dsLiteralPat pty f@(Float _) = Right (LiteralPattern NoSpanInfo pty f)
+dsLiteralPat pty (String cs) =
+  Left $ ListPattern NoSpanInfo pty $
+  map (LiteralPattern NoSpanInfo pty' . Char) cs
+  where pty' = predType $ elemType $ unpredType pty
+
+dsPat :: SpanInfo -> [Decl PredType] -> Pattern PredType
+      -> DsM ([Decl PredType], Pattern PredType)
+dsPat _ ds v@(VariablePattern       _ _ _) = return (ds, v)
+dsPat p ds (LiteralPattern      _ pty l) =
+  either (dsPat p ds) (return . (,) ds) (dsLiteralPat pty l)
+dsPat p ds (NegativePattern       _ pty l) =
+  dsPat p ds (LiteralPattern NoSpanInfo pty (negateLiteral l))
+dsPat p ds (ConstructorPattern _ pty c ts) =
+  second (ConstructorPattern NoSpanInfo pty c) <$> mapAccumM (dsPat p) ds ts
+dsPat p ds (InfixPattern   _ pty t1 op t2) =
+  dsPat p ds (ConstructorPattern NoSpanInfo pty op [t1, t2])
+dsPat p ds (ParenPattern              _ t) = dsPat p ds t
+dsPat p ds (RecordPattern      _ pty c fs) = do
+  vEnv <- getValueEnv
+  --TODO: Rework
+  let (ls, tys) = argumentTypes (unpredType pty) c vEnv
+      tsMap = map field2Tuple fs
+  anonTs <- mapM ((uncurry (VariablePattern NoSpanInfo) <$>) .
+                  freshVar "_#recpat") tys
+  let maybeTs = map (flip lookup tsMap) ls
+      ts = zipWith fromMaybe anonTs maybeTs
+  dsPat p ds (ConstructorPattern NoSpanInfo pty c ts)
+dsPat p ds (TuplePattern              _ ts) =
+  dsPat p ds (ConstructorPattern NoSpanInfo pty (qTupleId $ length ts) ts)
+  where pty = predType (tupleType (map typeOf ts))
+dsPat p ds (ListPattern           _ pty ts) =
+  second (dsList cons nil) <$> mapAccumM (dsPat p) ds ts
+  where nil = ConstructorPattern NoSpanInfo pty qNilId []
+        cons t ts' = ConstructorPattern NoSpanInfo pty qConsId [t, ts']
+dsPat p ds (AsPattern            _ v t) = dsAs p v <$> dsPat p ds t
+dsPat p ds (LazyPattern            _ t) = dsLazy p ds t
+dsPat p ds (FunctionPattern   _   pty f ts) =
+  second (FunctionPattern NoSpanInfo pty f) <$> mapAccumM (dsPat p) ds ts
+dsPat p ds (InfixFuncPattern _ pty t1 f t2) =
+  dsPat p ds (FunctionPattern NoSpanInfo pty f [t1, t2])
+
+dsAs :: SpanInfo -> Ident -> ([Decl PredType], Pattern PredType)
+     -> ([Decl PredType], Pattern PredType)
+dsAs p v (ds, t) = case t of
+  VariablePattern _ pty v' -> (varDecl p pty  v (mkVar pty  v') : ds,t)
+  AsPattern       _  v' t' -> (varDecl p pty' v (mkVar pty' v') : ds,t)
+    where pty' = predType $ typeOf t'
+  _                      -> (ds, AsPattern NoSpanInfo v t)
+
+dsLazy :: SpanInfo -> [Decl PredType] -> Pattern PredType
+       -> DsM ([Decl PredType], Pattern PredType)
+dsLazy p ds t = case t of
+  VariablePattern _ _ _ -> return (ds, t)
+  ParenPattern     _ t' -> dsLazy p ds t'
+  AsPattern      _ v t' -> dsAs p v <$> dsLazy p ds t'
+  LazyPattern      _ t' -> dsLazy p ds t'
+  _                 -> do
+    (pty, v') <- freshVar "_#lazy" t
+    return (patDecl NoSpanInfo t (mkVar pty v') : ds,
+            VariablePattern NoSpanInfo pty v')
+
+{-
+-- -----------------------------------------------------------------------------
+-- Desugaring of expressions
+-- -----------------------------------------------------------------------------
+
+-- Record construction expressions are transformed into normal
+-- constructor applications by rearranging fields in the order of the
+-- record's declaration, passing `Prelude.unknown` in place of
+-- omitted fields, and discarding the field labels. The transformation of
+-- record update expressions is a bit more involved as we must match the
+-- updated expression with all valid constructors of the expression's
+-- type. As stipulated by the Haskell 98 Report, a record update
+-- expression @e { l_1 = e_1, ..., l_k = e_k }@ succeeds only if @e@ reduces to
+-- a value @C e'_1 ... e'_n@ such that @C@'s declaration contains all
+-- field labels @l_1,...,l_k@. In contrast to Haskell, we do not report
+-- an error if this is not the case, but call failed instead.
+-}
+dsExpr :: SpanInfo -> Expression PredType -> DsM (Expression PredType)
+dsExpr p (Literal     _ pty l) =
+  either (dsExpr p) return (dsLiteral pty l)
+dsExpr _ var@(Variable _ pty v)
+  | isAnonId (unqualify v)   = return $ prelUnknown $ unpredType pty
+  | otherwise                = return var
+dsExpr _ c@(Constructor _ _ _) = return c
+dsExpr p (Paren           _ e) = dsExpr p e
+dsExpr p (Typed       _ e qty) = Typed NoSpanInfo
+  <$> dsExpr p e <*> dsQualTypeExpr qty
+dsExpr p (Record   _ pty c fs) = do
+  vEnv <- getValueEnv
+  --TODO: Rework
+  let (ls, tys) = argumentTypes (unpredType pty) c vEnv
+      esMap = map field2Tuple fs
+      unknownEs = map prelUnknown tys
+      maybeEs = map (flip lookup esMap) ls
+      es = zipWith fromMaybe unknownEs maybeEs
+  dsExpr p (applyConstr pty c tys es)
+dsExpr p (RecordUpdate _ e fs) = do
+  alts  <- constructors tc >>= concatMapM updateAlt
+  dsExpr p $ mkCase Flex e (map (uncurry (caseAlt p)) alts)
+  where ty = typeOf e
+        pty = predType ty
+        tc = rootOfType (arrowBase ty)
+        updateAlt (RecordConstr c ls _)
+          | all (`elem` qls2) (map fieldLabel fs)= do
+            let qc = qualifyLike tc c
+            vEnv <- getValueEnv
+            let (qls, tys) = argumentTypes ty qc vEnv
+            vs <- mapM (freshVar "_#rec") tys
+            let pat = constrPattern pty qc vs
+                esMap = map field2Tuple fs
+                originalEs = map (uncurry mkVar) vs
+                maybeEs = map (flip lookup esMap) qls
+                es = zipWith fromMaybe originalEs maybeEs
+            return [(pat, applyConstr pty qc tys es)]
+          where qls2 = map (qualifyLike tc) ls
+        updateAlt _ = return []
+dsExpr p (Tuple      _ es) =
+  apply (Constructor NoSpanInfo pty $ qTupleId $ length es)
+  <$> mapM (dsExpr p) es
+  where pty = predType (foldr TypeArrow (tupleType tys) tys)
+        tys = map typeOf es
+dsExpr p (List   _ pty es) = dsList cons nil <$> mapM (dsExpr p) es
+  where nil = Constructor NoSpanInfo pty qNilId
+        cons = (Apply NoSpanInfo) . (Apply NoSpanInfo)
+          (Constructor NoSpanInfo
+            (predType $ consType $ elemType $ unpredType pty) qConsId)
+dsExpr p (ListCompr          _ e qs) = dsListComp p e qs
+dsExpr p (EnumFrom              _ e) =
+  Apply NoSpanInfo (prelEnumFrom (typeOf e)) <$> dsExpr p e
+dsExpr p (EnumFromThen      _ e1 e2) =
+  apply (prelEnumFromThen (typeOf e1)) <$> mapM (dsExpr p) [e1, e2]
+dsExpr p (EnumFromTo        _ e1 e2) = apply (prelEnumFromTo (typeOf e1))
+                                    <$> mapM (dsExpr p) [e1, e2]
+dsExpr p (EnumFromThenTo _ e1 e2 e3) = apply (prelEnumFromThenTo (typeOf e1))
+                                    <$> mapM (dsExpr p) [e1, e2, e3]
+dsExpr p (UnaryMinus            _ e) = do
+  e' <- dsExpr p e
+  negativeLitsEnabled <- checkNegativeLitsExtension
+  return $ case e' of
+    Literal _ pty l | negativeLitsEnabled ->
+      Literal NoSpanInfo pty $ negateLiteral l
+    _                                     ->
+      Apply NoSpanInfo (prelNegate $ typeOf e') e'
+dsExpr p (Apply _ e1 e2) = Apply NoSpanInfo <$> dsExpr p e1 <*> dsExpr p e2
+dsExpr p (InfixApply _ e1 op e2) = do
+  op' <- dsExpr p (infixOp op)
+  e1' <- dsExpr p e1
+  e2' <- dsExpr p e2
+  return $ apply op' [e1', e2']
+dsExpr p (LeftSection  _ e op) =
+  Apply NoSpanInfo <$> dsExpr p (infixOp op) <*> dsExpr p e
+dsExpr p (RightSection _ op e) = do
+  op' <- dsExpr p (infixOp op)
+  e'  <- dsExpr p e
+  return $ apply (prelFlip ty1 ty2 ty3) [op', e']
+  where TypeArrow ty1 (TypeArrow ty2 ty3) = typeOf (infixOp op)
+dsExpr p expr@(Lambda _ ts e) = do
+  (pty, f) <- freshVar "_#lambda" expr
+  dsExpr p $ mkLet [funDecl p pty f ts e] $ mkVar pty f
+dsExpr p (Let _ _ ds e) = do
+  ds' <- dsDeclGroup ds
+  e'  <- dsExpr p e
+  return $ mkLet ds' e'
+dsExpr p (Do            _ _ sts e) = dsDo sts e >>= dsExpr p
+dsExpr p (IfThenElse _ e1 e2 e3) = do
+  e1' <- dsExpr p e1
+  e2' <- dsExpr p e2
+  e3' <- dsExpr p e3
+  return $ mkCase Rigid e1'
+             [caseAlt p truePat e2', caseAlt p falsePat e3']
+dsExpr p (Case _ _ ct e alts) = dsCase p ct e alts
+
+-- We ignore the context in the type signature of a typed expression, since
+-- there should be no possibility to provide an non-empty context without
+-- scoped type-variables.
+-- TODO: Verify
+
+dsQualTypeExpr :: QualTypeExpr -> DsM QualTypeExpr
+dsQualTypeExpr (QualTypeExpr _ cx ty) =
+  QualTypeExpr NoSpanInfo cx <$> dsTypeExpr ty
+
+dsTypeExpr :: TypeExpr -> DsM TypeExpr
+dsTypeExpr ty = do
+  m <- getModuleIdent
+  tcEnv <- getTyConsEnv
+  let tvs = typeVariables ty
+  return $ fromType tvs $ expandType m tcEnv $ toType tvs ty
+
+-- -----------------------------------------------------------------------------
+-- Desugaring of case expressions
+-- -----------------------------------------------------------------------------
+
+-- If an alternative in a case expression has boolean guards and all of
+-- these guards return 'False', the enclosing case expression does
+-- not fail but continues to match the remaining alternatives against the
+-- selector expression. In order to implement this semantics, which is
+-- compatible with Haskell, we expand an alternative with boolean guards
+-- such that it evaluates a case expression with the remaining cases that
+-- are compatible with the matched pattern when the guards fail.
+
+dsCase :: SpanInfo -> CaseType -> Expression PredType -> [Alt PredType]
+       -> DsM (Expression PredType)
+dsCase p ct e alts
+  | null alts = internalError "Desugar.dsCase: empty list of alternatives"
+  | otherwise = do
+    m  <- getModuleIdent
+    e' <- dsExpr p e
+    v  <- freshVar "_#case" e
+    alts'  <- mapM dsAltLhs alts
+    alts'' <- mapM (expandAlt v ct) (init (tails alts')) >>= mapM dsAltRhs
+    return (mkMyCase m v e' alts'')
+  where
+  mkMyCase m (pty, v) e' bs
+    | v `elem` qfv m bs = mkLet [varDecl p pty v e']
+                          (mkCase ct (mkVar pty v) bs)
+    | otherwise         = mkCase ct e' bs
+
+dsAltLhs :: Alt PredType -> DsM (Alt PredType)
+dsAltLhs (Alt p t rhs) = do
+  (ds', t') <- dsPat p [] t
+  return $ Alt p t' (addDecls ds' rhs)
+
+dsAltRhs :: Alt PredType -> DsM (Alt PredType)
+dsAltRhs (Alt p t rhs) = Alt p t <$> dsRhs id rhs
+
+expandAlt :: (PredType, Ident) -> CaseType -> [Alt PredType]
+          -> DsM (Alt PredType)
+expandAlt _ _  []                   = error "Desugar.expandAlt: empty list"
+expandAlt v ct (Alt p t rhs : alts) = caseAlt p t <$> expandRhs e0 id rhs
+  where
+  e0 | ct == Flex || null compAlts = prelFailed (typeOf rhs)
+     | otherwise = mkCase ct (uncurry mkVar v) compAlts
+  compAlts = filter (isCompatible t . altPattern) alts
+  altPattern (Alt _ t1 _) = t1
+
+isCompatible :: Pattern a -> Pattern a -> Bool
+isCompatible (VariablePattern _ _ _) _ = True
+isCompatible _ (VariablePattern _ _ _) = True
+isCompatible (AsPattern _ _ t1) t2 = isCompatible t1 t2
+isCompatible t1 (AsPattern _ _ t2) = isCompatible t1 t2
+isCompatible (ConstructorPattern _ _ c1 ts1) (ConstructorPattern _ _ c2 ts2)
+  = and ((c1 == c2) : zipWith isCompatible ts1 ts2)
+isCompatible (LiteralPattern _ _ l1) (LiteralPattern _ _ l2) = l1 == l2
+isCompatible _ _ = False
+
+-- -----------------------------------------------------------------------------
+-- Desugaring of do-Notation
+-- -----------------------------------------------------------------------------
+
+-- The do-notation is desugared in the following way:
+--
+-- `dsDo([]         , e)` -> `e`
+-- `dsDo(e'     ; ss, e)` -> `e' >>        dsDo(ss, e)`
+-- `dsDo(p <- e'; ss, e)` -> `e' >>= \v -> case v of
+--                                           p -> dsDo(ss, e)
+--                                           _ -> fail "..."`
+-- `dsDo(let ds ; ss, e)` -> `let ds in    dsDo(ss, e)`
+dsDo :: [Statement PredType] -> Expression PredType -> DsM (Expression PredType)
+dsDo sts e = foldrM dsStmt e sts
+
+dsStmt :: Statement PredType -> Expression PredType -> DsM (Expression PredType)
+dsStmt (StmtExpr   _ e1) e' =
+  return $ apply (prelBind_ (typeOf e1) (typeOf e')) [e1, e']
+dsStmt (StmtBind _ t e1) e' = do
+  v <- freshVar "_#var" t
+  failable <- checkFailableBind t
+  let func = mkLambda [uncurry (VariablePattern NoSpanInfo) v] $
+               mkCase Rigid (uncurry mkVar v) $
+                 caseAlt NoSpanInfo t e' :
+                   if failable
+                     then [caseAlt NoSpanInfo
+                                   (uncurry (VariablePattern NoSpanInfo) v)
+                                   (failedPatternMatch $ typeOf e')]
+                     else []
+  return $ apply (prelBind (typeOf e1) (typeOf t) (typeOf e')) [e1, func]
+  where failedPatternMatch ty =
+          apply (prelFail ty)
+            [Literal NoSpanInfo predStringType $ String "Pattern match failed!"]
+dsStmt (StmtDecl   _ _ ds) e' = return $ mkLet ds e'
+
+checkFailableBind :: Pattern a -> DsM Bool
+checkFailableBind (ConstructorPattern _ _ idt ps   ) = do
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfo idt tcEnv of
+    [RenamingType _ _ _ ] -> or <$> mapM checkFailableBind ps -- or [] == False
+    [DataType     _ _ cs]
+      | length cs == 1    -> or <$> mapM checkFailableBind ps
+      | otherwise         -> return True
+    _                     -> return True
+checkFailableBind (InfixPattern       _ _ p1 idt p2) = do
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfo idt tcEnv of
+    [RenamingType _ _ _ ] -> (||) <$> checkFailableBind p1
+                                  <*> checkFailableBind p2
+    [DataType     _ _ cs]
+      | length cs == 1    -> (||) <$> checkFailableBind p1
+                                  <*> checkFailableBind p2
+      | otherwise         -> return True
+    _                     -> return True
+checkFailableBind (RecordPattern      _ _ idt fs   ) = do
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfo idt tcEnv of
+    [RenamingType _ _ _ ] -> or <$> mapM (checkFailableBind . fieldContent) fs
+    [DataType     _ _ cs]
+      | length cs == 1    -> or <$> mapM (checkFailableBind . fieldContent) fs
+      | otherwise         -> return True
+    _                     -> return True
+  where fieldContent (Field _ _ c) = c
+checkFailableBind (TuplePattern       _       ps   ) =
+  or <$> mapM checkFailableBind ps
+checkFailableBind (AsPattern          _   _   p    ) = checkFailableBind p
+checkFailableBind (ParenPattern       _       p    ) = checkFailableBind p
+checkFailableBind (LazyPattern        _       _    ) = return False
+checkFailableBind (VariablePattern    _ _ _        ) = return False
+checkFailableBind _                                  = return True
+-- -----------------------------------------------------------------------------
+-- Desugaring of List Comprehensions
+-- -----------------------------------------------------------------------------
+
+-- In general, a list comprehension of the form
+-- '[e | t <- l, qs]'
+-- is transformed into an expression 'foldr f [] l' where 'f'
+-- is a new function defined as
+--
+--     f x xs =
+--       case x of
+--           t -> [e | qs] ++ xs
+--           _ -> xs
+--
+-- Note that this translation evaluates the elements of 'l' rigidly,
+-- whereas the translation given in the Curry report is flexible.
+-- However, it does not seem very useful to have the comprehension
+-- generate instances of 't' which do not contribute to the list.
+-- TODO: Unfortunately, this is incorrect.
+
+-- Actually, we generate slightly better code in a few special cases.
+-- When 't' is a plain variable, the 'case' expression degenerates
+-- into a let-binding and the auxiliary function thus becomes an alias
+-- for '(++)'. Instead of 'foldr (++)' we use the
+-- equivalent prelude function 'concatMap'. In addition, if the
+-- remaining list comprehension in the body of the auxiliary function has
+-- no qualifiers -- i.e., if it is equivalent to '[e]' -- we
+-- avoid the construction of the singleton list by calling '(:)'
+-- instead of '(++)' and 'map' in place of 'concatMap', respectively.
+
+dsListComp :: SpanInfo -> Expression PredType -> [Statement PredType]
+           -> DsM (Expression PredType)
+dsListComp p e []     =
+  dsExpr p (List NoSpanInfo (predType $ listType $ typeOf e) [e])
+dsListComp p e (q:qs) = dsQual p q (ListCompr NoSpanInfo e qs)
+
+dsQual :: SpanInfo -> Statement PredType -> Expression PredType
+       -> DsM (Expression PredType)
+dsQual p (StmtExpr   _ b) e =
+  dsExpr p (IfThenElse NoSpanInfo b e (List NoSpanInfo (predType $ typeOf e) []))
+dsQual p (StmtDecl _ _ ds) e = dsExpr p (mkLet ds e)
+dsQual p (StmtBind _ t l) e
+  | isVariablePattern t = dsExpr p (qualExpr t e l)
+  | otherwise = do
+    v <- freshVar "_#var" t
+    l' <- freshVar "_#var" e
+    dsExpr p (apply (prelFoldr (typeOf t) (typeOf e))
+      [foldFunct v l' e, List NoSpanInfo (predType $ typeOf e) [], l])
+  where
+  qualExpr v (ListCompr NoSpanInfo e1 []) l1
+    = apply (prelMap (typeOf v) (typeOf e1)) [mkLambda [v] e1, l1]
+  qualExpr v e1                  l1
+    = apply (prelConcatMap (typeOf v) (elemType $ typeOf e1))
+      [mkLambda [v] e1, l1]
+  foldFunct v l1 e1
+    = mkLambda (map (uncurry (VariablePattern NoSpanInfo)) [v, l1])
+       (mkCase Rigid (uncurry mkVar v)
+          [ caseAlt p t (append e1 (uncurry mkVar l1))
+          , caseAlt p (uncurry (VariablePattern NoSpanInfo) v)
+                                    (uncurry mkVar l1)])
+
+  append (ListCompr _ e1 []) l1 = apply (prelCons (typeOf e1)) [e1, l1]
+  append e1                  l1 =
+    apply (prelAppend (elemType $ typeOf e1)) [e1, l1]
+  prelCons ty                   =
+      Constructor NoSpanInfo (predType $ consType ty) $ qConsId
+
+-- -----------------------------------------------------------------------------
+-- Desugaring of Lists, labels, fields, and literals
+-- -----------------------------------------------------------------------------
+
+dsList :: (b -> b -> b) -> b -> [b] -> b
+dsList = foldr
+
+--dsLabel :: a -> [(QualIdent, a)] -> QualIdent -> a
+--dsLabel def fs l = fromMaybe def (lookup l fs)
+
+dsField :: (a -> b -> DsM (a, b)) -> a -> Field b -> DsM (a, Field b)
+dsField ds z (Field p l x) = second (Field p l) <$> ds z x
+
+dsLiteral :: PredType -> Literal
+          -> Either (Expression PredType) (Expression PredType)
+dsLiteral pty (Char c) = Right $ Literal NoSpanInfo pty $ Char c
+dsLiteral pty (Int i) = Right $ fixLiteral (unpredType pty)
+  where fixLiteral (TypeConstrained tys _) = fixLiteral (head tys)
+        fixLiteral ty
+          | ty == intType = Literal NoSpanInfo pty $ Int i
+          | ty == floatType = Literal NoSpanInfo pty $ Float $ fromInteger i
+          | otherwise = Apply NoSpanInfo (prelFromInt $ unpredType pty) $
+                          Literal NoSpanInfo predIntType $ Int i
+dsLiteral pty f@(Float _) = Right $ fixLiteral (unpredType pty)
+  where fixLiteral (TypeConstrained tys _) = fixLiteral (head tys)
+        fixLiteral ty
+          | ty == floatType = Literal NoSpanInfo pty f
+          | otherwise = Apply NoSpanInfo (prelFromFloat $ unpredType pty) $
+                          Literal NoSpanInfo predFloatType f
+dsLiteral pty (String cs) =
+  Left $ List NoSpanInfo pty $ map (Literal NoSpanInfo pty' . Char) cs
+  where pty' = predType $ elemType $ unpredType pty
+
+negateLiteral :: Literal -> Literal
+negateLiteral (Int i) = Int (-i)
+negateLiteral (Float f) = Float (-f)
+negateLiteral _ = internalError "Desugar.negateLiteral"
+
+-- ---------------------------------------------------------------------------
+-- Prelude entities
+-- ---------------------------------------------------------------------------
+
+preludeFun :: [Type] -> Type -> String -> Expression PredType
+preludeFun tys ty = Variable NoSpanInfo (predType $ foldr TypeArrow ty tys)
+                  . preludeIdent
+
+preludeIdent :: String -> QualIdent
+preludeIdent = qualifyWith preludeMIdent . mkIdent
+
+prelBind :: Type -> Type -> Type -> Expression PredType
+prelBind ma a mb = preludeFun [ma, TypeArrow a mb] mb ">>="
+
+prelBind_ :: Type -> Type -> Expression PredType
+prelBind_ ma mb = preludeFun [ma, mb] mb ">>"
+
+prelFlip :: Type -> Type -> Type -> Expression PredType
+prelFlip a b c = preludeFun [TypeArrow a (TypeArrow b c), b, a] c "flip"
+
+prelFromInt :: Type -> Expression PredType
+prelFromInt a = preludeFun [intType] a "fromInt"
+
+prelFromFloat :: Type -> Expression PredType
+prelFromFloat a = preludeFun [floatType] a "fromFloat"
+
+prelEnumFrom :: Type -> Expression PredType
+prelEnumFrom a = preludeFun [a] (listType a) "enumFrom"
+
+prelEnumFromTo :: Type -> Expression PredType
+prelEnumFromTo a = preludeFun [a, a] (listType a) "enumFromTo"
+
+prelEnumFromThen :: Type -> Expression PredType
+prelEnumFromThen a = preludeFun [a, a] (listType a) "enumFromThen"
+
+prelEnumFromThenTo :: Type -> Expression PredType
+prelEnumFromThenTo a = preludeFun [a, a, a] (listType a) "enumFromThenTo"
+
+prelNegate :: Type -> Expression PredType
+prelNegate a = preludeFun [a] a "negate"
+
+prelFail :: Type -> Expression PredType
+prelFail ma = preludeFun [stringType] ma "fail"
+
+prelFailed :: Type -> Expression PredType
+prelFailed a = preludeFun [] a "failed"
+
+prelUnknown :: Type -> Expression PredType
+prelUnknown a = preludeFun [] a "unknown"
+
+prelMap :: Type -> Type -> Expression PredType
+prelMap a b = preludeFun [TypeArrow a b, listType a] (listType b) "map"
+
+prelFoldr :: Type -> Type -> Expression PredType
+prelFoldr a b =
+  preludeFun [TypeArrow a (TypeArrow b b), b, listType a] b "foldr"
+
+prelAppend :: Type -> Expression PredType
+prelAppend a = preludeFun [listType a, listType a] (listType a) "++"
+
+prelConcatMap :: Type -> Type -> Expression PredType
+prelConcatMap a b =
+  preludeFun [TypeArrow a (listType b), listType a] (listType b) "concatMap"
+
+(=:<=) :: Expression PredType -> Expression PredType -> Expression PredType
+e1 =:<= e2 = apply (preludeFun [typeOf e1, typeOf e2] boolType "=:<=") [e1, e2]
+
+(=:=) :: Expression PredType -> Expression PredType -> Expression PredType
+e1 =:= e2 = apply (preludeFun [typeOf e1, typeOf e2] boolType "=:=") [e1, e2]
+
+(&>) :: Expression PredType -> Expression PredType -> Expression PredType
+e1 &> e2 = apply (preludeFun [boolType, typeOf e2] (typeOf e2) "cond") [e1, e2]
+
+(&) :: Expression PredType -> Expression PredType -> Expression PredType
+e1 & e2 = apply (preludeFun [boolType, boolType] boolType "&") [e1, e2]
+
+truePat :: Pattern PredType
+truePat = ConstructorPattern NoSpanInfo predBoolType qTrueId []
+
+falsePat :: Pattern PredType
+falsePat = ConstructorPattern NoSpanInfo predBoolType qFalseId []
+
+-- ---------------------------------------------------------------------------
+-- Auxiliary definitions
+-- ---------------------------------------------------------------------------
+
+conType :: QualIdent -> ValueEnv -> ([Ident], TypeScheme)
+conType c vEnv = case qualLookupValue c vEnv of
+  [DataConstructor _ _ ls ty] -> (ls , ty)
+  [NewtypeConstructor _ l ty] -> ([l], ty)
+  _                           -> internalError $ "Desguar.conType: " ++ show c
+
+varType :: QualIdent -> ValueEnv -> TypeScheme
+varType v vEnv = case qualLookupValue v vEnv of
+  Value _ _ _ tySc : _ -> tySc
+  Label _ _   tySc : _ -> tySc
+  _                    -> internalError $ "Desugar.varType: " ++ show v
+
+elemType :: Type -> Type
+elemType (TypeApply (TypeConstructor tc) ty) | tc == qListId = ty
+elemType ty = internalError $ "Base.Types.elemType " ++ show ty
+
+applyConstr :: PredType -> QualIdent -> [Type] -> [Expression PredType]
+            -> Expression PredType
+applyConstr pty c tys =
+  apply (Constructor NoSpanInfo
+    (predType (foldr TypeArrow (unpredType pty) tys)) c)
+
+-- The function 'instType' instantiates the universally quantified
+-- type variables of a type scheme with fresh type variables. Since this
+-- function is used only to instantiate the closed types of record
+-- constructors (recall that no existentially quantified type
+-- variables are allowed for records), the compiler can reuse the same
+-- monomorphic type variables for every instantiated type.
+
+instType :: TypeScheme -> Type
+instType (ForAll _ pty) = inst $ unpredType pty
+  where inst (TypeConstructor     tc) = TypeConstructor tc
+        inst (TypeApply      ty1 ty2) = TypeApply (inst ty1) (inst ty2)
+        inst (TypeVariable        tv) = TypeVariable (-1 - tv)
+        inst (TypeArrow      ty1 ty2) = TypeArrow (inst ty1) (inst ty2)
+        inst ty                       = ty
+
+-- Retrieve all constructors of a type
+constructors :: QualIdent -> DsM [DataConstr]
+constructors tc = getTyConsEnv >>= \tcEnv -> return $
+  case qualLookupTypeInfo tc tcEnv of
+    [DataType     _ _ cs] -> cs
+    [RenamingType _ _ nc] -> [nc]
+    _                     ->
+      internalError $ "Transformations.Desugar.constructors: " ++ show tc
+
+-- The function 'argumentTypes' returns the labels and the argument types
+-- of a data constructor instantiated at a particular type.
+
+argumentTypes :: Type -> QualIdent -> ValueEnv -> ([QualIdent], [Type])
+argumentTypes ty c vEnv =
+  (map (qualifyLike c) ls, map (subst (matchType ty0 ty idSubst)) tys)
+  where (ls, ForAll _ (PredType _ ty')) = conType c vEnv
+        (tys, ty0) = arrowUnapply ty'
diff --git a/src/Transformations/Dictionary.hs b/src/Transformations/Dictionary.hs
new file mode 100644
--- /dev/null
+++ b/src/Transformations/Dictionary.hs
@@ -0,0 +1,1143 @@
+{- |
+  Module      :  $Header$
+  Description :  Dictionary insertion
+  Copyright   :  (c) 2016 - 2017 Finn Teegen
+  License     :  BSD-3-clause
+
+  Maintainer  :  bjp@informatik.uni-kiel.de
+  Stability   :  experimental
+  Portability :  portable
+
+  TODO
+-}
+
+{-# LANGUAGE CPP #-}
+module Transformations.Dictionary
+  ( insertDicts
+  , dictTypeId, qDictTypeId, dictConstrId, qDictConstrId
+  , defaultMethodId, qDefaultMethodId, superDictStubId, qSuperDictStubId
+  , instFunId, qInstFunId, implMethodId, qImplMethodId
+  ) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative      ((<$>), (<*>))
+import           Data.Traversable         (traverse)
+#endif
+import           Control.Monad.Extra      ( concatMapM, liftM, maybeM, when
+                                          , zipWithM )
+import qualified Control.Monad.State as S (State, runState, gets, modify)
+
+import           Data.List         (inits, nub, partition, tails, zipWith4)
+import qualified Data.Map   as Map ( Map, empty, insert, lookup, mapWithKey
+                                   , toList )
+import           Data.Maybe        (fromMaybe, isJust)
+import qualified Data.Set   as Set ( deleteMin, fromList, null, size, toAscList
+                                   , toList, union )
+
+import Curry.Base.Ident
+import Curry.Base.Position
+import Curry.Base.SpanInfo
+import Curry.Syntax
+
+import Base.CurryTypes
+import Base.Expr
+import Base.Kinds
+import Base.Messages (internalError)
+import Base.TopEnv
+import Base.Types
+import Base.TypeSubst
+import Base.Typing
+
+import Env.Class
+import Env.Instance
+import Env.Interface
+import Env.OpPrec
+import Env.TypeConstructor
+import Env.Value
+
+data DTState = DTState
+  { moduleIdent :: ModuleIdent
+  , tyConsEnv   :: TCEnv
+  , valueEnv    :: ValueEnv
+  , classEnv    :: ClassEnv
+  , instEnv     :: InstEnv
+  , opPrecEnv   :: OpPrecEnv
+  , dictEnv     :: DictEnv    -- for dictionary insertion
+  , specEnv     :: SpecEnv    -- for dictionary specialization
+  , nextId      :: Integer
+  }
+
+type DTM = S.State DTState
+
+insertDicts :: Bool -> InterfaceEnv -> TCEnv -> ValueEnv -> ClassEnv
+            -> InstEnv -> OpPrecEnv -> Module PredType
+            -> (Module Type, InterfaceEnv, TCEnv, ValueEnv, OpPrecEnv)
+insertDicts inlDi intfEnv tcEnv vEnv clsEnv inEnv pEnv mdl@(Module _ _ _ m _ _ _) =
+  (mdl', intfEnv', tcEnv', vEnv', pEnv')
+  where initState =
+          DTState m tcEnv vEnv clsEnv inEnv pEnv emptyDictEnv emptySpEnv 1
+        (mdl', tcEnv', vEnv', pEnv') =
+          runDTM (dictTrans mdl >>= (if inlDi then specialize else return) >>= cleanup) initState
+        intfEnv' = dictTransInterfaces vEnv' clsEnv intfEnv
+
+runDTM :: DTM a -> DTState -> (a, TCEnv, ValueEnv, OpPrecEnv)
+runDTM dtm s =
+  let (a, s') = S.runState dtm s in (a, tyConsEnv s', valueEnv s', opPrecEnv s')
+
+getModuleIdent :: DTM ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+getTyConsEnv :: DTM TCEnv
+getTyConsEnv = S.gets tyConsEnv
+
+modifyTyConsEnv :: (TCEnv -> TCEnv) -> DTM ()
+modifyTyConsEnv f = S.modify $ \s -> s { tyConsEnv = f $ tyConsEnv s }
+
+getValueEnv :: DTM ValueEnv
+getValueEnv = S.gets valueEnv
+
+modifyValueEnv :: (ValueEnv -> ValueEnv) -> DTM ()
+modifyValueEnv f = S.modify $ \s -> s { valueEnv = f $ valueEnv s }
+
+withLocalValueEnv :: DTM a -> DTM a
+withLocalValueEnv act = do
+  oldEnv <- getValueEnv
+  res <- act
+  modifyValueEnv $ const oldEnv
+  return res
+
+getClassEnv :: DTM ClassEnv
+getClassEnv = S.gets classEnv
+
+getInstEnv :: DTM InstEnv
+getInstEnv = S.gets instEnv
+
+modifyInstEnv :: (InstEnv -> InstEnv) -> DTM ()
+modifyInstEnv f = S.modify $ \s -> s { instEnv = f $ instEnv s }
+
+getPrecEnv :: DTM OpPrecEnv
+getPrecEnv = S.gets opPrecEnv
+
+modifyPrecEnv :: (OpPrecEnv -> OpPrecEnv) -> DTM ()
+modifyPrecEnv f = S.modify $ \s -> s { opPrecEnv = f $ opPrecEnv s }
+
+getDictEnv :: DTM DictEnv
+getDictEnv = S.gets dictEnv
+
+modifyDictEnv :: (DictEnv -> DictEnv) -> DTM ()
+modifyDictEnv f = S.modify $ \s -> s { dictEnv = f $ dictEnv s }
+
+withLocalDictEnv :: DTM a -> DTM a
+withLocalDictEnv act = do
+  oldEnv <- getDictEnv
+  res <- act
+  modifyDictEnv $ const oldEnv
+  return res
+
+getSpEnv :: DTM SpecEnv
+getSpEnv = S.gets specEnv
+
+setSpEnv :: SpecEnv -> DTM ()
+setSpEnv spEnv = S.modify $ \s -> s { specEnv = spEnv }
+
+getNextId :: DTM Integer
+getNextId = do
+  nid <- S.gets nextId
+  S.modify $ \s -> s { nextId = succ nid }
+  return nid
+
+-- -----------------------------------------------------------------------------
+-- Lifting class and instance declarations
+-- -----------------------------------------------------------------------------
+
+-- When we lift class and instance declarations, we can remove the optional
+-- default declaration since it has already been considered during the type
+-- check.
+
+liftDecls :: Decl PredType -> DTM [Decl PredType]
+liftDecls (DefaultDecl _ _) = return []
+liftDecls (ClassDecl _ _ _ cls tv ds) = do
+  m <- getModuleIdent
+  liftClassDecls (qualifyWith m cls) tv ds
+liftDecls (InstanceDecl _ _ cx cls ty ds) = do
+  clsEnv <- getClassEnv
+  let PredType ps ty' = toPredType [] $ QualTypeExpr NoSpanInfo cx ty
+      ps' = minPredSet clsEnv ps
+  liftInstanceDecls ps' cls ty' ds
+liftDecls d = return [d]
+
+liftClassDecls :: QualIdent -> Ident -> [Decl PredType] -> DTM [Decl PredType]
+liftClassDecls cls tv ds = do
+  dictDecl <- createClassDictDecl cls tv ods
+  clsEnv <- getClassEnv
+  let fs = classMethods cls clsEnv
+  methodDecls <- mapM (createClassMethodDecl cls ms) fs
+  return $ dictDecl : methodDecls
+  where (vds, ods) = partition isValueDecl ds
+        ms = methodMap vds
+
+liftInstanceDecls :: PredSet -> QualIdent -> Type -> [Decl PredType]
+                  -> DTM [Decl PredType]
+liftInstanceDecls ps cls ty ds = do
+  dictDecl <- createInstDictDecl ps cls ty
+  clsEnv <- getClassEnv
+  let fs = classMethods cls clsEnv
+  methodDecls <- mapM (createInstMethodDecl ps cls ty ms) fs
+  return $ dictDecl : methodDecls
+  where ms = methodMap ds
+
+-- Since not every class method needs to be implemented in a class or instance
+-- declaration, we use a map to associate a class method identifier with its
+-- implementation.
+
+type MethodMap = [(Ident, Decl PredType)]
+
+-- We have to unrename the method's identifiers here because the syntax check
+-- has renamed them before.
+
+methodMap :: [Decl PredType] -> MethodMap
+methodMap ds = [(unRenameIdent f, d) | d@(FunctionDecl _ _ f _) <- ds]
+
+createClassDictDecl :: QualIdent -> Ident -> [Decl a] -> DTM (Decl a)
+createClassDictDecl cls tv ds = do
+  c <- createClassDictConstrDecl cls tv ds
+  return $ DataDecl NoSpanInfo (dictTypeId cls) [tv] [c] []
+
+createClassDictConstrDecl :: QualIdent -> Ident -> [Decl a] -> DTM ConstrDecl
+createClassDictConstrDecl cls tv ds = do
+  let tvs  = tv : filter (unRenameIdent tv /=) identSupply
+      mtys = map (fromType tvs . generalizeMethodType . transformMethodPredType)
+                 [toMethodType cls tv qty | TypeSig _ fs qty <- ds, _ <- fs]
+  return $ ConstrDecl NoSpanInfo (dictConstrId cls) mtys
+
+classDictConstrPredType :: ValueEnv -> ClassEnv -> QualIdent -> PredType
+classDictConstrPredType vEnv clsEnv cls = PredType ps $ foldr TypeArrow ty mtys
+  where sclss = superClasses cls clsEnv
+        ps    = Set.fromList [Pred scls (TypeVariable 0) | scls <- sclss]
+        fs    = classMethods cls clsEnv
+        mptys = map (classMethodType vEnv cls) fs
+        ty    = dictType $ Pred cls $ TypeVariable 0
+        mtys  = map (generalizeMethodType . transformMethodPredType) mptys
+
+createInstDictDecl :: PredSet -> QualIdent -> Type -> DTM (Decl PredType)
+createInstDictDecl ps cls ty = do
+  pty <- PredType ps . arrowBase <$> getInstDictConstrType cls ty
+  funDecl NoSpanInfo pty (instFunId cls ty) [ConstructorPattern NoSpanInfo predUnitType qUnitId []] <$> createInstDictExpr cls ty
+
+createInstDictExpr :: QualIdent -> Type -> DTM (Expression PredType)
+createInstDictExpr cls ty = do
+  ty' <- instType <$> getInstDictConstrType cls ty
+  m <- getModuleIdent
+  clsEnv <- getClassEnv
+  let fs = map (qImplMethodId m cls ty) $ classMethods cls clsEnv
+  return $ apply (Constructor NoSpanInfo (predType ty') (qDictConstrId cls))
+             (zipWith (Variable NoSpanInfo . predType) (arrowArgs ty') fs)
+
+getInstDictConstrType :: QualIdent -> Type -> DTM Type
+getInstDictConstrType cls ty = do
+  vEnv <- getValueEnv
+  clsEnv <- getClassEnv
+  return $ instanceType ty $ unpredType $ classDictConstrPredType vEnv clsEnv cls
+
+createClassMethodDecl :: QualIdent -> MethodMap -> Ident -> DTM (Decl PredType)
+createClassMethodDecl cls =
+  createMethodDecl (defaultMethodId cls) (defaultClassMethodDecl cls)
+
+defaultClassMethodDecl :: QualIdent -> Ident -> DTM (Decl PredType)
+defaultClassMethodDecl cls f = do
+  pty@(PredType _ ty) <- getClassMethodType cls f
+  return $ funDecl NoSpanInfo pty f [] $ preludeError (instType ty) $
+    "No instance or default method for class operation " ++ escName f
+
+getClassMethodType :: QualIdent -> Ident -> DTM PredType
+getClassMethodType cls f = do
+  vEnv <- getValueEnv
+  return $ classMethodType vEnv cls f
+
+classMethodType :: ValueEnv -> QualIdent -> Ident -> PredType
+classMethodType vEnv cls f = pty
+  where ForAll _ pty = funType (qualifyLike cls f) vEnv
+
+createInstMethodDecl :: PredSet -> QualIdent -> Type -> MethodMap -> Ident
+                     -> DTM (Decl PredType)
+createInstMethodDecl ps cls ty =
+  createMethodDecl (implMethodId cls ty) (defaultInstMethodDecl ps cls ty)
+
+defaultInstMethodDecl :: PredSet -> QualIdent -> Type -> Ident
+                      -> DTM (Decl PredType)
+defaultInstMethodDecl ps cls ty f = do
+  vEnv <- getValueEnv
+  let pty@(PredType _ ty') = instMethodType vEnv ps cls ty f
+  return $ funDecl NoSpanInfo pty f [] $
+    Variable NoSpanInfo (predType $ instType ty') (qDefaultMethodId cls f)
+
+-- Returns the type for a given instance's method of a given class. To this
+-- end, the class method's type is stripped of its first predicate (which is
+-- the implicit class constraint) and the class variable is replaced with the
+-- instance's type. The remaining predicate set is then united with the
+-- instance's predicate set.
+
+instMethodType :: ValueEnv -> PredSet -> QualIdent -> Type -> Ident -> PredType
+instMethodType vEnv ps cls ty f = PredType (ps `Set.union` ps'') ty''
+  where PredType ps'  ty'  = classMethodType vEnv cls f
+        PredType ps'' ty'' = instanceType ty $ PredType (Set.deleteMin ps') ty'
+
+createMethodDecl :: (Ident -> Ident) -> (Ident -> DTM (Decl PredType))
+                 -> MethodMap -> Ident -> DTM (Decl PredType)
+createMethodDecl methodId defaultDecl ms f =
+  liftM (renameDecl $ methodId f) $ maybe (defaultDecl f) return (lookup f ms)
+
+-- We have to rename the left hand side of lifted function declarations
+-- accordingly which is done by the function 'renameDecl'.
+
+renameDecl :: Ident -> Decl a -> Decl a
+renameDecl f (FunctionDecl p a _ eqs) = FunctionDecl p a f $ map renameEq eqs
+  where renameEq (Equation p' lhs rhs) = Equation p' (renameLhs lhs) rhs
+        renameLhs (FunLhs _ _ ts) = FunLhs NoSpanInfo f ts
+        renameLhs _ = internalError "Dictionary.renameDecl.renameLhs"
+renameDecl _ _ = internalError "Dictionary.renameDecl"
+
+-- -----------------------------------------------------------------------------
+-- Creating stub declarations
+-- -----------------------------------------------------------------------------
+
+-- For each class method f defined in the processed module we have to introduce
+-- a stub method with the same name that selects the appropriate function from
+-- the provided dictionary and applies the remaining arguments to it. We also
+-- create a stub method for each super class selecting the corresponding super
+-- class dictionary from the provided class dictionary.
+
+createStubs :: Decl PredType -> DTM [Decl Type]
+createStubs (ClassDecl _ _ _ cls _ _) = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  clsEnv <- getClassEnv
+  let ocls  = qualifyWith m cls
+      sclss = superClasses ocls clsEnv
+      fs    = classMethods ocls clsEnv
+      dictConstrPty = classDictConstrPredType vEnv clsEnv ocls
+      (superDictAndMethodTys, dictTy) =
+        arrowUnapply $ transformPredType dictConstrPty
+      (superDictTys, methodTys)       =
+        splitAt (length sclss) superDictAndMethodTys
+      (superStubTys, methodStubTys)   =
+        splitAt (length sclss) $ map (TypeArrow dictTy) superDictAndMethodTys
+  superDictVs <- mapM (freshVar "_#super" . instType) superDictTys
+  methodVs <- mapM (freshVar "_#meth" . instType) methodTys
+  let patternVs   = superDictVs ++ methodVs
+      pattern     = createDictPattern (instType dictTy) ocls patternVs
+      superStubs  = zipWith3 (createSuperDictStubDecl pattern ocls)
+                      superStubTys sclss superDictVs
+      methodStubs = zipWith3 (createMethodStubDecl pattern)
+                      methodStubTys fs methodVs
+  return $ superStubs ++ methodStubs
+createStubs _ = return []
+
+createDictPattern :: Type -> QualIdent -> [(Type, Ident)] -> Pattern Type
+createDictPattern a cls = constrPattern a (qDictConstrId cls)
+
+createSuperDictStubDecl :: Pattern Type -> QualIdent -> Type -> QualIdent
+                        -> (Type, Ident) -> Decl Type
+createSuperDictStubDecl t cls a super v =
+  createStubDecl t a (superDictStubId cls super) v
+
+createMethodStubDecl :: Pattern Type -> Type -> Ident -> (Type, Ident) -> Decl Type
+createMethodStubDecl = createStubDecl
+
+createStubDecl :: Pattern Type -> Type -> Ident -> (Type, Ident) -> Decl Type
+createStubDecl t a f v =
+  FunctionDecl NoSpanInfo a f [createStubEquation t f v]
+
+createStubEquation :: Pattern Type -> Ident -> (Type, Ident) -> Equation Type
+createStubEquation t f v = 
+  mkEquation NoSpanInfo f [VariablePattern NoSpanInfo (TypeArrow unitType (typeOf t)) (mkIdent "_#temp")] $
+    mkLet [FunctionDecl NoSpanInfo (TypeArrow (typeOf t) (fst v)) (mkIdent "_#lambda")
+      [mkEquation NoSpanInfo (mkIdent "_#lambda") [t] $ uncurry mkVar v]]
+      (apply (Variable NoSpanInfo (TypeArrow (typeOf t) (fst v)) (qualify $ mkIdent "_#lambda"))
+        [apply (Variable NoSpanInfo (TypeArrow unitType (typeOf t)) (qualify $ mkIdent "_#temp"))
+          [Constructor NoSpanInfo unitType qUnitId]])
+
+superDictStubType :: QualIdent -> QualIdent -> Type -> Type
+superDictStubType cls super ty =
+  TypeArrow (rtDictType $ Pred cls ty) (rtDictType $ Pred super ty)
+
+-- -----------------------------------------------------------------------------
+-- Entering new bindings into the environments
+-- -----------------------------------------------------------------------------
+
+bindDictTypes :: ModuleIdent -> ClassEnv -> TCEnv -> TCEnv
+bindDictTypes m clsEnv tcEnv =
+  foldr (bindDictType m clsEnv) tcEnv (allEntities tcEnv)
+
+bindDictType :: ModuleIdent -> ClassEnv -> TypeInfo -> TCEnv -> TCEnv
+bindDictType m clsEnv (TypeClass cls k ms) = bindEntity m tc ti
+  where ti    = DataType tc (KindArrow k KindStar) [c]
+        tc    = qDictTypeId cls
+        c     = DataConstr (dictConstrId cls) (map rtDictType (Set.toAscList ps) ++ tys)
+        sclss = superClasses cls clsEnv
+        ps    = Set.fromList [Pred scls (TypeVariable 0) | scls <- sclss]
+        tys   = map (generalizeMethodType . transformMethodPredType . methodType) ms
+bindDictType _ _      _                    = id
+
+bindClassDecls :: ModuleIdent -> TCEnv -> ClassEnv -> ValueEnv -> ValueEnv
+bindClassDecls m tcEnv clsEnv =
+  flip (foldr $ bindClassEntities m clsEnv) $ allEntities tcEnv
+
+-- It is safe to use 'fromMaybe 0' in 'bindClassEntities', because the
+-- augmentation has already replaced the 'Nothing' value for the arity
+-- of a method's implementation with 'Just 1' (despite the fact that
+-- maybe no default implementation has been provided) if the method has
+-- been augmented.
+
+bindClassEntities :: ModuleIdent -> ClassEnv -> TypeInfo -> ValueEnv -> ValueEnv
+bindClassEntities m clsEnv (TypeClass cls _ ms) =
+  bindClassDict m clsEnv cls . bindSuperStubs m cls sclss .
+    bindDefaultMethods m cls fs
+  where fs    = zip (map methodName ms) (map (fromMaybe 0 . methodArity) ms)
+        sclss = superClasses cls clsEnv
+bindClassEntities _ _ _ = id
+
+bindClassDict :: ModuleIdent -> ClassEnv -> QualIdent -> ValueEnv -> ValueEnv
+bindClassDict m clsEnv cls vEnv = bindEntity m c dc vEnv
+  where c  = qDictConstrId cls
+        dc = DataConstructor c a (replicate a anonId) tySc
+        a  = Set.size ps + arrowArity ty
+        pty@(PredType ps ty) = classDictConstrPredType vEnv clsEnv cls
+        tySc = ForAll 1 pty
+
+bindDefaultMethods :: ModuleIdent -> QualIdent -> [(Ident, Int)] -> ValueEnv
+                   -> ValueEnv
+bindDefaultMethods m = flip . foldr . bindDefaultMethod m
+
+bindDefaultMethod :: ModuleIdent -> QualIdent -> (Ident, Int) -> ValueEnv
+                  -> ValueEnv
+bindDefaultMethod m cls (f, n) vEnv =
+  bindMethod m (qDefaultMethodId cls f) n (classMethodType vEnv cls f) vEnv
+
+bindSuperStubs :: ModuleIdent -> QualIdent -> [QualIdent] -> ValueEnv
+               -> ValueEnv
+bindSuperStubs m = flip . foldr . bindSuperStub m
+
+bindSuperStub :: ModuleIdent -> QualIdent -> QualIdent -> ValueEnv -> ValueEnv
+bindSuperStub m cls scls = bindEntity m f $ Value f Nothing 1 $ polyType ty
+  where f  = qSuperDictStubId cls scls
+        ty = superDictStubType cls scls (TypeVariable 0)
+
+bindInstDecls :: ModuleIdent -> TCEnv -> ClassEnv -> InstEnv -> ValueEnv
+                  -> ValueEnv
+bindInstDecls m tcEnv clsEnv =
+  flip (foldr $ bindInstFuns m tcEnv clsEnv) . Map.toList
+
+bindInstFuns :: ModuleIdent -> TCEnv -> ClassEnv -> (InstIdent, InstInfo)
+             -> ValueEnv -> ValueEnv
+bindInstFuns m tcEnv clsEnv ((cls, tc), (m', ps, is)) =
+  bindInstDict m cls ty m' ps . bindInstMethods m clsEnv cls ty m' ps is
+  where ty = applyType (TypeConstructor tc) (take n (map TypeVariable [0..]))
+        n = kindArity (tcKind m tc tcEnv) - kindArity (clsKind m cls tcEnv)
+
+bindInstDict :: ModuleIdent -> QualIdent -> Type -> ModuleIdent -> PredSet
+             -> ValueEnv -> ValueEnv
+bindInstDict m cls ty m' ps =
+  bindMethod m (qInstFunId m' cls ty) 1 $ PredType ps $ rtDictType $ Pred cls ty
+
+bindInstMethods :: ModuleIdent -> ClassEnv -> QualIdent -> Type -> ModuleIdent
+                -> PredSet -> [(Ident, Int)] -> ValueEnv -> ValueEnv
+bindInstMethods m clsEnv cls ty m' ps is =
+  flip (foldr (bindInstMethod m cls ty m' ps is)) (classMethods cls clsEnv)
+
+bindInstMethod :: ModuleIdent -> QualIdent -> Type -> ModuleIdent
+               -> PredSet -> [(Ident, Int)] -> Ident -> ValueEnv -> ValueEnv
+bindInstMethod m cls ty m' ps is f vEnv = bindMethod m f' a pty vEnv
+  where f'  = qImplMethodId m' cls ty f
+        a   = fromMaybe 0 $ lookup f is
+        pty = instMethodType vEnv ps cls ty f
+
+bindMethod :: ModuleIdent -> QualIdent -> Int -> PredType -> ValueEnv
+           -> ValueEnv
+bindMethod m f n pty = bindEntity m f $ Value f Nothing n $ typeScheme pty
+
+-- The function 'bindEntity' introduces a binding for an entity into a top-level
+-- environment. Depending on whether the entity is defined in the current module
+-- or not, either an unqualified and a qualified local binding or a qualified
+-- import are added to the environment.
+
+bindEntity :: Entity a => ModuleIdent -> QualIdent -> a -> TopEnv a
+           -> TopEnv a
+bindEntity m x = case qidModule (qualUnqualify m x) of
+  Just m' | m /= m' -> qualImportTopEnv m' x'
+  _                 -> qualBindTopEnv (qualifyWith m x')
+  where x' = unqualify x
+
+-- -----------------------------------------------------------------------------
+-- Transforming the environments
+-- -----------------------------------------------------------------------------
+
+dictTransTypes :: TCEnv -> TCEnv
+dictTransTypes = fmap dictTransTypeInfo
+
+dictTransTypeInfo :: TypeInfo -> TypeInfo
+dictTransTypeInfo (DataType tc k cs) =
+  DataType tc k $ map dictTransDataConstr cs
+dictTransTypeInfo (RenamingType tc k nc) =
+  RenamingType tc k $ dictTransDataConstr nc
+dictTransTypeInfo ti@(AliasType _ _ _ _) = ti
+dictTransTypeInfo (TypeClass cls k ms) =
+  TypeClass cls k $ map dictTransClassMethod ms
+dictTransTypeInfo (TypeVar _) =
+  internalError "Dictionary.dictTransTypeInfo: type variable"
+
+dictTransDataConstr :: DataConstr -> DataConstr
+dictTransDataConstr (DataConstr c tys) = DataConstr c tys
+dictTransDataConstr (RecordConstr c _ tys) =
+  dictTransDataConstr $ DataConstr c tys
+
+-- For the same reason as in 'bindClassEntities' it is safe to use 'fromMaybe 0'
+-- in 'dictTransClassMethod'. Note that type classes are removed anyway in the
+-- cleanup phase.
+
+dictTransClassMethod :: ClassMethod -> ClassMethod
+dictTransClassMethod (ClassMethod f a pty) = ClassMethod f a' $ predType ty
+  where a' = Just $ fromMaybe 0 a + arrowArity ty - arrowArity (unpredType pty)
+        ty = transformPredType pty
+
+dictTransValues :: ValueEnv -> ValueEnv
+dictTransValues = fmap dictTransValueInfo
+
+dictTransValueInfo :: ValueInfo -> ValueInfo
+dictTransValueInfo (DataConstructor c a ls (ForAll n pty)) =
+  DataConstructor c a' ls' $ ForAll n $ predType ty
+  where a'  = arrowArity ty
+        ls' = replicate (a' - a) anonId ++ ls
+        ty  = transformPredType pty
+dictTransValueInfo (NewtypeConstructor c l (ForAll n pty)) =
+  NewtypeConstructor c l (ForAll n (predType (unpredType pty)))
+dictTransValueInfo (Value f cm a (ForAll n pty)) =
+  Value f Nothing a' $ ForAll n $ predType ty
+  where a' = a + if isJust cm then 1 else arrowArity ty - arrowArity (unpredType pty)
+        ty = transformPredType pty
+dictTransValueInfo (Label l cs (ForAll n pty)) =
+  Label l cs $ ForAll n $ predType $ unpredType pty
+
+-- -----------------------------------------------------------------------------
+-- Adding exports
+-- -----------------------------------------------------------------------------
+
+addExports :: Maybe ExportSpec -> [Export] -> Maybe ExportSpec
+addExports (Just (Exporting p es)) es' = Just $ Exporting p $ es ++ es'
+addExports Nothing                 _   = internalError "Dictionary.addExports"
+
+dictExports :: Decl a -> DTM [Export]
+dictExports (ClassDecl _ _ _ cls _ _) = do
+  m <- getModuleIdent
+  clsEnv <- getClassEnv
+  return $ classExports m clsEnv cls
+dictExports (InstanceDecl _ _ _ cls ty _) = do
+  m <- getModuleIdent
+  clsEnv <- getClassEnv
+  return $ instExports m clsEnv cls (toType [] ty)
+dictExports _ = return []
+
+classExports :: ModuleIdent -> ClassEnv -> Ident -> [Export]
+classExports m clsEnv cls =
+  ExportTypeWith NoSpanInfo (qDictTypeId qcls) [dictConstrId qcls] :
+   map (Export NoSpanInfo . qSuperDictStubId qcls) (superClasses qcls clsEnv) ++
+    map (Export NoSpanInfo . qDefaultMethodId qcls) (classMethods qcls clsEnv)
+  where qcls = qualifyWith m cls
+
+instExports :: ModuleIdent -> ClassEnv -> QualIdent -> Type -> [Export]
+instExports m clsEnv cls ty =
+  Export NoSpanInfo (qInstFunId m cls ty) :
+    map (Export NoSpanInfo . qImplMethodId m cls ty) (classMethods cls clsEnv)
+
+-- -----------------------------------------------------------------------------
+-- Transforming the module
+-- -----------------------------------------------------------------------------
+
+type DictEnv = [(Pred, Expression Type)]
+
+emptyDictEnv :: DictEnv
+emptyDictEnv = []
+
+class DictTrans a where
+  dictTrans :: a PredType -> DTM (a Type)
+
+instance DictTrans Module where
+  dictTrans (Module spi li ps m es is ds) = do
+    liftedDs <- concatMapM liftDecls ds
+    stubDs <- concatMapM createStubs ds
+    tcEnv <- getTyConsEnv
+    clsEnv <- getClassEnv
+    inEnv <- getInstEnv
+    modifyValueEnv $ bindClassDecls m tcEnv clsEnv
+    modifyValueEnv $ bindInstDecls m tcEnv clsEnv inEnv
+    modifyTyConsEnv $ bindDictTypes m clsEnv
+    transDs <- mapM dictTrans liftedDs
+    modifyValueEnv $ dictTransValues
+    modifyTyConsEnv $ dictTransTypes
+    dictEs <- addExports es <$> concatMapM dictExports ds
+    return $ Module spi li ps m dictEs is $ transDs ++ stubDs
+
+-- We use and transform the type from the type constructor environment for
+-- transforming a constructor declaration as it contains the reduced and
+-- restricted predicate set for each data constructor.
+
+-- The pattern declaration case of the DictTrans Decl instance converts
+-- variable declarations with an overloaded type into function declarations.
+-- This is necessary so that the compiler can add the implicit dictionary
+-- arguments to the declaration.
+
+instance DictTrans Decl where
+  dictTrans (InfixDecl      p fix prec ops) = return $ InfixDecl p fix prec ops
+  dictTrans (DataDecl        p tc tvs cs _) = do
+    m <- getModuleIdent
+    tcEnv <- getTyConsEnv
+    let DataType _ _ cs' = head $ qualLookupTypeInfo (qualifyWith m tc) tcEnv
+    return $ DataDecl p tc tvs (zipWith (dictTransConstrDecl tvs) cs cs') []
+  dictTrans (ExternalDataDecl     p tc tvs) = return $ ExternalDataDecl p tc tvs
+  dictTrans (NewtypeDecl     p tc tvs nc _) =
+    return $ NewtypeDecl p tc tvs nc []
+  dictTrans (TypeDecl          p tc tvs ty) = return $ TypeDecl p tc tvs ty
+  dictTrans (FunctionDecl p      pty f eqs) =
+    FunctionDecl p (transformPredType pty) f <$> mapM dictTrans eqs
+  dictTrans (PatternDecl           p t rhs) = case t of
+    VariablePattern _ pty@(PredType ps _) v | not (Set.null ps) ->
+      dictTrans $ FunctionDecl p pty v [Equation p (FunLhs NoSpanInfo v []) rhs]
+    _ -> withLocalDictEnv $ PatternDecl p <$> dictTrans t <*> dictTrans rhs
+  dictTrans d@(FreeDecl                _ _) = return $ fmap unpredType d
+  dictTrans d@(ExternalDecl            _ _) = return $ fmap transformPredType d
+  dictTrans d                               =
+    internalError $ "Dictionary.dictTrans: " ++ show d
+
+dictTransConstrDecl :: [Ident] -> ConstrDecl -> DataConstr -> ConstrDecl
+dictTransConstrDecl tvs (ConstrDecl p c tes) dc =
+  ConstrDecl p c $ map (fromType $ tvs ++ bvs) (constrTypes dc)
+  where bvs = nub $ bv tes
+dictTransConstrDecl tvs (ConOpDecl p ty1 op ty2) dc =
+  dictTransConstrDecl tvs (ConstrDecl p op [ty1, ty2]) dc
+dictTransConstrDecl _ d _ = internalError $ "Dictionary.dictTrans: " ++ show d
+
+instance DictTrans Equation where
+  dictTrans (Equation p (FunLhs _ f ts) rhs) = withLocalValueEnv $ do
+    m <- getModuleIdent
+    pls <- matchPredList (varType m f) $
+             foldr (TypeArrow . typeOf) (typeOf rhs) ts
+    ts' <- addDictArgs pls ts
+    modifyValueEnv $ bindPatterns ts'
+    Equation p (FunLhs NoSpanInfo f ts') <$> dictTrans rhs
+  dictTrans eq                             =
+    internalError $ "Dictionary.dictTrans: " ++ show eq
+
+instance DictTrans Rhs where
+  dictTrans (SimpleRhs p _ e []) = simpleRhs p <$> dictTrans e
+  dictTrans rhs                  =
+    internalError $ "Dictionary.dictTrans: " ++ show rhs
+
+instance DictTrans Pattern where
+  dictTrans (LiteralPattern        _ pty l) =
+    return $ LiteralPattern NoSpanInfo (unpredType pty) l
+  dictTrans (VariablePattern       _ pty v) =
+    return $ VariablePattern NoSpanInfo (unpredType pty) v
+  dictTrans (ConstructorPattern _ pty c ts) = do
+    pls <- matchPredList (conType c) $
+             foldr (TypeArrow . typeOf) (unpredType pty) ts
+    ConstructorPattern NoSpanInfo (unpredType pty) c <$> addDictArgs pls ts
+  dictTrans (AsPattern               _ v t) =
+    AsPattern NoSpanInfo v <$> dictTrans t
+  dictTrans t                               =
+    internalError $ "Dictionary.dictTrans: " ++ show t
+
+instance DictTrans Expression where
+  dictTrans (Literal     _ pty l) =
+    return $ Literal NoSpanInfo (unpredType pty) l
+  dictTrans (Variable    _ pty v) = do
+    pls <- matchPredList (funType v) (unpredType pty)
+    es <- mapM dictArg pls
+    let ty = foldr (TypeArrow . typeOf) (unpredType pty) es
+    return $ apply (Variable NoSpanInfo ty v) es
+  dictTrans (Constructor _ pty c) = do
+    pls <- matchPredList (conType c) (unpredType pty)
+    es <- mapM dictArg pls
+    let ty = foldr (TypeArrow . typeOf) (unpredType pty) es
+    return $ apply (Constructor NoSpanInfo ty c) es
+  dictTrans (Apply       _ e1 e2) =
+    Apply NoSpanInfo <$> dictTrans e1 <*> dictTrans e2
+  dictTrans (Typed       _ e qty) =
+    Typed NoSpanInfo <$> dictTrans e <*> dictTransQualTypeExpr qty
+  dictTrans (Lambda       _ ts e) = withLocalValueEnv $ withLocalDictEnv $ do
+    ts' <- mapM dictTrans ts
+    modifyValueEnv $ bindPatterns ts'
+    mkLambda ts' <$> dictTrans e
+  dictTrans (Let        _ _ ds e) = withLocalValueEnv $ do
+    modifyValueEnv $ bindDecls ds
+    mkLet <$> mapM dictTrans ds <*> dictTrans e
+  dictTrans (Case    _ _ ct e as) =
+    mkCase ct <$> dictTrans e <*> mapM dictTrans as
+  dictTrans e                   =
+    internalError $ "Dictionary.dictTrans: " ++ show e
+
+-- Just like before in desugaring, we ignore the context in the type signature
+-- of a typed expression, since there should be no possibility to provide an
+-- non-empty context without scoped type-variables.
+-- TODO: Verify
+
+dictTransQualTypeExpr :: QualTypeExpr -> DTM QualTypeExpr
+dictTransQualTypeExpr (QualTypeExpr spi _ ty) = return $ QualTypeExpr spi [] ty
+
+instance DictTrans Alt where
+  dictTrans (Alt p t rhs) = withLocalValueEnv $ withLocalDictEnv $ do
+    t' <- dictTrans t
+    modifyValueEnv $ bindPattern t'
+    Alt p t' <$> dictTrans rhs
+
+addDictArgs :: [Pred] -> [Pattern PredType] -> DTM [Pattern Type]
+addDictArgs pls ts = do
+  dictVars <- mapM (freshVar "_#dict" . rtDictType) pls
+  clsEnv <- getClassEnv
+  modifyDictEnv $ (++) $ dicts clsEnv $ zip pls (map (uncurry mkVar) dictVars)
+  (++) (map (uncurry (VariablePattern NoSpanInfo )) dictVars)
+         <$> mapM dictTrans ts
+  where dicts clsEnv vs
+          | null vs = vs
+          | otherwise = vs ++ dicts clsEnv (concatMap (superDicts clsEnv) vs)
+        superDicts clsEnv (Pred cls ty, e) =
+          map (superDict cls ty e) (superClasses cls clsEnv)
+        superDict cls ty e scls =
+          (Pred scls ty, Apply NoSpanInfo (superDictExpr cls scls ty) e)
+        superDictExpr cls scls ty =
+          Variable NoSpanInfo (superDictStubType cls scls ty)
+            (qSuperDictStubId cls scls)
+
+-- The function 'dictArg' constructs the dictionary argument for a predicate
+-- from the predicates of a class method or an overloaded function. It checks
+-- whether a dictionary for the predicate is available in the dictionary
+-- environment, which is the case when the predicate's type is a type variable,
+-- and uses 'instDict' otherwise in order to supply a new dictionary using the
+-- appropriate instance dictionary construction function. If the corresponding
+-- instance declaration has a non-empty context, the dictionary construction
+-- function is applied to the dictionaries computed for the context instantiated
+-- at the appropriate types.
+
+dictArg :: Pred -> DTM (Expression Type)
+dictArg p = maybeM (instDict p) return (lookup p <$> getDictEnv)
+
+instDict :: Pred -> DTM (Expression Type)
+instDict p = instPredList p >>= flip (uncurry instFunApp) p
+
+instFunApp :: ModuleIdent -> [Pred] -> Pred -> DTM (Expression Type)
+instFunApp m pls p@(Pred cls ty) = apply (Variable NoSpanInfo ty' f)
+  <$> mapM dictArg pls
+  where f   = qInstFunId m cls ty
+        ty' = foldr1 TypeArrow $ map rtDictType $ pls ++ [p]
+
+instPredList :: Pred -> DTM (ModuleIdent, [Pred])
+instPredList (Pred cls ty) = case unapplyType True ty of
+  (TypeConstructor tc, tys) -> do
+    inEnv <- getInstEnv
+    case lookupInstInfo (cls, tc) inEnv of
+      Just (m, ps, _) -> return (m, expandAliasType tys $ Set.toAscList ps)
+      Nothing -> internalError $ "Dictionary.instPredList: " ++ show (cls, tc)
+  _ -> internalError $ "Dictionary.instPredList: " ++ show ty
+
+-- When adding dictionary arguments on the left hand side of an equation and
+-- in applications, respectively, the compiler must unify the function's type
+-- with the concrete instance at which that type is used in order to determine
+-- the correct context.
+
+-- Polymorphic methods make things a little bit more complicated. When an
+-- instance dictionary constructor is applied to an instance method, the
+-- suffix of the instance method type's context that corresponds to the
+-- additional constraints of the type class method must be discarded and
+-- no dictionaries must be added for these constraints. Unfortunately, the
+-- dictionary transformation has already been applied to the component types
+-- of the dictionary constructor. Therefore, the function 'matchPredList'
+-- tries to find a suffix of the context whose transformation matches the
+-- initial arrows of the instance type.
+
+matchPredList :: (ValueEnv -> TypeScheme) -> Type -> DTM [Pred]
+matchPredList tySc ty2 = do
+  ForAll _ (PredType ps ty1) <- tySc <$> getValueEnv
+  return $ foldr (\(pls1, pls2) pls' ->
+                   fromMaybe pls' $ qualMatch pls1 ty1 pls2 ty2)
+                 (internalError $ "Dictionary.matchPredList: " ++ show ps)
+                 (splits $ Set.toAscList ps)
+
+qualMatch :: [Pred] -> Type -> [Pred] -> Type -> Maybe [Pred]
+qualMatch pls1 ty1 pls2 ty2 = case predListMatch pls2 ty2 of
+  Just ty2' -> Just $ subst (matchType ty1 ty2' idSubst) pls1
+  Nothing -> Nothing
+
+predListMatch :: [Pred] -> Type -> Maybe Type
+predListMatch []     ty = Just ty
+predListMatch (p:ps) ty = case ty of
+  TypeForall _ ty'                                 -> predListMatch (p : ps) ty'
+  TypeArrow ty1 ty2 | ty1 == rtDictType (instPred p) -> predListMatch ps ty2
+  _                                                -> Nothing
+
+splits :: [a] -> [([a], [a])]
+splits xs = zip (inits xs) (tails xs)
+
+-- -----------------------------------------------------------------------------
+-- Optimizing method calls
+-- -----------------------------------------------------------------------------
+
+-- Whenever a type class method is applied at a known type, the compiler can
+-- apply the type instance's implementation directly.
+
+type SpecEnv = Map.Map (QualIdent, QualIdent) QualIdent
+
+emptySpEnv :: SpecEnv
+emptySpEnv = Map.empty
+
+initSpEnv :: ClassEnv -> InstEnv -> SpecEnv
+initSpEnv clsEnv = foldr (uncurry bindInstance) emptySpEnv . Map.toList
+  where bindInstance (cls, tc) (m, _, _) =
+          flip (foldr $ bindInstanceMethod m cls tc) $ classMethods cls clsEnv
+        bindInstanceMethod m cls tc f = Map.insert (f', d) f''
+          where f'  = qualifyLike cls f
+                d   = qInstFunId m cls ty
+                f'' = qImplMethodId m cls ty f
+                ty  = TypeConstructor tc
+
+class Specialize a where
+  specialize :: a Type -> DTM (a Type)
+
+instance Specialize Module where
+  specialize (Module spi li ps m es is ds) = do
+    clsEnv <- getClassEnv
+    inEnv <- getInstEnv
+    setSpEnv $ initSpEnv clsEnv inEnv
+    Module spi li ps m es is <$> mapM specialize ds
+
+instance Specialize Decl where
+  specialize (FunctionDecl p ty f eqs) =
+    FunctionDecl p ty f <$> mapM specialize eqs
+  specialize (PatternDecl     p t rhs) = PatternDecl p t <$> specialize rhs
+  specialize d                         = return d
+
+instance Specialize Equation where
+  specialize (Equation p lhs rhs) = Equation p lhs <$> specialize rhs
+
+instance Specialize Rhs where
+  specialize (SimpleRhs p _ e []) = simpleRhs p <$> specialize e
+  specialize rhs                  =
+    internalError $ "Dictionary.specialize: " ++ show rhs
+
+instance Specialize Expression where
+  specialize e = specialize' e []
+
+specialize' :: Expression Type -> [Expression Type] -> DTM (Expression Type)
+specialize' l@(Literal     _ _ _) es = return $ apply l es
+specialize' v@(Variable   _ _ v') es = do
+  spEnv <- getSpEnv
+  return $ case Map.lookup (v', f) spEnv of
+    Just f' -> apply (Variable NoSpanInfo ty' f') $ es'' ++ es'
+    Nothing -> apply v es
+  where d:es' = es
+        (Variable _ _ f, es'') = unapply d []
+        ty' = foldr (TypeArrow . typeOf) (typeOf $ Apply NoSpanInfo v d) es''
+specialize' c@(Constructor _ _ _) es = return $ apply c es
+specialize' (Typed       _ e qty) es = do
+  e' <- specialize e
+  return $ apply (Typed NoSpanInfo e' qty) es
+specialize' (Apply       _ e1 e2) es = do
+  e2' <- specialize e2
+  specialize' e1 $ e2' : es
+specialize' (Lambda       _ ts e) es = do
+  e' <- specialize e
+  return $ apply (Lambda NoSpanInfo ts e') es
+specialize' (Let        _ _ ds e) es = do
+  ds' <- mapM specialize ds
+  e' <- specialize e
+  return $ apply (mkLet ds' e') es
+specialize' (Case    _ _ ct e as) es = do
+  e' <- specialize e
+  as' <- mapM specialize as
+  return $ apply (mkCase ct e' as') es
+specialize' e                   _  =
+  internalError $ "Dictionary.specialize': " ++ show e
+
+instance Specialize Alt where
+  specialize (Alt p t rhs) = Alt p t <$> specialize rhs
+
+-- -----------------------------------------------------------------------------
+-- Cleaning up
+-- -----------------------------------------------------------------------------
+
+-- After we have transformed the module we have to remove class exports from
+-- the export list and type classes from the type constructor environment.
+-- Furthermore, we may have to remove some infix declarations and operators
+-- from the precedence environment as functions with class constraint have
+-- been supplemented with addiontal dictionary arguments during the dictionary
+-- transformation.
+
+cleanup :: Module a -> DTM (Module a)
+cleanup (Module spi li ps m es is ds) = do
+  cleanedEs <- traverse cleanupExportSpec es
+  cleanedDs <- concatMapM cleanupInfixDecl ds
+  cleanupTyConsEnv
+  cleanupPrecEnv
+  return $ Module spi li ps m cleanedEs is cleanedDs
+
+cleanupExportSpec :: ExportSpec -> DTM ExportSpec
+cleanupExportSpec (Exporting p es) = Exporting p <$> concatMapM cleanupExport es
+
+cleanupExport :: Export -> DTM [Export]
+cleanupExport e@(Export             _ _) = return [e]
+cleanupExport e@(ExportTypeWith spi tc cs) = do
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfo tc tcEnv of
+    [TypeClass _ _ _] -> return $ map (Export spi . qualifyLike tc) cs
+    _                 -> return [e]
+cleanupExport e                        =
+  internalError $ "Dictionary.cleanupExport: " ++ show e
+
+cleanupInfixDecl :: Decl a -> DTM [Decl a]
+cleanupInfixDecl (InfixDecl p fix pr ops) = do
+  m <- getModuleIdent
+  vEnv <- getValueEnv
+  let opArity = arrowArity . rawType . flip opType vEnv . qualifyWith m
+      ops' = filter ((== 2) . opArity) ops
+  return [InfixDecl p fix pr ops' | not (null ops')]
+cleanupInfixDecl d                        = return [d]
+
+cleanupTyConsEnv :: DTM ()
+cleanupTyConsEnv = getTyConsEnv >>= mapM_ (cleanupTyCons . fst) . allBindings
+
+cleanupTyCons :: QualIdent -> DTM ()
+cleanupTyCons tc = do
+  tcEnv <- getTyConsEnv
+  case qualLookupTypeInfo tc tcEnv of
+    [TypeClass _ _ _] -> modifyTyConsEnv $ qualUnbindTopEnv tc
+    _                 -> return ()
+
+cleanupPrecEnv :: DTM ()
+cleanupPrecEnv = getPrecEnv >>= mapM_ (cleanupOp . fst) . allBindings
+
+cleanupOp :: QualIdent -> DTM ()
+cleanupOp op = do
+  opArity <- arrowArity . rawType . opType op <$> getValueEnv
+  when (opArity /= 2) $ modifyPrecEnv $ qualUnbindTopEnv op
+
+-- -----------------------------------------------------------------------------
+-- Transforming interfaces
+-- -----------------------------------------------------------------------------
+
+-- The following functions expect an already transformed value environment.
+-- The transformation of interface declarations with it is quite simple and
+-- straightforward.
+
+dictTransInterfaces :: ValueEnv -> ClassEnv -> InterfaceEnv -> InterfaceEnv
+dictTransInterfaces vEnv clsEnv = fmap $ dictTransInterface vEnv clsEnv
+
+dictTransInterface :: ValueEnv -> ClassEnv -> Interface -> Interface
+dictTransInterface vEnv clsEnv (Interface m is ds) =
+  Interface m is $ concatMap (dictTransIDecl m vEnv clsEnv) ds
+
+dictTransIDecl :: ModuleIdent -> ValueEnv -> ClassEnv -> IDecl -> [IDecl]
+dictTransIDecl m vEnv _      d@(IInfixDecl         _ _ _ op)
+  | arrowArity (rawType $ opType (qualQualify m op) vEnv) /= 2 = []
+  | otherwise = [d]
+dictTransIDecl _ _    _      d@(HidingDataDecl      _ _ _ _) = [d]
+dictTransIDecl m _    _      (IDataDecl    p tc k tvs cs hs) =
+  [IDataDecl p tc k tvs (map (dictTransIConstrDecl m tvs) cs) hs]
+dictTransIDecl _ _    _      d@(INewtypeDecl    _ _ _ _ _ _) = [d]
+dictTransIDecl _ _    _      d@(ITypeDecl         _ _ _ _ _) = [d]
+dictTransIDecl m vEnv _      (IFunctionDecl       _ f _ _ _) =
+  [iFunctionDeclFromValue m vEnv (qualQualify m f)]
+dictTransIDecl _ _    _      (HidingClassDecl  p _ cls k tv) =
+  [HidingDataDecl p (qDictTypeId cls) (fmap (flip ArrowKind Star) k) [tv]]
+dictTransIDecl m vEnv clsEnv (IClassDecl   p _ cls k _ _ hs) =
+  dictDecl : defaults ++ methodStubs ++ superDictStubs
+  where qcls  = qualQualify m cls
+        sclss = superClasses qcls clsEnv
+        ms    = classMethods qcls clsEnv
+        dictDecl    = IDataDecl p (qDictTypeId cls)
+                        (fmap (flip ArrowKind Star) k)
+                        [head identSupply] [constrDecl] []
+        constrDecl  = iConstrDeclFromDataConstructor m vEnv $ qDictConstrId qcls
+        defaults    = map (iFunctionDeclFromValue m vEnv .
+                            qDefaultMethodId qcls) ms
+        methodStubs = map (iFunctionDeclFromValue m vEnv . qualifyLike qcls) $
+                        filter (`notElem` hs) ms
+        superDictStubs = map (iFunctionDeclFromValue m vEnv .
+                               qSuperDictStubId qcls) sclss
+dictTransIDecl m vEnv clsEnv (IInstanceDecl _ _ cls ty _ mm) =
+  iFunctionDeclFromValue m vEnv (qInstFunId m' qcls ty') :
+    map (iFunctionDeclFromValue m vEnv . qImplMethodId m' qcls ty') ms
+  where m'   = fromMaybe m mm
+        qcls = qualQualify m cls
+        ty'  = toQualType m [] ty
+        ms   = classMethods qcls clsEnv
+
+dictTransIConstrDecl :: ModuleIdent -> [Ident] -> ConstrDecl -> ConstrDecl
+dictTransIConstrDecl _ _ (ConOpDecl p ty1 op ty2) = ConstrDecl p op [ty1, ty2]
+dictTransIConstrDecl _ _ cd                       = cd
+
+iFunctionDeclFromValue :: ModuleIdent -> ValueEnv -> QualIdent -> IDecl
+iFunctionDeclFromValue m vEnv f = case qualLookupValue f vEnv of
+  [Value _ _ a (ForAll _ pty)] ->
+    IFunctionDecl NoPos (qualUnqualify m f) Nothing a $
+      fromQualPredType m identSupply pty
+  _ -> internalError $ "Dictionary.iFunctionDeclFromValue: " ++ show f
+
+iConstrDeclFromDataConstructor :: ModuleIdent -> ValueEnv -> QualIdent
+                               -> ConstrDecl
+iConstrDeclFromDataConstructor m vEnv c = case qualLookupValue c vEnv of
+  [DataConstructor _ _ _ (ForAll _ pty)] ->
+    ConstrDecl NoSpanInfo (unqualify c) tys
+    where tys = map (fromQualType m identSupply) $ arrowArgs $ unpredType pty
+  _ -> internalError $ "Dictionary.iConstrDeclFromDataConstructor: " ++ show c
+
+-- -----------------------------------------------------------------------------
+-- Functions for naming newly created types, functions and parameters
+-- -----------------------------------------------------------------------------
+
+dictTypeId :: QualIdent -> Ident
+dictTypeId cls = mkIdent $ "_Dict#" ++ idName (unqualify cls)
+
+qDictTypeId :: QualIdent -> QualIdent
+qDictTypeId cls = qualifyLike cls $ dictTypeId cls
+
+dictConstrId :: QualIdent -> Ident
+dictConstrId = dictTypeId
+
+qDictConstrId :: QualIdent -> QualIdent
+qDictConstrId cls = qualifyLike cls $ dictConstrId cls
+
+defaultMethodId :: QualIdent -> Ident -> Ident
+defaultMethodId cls f = mkIdent $ "_def#" ++ idName f ++ '#' : qualName cls
+
+qDefaultMethodId :: QualIdent -> Ident -> QualIdent
+qDefaultMethodId cls = qualifyLike cls . defaultMethodId cls
+
+superDictStubId :: QualIdent -> QualIdent -> Ident
+superDictStubId cls scls = mkIdent $
+  "_super#" ++ qualName cls ++ '#' : qualName scls
+
+qSuperDictStubId :: QualIdent -> QualIdent -> QualIdent
+qSuperDictStubId cls = qualifyLike cls . superDictStubId cls
+
+instFunId :: QualIdent -> Type -> Ident
+instFunId cls ty = mkIdent $
+  "_inst#" ++ qualName cls ++ '#' : qualName (rootOfType ty)
+
+qInstFunId :: ModuleIdent -> QualIdent -> Type -> QualIdent
+qInstFunId m cls = qualifyWith m . instFunId cls
+
+implMethodId :: QualIdent -> Type -> Ident -> Ident
+implMethodId cls ty f = mkIdent $
+  "_impl#" ++ idName f ++ '#' : qualName cls ++ '#' : qualName (rootOfType ty)
+
+qImplMethodId :: ModuleIdent -> QualIdent -> Type -> Ident -> QualIdent
+qImplMethodId m cls ty = qualifyWith m . implMethodId cls ty
+
+-- -----------------------------------------------------------------------------
+-- Generating variables
+-- -----------------------------------------------------------------------------
+
+freshVar :: String -> Type -> DTM (Type, Ident)
+freshVar name ty = ((,) ty) . mkIdent . (name ++) .  show <$> getNextId
+
+-- -----------------------------------------------------------------------------
+-- Auxiliary functions
+-- -----------------------------------------------------------------------------
+
+-- The function 'dictType' returns the type of the dictionary corresponding to
+-- a particular C-T instance.
+
+rtDictType :: Pred -> Type
+rtDictType = TypeArrow unitType . dictType
+
+dictType :: Pred -> Type
+dictType (Pred cls ty) = TypeApply (TypeConstructor $ qDictTypeId cls) ty
+
+-- The function 'transformPredType' replaces each predicate with a new
+-- dictionary type argument.
+
+transformPredType :: PredType -> Type
+transformPredType (PredType ps ty) =
+  foldr (TypeArrow . rtDictType) ty $ Set.toList ps
+
+-- The function 'transformMethodPredType' first deletes the implicit class
+-- constraint and then transforms the resulting predicated type as above.
+
+transformMethodPredType :: PredType -> Type
+transformMethodPredType (PredType ps ty) =
+  transformPredType $ PredType (Set.deleteMin ps) ty
+
+-- The function 'generalizeMethodType' generalizes an already transformed
+-- method type to a forall type by quantifying all occuring type variables
+-- except for the class variable whose index is 0.
+generalizeMethodType :: Type -> Type
+generalizeMethodType ty
+  | null tvs  = ty
+  | otherwise = TypeForall tvs ty
+  where tvs = nub $ filter (/= 0) $ typeVars ty
+
+instTypeVar :: Int -> Int
+instTypeVar tv = -1 - tv
+
+instType :: Type -> Type
+instType (TypeConstructor tc) = TypeConstructor tc
+instType (TypeVariable    tv) = TypeVariable (instTypeVar tv)
+instType (TypeApply  ty1 ty2) = TypeApply (instType ty1) (instType ty2)
+instType (TypeArrow  ty1 ty2) = TypeArrow (instType ty1) (instType ty2)
+instType (TypeForall  tvs ty) = TypeForall (map instTypeVar tvs) (instType ty)
+instType ty = ty
+
+instPred :: Pred -> Pred
+instPred (Pred cls ty) = Pred cls (instType ty)
+
+unRenameIdentIf :: Bool -> Ident -> Ident
+unRenameIdentIf b = if b then unRenameIdent else id
+
+-- The string for the error message for a class method's default method
+-- implementation has to be constructed in its desugared form since the
+-- desugaring has already taken place.
+
+preludeError :: Type -> String -> Expression PredType
+preludeError a =
+  Apply NoSpanInfo (Variable NoSpanInfo
+                     (predType (TypeArrow stringType a)) qErrorId) . stringExpr
+
+stringExpr :: String -> Expression PredType
+stringExpr = foldr (consExpr . Literal NoSpanInfo (predType charType) . Char)
+               nilExpr
+  where
+  nilExpr = Constructor NoSpanInfo (predType stringType) qNilId
+  consExpr = (Apply NoSpanInfo) . (Apply NoSpanInfo)
+    (Constructor NoSpanInfo (predType $ consType charType) qConsId)
+
+-- The function 'varType' is able to lookup both local and global identifiers.
+-- Since the environments have been qualified before, global declarations are
+-- only visible under their original name whereas local declarations are always
+-- entered unqualified.
+
+varType :: ModuleIdent -> Ident -> ValueEnv -> TypeScheme
+varType m v vEnv = case qualLookupValue (qualify v) vEnv of
+  Value _ _ _ tySc : _ -> tySc
+  Label _ _   tySc : _ -> tySc
+  _ -> case qualLookupValue (qualifyWith m v) vEnv of
+    Value _ _ _ tySc : _ -> tySc
+    Label _ _   tySc : _ -> tySc
+    _ -> internalError $ "Dictionary.varType: " ++ show v
+
+conType :: QualIdent -> ValueEnv -> TypeScheme
+conType c vEnv = case qualLookupValue c vEnv of
+  [DataConstructor  _ _ _ (ForAll n pty)] -> ForAll n pty
+  [NewtypeConstructor _ _ (ForAll n pty)] -> ForAll n pty
+  _ -> internalError $ "Dictionary.conType: " ++ show c
+
+funType :: QualIdent -> ValueEnv -> TypeScheme
+funType f vEnv = case qualLookupValue f vEnv of
+  [Value _ _ _ tySc] -> tySc
+  [Label _ _   tySc] -> tySc
+  _ -> internalError $ "Dictionary.funType " ++ show f
+
+opType :: QualIdent -> ValueEnv -> TypeScheme
+opType op vEnv = case qualLookupValue op vEnv of
+  [DataConstructor  _ _ _ (ForAll n pty)] -> ForAll n pty
+  [NewtypeConstructor _ _ (ForAll n pty)] -> ForAll n pty
+  [Value _ _ _                             tySc] -> tySc
+  [Label _ _                               tySc] -> tySc
+  _ -> internalError $ "Dictionary.opType " ++ show op
diff --git a/src/Transformations/Lift.hs b/src/Transformations/Lift.hs
new file mode 100644
--- /dev/null
+++ b/src/Transformations/Lift.hs
@@ -0,0 +1,451 @@
+{- |
+    Module      :  $Header$
+    Description :  Lifting of lambda-expressions and local functions
+    Copyright   :  (c) 2001 - 2003 Wolfgang Lux
+                       2011 - 2015 Björn Peemöller
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   After desugaring and simplifying the code, the compiler lifts all local
+   function declarations to the top-level keeping only local variable
+   declarations. The algorithm used here is similar to Johnsson's, consisting
+   of two phases. First, we abstract each local function declaration,
+   adding its free variables as initial parameters and update all calls
+   to take these variables into account. Second, all local function
+   declarations are collected and lifted to the top-level.
+-}
+{-# LANGUAGE CPP #-}
+module Transformations.Lift (lift) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative        ((<$>), (<*>))
+#endif
+import           Control.Arrow              (first)
+import qualified Control.Monad.State as S   (State, runState, gets, modify)
+import           Data.List
+import qualified Data.Map            as Map (Map, empty, insert, lookup)
+import           Data.Maybe                 (mapMaybe, fromJust)
+import qualified Data.Set            as Set (fromList, toList, unions)
+
+import Curry.Base.Ident
+import Curry.Base.SpanInfo
+import Curry.Syntax
+
+import Base.AnnotExpr
+import Base.Expr
+import Base.Messages                        (internalError)
+import Base.SCC
+import Base.Types
+import Base.TypeSubst
+import Base.Typing
+import Base.Utils
+
+import Env.Value
+
+lift :: ValueEnv -> Module Type -> (Module Type, ValueEnv)
+lift vEnv (Module spi li ps m es is ds) = (lifted, valueEnv s')
+  where
+  (ds', s') = S.runState (mapM (absDecl "" []) ds) initState
+  initState = LiftState m vEnv Map.empty
+  lifted    = Module spi li ps m es is $ concatMap liftFunDecl ds'
+
+-- -----------------------------------------------------------------------------
+-- Abstraction
+-- -----------------------------------------------------------------------------
+
+-- Besides adding the free variables to every (local) function, the
+-- abstraction pass also has to update the type environment in order to
+-- reflect the new types of the abstracted functions. As usual, we use a
+-- state monad transformer in order to pass the type environment
+-- through. The environment constructed in the abstraction phase maps
+-- each local function declaration onto its replacement expression,
+-- i.e. the function applied to its free variables. In order to generate
+-- correct type annotations for an inserted replacement expression, we also
+-- save a function's original type. The original type is later unified with
+-- the concrete type of the replaced expression to obtain a type substitution
+-- which is then applied to the replacement expression.
+
+type AbstractEnv = Map.Map Ident (Expression Type, Type)
+
+data LiftState = LiftState
+  { moduleIdent :: ModuleIdent
+  , valueEnv    :: ValueEnv
+  , abstractEnv :: AbstractEnv
+  }
+
+type LiftM a = S.State LiftState a
+
+getModuleIdent :: LiftM ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+getValueEnv :: LiftM ValueEnv
+getValueEnv = S.gets valueEnv
+
+modifyValueEnv :: (ValueEnv -> ValueEnv) -> LiftM ()
+modifyValueEnv f = S.modify $ \s -> s { valueEnv = f $ valueEnv s }
+
+getAbstractEnv :: LiftM AbstractEnv
+getAbstractEnv = S.gets abstractEnv
+
+withLocalAbstractEnv :: AbstractEnv -> LiftM a -> LiftM a
+withLocalAbstractEnv ae act = do
+  old <- getAbstractEnv
+  S.modify $ \s -> s { abstractEnv = ae }
+  res <- act
+  S.modify $ \s -> s { abstractEnv = old }
+  return res
+
+absDecl :: String -> [Ident] -> Decl Type -> LiftM (Decl Type)
+absDecl _   lvs (FunctionDecl p ty f eqs) = FunctionDecl p ty f
+                                            <$> mapM (absEquation lvs) eqs
+absDecl pre lvs (PatternDecl     p t rhs) = PatternDecl p t
+                                            <$> absRhs pre lvs rhs
+absDecl _   _   d                         = return d
+
+absEquation :: [Ident] -> Equation Type -> LiftM (Equation Type)
+absEquation lvs (Equation p lhs@(FunLhs _ f ts) rhs) =
+  Equation p lhs <$> absRhs (idName f ++ ".") lvs' rhs
+  where lvs' = lvs ++ bv ts
+absEquation _ _ = error "Lift.absEquation: no pattern match"
+
+absRhs :: String -> [Ident] -> Rhs Type -> LiftM (Rhs Type)
+absRhs pre lvs (SimpleRhs p _ e _) = simpleRhs p <$> absExpr pre lvs e
+absRhs _   _   _                   = error "Lift.absRhs: no simple RHS"
+
+-- Within a declaration group we have to split the list of declarations
+-- into the function and value declarations. Only the function
+-- declarations are affected by the abstraction algorithm; the value
+-- declarations are left unchanged except for abstracting their right
+-- hand sides.
+
+-- The abstraction of a recursive declaration group is complicated by the
+-- fact that not all functions need to call each in a recursive
+-- declaration group. E.g., in the following example neither 'g' nor 'h'
+-- call each other.
+--
+--   f = g True
+--     where x = h 1
+--           h z = y + z
+--           y = g False
+--           g z = if z then x else 0
+--
+-- Because of this fact, 'g' and 'h' can be abstracted separately by adding
+-- only 'y' to 'h' and 'x' to 'g'. On the other hand, in the following example
+--
+--   f x y = g 4
+--     where g p = h p + x
+--           h q = k + y + q
+--           k = g x
+--
+-- the local function 'g' uses 'h', so the free variables
+-- of 'h' have to be added to 'g' as well. However, because
+-- 'h' does not call 'g' it is sufficient to add only
+-- 'k' and 'y' (and not 'x') to its definition. We handle this by computing
+-- the dependency graph between the functions and splitting this graph into
+-- its strongly connected components. Each component is then processed
+-- separately, adding the free variables in the group to its functions.
+
+-- We have to be careful with local declarations within desugared case
+-- expressions. If some of the cases have guards, e.g.,
+--
+--   case e of
+--     x | x < 1 -> 1
+--     x -> let double y = y * y in double x
+--
+-- the desugarer at present may duplicate code. While there is no problem
+-- with local variable declaration being duplicated, we must avoid to
+-- lift local function declarations more than once. Therefore
+-- 'absFunDecls' transforms only those function declarations
+-- that have not been lifted and discards the other declarations. Note
+-- that it is easy to check whether a function has been lifted by
+-- checking whether an entry for its transformed name is present
+-- in the value environment.
+
+absDeclGroup :: String -> [Ident] -> [Decl Type] -> Expression Type
+             -> LiftM (Expression Type)
+absDeclGroup pre lvs ds e = do
+  m <- getModuleIdent
+  absFunDecls pre lvs' (scc bv (qfv m) fds) vds e
+  where lvs' = lvs ++ bv vds
+        (fds, vds) = partition isFunDecl ds
+
+absFunDecls :: String -> [Ident] -> [[Decl Type]] -> [Decl Type]
+            -> Expression Type -> LiftM (Expression Type)
+absFunDecls pre lvs []         vds e = do
+  vds' <- mapM (absDecl pre lvs) vds
+  e' <- absExpr pre lvs e
+  return (mkLet vds' e')
+absFunDecls pre lvs (fds:fdss) vds e = do
+  m <- getModuleIdent
+  env <- getAbstractEnv
+  vEnv <- getValueEnv
+  let -- defined functions
+      fs      = bv fds
+      -- function types
+      ftys    = map extractFty fds
+      extractFty (FunctionDecl _ _ f (Equation _ (FunLhs _ _ ts) rhs : _)) =
+        (f, foldr TypeArrow (typeOf rhs) $ map typeOf ts)
+      extractFty _                                                         =
+        internalError "Lift.absFunDecls.extractFty"
+      -- typed free variables on the right-hand sides
+      fvsRhs  = Set.unions
+                  [ Set.fromList (filter (not . isDummyType . fst)
+                                         (maybe [(ty, v)]
+                                                (qafv' ty)
+                                                (Map.lookup v env)))
+                  | (ty, v) <- concatMap (qafv m) fds ]
+      -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+      -- !!! HACK: When calculating the typed free variables on the     !!!
+      -- !!! right-hand side, we have to filter out the ones annotated  !!!
+      -- !!! with dummy types (see below). Additionally, we have to be  !!!
+      -- !!! careful when we calculate the typed free variables in a    !!!
+      -- !!! replacement expression: We have to unify the original      !!!
+      -- !!! function type with the instantiated function type in order !!!
+      -- !!! to obtain a type substitution that can then be applied to  !!!
+      -- !!! the typed free variables in the replacement expression.    !!!
+      -- !!! This is analogous to the procedure when inserting a        !!!
+      -- !!! replacement expression with a correct type annotation      !!!
+      -- !!! (see 'absType' in 'absExpr' below).                        !!!
+      -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+      qafv' ty (re, fty) =
+        let unifier = matchType fty ty idSubst
+        in  map (\(ty', v) -> (subst unifier ty', v)) $ qafv m re
+      -- free variables that are local
+      fvs     = filter ((`elem` lvs) . snd) (Set.toList fvsRhs)
+      -- extended abstraction environment
+      env'    = foldr bindF env fs
+      -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+      -- !!! HACK: Since we do not know how to annotate the function    !!!
+      -- !!! call within the replacement expression until the replace-  !!!                          !!!
+      -- !!! ment expression is actually inserted (see 'absType' in     !!!
+      -- !!! 'absExpr' below), we use a dummy type for this. In turn,   !!!
+      -- !!! this dummy type has to be filtered out when calculating    !!!
+      -- !!! the typed free variables on right-hand sides (see above).  !!!                                             !!!
+      -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+      bindF f =
+        Map.insert f ( apply (mkFun m pre dummyType f) (map (uncurry mkVar) fvs)
+                     , fromJust $ lookup f ftys )
+      -- newly abstracted functions
+      fs'     = filter (\f -> null $ lookupValue (liftIdent pre f) vEnv) fs
+  withLocalAbstractEnv env' $ do
+    -- add variables to functions
+    fds' <- mapM (absFunDecl pre fvs lvs) [d | d <- fds, any (`elem` fs') (bv d)]
+    -- abstract remaining declarations
+    e'   <- absFunDecls pre lvs fdss vds e
+    return (mkLet fds' e')
+
+-- When the free variables of a function are abstracted, the type of the
+-- function must be changed as well.
+
+absFunDecl :: String -> [(Type, Ident)] -> [Ident] -> Decl Type
+           -> LiftM (Decl Type)
+absFunDecl pre fvs lvs (FunctionDecl p _ f eqs) = do
+  m <- getModuleIdent
+  d <- absDecl pre lvs $ FunctionDecl p undefined f' eqs'
+  let FunctionDecl _ _ _ eqs'' = d
+  modifyValueEnv $ bindGlobalInfo
+    (\qf tySc -> Value qf Nothing (eqnArity $ head eqs') tySc) m f' $
+                 polyType ty''
+  return $ FunctionDecl p ty'' f' eqs''
+  where f' = liftIdent pre f
+        ty' = foldr TypeArrow (typeOf rhs') (map typeOf ts')
+          where Equation _ (FunLhs _ _ ts') rhs' = head eqs'
+        ty'' = genType ty'
+        eqs' = map addVars eqs
+        genType ty''' = subst (foldr2 bindSubst idSubst tvs tvs') ty'''
+          where tvs = nub (typeVars ty''')
+                tvs' = map TypeVariable [0 ..]
+        addVars (Equation p' (FunLhs _ _ ts) rhs) =
+          Equation p' (FunLhs NoSpanInfo
+            f' (map (uncurry (VariablePattern NoSpanInfo)) fvs ++ ts)) rhs
+        addVars _ = error "Lift.absFunDecl.addVars: no pattern match"
+absFunDecl pre _ _ (ExternalDecl p vs) = ExternalDecl p <$> mapM (absVar pre) vs
+absFunDecl _ _ _ _ = error "Lift.absFunDecl: no pattern match"
+
+absVar :: String -> Var Type -> LiftM (Var Type)
+absVar pre (Var ty f) = do
+  m <- getModuleIdent
+  modifyValueEnv $ bindGlobalInfo
+    (\qf tySc -> Value qf Nothing (arrowArity ty) tySc) m f' $ polyType ty
+  return $ Var ty f'
+  where f' = liftIdent pre f
+
+absExpr :: String -> [Ident] -> Expression Type -> LiftM (Expression Type)
+absExpr _   _   l@(Literal     _ _ _) = return l
+absExpr pre lvs var@(Variable _ ty v)
+  | isQualified v = return var
+  | otherwise     = do
+    getAbstractEnv >>= \env -> case Map.lookup (unqualify v) env of
+      Nothing       -> return var
+      Just (e, fty) -> let unifier = matchType fty ty idSubst
+                       in  absExpr pre lvs $ fmap (subst unifier) $ absType ty e
+  where -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        -- !!! HACK: When inserting the replacement expression for an     !!!
+        -- !!! abstracted function, we have to unify the original         !!!
+        -- !!! function type with the instantiated function type in order !!!
+        -- !!! to obtain a type substitution that can then be applied to  !!!
+        -- !!! the type annotations in the replacement expression.        !!!
+        -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        absType ty' (Variable spi _ v') = Variable spi ty' v'
+        absType ty' (Apply   spi e1 e2) =
+          Apply spi (absType (TypeArrow (typeOf e2) ty') e1) e2
+        absType _ _ = internalError "Lift.absExpr.absType"
+absExpr _   _   c@(Constructor _ _ _) = return c
+absExpr pre lvs (Apply       spi e1 e2) = Apply spi <$> absExpr pre lvs e1
+                                                    <*> absExpr pre lvs e2
+absExpr pre lvs (Let          _ _ ds e) = absDeclGroup pre lvs ds e
+absExpr pre lvs (Case      _ _ ct e bs) =
+  mkCase ct <$> absExpr pre lvs e <*> mapM (absAlt pre lvs) bs
+absExpr pre lvs (Typed        spi e ty) =
+  flip (Typed spi) ty <$> absExpr pre lvs e
+absExpr _   _   e                   = internalError $ "Lift.absExpr: " ++ show e
+
+absAlt :: String -> [Ident] -> Alt Type -> LiftM (Alt Type)
+absAlt pre lvs (Alt p t rhs) = Alt p t <$> absRhs pre lvs' rhs
+  where lvs' = lvs ++ bv t
+
+-- -----------------------------------------------------------------------------
+-- Lifting
+-- -----------------------------------------------------------------------------
+
+-- After the abstraction pass, all local function declarations are lifted
+-- to the top-level.
+
+liftFunDecl :: Eq a => Decl a -> [Decl a]
+liftFunDecl (FunctionDecl p a f eqs) =
+  FunctionDecl p a f eqs' : map renameFunDecl (concat dss')
+  where (eqs', dss') = unzip $ map liftEquation eqs
+liftFunDecl d                        = [d]
+
+liftVarDecl :: Eq a => Decl a -> (Decl a, [Decl a])
+liftVarDecl (PatternDecl   p t rhs) = (PatternDecl p t rhs', ds')
+  where (rhs', ds') = liftRhs rhs
+liftVarDecl ex@(FreeDecl       _ _) = (ex, [])
+liftVarDecl _ = error "Lift.liftVarDecl: no pattern match"
+
+liftEquation :: Eq a => Equation a -> (Equation a, [Decl a])
+liftEquation (Equation p lhs rhs) = (Equation p lhs rhs', ds')
+  where (rhs', ds') = liftRhs rhs
+
+liftRhs :: Eq a => Rhs a -> (Rhs a, [Decl a])
+liftRhs (SimpleRhs p _ e _) = first (simpleRhs p) (liftExpr e)
+liftRhs _                   = error "Lift.liftRhs: no pattern match"
+
+liftDeclGroup :: Eq a => [Decl a] -> ([Decl a], [Decl a])
+liftDeclGroup ds = (vds', concat (map liftFunDecl fds ++ dss'))
+  where (fds , vds ) = partition isFunDecl ds
+        (vds', dss') = unzip $ map liftVarDecl vds
+
+liftExpr :: Eq a => Expression a -> (Expression a, [Decl a])
+liftExpr l@(Literal     _ _ _) = (l, [])
+liftExpr v@(Variable    _ _ _) = (v, [])
+liftExpr c@(Constructor _ _ _) = (c, [])
+liftExpr (Apply       spi e1 e2) = (Apply spi e1' e2', ds1 ++ ds2)
+  where (e1', ds1) = liftExpr e1
+        (e2', ds2) = liftExpr e2
+liftExpr (Let        _ _ ds e) = (mkLet ds' e', ds1 ++ ds2)
+  where (ds', ds1) = liftDeclGroup ds
+        (e' , ds2) = liftExpr e
+liftExpr (Case    _ _ ct e alts) = (mkCase ct e' alts', concat $ ds' : dss')
+  where (e'   , ds' ) = liftExpr e
+        (alts', dss') = unzip $ map liftAlt alts
+liftExpr (Typed        spi e ty) =
+  (Typed spi e' ty, ds) where (e', ds) = liftExpr e
+liftExpr _ = internalError "Lift.liftExpr"
+
+liftAlt :: Eq a => Alt a -> (Alt a, [Decl a])
+liftAlt (Alt p t rhs) = (Alt p t rhs', ds') where (rhs', ds') = liftRhs rhs
+
+-- -----------------------------------------------------------------------------
+-- Renaming
+-- -----------------------------------------------------------------------------
+
+-- After all local function declarations have been lifted to top-level, we
+-- may have to rename duplicate function arguments. Due to polymorphic let
+-- declarations it could happen that an argument was added multiple times
+-- instantiated with different types during the abstraction pass beforehand.
+
+type RenameMap a = [((a, Ident), Ident)]
+
+renameFunDecl :: Eq a => Decl a -> Decl a
+renameFunDecl (FunctionDecl p a f eqs) =
+  FunctionDecl p a f (map renameEquation eqs)
+renameFunDecl d                        = d
+
+renameEquation :: Eq a => Equation a -> Equation a
+renameEquation (Equation p lhs rhs) = Equation p lhs' (renameRhs rm rhs)
+  where (rm, lhs') = renameLhs lhs
+
+renameLhs :: Eq a => Lhs a -> (RenameMap a, Lhs a)
+renameLhs (FunLhs spi f ts) = (rm, FunLhs spi f ts')
+  where (rm, ts') = foldr renamePattern ([], []) ts
+renameLhs _             = error "Lift.renameLhs"
+
+renamePattern :: Eq a => Pattern a -> (RenameMap a, [Pattern a])
+              -> (RenameMap a, [Pattern a])
+renamePattern (VariablePattern spi a v) (rm, ts)
+  | v `elem` varPatNames ts =
+    let v' = updIdentName (++ ("." ++ show (length rm))) v
+    in  (((a, v), v') : rm, VariablePattern spi a v' : ts)
+renamePattern t                     (rm, ts) = (rm, t : ts)
+
+renameRhs :: Eq a => RenameMap a -> Rhs a -> Rhs a
+renameRhs rm (SimpleRhs p _ e _) = simpleRhs p (renameExpr rm e)
+renameRhs _  _                   = error "Lift.renameRhs"
+
+renameExpr :: Eq a => RenameMap a -> Expression a -> Expression a
+renameExpr _  l@(Literal       _ _ _) = l
+renameExpr rm v@(Variable   spi a v')
+  | isQualified v' = v
+  | otherwise      = case lookup (a, unqualify v') rm of
+                       Just v'' -> Variable spi a (qualify v'')
+                       _        -> v
+renameExpr _  c@(Constructor _ _ _) = c
+renameExpr rm (Typed       spi e ty) = Typed spi (renameExpr rm e) ty
+renameExpr rm (Apply       spi e1 e2) =
+  Apply spi (renameExpr rm e1) (renameExpr rm e2)
+renameExpr rm (Let       _ _ ds e) =
+  mkLet (map (renameDecl rm) ds) (renameExpr rm e)
+renameExpr rm (Case    _ _ ct e alts) =
+  mkCase ct (renameExpr rm e) (map (renameAlt rm) alts)
+renameExpr _  _                   = error "Lift.renameExpr"
+
+renameDecl :: Eq a => RenameMap a -> Decl a -> Decl a
+renameDecl rm (PatternDecl p t rhs) = PatternDecl p t (renameRhs rm rhs)
+renameDecl _  d                     = d
+
+renameAlt :: Eq a => RenameMap a -> Alt a -> Alt a
+renameAlt rm (Alt p t rhs) = Alt p t (renameRhs rm rhs)
+
+-- ---------------------------------------------------------------------------
+-- Auxiliary definitions
+-- ---------------------------------------------------------------------------
+
+isFunDecl :: Decl a -> Bool
+isFunDecl (FunctionDecl _ _ _ _) = True
+isFunDecl (ExternalDecl _ _    ) = True
+isFunDecl _                      = False
+
+mkFun :: ModuleIdent -> String -> a -> Ident -> Expression a
+mkFun m pre a = Variable NoSpanInfo a . qualifyWith m . liftIdent pre
+
+liftIdent :: String -> Ident -> Ident
+liftIdent prefix x = renameIdent (mkIdent $ prefix ++ showIdent x) $ idUnique x
+
+varPatNames :: [Pattern a] -> [Ident]
+varPatNames = mapMaybe varPatName
+
+varPatName :: Pattern a -> Maybe Ident
+varPatName (VariablePattern _ _ i) = Just i
+varPatName _                     = Nothing
+
+dummyType :: Type
+dummyType = TypeForall [] undefined
+
+isDummyType :: Type -> Bool
+isDummyType (TypeForall [] _) = True
+isDummyType _                 = False
diff --git a/src/Transformations/Newtypes.hs b/src/Transformations/Newtypes.hs
new file mode 100644
--- /dev/null
+++ b/src/Transformations/Newtypes.hs
@@ -0,0 +1,113 @@
+{- |
+  Module      :  $Header$
+  Description :  Removing newtype constructors
+  Copyright   :  (c) 2017        Finn Teegen
+  License     :  BSD-3-clause
+
+  Maintainer  :  fte@informatik.uni-kiel.de
+  Stability   :  experimental
+  Portability :  portable
+
+  After inserting dictionaries, the compiler removes all occurences of
+  newtype declarations. Applications 'N x' in patterns and expressions,
+  where 'N' is a newtype constructor, are replaced by a 'x'. The newtype
+  declarations are replaced by type synonyms and partial applications of
+  newtype constructors are changed into calls to 'Prelude.id'.
+-}
+{-# LANGUAGE CPP #-}
+module Transformations.Newtypes (removeNewtypes) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative        ((<$>), (<*>))
+#endif
+import qualified Control.Monad.Reader as R
+
+import Curry.Base.Ident
+import Curry.Syntax
+
+import Base.Messages (internalError)
+import Base.Types
+
+import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)
+
+removeNewtypes :: Bool -> ValueEnv -> Module Type -> Module Type
+removeNewtypes remNT vEnv mdl
+  | remNT     = R.runReader (nt mdl) vEnv
+  | otherwise = mdl
+
+type NTM a = R.Reader ValueEnv a
+
+class Show a => Newtypes a where
+  nt :: a -> NTM a
+
+instance Newtypes a => Newtypes [a] where
+  nt = mapM nt
+
+instance Show a => Newtypes (Module a) where
+  nt (Module spi li ps m es is ds) = Module spi li ps m es is <$> mapM nt ds
+
+instance Show a => Newtypes (Decl a) where
+  nt d@(InfixDecl       _ _ _ _) = return d
+  nt d@(DataDecl      _ _ _ _ _) = return d
+  nt d@(ExternalDataDecl  _ _ _) = return d
+  nt (NewtypeDecl p tc vs nc []) = return $ TypeDecl p tc vs $ nconstrType nc
+  nt d@(TypeDecl        _ _ _ _) = return d
+  nt (FunctionDecl    p a f eqs) = FunctionDecl p a f <$> nt eqs
+  nt d@(ExternalDecl        _ _) = return d
+  nt (PatternDecl       p t rhs) = PatternDecl p <$> nt t <*> nt rhs
+  nt d@(FreeDecl            _ _) = return d
+  nt d                           = internalError $
+    "Newtypes.Newtypes.nt: unexpected declaration: " ++ show d
+
+instance Show a => Newtypes (Equation a) where
+  nt (Equation p lhs rhs) = Equation p <$> nt lhs <*> nt rhs
+
+instance Show a => Newtypes (Lhs a) where
+  nt (FunLhs spi f ts) = FunLhs spi f <$> nt ts
+  nt lhs           = internalError $
+    "Newtypes.Newtypes.nt: unexpected left-hand-side: " ++ show lhs
+
+instance Show a => Newtypes (Rhs a) where
+  nt (SimpleRhs p li e []) = flip (SimpleRhs p li) [] <$> nt e
+  nt rhs                   = internalError $
+    "Newtypes.Newtypes.nt: unexpected right-hand-side: " ++ show rhs
+
+instance Show a => Newtypes (Pattern a) where
+  nt t@(LiteralPattern        _ _ _) = return t
+  nt t@(VariablePattern       _ _ _) = return t
+  nt (ConstructorPattern spi a c ts) = case ts of
+    [t] -> do
+      isNc <- isNewtypeConstr c
+      if isNc then nt t
+              else ConstructorPattern spi a c <$> ((: []) <$> nt t)
+    _   -> ConstructorPattern spi a c <$> mapM nt ts
+  nt (AsPattern             spi v t) = AsPattern spi v <$> nt t
+  nt t                               = internalError $
+    "Newtypes.Newtypes.nt: unexpected pattern: " ++ show t
+
+instance Show a => Newtypes (Expression a) where
+  nt e@(Literal   _   _ _) = return e
+  nt e@(Variable    _ _ _) = return e
+  nt (Constructor spi a c) = do
+    isNc <- isNewtypeConstr c
+    return $ if isNc then Variable spi a qIdId else Constructor spi a c
+  nt (Apply     spi e1 e2) = case e1 of
+    Constructor _ _ c -> do
+      isNc <- isNewtypeConstr c
+      if isNc then nt e2 else Apply spi <$> nt e1 <*> nt e2
+    _ -> Apply spi <$> nt e1 <*> nt e2
+  nt (Case spi li ct e as) = Case spi li ct <$> nt e <*> mapM nt as
+  nt (Let     spi li ds e) = Let spi li <$> nt ds <*> nt e
+  nt (Typed     spi e qty) = flip (Typed spi) qty <$> nt e
+  nt e                 = internalError $
+    "Newtypes.Newtypes.nt: unexpected expression: " ++ show e
+
+instance Show a => Newtypes (Alt a) where
+  nt (Alt p t rhs) = Alt p <$> nt t <*> nt rhs
+
+isNewtypeConstr :: QualIdent -> NTM Bool
+isNewtypeConstr c = R.ask >>= \vEnv -> return $
+  case qualLookupValue c vEnv of
+    [NewtypeConstructor _ _ _] -> True
+    [DataConstructor  _ _ _ _] -> False
+    _ -> internalError $ "Newtypes.isNewtypeConstr: " ++ show c
diff --git a/src/Transformations/Qual.hs b/src/Transformations/Qual.hs
new file mode 100644
--- /dev/null
+++ b/src/Transformations/Qual.hs
@@ -0,0 +1,250 @@
+{- |
+    Module      :  $Header$
+    Description :  Proper Qualification
+    Copyright   :  (c) 2001 - 2004 Wolfgang Lux
+                       2005        Martin Engelke
+                       2011 - 2015 Björn Peemöller
+                       2016 - 2017 Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+    After checking the module and before starting the translation into the
+    intermediate language, the compiler properly qualifies all type
+    constructors, data constructors and (global) functions
+    occurring in a pattern or expression such that their module prefix
+    matches the module of their definition.
+    This is done also for functions and constructors declared
+    in the current module.
+    Only functions and variables declared in local declarations groups
+    as well as function arguments remain unchanged.
+-}
+{-# LANGUAGE CPP #-}
+module Transformations.Qual (qual) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative       ((<$>), (<*>), pure)
+#endif
+import qualified Control.Monad.Reader as R (Reader, asks, runReader)
+import           Data.Traversable
+import           Prelude hiding            (mapM)
+
+import Curry.Base.Ident
+import Curry.Syntax
+
+import Base.TopEnv         (origName)
+
+import Env.TypeConstructor (TCEnv   , qualLookupTypeInfo)
+import Env.Value           (ValueEnv, qualLookupValue)
+
+data QualEnv = QualEnv
+  { moduleIdent :: ModuleIdent
+  , tyConsEnv   :: TCEnv
+  , valueEnv    :: ValueEnv
+  }
+
+type Qual a = a -> R.Reader QualEnv a
+
+qual :: ModuleIdent -> TCEnv -> ValueEnv -> Module a -> Module a
+qual m tcEnv tyEnv mdl = R.runReader (qModule mdl) (QualEnv m tcEnv tyEnv)
+
+qModule :: Qual (Module a)
+qModule (Module spi li ps m es is ds) = do
+  es' <- qExportSpec es
+  ds' <- mapM qDecl  ds
+  return (Module spi li ps m es' is ds')
+
+qExportSpec :: Qual (Maybe ExportSpec)
+qExportSpec Nothing                 = return Nothing
+qExportSpec (Just (Exporting p es)) = (Just . Exporting p) <$> mapM qExport es
+
+qExport :: Qual Export
+qExport (Export            spi x) = Export spi <$> qIdent x
+qExport (ExportTypeWith spi t cs) = flip (ExportTypeWith spi) cs <$> qConstr t
+qExport (ExportTypeAll     spi t) = ExportTypeAll spi <$> qConstr t
+qExport m@(ExportModule      _ _) = return m
+
+qDecl :: Qual (Decl a)
+qDecl i@(InfixDecl             _ _ _ _) = return i
+qDecl (DataDecl         p n vs cs clss) = DataDecl p n vs <$>
+  mapM qConstrDecl cs <*> mapM qClass clss
+qDecl e@(ExternalDataDecl        _ _ _) = return e
+qDecl (NewtypeDecl      p n vs nc clss) = NewtypeDecl p n vs <$>
+  qNewConstrDecl nc <*> mapM qClass clss
+qDecl (TypeDecl              p n vs ty) = TypeDecl p n vs <$> qTypeExpr ty
+qDecl (TypeSig                p fs qty) = TypeSig p fs <$> qQualTypeExpr qty
+qDecl (FunctionDecl          a p f eqs) = FunctionDecl a p f <$> mapM qEquation eqs
+qDecl e@(ExternalDecl              _ _) = return e
+qDecl (PatternDecl             p t rhs) = PatternDecl p <$> qPattern t <*> qRhs rhs
+qDecl vs@(FreeDecl                 _ _) = return vs
+qDecl (DefaultDecl               p tys) = DefaultDecl p <$> mapM qTypeExpr tys
+qDecl (ClassDecl     p li cx cls tv ds) = ClassDecl p li <$>
+  qContext cx <*> pure cls <*> pure tv <*> mapM qDecl ds
+qDecl (InstanceDecl p li cx qcls ty ds) = InstanceDecl p li <$>
+  qContext cx <*> qClass qcls <*> qTypeExpr ty <*> mapM qDecl ds
+
+qConstrDecl :: Qual ConstrDecl
+qConstrDecl (ConstrDecl p      n tys) =
+  ConstrDecl p n <$> mapM qTypeExpr tys
+qConstrDecl (ConOpDecl  p ty1 op ty2) =
+  ConOpDecl p <$> qTypeExpr ty1 <*> pure op <*> qTypeExpr ty2
+qConstrDecl (RecordDecl p       c fs) =
+  RecordDecl p c <$> mapM qFieldDecl fs
+
+qNewConstrDecl :: Qual NewConstrDecl
+qNewConstrDecl (NewConstrDecl p n ty)
+  = NewConstrDecl p n <$> qTypeExpr ty
+qNewConstrDecl (NewRecordDecl p n (f, ty))
+  = (\ty' -> NewRecordDecl p n (f, ty')) <$> qTypeExpr ty
+
+qFieldDecl :: Qual FieldDecl
+qFieldDecl (FieldDecl p fs ty) = FieldDecl p fs <$> qTypeExpr ty
+
+qConstraint :: Qual Constraint
+qConstraint (Constraint spi cls ty) =
+  Constraint spi <$> qClass cls <*> qTypeExpr ty
+
+qContext :: Qual Context
+qContext = mapM qConstraint
+
+qTypeExpr :: Qual TypeExpr
+qTypeExpr (ConstructorType     spi c) = ConstructorType spi <$> qConstr c
+qTypeExpr (ApplyType     spi ty1 ty2) = ApplyType spi <$> qTypeExpr ty1
+                                              <*> qTypeExpr ty2
+qTypeExpr v@(VariableType        _ _) = return v
+qTypeExpr (TupleType         spi tys) = TupleType spi <$> mapM qTypeExpr tys
+qTypeExpr (ListType           spi ty) = ListType spi  <$> qTypeExpr ty
+qTypeExpr (ArrowType     spi ty1 ty2) = ArrowType spi <$> qTypeExpr ty1
+                                              <*> qTypeExpr ty2
+qTypeExpr (ParenType          spi ty) = ParenType spi <$> qTypeExpr ty
+qTypeExpr (ForallType      spi vs ty) = ForallType spi vs <$> qTypeExpr ty
+
+qQualTypeExpr :: Qual QualTypeExpr
+qQualTypeExpr (QualTypeExpr spi cx ty) = QualTypeExpr spi <$> qContext cx
+                                                          <*> qTypeExpr ty
+
+qEquation :: Qual (Equation a)
+qEquation (Equation p lhs rhs) = Equation p <$> qLhs lhs <*> qRhs rhs
+
+qLhs :: Qual (Lhs a)
+qLhs (FunLhs sp    f ts) = FunLhs sp       f  <$> mapM qPattern ts
+qLhs (OpLhs sp t1 op t2) = flip (OpLhs sp) op <$> qPattern t1 <*> qPattern t2
+qLhs (ApLhs sp   lhs ts) = ApLhs sp           <$> qLhs lhs <*> mapM qPattern ts
+
+qPattern :: Qual (Pattern a)
+qPattern l@(LiteralPattern          _ _ _) = return l
+qPattern n@(NegativePattern         _ _ _) = return n
+qPattern v@(VariablePattern         _ _ _) = return v
+qPattern (ConstructorPattern   spi a c ts) =
+  ConstructorPattern spi a <$> qIdent c <*> mapM qPattern ts
+qPattern (InfixPattern     spi a t1 op t2) =
+  InfixPattern spi a <$> qPattern t1 <*> qIdent op <*> qPattern t2
+qPattern (ParenPattern              spi t) = ParenPattern spi <$> qPattern t
+qPattern (RecordPattern        spi a c fs) = RecordPattern spi a <$> qIdent c
+                                          <*> mapM (qField qPattern) fs
+qPattern (TuplePattern             spi ts) =
+  TuplePattern spi <$> mapM qPattern ts
+qPattern (ListPattern            spi a ts) =
+  ListPattern spi a <$> mapM qPattern ts
+qPattern (AsPattern               spi v t) = AsPattern spi v <$> qPattern t
+qPattern (LazyPattern               spi t) = LazyPattern spi <$> qPattern t
+qPattern (FunctionPattern      spi a f ts) =
+  FunctionPattern spi a <$> qIdent f <*> mapM qPattern ts
+qPattern (InfixFuncPattern spi a t1 op t2) =
+  InfixFuncPattern spi a <$> qPattern t1 <*> qIdent op <*> qPattern t2
+
+qRhs :: Qual (Rhs a)
+qRhs (SimpleRhs spi li e ds) =
+  SimpleRhs  spi li <$> qExpr e           <*> mapM qDecl ds
+qRhs (GuardedRhs spi li es ds) =
+  GuardedRhs spi li <$> mapM qCondExpr es <*> mapM qDecl ds
+
+qCondExpr :: Qual (CondExpr a)
+qCondExpr (CondExpr p g e) = CondExpr p <$> qExpr g <*> qExpr e
+
+qExpr :: Qual (Expression a)
+qExpr l@(Literal             _ _ _) = return l
+qExpr (Variable            spi a v) = Variable     spi a <$> qIdent v
+qExpr (Constructor         spi a c) = Constructor  spi a <$> qIdent c
+qExpr (Paren                 spi e) = Paren        spi   <$> qExpr e
+qExpr (Typed             spi e qty) = Typed        spi   <$> qExpr e
+                                                         <*> qQualTypeExpr qty
+qExpr (Record           spi a c fs) =
+  Record spi a <$> qIdent c <*> mapM (qField qExpr) fs
+qExpr (RecordUpdate       spi e fs) =
+  RecordUpdate spi <$> qExpr e <*> mapM (qField qExpr) fs
+qExpr (Tuple                spi es) = Tuple          spi <$> mapM qExpr es
+qExpr (List               spi a es) = List           spi a <$> mapM qExpr es
+qExpr (ListCompr          spi e qs) = ListCompr      spi <$> qExpr e
+                                                         <*> mapM qStmt qs
+qExpr (EnumFrom              spi e) = EnumFrom       spi <$> qExpr e
+qExpr (EnumFromThen      spi e1 e2) = EnumFromThen   spi <$> qExpr e1
+                                                         <*> qExpr e2
+qExpr (EnumFromTo        spi e1 e2) = EnumFromTo     spi <$> qExpr e1
+                                                         <*> qExpr e2
+qExpr (EnumFromThenTo spi e1 e2 e3) = EnumFromThenTo spi <$> qExpr e1
+                                                         <*> qExpr e2
+                                                         <*> qExpr e3
+qExpr (UnaryMinus            spi e) = UnaryMinus     spi <$> qExpr e
+qExpr (Apply             spi e1 e2) = Apply          spi <$> qExpr e1
+                                                         <*> qExpr e2
+qExpr (InfixApply     spi e1 op e2) = InfixApply     spi <$> qExpr e1
+                                                         <*> qInfixOp op
+                                                         <*> qExpr e2
+qExpr (LeftSection        spi e op) = LeftSection  spi <$> qExpr e
+                                                       <*> qInfixOp op
+qExpr (RightSection       spi op e) = RightSection spi <$> qInfixOp op
+                                                       <*> qExpr e
+qExpr (Lambda             spi ts e) = Lambda       spi <$> mapM qPattern ts
+                                                       <*> qExpr e
+qExpr (Let             spi li ds e) = Let spi li <$> mapM qDecl ds  <*> qExpr e
+qExpr (Do             spi li sts e) = Do  spi li <$> mapM qStmt sts <*> qExpr e
+qExpr (IfThenElse     spi e1 e2 e3) = IfThenElse spi <$> qExpr e1 <*> qExpr e2
+                                                     <*> qExpr e3
+qExpr (Case         spi li ct e as) = Case spi li ct <$> qExpr e <*> mapM qAlt as
+
+qStmt :: Qual (Statement a)
+qStmt (StmtExpr spi     e) = StmtExpr spi    <$> qExpr e
+qStmt (StmtBind spi t   e) = StmtBind spi    <$> qPattern t <*> qExpr e
+qStmt (StmtDecl spi li ds) = StmtDecl spi li <$> mapM qDecl ds
+
+qAlt :: Qual (Alt a)
+qAlt (Alt p t rhs) = Alt p <$> qPattern t <*> qRhs rhs
+
+qField :: Qual a -> Qual (Field a)
+qField q (Field p l x) = Field p <$> qIdent l <*> q x
+
+qInfixOp :: Qual (InfixOp a)
+qInfixOp (InfixOp     a op) = InfixOp     a <$> qIdent op
+qInfixOp (InfixConstr a op) = InfixConstr a <$> qIdent op
+
+qIdent :: Qual QualIdent
+qIdent x | isQualified x                = x'
+         | hasGlobalScope (unqualify x) = x'
+         | otherwise                    = return x
+  where
+  x' = do
+    m     <- R.asks moduleIdent
+    tyEnv <- R.asks valueEnv
+    return $ case qualLookupValue x tyEnv of
+      [y] -> origName y
+      _   -> case qualLookupValue qmx tyEnv of
+        [y] -> origName y
+        _   -> qmx
+        where qmx = qualQualify m x
+
+qConstr :: Qual QualIdent
+qConstr x = do
+  m     <- R.asks moduleIdent
+  tcEnv <- R.asks tyConsEnv
+  return $ case qualLookupTypeInfo x tcEnv of
+    [y] -> origName y
+    _   -> case qualLookupTypeInfo qmx tcEnv of
+      [y] -> origName y
+      _   -> qmx
+      where qmx = qualQualify m x
+
+qClass :: Qual QualIdent
+qClass = qConstr
diff --git a/src/Transformations/Simplify.hs b/src/Transformations/Simplify.hs
new file mode 100644
--- /dev/null
+++ b/src/Transformations/Simplify.hs
@@ -0,0 +1,347 @@
+{- |
+    Module      :  $Header$
+    Description :  Optimizing the Desugared Code
+    Copyright   :  (c) 2003        Wolfgang Lux
+                                   Martin Engelke
+                       2011 - 2015 Björn Peemöller
+                       2016        Finn Teegen
+    License     :  BSD-3-clause
+
+    Maintainer  :  bjp@informatik.uni-kiel.de
+    Stability   :  experimental
+    Portability :  portable
+
+   After desugaring the source code, but before lifting local
+   declarations, the compiler performs a few simple optimizations to
+   improve the efficiency of the generated code. In addition, the
+   optimizer replaces pattern bindings with simple variable bindings and
+   selector functions.
+
+   Currently, the following optimizations are implemented:
+
+     * Under certain conditions, inline local function definitions.
+     * Remove unused declarations.
+     * Compute minimal binding groups for let expressions.
+     * Remove pattern bindings to constructor terms
+     * Inline simple constants.
+-}
+{-# LANGUAGE CPP #-}
+module Transformations.Simplify (simplify) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative        ((<$>), (<*>))
+#endif
+import           Control.Monad.Extra        (concatMapM)
+import           Control.Monad.State as S   (State, runState, gets, modify)
+import qualified Data.Map            as Map (Map, empty, insert, lookup)
+
+import Curry.Base.Ident
+import Curry.Base.SpanInfo
+import Curry.Syntax
+
+import Base.Expr
+import Base.Messages (internalError)
+import Base.SCC
+import Base.Types
+import Base.Typing
+import Base.Utils
+
+import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)
+
+-- -----------------------------------------------------------------------------
+-- Simplification
+-- -----------------------------------------------------------------------------
+
+simplify :: ValueEnv -> Module Type -> (Module Type, ValueEnv)
+simplify vEnv mdl@(Module _ _ _ m _ _ _) = (mdl', valueEnv s')
+  where (mdl', s') = S.runState (simModule mdl) (SimplifyState m vEnv 1)
+
+-- -----------------------------------------------------------------------------
+-- Internal state monad
+-- -----------------------------------------------------------------------------
+
+data SimplifyState = SimplifyState
+  { moduleIdent :: ModuleIdent -- read-only!
+  , valueEnv    :: ValueEnv    -- updated for new pattern selection functions
+  , nextId      :: Int         -- counter
+  }
+
+type SIM = S.State SimplifyState
+
+getModuleIdent :: SIM ModuleIdent
+getModuleIdent = S.gets moduleIdent
+
+getNextId :: SIM Int
+getNextId = do
+  nid <- S.gets nextId
+  S.modify $ \s -> s { nextId = succ nid }
+  return nid
+
+getFunArity :: QualIdent -> SIM Int
+getFunArity f = do
+  vEnv <- getValueEnv
+  return $ case qualLookupValue f vEnv of
+    [Value _ _ a _] -> a
+    [Label   _ _ _] -> 1
+    _               -> internalError $ "Simplify.funType " ++ show f
+
+getValueEnv :: SIM ValueEnv
+getValueEnv = S.gets valueEnv
+
+freshIdent :: (Int -> Ident) -> SIM Ident
+freshIdent f = f <$> getNextId
+
+-- -----------------------------------------------------------------------------
+-- Simplification
+-- -----------------------------------------------------------------------------
+
+simModule :: Module Type -> SIM (Module Type)
+simModule (Module spi li ps m es is ds) = Module spi li ps m es is
+                                       <$> mapM (simDecl Map.empty) ds
+
+-- Inline an expression for a variable
+type InlineEnv = Map.Map Ident (Expression Type)
+
+simDecl :: InlineEnv -> Decl Type -> SIM (Decl Type)
+simDecl env (FunctionDecl p ty f eqs) = FunctionDecl p ty f
+                                        <$> concatMapM (simEquation env) eqs
+simDecl env (PatternDecl     p t rhs) = PatternDecl p t <$> simRhs env rhs
+simDecl _   d                         = return d
+
+simEquation :: InlineEnv -> Equation Type -> SIM [Equation Type]
+simEquation env (Equation p lhs rhs) = do
+  rhs'  <- simRhs env rhs
+  inlineFun env p lhs rhs'
+
+simRhs :: InlineEnv -> Rhs Type -> SIM (Rhs Type)
+simRhs env (SimpleRhs  p _ e _) = simpleRhs p <$> simExpr env e
+simRhs _   (GuardedRhs _ _ _ _) = error "Simplify.simRhs: guarded rhs"
+
+-- -----------------------------------------------------------------------------
+-- Inlining of Functions
+-- -----------------------------------------------------------------------------
+
+-- After simplifying the right hand side of an equation, the compiler
+-- transforms declarations of the form
+--
+--   f t_1 ... t_{k-l} x_{k-l+1} ... x_k =
+--     let g y_1 ... y_l = e
+--     in  g x_{k-l+1} ... x_k
+--
+-- into the equivalent definition
+--
+--   f t_1 ... t_{k-l} x_{k-l+1} x_k = let y_1   = x_{k-l+1}
+--                                              ...
+--                                         y_l   = x_k
+--                                     in  e
+--
+-- where the arities of 'f' and 'g' are 'k' and 'l', respectively, and
+-- 'x_{k-l+1}, ... ,x_k' are variables. The transformation can obviously be
+-- generalized to the case where 'g' is defined by more than one equation.
+-- However, we must be careful not to change the evaluation mode of arguments.
+-- Therefore, the transformation is applied only all of the arguments of 'g'
+-- are variables.
+--
+-- This transformation is actually just a special case of inlining a
+-- (local) function definition. We are unable to handle the general case
+-- because it would require to represent the pattern matching code
+-- explicitly in a Curry expression.
+
+inlineFun :: InlineEnv -> SpanInfo -> Lhs Type -> Rhs Type
+          -> SIM [Equation Type]
+inlineFun env p lhs rhs = do
+  m <- getModuleIdent
+  case rhs of
+    SimpleRhs _ _ (Let _ _ [FunctionDecl _ _ f' eqs'] e) _
+      | -- @f'@ is not recursive
+        f' `notElem` qfv m eqs'
+        -- @f'@ does not perform any pattern matching
+        && and [all isVariablePattern ts1 | Equation _ (FunLhs _ _ ts1) _ <- eqs']
+      -> do
+        let a = eqnArity $ head eqs'
+            (n, vs', e') = etaReduce 0 [] (reverse (snd $ flatLhs lhs)) e
+        if  -- the eta-reduced rhs of @f@ is a call to @f'@
+            setSpanInfo NoSpanInfo e' == Variable NoSpanInfo (typeOf e') (qualify f')
+            -- @f'@ was fully applied before eta-reduction
+            && n  == a
+          then mapM (mergeEqns p vs') eqs'
+          else return [Equation p lhs rhs]
+    _ -> return [Equation p lhs rhs]
+  where
+  etaReduce n1 vs (VariablePattern _ ty v : ts1)
+                  (Apply _ e1 (Variable _ _ v'))
+    | qualify v == v' = etaReduce (n1 + 1) ((ty, v) : vs) ts1 e1
+  etaReduce n1 vs _ e1 = (n1, vs, e1)
+
+  mergeEqns p1 vs (Equation _ (FunLhs _ _ ts2) (SimpleRhs p2 _ e _))
+    = Equation p1 lhs <$> simRhs env (simpleRhs p2 (mkLet ds e))
+      where
+      ds = zipWith (\t v -> PatternDecl NoSpanInfo t (simpleRhs p2 (uncurry mkVar v)))
+                   ts2
+                   vs
+  mergeEqns _ _ _ = error "Simplify.inlineFun.mergeEqns: no pattern match"
+
+-- -----------------------------------------------------------------------------
+-- Simplification of Expressions
+-- -----------------------------------------------------------------------------
+
+-- Variables that are bound to (simple) constants and aliases to other
+-- variables are substituted. In terms of conventional compiler technology,
+-- these optimizations correspond to constant propagation and copy propagation,
+-- respectively. The transformation is applied recursively to a substituted
+-- variable in order to handle chains of variable definitions.
+
+-- Applications of let-expressions and case-expressions to other expressions
+-- are simplified according to the following rules:
+--   (let ds in e_1)            e_2 -> let ds in (e1 e2)
+--   (case e_1 of p'_n -> e'_n) e_2 -> case e_1 of p'_n -> (e'n e_2)
+
+-- The bindings of a let expression are sorted topologically in
+-- order to split them into minimal binding groups. In addition,
+-- local declarations occurring on the right hand side of a pattern
+-- declaration are lifted into the enclosing binding group using the
+-- equivalence (modulo alpha-conversion) of 'let x = let ds in e_1 in e_2'
+-- and 'let ds; x = e_1 in e_2'.
+-- This transformation avoids the creation of some redundant lifted
+-- functions in later phases of the compiler.
+
+simExpr :: InlineEnv -> Expression Type -> SIM (Expression Type)
+simExpr _   l@(Literal     _ _ _) = return l
+simExpr _   c@(Constructor _ _ _) = return c
+-- subsitution of variables
+simExpr env v@(Variable   _ ty x)
+  | isQualified x = return v
+  | otherwise     =
+    maybe (return v) (simExpr env . withType ty) (Map.lookup (unqualify x) env)
+-- simplification of application
+simExpr env (Apply       _ e1 e2) = case e1 of
+  Let _ _ ds e'     -> simExpr env (mkLet ds (Apply NoSpanInfo e' e2))
+  Case _ _ ct e' bs -> simExpr env (mkCase ct e' (map (applyToAlt e2) bs))
+  _                 -> Apply NoSpanInfo <$> simExpr env e1 <*> simExpr env e2
+  where
+  applyToAlt e (Alt        p t rhs) = Alt p t (applyToRhs e rhs)
+  applyToRhs e (SimpleRhs  p _ e1' _) = simpleRhs p (Apply NoSpanInfo e1' e)
+  applyToRhs _ (GuardedRhs _ _ _ _) = error "Simplify.simExpr.applyRhs: Guarded rhs"
+-- simplification of declarations
+simExpr env (Let        _ _ ds e) = do
+  m   <- getModuleIdent
+  dss <- mapM sharePatternRhs ds
+  simplifyLet env (scc bv (qfv m) (foldr hoistDecls [] (concat dss))) e
+simExpr env (Case    _ _ ct e bs) =
+  mkCase ct <$> simExpr env e <*> mapM (simplifyAlt env) bs
+simExpr env (Typed       _ e qty) =
+  flip (Typed NoSpanInfo) qty <$> simExpr env e
+simExpr _   _                     = error "Simplify.simExpr: no pattern match"
+
+-- Simplify a case alternative
+simplifyAlt :: InlineEnv -> Alt Type -> SIM (Alt Type)
+simplifyAlt env (Alt p t rhs) = Alt p t <$> simRhs env rhs
+
+-- Transform a pattern declaration @t = e@ into two declarations
+-- @t = v, v = e@ whenever @t@ is not a variable. This is used to share
+-- the expression @e@ using the fresh variable @v@.
+sharePatternRhs :: Decl Type -> SIM [Decl Type]
+--TODO: change to patterns instead of case
+sharePatternRhs (PatternDecl p t rhs) = case t of
+  VariablePattern _ _ _ -> return [PatternDecl p t rhs]
+  _                     -> do
+    let ty = typeOf t
+    v  <- freshIdent patternId
+    return [ PatternDecl p t                      (simpleRhs p (mkVar ty v))
+           , PatternDecl p (VariablePattern NoSpanInfo ty v) rhs
+           ]
+  where patternId n = mkIdent ("_#pat" ++ show n)
+sharePatternRhs d                     = return [d]
+
+-- Lift up nested let declarations in pattern declarations, i.e., replace
+-- @let p = let ds' in e'; ds in e@ by @let ds'; p = e'; ds in e@.
+hoistDecls :: Decl a -> [Decl a] -> [Decl a]
+hoistDecls (PatternDecl p t (SimpleRhs p' _ (Let _ _ ds' e) _)) ds
+ = foldr hoistDecls ds (PatternDecl p t (simpleRhs p' e) : ds')
+hoistDecls d ds = d : ds
+
+-- The declaration groups of a let expression are first processed from
+-- outside to inside, simplifying the right hand sides and collecting
+-- inlineable expressions on the fly. At present, only simple constants
+-- and aliases to other variables are inlined. A constant is considered
+-- simple if it is either a literal, a constructor, or a non-nullary
+-- function. Note that it is not possible to define nullary functions in
+-- local declarations in Curry. Thus, an unqualified name always refers
+-- to either a variable or a non-nullary function. Applications of
+-- constructors and partial applications of functions to at least one
+-- argument are not inlined because the compiler has to allocate space
+-- for them, anyway. In order to prevent non-termination, recursive
+-- binding groups are not processed for inlining.
+
+-- With the list of inlineable expressions, the body of the let is
+-- simplified and then the declaration groups are processed from inside
+-- to outside to construct the simplified, nested let expression. In
+-- doing so, unused bindings are discarded. In addition, all pattern
+-- bindings are replaced by simple variable declarations using selector
+-- functions to access the pattern variables.
+
+simplifyLet :: InlineEnv -> [[Decl Type]] -> Expression Type
+            -> SIM (Expression Type)
+simplifyLet env []       e = simExpr env e
+simplifyLet env (ds:dss) e = do
+  m     <- getModuleIdent
+  ds'   <- mapM (simDecl env) ds  -- simplify declarations
+  env'  <- inlineVars env ds'     -- inline a simple variable binding
+  e'    <- simplifyLet env' dss e -- simplify remaining bindings
+  ds''  <- concatMapM (expandPatternBindings (qfv m ds' ++ qfv m e')) ds'
+  return $ foldr (mkLet' m) e' (scc bv (qfv m) ds'')
+
+inlineVars :: InlineEnv -> [Decl Type] -> SIM InlineEnv
+inlineVars env ds = case ds of
+  [PatternDecl _ (VariablePattern _ _ v) (SimpleRhs _ _ e _)] -> do
+    allowed <- canInlineVar v e
+    return $ if allowed then Map.insert v e env else env
+  _ -> return env
+  where
+  canInlineVar _ (Literal     _ _ _) = return True
+  canInlineVar _ (Constructor _ _ _) = return True
+  canInlineVar v (Variable   _ _ v')
+    | isQualified v'             = (> 0) <$> getFunArity v'
+    | otherwise                  = return $ v /= unqualify v'
+  canInlineVar _ _               = return False
+
+mkLet' :: ModuleIdent -> [Decl Type] -> Expression Type -> Expression Type
+mkLet' m [FreeDecl p vs] e
+  | null vs'  = e
+  | otherwise = mkLet [FreeDecl p vs'] e -- remove unused free variables
+  where vs' = filter ((`elem` qfv m e) . varIdent) vs
+mkLet' m [PatternDecl _ (VariablePattern _ ty v) (SimpleRhs _ _ e _)] (Variable _ _ v')
+  | v' == qualify v && v `notElem` qfv m e = withType ty e -- inline single binding
+mkLet' m ds e
+  | not (any (`elem` qfv m e) (bv ds)) = e -- removed unused bindings
+  | otherwise                              = mkLet ds e
+
+-- In order to implement lazy pattern matching in local declarations,
+-- pattern declarations 't = e' where 't' is not a variable
+-- are transformed into a list of declarations
+-- 'v_0 = e; v_1 = f_1 v_0; ...; v_n = f_n v_0' where 'v_0' is a fresh
+-- variable, 'v_1,...,v_n' are the variables occurring in 't' and the
+-- auxiliary functions 'f_i' are defined by 'f_i t = v_i' (see also
+-- appendix D.8 of the Curry report). The bindings 'v_0 = e' are introduced
+-- before splitting the declaration groups of the enclosing let expression
+-- (cf. the 'Let' case in 'simExpr' above) so that they are placed in their own
+-- declaration group whenever possible. In particular, this ensures that
+-- the new binding is discarded when the expression 'e' is itself a variable.
+
+-- fvs contains all variables used in the declarations and the body
+-- of the let expression.
+expandPatternBindings :: [Ident] -> Decl Type -> SIM [Decl Type]
+expandPatternBindings fvs d@(PatternDecl p t (SimpleRhs _ _ e _)) = case t of
+  VariablePattern _ _ _ -> return [d]
+  _                     ->
+    -- used variables
+    mapM mkSelectorDecl (filter ((`elem` fvs) . fst3) (patternVars t))
+  where
+    pty = typeOf t -- type of pattern
+    mkSelectorDecl (v, _, vty) = do
+      let fty = TypeArrow pty vty
+      f <- freshIdent (updIdentName (++ '#' : idName v) . fpSelectorId)
+      return $ varDecl p vty v $
+        mkLet [funDecl p fty f [t] (mkVar vty v)]
+        (Apply NoSpanInfo (mkVar fty f) e)
+expandPatternBindings _ d = return [d]
diff --git a/src/TypeCheck.lhs b/src/TypeCheck.lhs
deleted file mode 100644
--- a/src/TypeCheck.lhs
+++ /dev/null
@@ -1,1331 +0,0 @@
-
-% $Id: TypeCheck.lhs,v 1.90 2004/11/06 18:34:07 wlux Exp $
-%
-% Copyright (c) 1999-2004, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{TypeCheck.lhs}
-\section{Type Checking Curry Programs}
-This module implements the type checker of the Curry compiler. The
-type checker is invoked after the syntactic correctness of the program
-has been verified. Local variables have been renamed already. Thus the
-compiler can maintain a flat type environment (which is necessary in
-order to pass the type information to later phases of the compiler).
-The type checker now checks the correct typing of all expressions and
-also verifies that the type signatures given by the user match the
-inferred types. The type checker uses algorithm
-W~\cite{DamasMilner82:Principal} for inferring the types of
-unannotated declarations, but allows for polymorphic recursion when a
-type annotation is present.
-\begin{verbatim}
-
-> module TypeCheck(typeCheck) where
-
-> import Text.PrettyPrint.HughesPJ
-> import Control.Monad.State as S
-> import Data.List
-> import Data.Maybe
-> import qualified Data.Map as Map
-> import qualified Data.Set as Set
-
-> import Curry.Base.Position
-> import Curry.Base.Ident
-> import Curry.Syntax
-> import Curry.Syntax.Pretty
-> import Curry.Syntax.Utils
-
-
-> import Base
-> import Types
-> import TopEnv
-> import SCC
-> import TypeSubst
-> import Utils
-
-> infixl 5 $-$
-
-> ($-$) :: Doc -> Doc -> Doc
-> x $-$ y = x $$ space $$ y
-
-\end{verbatim}
-Type checking proceeds as follows. First, the type constructor
-environment is initialized by adding all types defined in the current
-module. Next, the types of all data constructors and field labels
-are entered into the type environment and then a type inference 
-for all function and value definitions is performed. 
-The type checker returns the resulting type
-constructor and type environments.
-\begin{verbatim}
-
-> typeCheck :: ModuleIdent -> TCEnv -> ValueEnv -> [Decl] -> (TCEnv,ValueEnv)
-> typeCheck m tcEnv tyEnv ds =
->   run (tcDecls m tcEnv' Map.empty vds >>
->        S.lift S.get >>= \theta -> S.get >>= \tyEnv' ->
->        return (tcEnv',subst theta tyEnv'))
->       (bindLabels m tcEnv' (bindConstrs m tcEnv' tyEnv))
->   where (tds,vds) = partition isTypeDecl ds
->         tcEnv' = bindTypes m tds tcEnv
-
-\end{verbatim}
-
-The type checker makes use of nested state monads in order to
-maintain the type environment, the current substitution, and a counter
-which is used for generating fresh type variables.
-\begin{verbatim}
-
-> type TcState a = S.StateT ValueEnv (S.StateT TypeSubst (S.State Int)) a
-
-> run :: TcState a -> ValueEnv -> a
-> run m tyEnv = S.evalState (S.evalStateT (S.evalStateT m tyEnv) idSubst) 0
-
-\end{verbatim}
-\paragraph{Defining Types}
-Before type checking starts, the types defined in the local module
-have to be entered into the type constructor environment. All type
-synonyms occurring in the definitions are fully expanded and all type
-constructors are qualified with the name of the module in which they
-are defined. This is possible because Curry does not allow (mutually)
-recursive type synonyms. In order to simplify the expansion of type
-synonyms, the compiler first performs a dependency analysis on the
-type definitions. This also makes it easy to identify (mutually)
-recursive synonyms.
-
-Note that \texttt{bindTC} is passed the \emph{final} type constructor
-environment in order to handle the expansion of type synonyms. This
-does not lead to a termination problem because \texttt{sortTypeDecls}
-already has checked that there are no recursive type synonyms.
-
-We have to be careful with existentially quantified type variables for
-data constructors. An existentially quantified type variable may
-shadow a universally quantified variable from the left hand side of
-the type declaration. In order to avoid wrong indices being assigned
-to these variables, we replace all shadowed variables in the left hand
-side by \texttt{anonId} before passing them to \texttt{expandMonoType}
-and \texttt{expandMonoTypes}, respectively.
-\begin{verbatim}
-
-> bindTypes :: ModuleIdent -> [Decl] -> TCEnv -> TCEnv
-> bindTypes m ds tcEnv = tcEnv'
->   where tcEnv' = foldr (bindTC m tcEnv') tcEnv (sortTypeDecls m ds)
-
-> bindTC :: ModuleIdent -> TCEnv -> Decl -> TCEnv -> TCEnv
-> bindTC m tcEnv (DataDecl _ tc tvs cs) =
->   bindTypeInfo DataType m tc tvs (map (Just . mkData) cs)
->   where mkData (ConstrDecl _ evs c tys) = Data c (length evs) tys'
->           where tys' = expandMonoTypes m tcEnv (cleanTVars tvs evs) tys
->         mkData (ConOpDecl _ evs ty1 op ty2) = Data op (length evs) tys'
->           where tys' = expandMonoTypes m tcEnv (cleanTVars tvs evs) [ty1,ty2]
-> bindTC m tcEnv (NewtypeDecl _ tc tvs (NewConstrDecl _ evs c ty)) =
->   bindTypeInfo RenamingType m tc tvs (Data c (length evs) ty')
->   where ty' = expandMonoType m tcEnv (cleanTVars tvs evs) ty
-> bindTC m tcEnv (TypeDecl _ tc tvs ty) =
->   bindTypeInfo AliasType m tc tvs (expandMonoType m tcEnv tvs ty)
-> bindTC _ _ _ = id
-
-> cleanTVars :: [Ident] -> [Ident] -> [Ident]
-> cleanTVars tvs evs = [if tv `elem` evs then anonId else tv | tv <- tvs]
-
-> sortTypeDecls :: ModuleIdent -> [Decl] -> [Decl]
-> sortTypeDecls m = map (typeDecl m) . scc bound free
->   where bound (DataDecl _ tc _ _) = [tc]
->         bound (NewtypeDecl _ tc _ _) = [tc]
->         bound (TypeDecl _ tc _ _) = [tc]
->         free (DataDecl _ _ _ _) = []
->         free (NewtypeDecl _ _ _ _) = []
->         free (TypeDecl _ _ _ ty) = ft m ty []
-
-> typeDecl :: ModuleIdent -> [Decl] -> Decl
-> typeDecl _ [] = internalError "typeDecl"
-> typeDecl _ [d@(DataDecl _ _ _ _)] = d
-> typeDecl _ [d@(NewtypeDecl _ _ _ _)] = d
-> typeDecl m [d@(TypeDecl p tc _ ty)]
->   | tc `elem` ft m ty [] = errorAt' (recursiveTypes [tc])
->   | otherwise = d
-> typeDecl _ (TypeDecl p tc _ _ : ds) =
->   errorAt' (recursiveTypes (tc : [tc' | TypeDecl _ tc' _ _ <- ds]))
-
-> ft :: ModuleIdent -> TypeExpr -> [Ident] -> [Ident]
-> ft m (ConstructorType tc tys) tcs =
->   maybe id (:) (localIdent m tc) (foldr (ft m) tcs tys)
-> ft _ (VariableType _) tcs = tcs
-> ft m (TupleType tys) tcs = foldr (ft m) tcs tys
-> ft m (ListType ty) tcs = ft m ty tcs
-> ft m (ArrowType ty1 ty2) tcs = ft m ty1 $ ft m ty2 $ tcs
-> ft m (RecordType fs rty) tcs = 
->   foldr (ft m) (maybe tcs (\ty -> ft m ty tcs) rty) (map snd fs)
-
-\end{verbatim}
-\paragraph{Defining Data Constructors}
-In the next step, the types of all data constructors are entered into
-the type environment using the information just entered into the type
-constructor environment. Thus, we can be sure that all type variables
-have been properly renamed and all type synonyms are already expanded.
-\begin{verbatim}
-
-> bindConstrs :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv
-> bindConstrs m tcEnv tyEnv =
->   foldr (bindData . snd) tyEnv (localBindings tcEnv)
->   where bindData (DataType tc n cs) tyEnv =
->           foldr (bindConstr m n (constrType tc n)) tyEnv (catMaybes cs)
->         bindData (RenamingType tc n (Data c n' ty)) tyEnv =
->           bindGlobalInfo NewtypeConstructor m c
->                          (ForAllExist n n' (TypeArrow ty (constrType tc n)))
->                          tyEnv
->         bindData (AliasType _ _ _) tyEnv = tyEnv
->         bindConstr m n ty (Data c n' tys) =
->           bindGlobalInfo DataConstructor m c
->                          (ForAllExist n n' (foldr TypeArrow ty tys))
->         constrType tc n = TypeConstructor tc (map TypeVariable [0..n-1])
-
-\end{verbatim}
-\paragraph{Defining Field Labels}
-Records can only be declared as type aliases. So currently there is
-nothing more to do than entering all typed record fields (labels) 
-which occur in record types on the right-hand-side of type aliases 
-into the type environment. Since we use the type constructor environment
-again, we can be sure that all type variables
-have been properly renamed and all type synonyms are already expanded.
-\begin{verbatim}
-
-> bindLabels :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv
-> bindLabels m tcEnv tyEnv =
->   foldr (bindFieldLabels . snd) tyEnv (localBindings tcEnv)
->   where bindFieldLabels (AliasType r _ (TypeRecord fs _)) tyEnv =
->           foldr (bindField r) tyEnv fs
->	  bindFieldLabels _ tyEnv = tyEnv
->	  
->         bindField r (l,ty) tyEnv =
->           case (lookupValue l tyEnv) of
->             [] -> bindLabel l r (polyType ty) tyEnv 
->             _  -> tyEnv
-
-\end{verbatim}
-\paragraph{Type Signatures}
-The type checker collects type signatures in a flat environment. All
-anonymous variables occurring in a signature are replaced by fresh
-names. However, the type is not expanded so that the signature is
-available for use in the error message that is printed when the
-inferred type is less general than the signature.
-\begin{verbatim}
-
-> type SigEnv = Map.Map Ident TypeExpr
-
-> bindTypeSig :: Ident -> TypeExpr -> SigEnv -> SigEnv
-> bindTypeSig = Map.insert
-
-> bindTypeSigs :: Decl -> SigEnv -> SigEnv
-> bindTypeSigs (TypeSig _ vs ty) env =
->   foldr (flip bindTypeSig (nameSigType ty)) env vs 
-> bindTypeSigs _ env = env
-
-> lookupTypeSig :: Ident -> SigEnv -> Maybe TypeExpr
-> lookupTypeSig = Map.lookup
-
-> qualLookupTypeSig :: ModuleIdent -> QualIdent -> SigEnv -> Maybe TypeExpr
-> qualLookupTypeSig m f sigs = localIdent m f >>= flip lookupTypeSig sigs
-
-> nameSigType :: TypeExpr -> TypeExpr
-> nameSigType ty = fst (nameType ty (filter (`notElem` fv ty) nameSupply))
-
-> nameTypes :: [TypeExpr] -> [Ident] -> ([TypeExpr],[Ident])
-> nameTypes (ty:tys) tvs = (ty':tys',tvs'')
->   where (ty',tvs') = nameType ty tvs
->         (tys',tvs'') = nameTypes tys tvs'
-> nameTypes [] tvs = ([],tvs)
-
-> nameType :: TypeExpr -> [Ident] -> (TypeExpr,[Ident])
-> nameType (ConstructorType tc tys) tvs = (ConstructorType tc tys',tvs')
->   where (tys',tvs') = nameTypes tys tvs
-> nameType (VariableType tv) (tv':tvs)
->   | tv == anonId = (VariableType tv',tvs)
->   | otherwise = (VariableType tv,tv':tvs)
-> nameType (TupleType tys) tvs = (TupleType tys',tvs')
->   where (tys',tvs') = nameTypes tys tvs
-> nameType (ListType ty) tvs = (ListType ty',tvs')
->   where (ty',tvs') = nameType ty tvs
-> nameType (ArrowType ty1 ty2) tvs = (ArrowType ty1' ty2',tvs'')
->   where (ty1',tvs') = nameType ty1 tvs
->         (ty2',tvs'') = nameType ty2 tvs'
-> nameType (RecordType fs rty) tvs = 
->   (RecordType (zip ls tys') (listToMaybe rty'), tvs)
->   where (ls, tys) = unzip fs
->         (tys', _) = nameTypes tys tvs
->         (rty', _) = nameTypes (maybeToList rty) tvs
-        
-\end{verbatim}
-\paragraph{Type Inference}
-Before type checking a group of declarations, a dependency analysis is
-performed and the declaration group is eventually transformed into
-nested declaration groups which are checked separately. Within each
-declaration group, first the left hand sides of all declarations are
-typed. Next, the right hand sides of the declarations are typed in the
-extended type environment. Finally, the types for the left and right
-hand sides are unified and the types of all defined functions are
-generalized. The generalization step will also check that the type
-signatures given by the user match the inferred types.
-
-Argument and result types of foreign functions using the
-\texttt{ccall} calling convention are restricted to the basic types
-\texttt{Bool}, \texttt{Char}, \texttt{Int}, and \texttt{Float}. In
-addition, \texttt{IO}~$t$ is a legitimate result type when $t$ is
-either one of the basic types or \texttt{()}.
-
-\ToDo{Extend the set of legitimate types to match the types admitted
-  by the Haskell Foreign Function Interface
-  Addendum.~\cite{Chakravarty03:FFI}}
-\begin{verbatim}
-
-> tcDecls :: ModuleIdent -> TCEnv -> SigEnv -> [Decl] -> TcState ()
-> tcDecls m tcEnv sigs ds =
->   mapM_ (tcDeclGroup m tcEnv (foldr bindTypeSigs sigs ods))
->         (scc bv (qfv m) vds)
->   where (vds,ods) = partition isValueDecl ds
-
-> tcDeclGroup :: ModuleIdent -> TCEnv -> SigEnv -> [Decl] -> TcState ()
-> --tcDeclGroup m tcEnv _ [ForeignDecl p cc _ f ty] =
-> --  tcForeignFunct m tcEnv p cc f ty
-> tcDeclGroup m tcEnv _ [ExternalDecl _ _ _ f ty] =
->   tcExternalFunct m tcEnv f ty
-> tcDeclGroup m tcEnv sigs [FlatExternalDecl _ fs] =
->   mapM_ (tcFlatExternalFunct m tcEnv sigs) fs
-> tcDeclGroup m tcEnv sigs [ExtraVariables _ vs] =
->   mapM_ (tcExtraVar m tcEnv sigs ) vs
-> tcDeclGroup m tcEnv sigs ds =
->   do
->     tyEnv0 <- S.get
->     tysLhs <- mapM (tcDeclLhs m tcEnv sigs) ds
->     tysRhs <- mapM (tcDeclRhs m tcEnv tyEnv0 sigs) ds
->     sequence_ (zipWith3 (unifyDecl m) ds tysLhs tysRhs)
->     theta <- S.lift S.get
->     mapM_ (genDecl m tcEnv sigs (fvEnv (subst theta tyEnv0)) theta) ds
-
-> --tcForeignFunct :: ModuleIdent -> TCEnv -> Position -> CallConv -> Ident
-> --               -> TypeExpr -> TcState ()
-> --tcForeignFunct m tcEnv p cc f ty =
-> --  S.modify (bindFun m f (checkForeignType cc (expandPolyType tcEnv ty)))
-> --  where checkForeignType CallConvPrimitive ty = ty
-> --        checkForeignType CallConvCCall (ForAll n ty) =
-> --          ForAll n (checkCCallType ty)
-> --        checkCCallType (TypeArrow ty1 ty2)
-> --          | isCArgType ty1 = TypeArrow ty1 (checkCCallType ty2)
-> --          | otherwise = errorAt p (invalidCType "argument" m ty1)
-> --        checkCCallType ty
-> --          | isCResultType ty = ty
-> --          | otherwise = errorAt p (invalidCType "result" m ty)
-> --        isCArgType (TypeConstructor tc []) = tc `elem` basicTypeId
-> --        isCArgType _ = False
-> --        isCResultType (TypeConstructor tc []) = tc `elem` basicTypeId
-> --        isCResultType (TypeConstructor tc [ty]) =
-> --          tc == qIOId && (ty == unitType || isCArgType ty)
-> --        isCResultType _ = False
-> --        basicTypeId = [qBoolId,qCharId,qIntId,qFloatId]
-
-> tcExternalFunct :: ModuleIdent -> TCEnv -> Ident -> TypeExpr -> TcState ()
-> tcExternalFunct m tcEnv  f ty =
->   S.modify (bindFun m f (expandPolyType m tcEnv ty))
-
-> tcFlatExternalFunct :: ModuleIdent -> TCEnv -> SigEnv -> Ident -> TcState ()
-> tcFlatExternalFunct m tcEnv sigs f =
->   typeOf f tcEnv sigs >>= S.modify . bindFun m f
->   where typeOf f tcEnv sigs =
->           case lookupTypeSig f sigs of
->             Just ty -> return (expandPolyType m tcEnv ty)
->             Nothing -> internalError "tcFlatExternalFunct"
-
-> tcExtraVar :: ModuleIdent -> TCEnv -> SigEnv -> Ident
->            -> TcState ()
-> tcExtraVar m tcEnv sigs v =
->   typeOf v tcEnv sigs >>= S.modify . bindFun m v . monoType
->   where typeOf v tcEnv sigs =
->           case lookupTypeSig v sigs of
->             Just ty
->               | n == 0 -> return ty'
->               | otherwise -> errorAt' (polymorphicFreeVar v)
->               where ForAll n ty' = expandPolyType m tcEnv ty
->             Nothing -> freshTypeVar
-
-> tcDeclLhs :: ModuleIdent -> TCEnv -> SigEnv -> Decl -> TcState Type
-> tcDeclLhs m tcEnv sigs (FunctionDecl p f _) =
->   tcConstrTerm m tcEnv sigs p (VariablePattern f)
-> tcDeclLhs m tcEnv sigs (PatternDecl p t _) = tcConstrTerm m tcEnv sigs p t
-
-> tcDeclRhs :: ModuleIdent -> TCEnv -> ValueEnv -> SigEnv -> Decl
->           -> TcState Type
-> tcDeclRhs m tcEnv tyEnv0 sigs (FunctionDecl _ f (eq:eqs)) =
->   tcEquation m tcEnv tyEnv0 sigs eq >>= flip tcEqns eqs
->   where tcEqns ty [] = return ty
->         tcEqns ty (eq@(Equation p _ _):eqs) =
->           tcEquation m tcEnv tyEnv0 sigs eq >>=
->           unify p "equation" (ppDecl (FunctionDecl p f [eq])) m ty >>
->           tcEqns ty eqs
-> tcDeclRhs m tcEnv tyEnv0 sigs (PatternDecl _ _ rhs) =
->   tcRhs m tcEnv tyEnv0 sigs rhs
-
-> unifyDecl :: ModuleIdent -> Decl -> Type -> Type -> TcState ()
-> unifyDecl m (FunctionDecl p f _) =
->   unify p "function binding" (text "Function:" <+> ppIdent f) m
-> unifyDecl m (PatternDecl p t _) =
->   unify p "pattern binding" (ppConstrTerm 0 t) m
-
-\end{verbatim}
-In Curry we cannot generalize the types of let-bound variables because
-they can refer to logic variables. Without this monomorphism
-restriction unsound code like
-\begin{verbatim}
-bug = x =:= 1 & x =:= 'a'
-  where x :: a
-        x = fresh
-fresh :: a
-fresh = x where x free
-\end{verbatim}
-could be written. Note that \texttt{fresh} has the polymorphic type
-$\forall\alpha.\alpha$. This is correct because \texttt{fresh} is a
-function and therefore returns a different variable at each
-invocation.
-
-The code in \texttt{genVar} below also verifies that the inferred type
-for a variable or function matches the type declared in a type
-signature. As the declared type is already used for assigning an initial
-type to a variable when it is used, the inferred type can only be more
-specific. Therefore, if the inferred type does not match the type
-signature the declared type must be too general.
-\begin{verbatim}
-
-> genDecl :: ModuleIdent -> TCEnv -> SigEnv -> Set.Set Int -> TypeSubst -> Decl
->         -> TcState ()
-> genDecl m tcEnv sigs lvs theta (FunctionDecl _ f _) =
->   S.modify (genVar True m tcEnv sigs lvs theta f)
-> genDecl m tcEnv sigs lvs theta (PatternDecl p t _) =
->   mapM_ (S.modify . genVar False m tcEnv sigs lvs theta ) (bv t)
-
-> genVar :: Bool -> ModuleIdent -> TCEnv -> SigEnv -> Set.Set Int -> TypeSubst
->        -> Ident -> ValueEnv -> ValueEnv
-> genVar poly m tcEnv sigs lvs theta v tyEnv =
->   case lookupTypeSig v sigs of
->     Just sigTy
->       | cmpTypes sigma (expandPolyType m tcEnv sigTy) -> tyEnv'
->       | otherwise -> errorAt (positionOfIdent v) 
->                              (typeSigTooGeneral m what sigTy sigma)
->     Nothing -> tyEnv'
->   where what = text (if poly then "Function:" else "Variable:") <+> ppIdent v
->         tyEnv' = rebindFun m v sigma tyEnv
->         sigma = genType poly (subst theta (varType v tyEnv))
->         genType poly (ForAll n ty)
->           | n > 0 = internalError ("genVar: " ++ showLine (positionOfIdent v) ++ 
->                                    show v ++ " :: " ++ show ty)
->           | poly = gen lvs ty
->           | otherwise = monoType ty
->         cmpTypes (ForAll _ t1) (ForAll _ t2) = equTypes t1 t2
-
-> tcEquation :: ModuleIdent -> TCEnv -> ValueEnv -> SigEnv -> Equation
->            -> TcState Type
-> tcEquation m tcEnv tyEnv0 sigs (Equation p lhs rhs) =
->   do
->     tys <- mapM (tcConstrTerm m tcEnv sigs p) ts
->     ty <- tcRhs m tcEnv tyEnv0 sigs rhs
->     checkSkolems p m (text "Function: " <+> ppIdent f) tyEnv0
->                  (foldr TypeArrow ty tys)
->   where (f,ts) = flatLhs lhs
-
-> tcLiteral :: ModuleIdent -> Literal -> TcState Type
-> tcLiteral _ (Char _ _) = return charType
-> tcLiteral m (Int v _)  = --return intType
->   do
->     ty <- freshConstrained [intType,floatType]
->     S.modify (bindFun m v (monoType ty))
->     return ty
-> tcLiteral _ (Float _ _) = return floatType
-> tcLiteral _ (String _ _) = return stringType
-
-> tcConstrTerm :: ModuleIdent -> TCEnv -> SigEnv -> Position -> ConstrTerm
->              -> TcState Type
-> tcConstrTerm m tcEnv sigs _ (LiteralPattern l) = tcLiteral m l
-> tcConstrTerm m tcEnv sigs _ (NegativePattern _ l) = tcLiteral m l
-> tcConstrTerm m tcEnv sigs _ (VariablePattern v) =
->   do 
->     ty <- case lookupTypeSig v sigs of
->             Just t -> inst (expandPolyType m tcEnv t)
->             Nothing -> freshTypeVar
->     S.modify (bindFun m v (monoType ty))
->     return ty
->   
-> tcConstrTerm m tcEnv sigs p t@(ConstructorPattern c ts) =
->   do
->     tyEnv <- S.get
->     ty <- skol (constrType m c tyEnv)
->     unifyArgs (ppConstrTerm 0 t) ts ty
->   where unifyArgs _ [] ty = return ty
->         unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =
->           tcConstrTerm m tcEnv sigs p t >>=
->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)
->                 m ty1 >>
->           unifyArgs doc ts ty2
->         unifyArgs _ _ _ = internalError "tcConstrTerm"
-> tcConstrTerm m tcEnv sigs p t@(InfixPattern t1 op t2) =
->   do
->     tyEnv <- S.get
->     ty <- skol (constrType m op tyEnv)
->     unifyArgs (ppConstrTerm 0 t) [t1,t2] ty
->   where unifyArgs _ [] ty = return ty
->         unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =
->           tcConstrTerm m tcEnv sigs p t >>=
->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)
->                 m ty1 >>
->           unifyArgs doc ts ty2
->         unifyArgs _ _ _ = internalError "tcConstrTerm"
-> tcConstrTerm m tcEnv sigs p (ParenPattern t) = tcConstrTerm m tcEnv sigs p t
-> tcConstrTerm m tcEnv sigs p (TuplePattern _ ts)
->  | null ts = return unitType
->  | otherwise = liftM tupleType $ mapM (tcConstrTerm m tcEnv sigs p) ts
-> tcConstrTerm m tcEnv sigs p t@(ListPattern _ ts) =
->   freshTypeVar >>= flip (tcElems (ppConstrTerm 0 t)) ts
->   where tcElems _ ty [] = return (listType ty)
->         tcElems doc ty (t:ts) =
->           tcConstrTerm m tcEnv sigs p t >>=
->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)
->                 m ty >>
->           tcElems doc ty ts
-> tcConstrTerm m tcEnv sigs p t@(AsPattern v t') =
->   do
->     ty1 <- tcConstrTerm m tcEnv sigs p (VariablePattern v)
->     ty2 <- tcConstrTerm m tcEnv sigs p t'
->     unify p "pattern" (ppConstrTerm 0 t) m ty1 ty2
->     return ty1
-> tcConstrTerm m tcEnv sigs p (LazyPattern _ t) = tcConstrTerm m tcEnv sigs p t
-> tcConstrTerm m tcEnv sigs p t@(FunctionPattern f ts) =
->   do
->     tyEnv <- S.get
->     ty <- inst (funType m f tyEnv) --skol (constrType m c tyEnv)
->     unifyArgs (ppConstrTerm 0 t) ts ty
->   where unifyArgs _ [] ty = return ty
->         unifyArgs doc (t:ts) ty@(TypeVariable _) =
->           do (alpha,beta) <- tcArrow p "function pattern" doc m ty
->	       ty' <- tcConstrTermFP m tcEnv sigs p t
->	       unify p "function pattern"
->	             (doc $-$ text "Term:" <+> ppConstrTerm 0 t)
->	             m ty' alpha
->	       unifyArgs doc ts beta
->         unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =
->           tcConstrTermFP m tcEnv sigs p t >>=
->           unify p "function pattern" 
->	          (doc $-$ text "Term:" <+> ppConstrTerm 0 t)
->                 m ty1 >>
->           unifyArgs doc ts ty2
->         unifyArgs _ _ ty = internalError ("tcConstrTerm: " ++ show ty)
-> tcConstrTerm m tcEnv sigs p t@(InfixFuncPattern t1 op t2) =
->   tcConstrTerm m tcEnv sigs p (FunctionPattern op [t1,t2])
-> tcConstrTerm m tcEnv sigs p r@(RecordPattern fs rt)
->   | isJust rt =
->     do
->       ty <- tcConstrTerm m tcEnv sigs p (fromJust rt)
->       fts <- mapM (tcFieldPatt (tcConstrTerm m tcEnv sigs) m) fs
->       alpha <- freshVar id
->	let rty = TypeRecord fts (Just alpha)
->	unify p "record pattern" (ppConstrTerm 0 r) m ty rty
->       return rty
->   | otherwise =
->     do
->       fts <- mapM (tcFieldPatt (tcConstrTerm m tcEnv sigs) m) fs
->       return (TypeRecord fts Nothing)
-
-\end{verbatim}
-In contrast to usual patterns, the type checking routine for arguments of 
-function patterns \texttt{tcConstrTermFP} differs from \texttt{tcConstrTerm}
-because of possibly multiple occurrences of variables.
-\begin{verbatim}
-
-> tcConstrTermFP :: ModuleIdent -> TCEnv -> SigEnv -> Position -> ConstrTerm
->                   -> TcState Type
-> tcConstrTermFP m tcEnv sigs p (LiteralPattern l) = tcLiteral m l
-> tcConstrTermFP m tcEnv sigs p (NegativePattern _ l) = tcLiteral m l
-> tcConstrTermFP m tcEnv sigs p (VariablePattern v) =
->   do
->     ty <- maybe freshTypeVar 
->                 (inst . expandPolyType m tcEnv) 
->                 (lookupTypeSig v sigs)
->     tyEnv <- S.get
->     ty' <- maybe (S.modify (bindFun m v (monoType ty)) >> return ty)
->                  (\ (ForAll _ t) -> return t)
->	           (sureVarType v tyEnv)
->     return ty' 
-> tcConstrTermFP m tcEnv sigs p t@(ConstructorPattern c ts) =
->   do
->     tyEnv <- S.get
->     ty <- skol (constrType m c tyEnv)
->     unifyArgs (ppConstrTerm 0 t) ts ty
->   where unifyArgs _ [] ty = return ty
->         unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =
->           tcConstrTermFP m tcEnv sigs p t >>=
->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)
->                 m ty1 >>
->           unifyArgs doc ts ty2
->         unifyArgs _ _ _ = internalError "tcConstrTermFP"
-> tcConstrTermFP m tcEnv sigs p t@(InfixPattern t1 op t2) =
->   do
->     tyEnv <- S.get
->     ty <- skol (constrType m op tyEnv)
->     unifyArgs (ppConstrTerm 0 t) [t1,t2] ty
->   where unifyArgs _ [] ty = return ty
->         unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =
->           tcConstrTermFP m tcEnv sigs p t >>=
->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)
->                 m ty1 >>
->           unifyArgs doc ts ty2
->         unifyArgs _ _ _ = internalError "tcConstrTermFP"
-> tcConstrTermFP m tcEnv sigs p (ParenPattern t) = tcConstrTermFP m tcEnv sigs p t
-> tcConstrTermFP m tcEnv sigs p (TuplePattern _ ts)
->  | null ts = return unitType
->  | otherwise = liftM tupleType $ mapM (tcConstrTermFP m tcEnv sigs p) ts
-> tcConstrTermFP m tcEnv sigs p t@(ListPattern _ ts) =
->   freshTypeVar >>= flip (tcElems (ppConstrTerm 0 t)) ts
->   where tcElems _ ty [] = return (listType ty)
->         tcElems doc ty (t:ts) =
->           tcConstrTermFP m tcEnv sigs p t >>=
->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)
->                 m ty >>
->           tcElems doc ty ts
-> tcConstrTermFP m tcEnv sigs p t@(AsPattern v t') =
->   do
->     ty1 <- tcConstrTermFP m tcEnv sigs p (VariablePattern v)
->     ty2 <- tcConstrTermFP m tcEnv sigs p t'
->     unify p "pattern" (ppConstrTerm 0 t) m ty1 ty2
->     return ty1
-> tcConstrTermFP m tcEnv sigs p (LazyPattern _ t) = tcConstrTermFP m tcEnv sigs p t
-> tcConstrTermFP m tcEnv sigs p t@(FunctionPattern f ts) =
->   do
->     tyEnv <- S.get
->     ty <- inst (funType m f tyEnv) --skol (constrType m c tyEnv)
->     unifyArgs (ppConstrTerm 0 t) ts ty
->   where unifyArgs _ [] ty = return ty
->         unifyArgs doc (t:ts) ty@(TypeVariable _) =
->           do (alpha,beta) <- tcArrow p "function pattern" doc m ty
->	       ty' <- tcConstrTermFP m tcEnv sigs p t
->	       unify p "function pattern"
->	             (doc $-$ text "Term:" <+> ppConstrTerm 0 t)
->	             m ty' alpha
->	       unifyArgs doc ts beta
->         unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =
->           tcConstrTermFP m tcEnv sigs p t >>=
->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)
->                 m ty1 >>
->           unifyArgs doc ts ty2
->         unifyArgs _ _ _ = internalError "tcConstrTermFP"
-> tcConstrTermFP m tcEnv sigs p t@(InfixFuncPattern t1 op t2) =
->   tcConstrTermFP m tcEnv sigs p (FunctionPattern op [t1,t2])
-> tcConstrTermFP m tcEnv sigs p r@(RecordPattern fs rt)
->   | isJust rt =
->     do
->       ty <- tcConstrTermFP m tcEnv sigs p (fromJust rt)
->       fts <- mapM (tcFieldPatt (tcConstrTermFP m tcEnv sigs) m) fs
->       alpha <- freshVar id
->	let rty = TypeRecord fts (Just alpha)
->	unify p "record pattern" (ppConstrTerm 0 r) m ty rty
->       return rty
->   | otherwise =
->     do
->       fts <- mapM (tcFieldPatt (tcConstrTermFP m tcEnv sigs) m) fs
->       return (TypeRecord fts Nothing)
-
-> tcFieldPatt :: (Position -> ConstrTerm -> TcState Type) -> ModuleIdent
->             -> Field ConstrTerm -> TcState (Ident,Type)
-> tcFieldPatt tcPatt m f@(Field _ l t) =
->   do
->     tyEnv <- S.get
->     let p = positionOfIdent l
->     lty <- maybe (freshTypeVar
->	             >>= (\lty' ->
->		           S.modify
->		             (bindLabel l (qualifyWith m (mkIdent "#Rec"))
->		                        (polyType lty'))
->		           >> return lty'))
->	           (\ (ForAll _ lty') -> return lty')
->	           (sureLabelType l tyEnv)
->     ty <- tcPatt p t
->     unify p "record" (text "Field:" <+> ppFieldPatt f) m lty ty
->     return (l,ty)
-
-> tcRhs :: ModuleIdent -> TCEnv -> ValueEnv -> SigEnv -> Rhs -> TcState Type
-> tcRhs m tcEnv tyEnv0 sigs (SimpleRhs p e ds) =
->   do
->     tcDecls m tcEnv sigs ds
->     ty <- tcExpr m tcEnv sigs p e
->     checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 ty
-> tcRhs m tcEnv tyEnv0 sigs (GuardedRhs es ds) =
->   do
->     tcDecls m tcEnv sigs ds
->     tcCondExprs m tcEnv tyEnv0 sigs es
-
-> tcCondExprs :: ModuleIdent -> TCEnv -> ValueEnv -> SigEnv -> [CondExpr]
->             -> TcState Type
-> tcCondExprs m tcEnv tyEnv0 sigs es =
->   do
->     gty <- if length es > 1 then return boolType
->                             else freshConstrained [successType,boolType]
->     ty <- freshTypeVar
->     tcCondExprs' gty ty es
->   where tcCondExprs' gty ty [] = return ty
->         tcCondExprs' gty ty (e:es) =
->           tcCondExpr gty ty e >> tcCondExprs' gty ty es
->         tcCondExpr gty ty (CondExpr p g e) =
->           tcExpr m tcEnv sigs p g >>=
->           unify p "guard" (ppExpr 0 g) m gty >>
->           tcExpr m tcEnv sigs p e >>=
->           checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 >>=
->           unify p "guarded expression" (ppExpr 0 e) m ty
-
-> tcExpr :: ModuleIdent -> TCEnv -> SigEnv -> Position -> Expression
->        -> TcState Type
-> tcExpr m _ _ _ (Literal l) = tcLiteral m l
-> tcExpr m tcEnv sigs p (Variable v) =
->   case qualLookupTypeSig m v sigs of
->     Just ty -> inst (expandPolyType m tcEnv ty)
->     Nothing -> S.get >>= inst . funType m v
-> tcExpr m tcEnv sigs p (Constructor c) = S.get >>= instExist . constrType m c
-> tcExpr m tcEnv sigs p (Typed e sig) =
->   do
->     tyEnv0 <- S.get
->     ty <- tcExpr m tcEnv sigs p e
->     inst sigma' >>=
->       flip (unify p "explicitly typed expression" (ppExpr 0 e) m) ty
->     theta <- S.lift S.get
->     let sigma = gen (fvEnv (subst theta tyEnv0)) (subst theta ty)
->     unless (sigma == sigma')
->       (errorAt p (typeSigTooGeneral m (text "Expression:" <+> ppExpr 0 e)
->                  sig' sigma))
->     return ty
->   where sig' = nameSigType sig
->         sigma' = expandPolyType m tcEnv sig'
-> tcExpr m tcEnv sigs p (Paren e) = tcExpr m tcEnv sigs p e
-> tcExpr m tcEnv sigs p (Tuple _ es)
->   | null es = return unitType
->   | otherwise = liftM tupleType $ mapM (tcExpr m tcEnv sigs p) es
-> tcExpr m tcEnv sigs p e@(List _ es) = freshTypeVar >>= tcElems (ppExpr 0 e) es
->   where tcElems _ [] ty = return (listType ty)
->         tcElems doc (e:es) ty =
->           tcExpr m tcEnv sigs p e >>=
->           unify p "expression" (doc $-$ text "Term:" <+> ppExpr 0 e)
->                 m ty >>
->           tcElems doc es ty
-> tcExpr m tcEnv sigs p (ListCompr _ e qs) =
->   do
->     tyEnv0 <- S.get
->     mapM_ (tcQual m tcEnv sigs p) qs
->     ty <- tcExpr m tcEnv sigs p e
->     checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 (listType ty)
-> tcExpr m tcEnv sigs p e@(EnumFrom e1) =
->   do
->     ty1 <- tcExpr m tcEnv sigs p e1
->     unify p "arithmetic sequence"
->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1) m intType ty1
->     return (listType intType)
-> tcExpr m tcEnv sigs p e@(EnumFromThen e1 e2) =
->   do
->     ty1 <- tcExpr m tcEnv sigs p e1
->     ty2 <- tcExpr m tcEnv sigs p e2
->     unify p "arithmetic sequence"
->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1) m intType ty1
->     unify p "arithmetic sequence"
->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2) m intType ty2
->     return (listType intType)
-> tcExpr m tcEnv sigs p e@(EnumFromTo e1 e2) =
->   do
->     ty1 <- tcExpr m tcEnv sigs p e1
->     ty2 <- tcExpr m tcEnv sigs p e2
->     unify p "arithmetic sequence"
->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1) m intType ty1
->     unify p "arithmetic sequence"
->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2) m intType ty2
->     return (listType intType)
-> tcExpr m tcEnv sigs p e@(EnumFromThenTo e1 e2 e3) =
->   do
->     ty1 <- tcExpr m tcEnv sigs p e1
->     ty2 <- tcExpr m tcEnv sigs p e2
->     ty3 <- tcExpr m tcEnv sigs p e3
->     unify p "arithmetic sequence"
->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1) m intType ty1
->     unify p "arithmetic sequence"
->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2) m intType ty2
->     unify p "arithmetic sequence"
->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e3) m intType ty3
->     return (listType intType)
-> tcExpr m tcEnv sigs p e@(UnaryMinus op e1) =
->   do
->     opTy <- opType op
->     ty1 <- tcExpr m tcEnv sigs p e1
->     unify p "unary negation" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)
->           m opTy ty1
->     return ty1
->   where opType op
->           | op == minusId = freshConstrained [intType,floatType]
->           | op == fminusId = return floatType
->           | otherwise = internalError ("tcExpr unary " ++ name op)
-> tcExpr m tcEnv sigs p e@(Apply e1 e2) =
->   do
->     ty1 <- tcExpr m tcEnv sigs p e1
->     ty2 <- tcExpr m tcEnv sigs p e2
->     (alpha,beta) <-
->       tcArrow p "application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)
->               m ty1
->     unify p "application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2)
->           m alpha ty2
->     return beta
-> tcExpr m tcEnv sigs p e@(InfixApply e1 op e2) =
->   do
->     opTy <- tcExpr m tcEnv sigs p (infixOp op)
->     ty1 <- tcExpr m tcEnv sigs p e1
->     ty2 <- tcExpr m tcEnv sigs p e2
->     (alpha,beta,gamma) <-
->       tcBinary p "infix application"
->                (ppExpr 0 e $-$ text "Operator:" <+> ppOp op) m opTy
->     unify p "infix application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)
->           m alpha ty1
->     unify p "infix application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2)
->           m beta ty2
->     return gamma
-> tcExpr m tcEnv sigs p e@(LeftSection e1 op) =
->   do
->     opTy <- tcExpr m tcEnv sigs p (infixOp op)
->     ty1 <- tcExpr m tcEnv sigs p e1
->     (alpha,beta) <-
->       tcArrow p "left section" (ppExpr 0 e $-$ text "Operator:" <+> ppOp op)
->               m opTy
->     unify p "left section" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)
->           m alpha ty1
->     return beta
-> tcExpr m tcEnv sigs p e@(RightSection op e1) =
->   do
->     opTy <- tcExpr m tcEnv sigs p (infixOp op)
->     ty1 <- tcExpr m tcEnv sigs p e1
->     (alpha,beta,gamma) <-
->       tcBinary p "right section"
->                (ppExpr 0 e $-$ text "Operator:" <+> ppOp op) m opTy
->     unify p "right section" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)
->           m beta ty1
->     return (TypeArrow alpha gamma)
-> tcExpr m tcEnv sigs p exp@(Lambda r ts e) =
->   do
->     tyEnv0 <- S.get
->     tys <- mapM (tcConstrTerm m tcEnv sigs p) ts
->     ty <- tcExpr m tcEnv sigs p e
->     checkSkolems p m (text "Expression:" <+> ppExpr 0 exp) tyEnv0
->                  (foldr TypeArrow ty tys)
-> tcExpr m tcEnv sigs p (Let ds e) =
->   do
->     tyEnv0 <- S.get
->     theta <- S.lift S.get
->     tcDecls m tcEnv sigs ds
->     ty <- tcExpr m tcEnv sigs p e
->     checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 ty
-> tcExpr m tcEnv sigs p (Do sts e) =
->   do
->     tyEnv0 <- S.get
->     mapM_ (tcStmt m tcEnv sigs p) sts
->     alpha <- freshTypeVar
->     ty <- tcExpr m tcEnv sigs p e
->     unify p "statement" (ppExpr 0 e) m (ioType alpha) ty
->     checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 ty
-> tcExpr m tcEnv sigs p e@(IfThenElse _ e1 e2 e3) =
->   do
->     ty1 <- tcExpr m tcEnv sigs p e1
->     unify p "expression" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)
->           m boolType ty1
->     ty2 <- tcExpr m tcEnv sigs p e2
->     ty3 <- tcExpr m tcEnv sigs p e3
->     unify p "expression" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e3)
->           m ty2 ty3
->     return ty3
-> tcExpr m tcEnv sigs p (Case _ e alts) =
->   do
->     tyEnv0 <- S.get
->     ty <- tcExpr m tcEnv sigs p e
->     alpha <- freshTypeVar
->     tcAlts tyEnv0 ty alpha alts
->   where tcAlts tyEnv0 _ ty [] = return ty
->         tcAlts tyEnv0 ty1 ty2 (alt:alts) =
->           tcAlt (ppAlt alt) tyEnv0 ty1 ty2 alt >> tcAlts tyEnv0 ty1 ty2 alts
->         tcAlt doc tyEnv0 ty1 ty2 (Alt p t rhs) =
->           tcConstrTerm m tcEnv sigs p t >>=
->           unify p "case pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)
->                 m ty1 >>
->           tcRhs m tcEnv tyEnv0 sigs rhs >>=
->           unify p "case branch" doc m ty2
-> tcExpr m tcEnv sigs p (RecordConstr fs) =
->   do 
->     fts <- mapM (tcFieldExpr m tcEnv sigs equals) fs
->     --when (1 == length fs)
->     --     (error (show fs ++ "\n" ++ show fts))
->     return (TypeRecord fts Nothing)
-> tcExpr m tcEnv sigs p r@(RecordSelection e l) =
->   do
->     ty <- tcExpr m tcEnv sigs p e
->     tyEnv <- S.get
->     lty <- maybe (freshTypeVar 
->	             >>= (\lty' -> 
->		           S.modify 
->		             (bindLabel l (qualifyWith m (mkIdent "#Rec"))
->		                        (monoType lty'))
->	                   >> return lty'))
->                  (\ (ForAll _ lty') -> return lty')
->	           (sureLabelType l tyEnv)
->     alpha <- freshVar id
->     let rty = TypeRecord [(l,lty)] (Just alpha)
->     unify p "record selection" (ppExpr 0 r) m ty rty
->     return lty
-> tcExpr m tcEnv sigs p r@(RecordUpdate fs e) =
->   do
->     ty <- tcExpr m tcEnv sigs p e
->     fts <- mapM (tcFieldExpr m tcEnv sigs (text ":=")) fs
->     alpha <- freshVar id
->     let rty = TypeRecord fts (Just alpha)
->     unify p "record update" (ppExpr 0 r) m ty rty
->     return ty
-
-> tcQual :: ModuleIdent -> TCEnv -> SigEnv -> Position -> Statement
->        -> TcState ()
-> tcQual m tcEnv sigs p (StmtExpr _ e) =
->   do
->     ty <- tcExpr m tcEnv sigs p e
->     unify p "guard" (ppExpr 0 e) m boolType ty
-> tcQual m tcEnv sigs p q@(StmtBind _ t e) =
->   do
->     ty1 <- tcConstrTerm m tcEnv sigs p t
->     ty2 <- tcExpr m tcEnv sigs p e
->     unify p "generator" (ppStmt q $-$ text "Term:" <+> ppExpr 0 e)
->           m (listType ty1) ty2
-> tcQual m tcEnv sigs p (StmtDecl ds) = tcDecls m tcEnv sigs ds
-
-> tcStmt :: ModuleIdent -> TCEnv -> SigEnv -> Position -> Statement
->        -> TcState ()
-> tcStmt m tcEnv sigs p (StmtExpr _ e) =
->   do
->     alpha <- freshTypeVar
->     ty <- tcExpr m tcEnv sigs p e
->     unify p "statement" (ppExpr 0 e) m (ioType alpha) ty
-> tcStmt m tcEnv sigs p st@(StmtBind _ t e) =
->   do
->     ty1 <- tcConstrTerm m tcEnv sigs p t
->     ty2 <- tcExpr m tcEnv sigs p e
->     unify p "statement" (ppStmt st $-$ text "Term:" <+> ppExpr 0 e)
->           m (ioType ty1) ty2
-> tcStmt m tcEnv sigs p (StmtDecl ds) = tcDecls m tcEnv sigs ds
-
-> tcFieldExpr :: ModuleIdent -> TCEnv -> SigEnv -> Doc -> Field Expression
->	      -> TcState (Ident,Type)
-> tcFieldExpr m tcEnv sigs comb f@(Field _ l e) =
->   do
->     tyEnv <- S.get
->     let p = positionOfIdent l
->     lty <- maybe (freshTypeVar 
->	             >>= (\lty' -> 
->		           S.modify 
->		             (bindLabel l (qualifyWith m (mkIdent "#Rec"))
->		                          (monoType lty'))
->	                   >> return lty'))
->                  inst
->	           (sureLabelType l tyEnv)
->     ty <- tcExpr m tcEnv sigs p e
->     unify p "record" (text "Field:" <+> ppFieldExpr comb f) m lty ty
->     return (l,ty)
-
-\end{verbatim}
-The function \texttt{tcArrow} checks that its argument can be used as
-an arrow type $\alpha\rightarrow\beta$ and returns the pair
-$(\alpha,\beta)$. Similarly, the function \texttt{tcBinary} checks
-that its argument can be used as an arrow type
-$\alpha\rightarrow\beta\rightarrow\gamma$ and returns the triple
-$(\alpha,\beta,\gamma)$.
-\begin{verbatim}
-
-> tcArrow :: Position -> String -> Doc -> ModuleIdent -> Type
->         -> TcState (Type,Type)
-> tcArrow p what doc m ty =
->   do
->     theta <- S.lift S.get
->     unaryArrow (subst theta ty)
->   where unaryArrow (TypeArrow ty1 ty2) = return (ty1,ty2)
->         unaryArrow (TypeVariable tv) =
->           do
->             alpha <- freshTypeVar
->             beta <- freshTypeVar
->             S.lift (S.modify (bindVar tv (TypeArrow alpha beta)))
->             return (alpha,beta)
->         unaryArrow ty = errorAt p (nonFunctionType what doc m ty)
-
-> tcBinary :: Position -> String -> Doc -> ModuleIdent -> Type
->          -> TcState (Type,Type,Type)
-> tcBinary p what doc m ty = tcArrow p what doc m ty >>= uncurry binaryArrow
->   where binaryArrow ty1 (TypeArrow ty2 ty3) = return (ty1,ty2,ty3)
->         binaryArrow ty1 (TypeVariable tv) =
->           do
->             beta <- freshTypeVar
->             gamma <- freshTypeVar
->             S.lift (S.modify (bindVar tv (TypeArrow beta gamma)))
->             return (ty1,beta,gamma)
->         binaryArrow ty1 ty2 =
->           errorAt p (nonBinaryOp what doc m (TypeArrow ty1 ty2))
-
-\end{verbatim}
-\paragraph{Unification}
-The unification uses Robinson's algorithm (cf., e.g., Chap.~9
-of~\cite{PeytonJones87:Book}).
-\begin{verbatim}
-
-> unify :: Position -> String -> Doc -> ModuleIdent -> Type -> Type
->       -> TcState ()
-> unify p what doc m ty1 ty2 =
->   S.lift $
->   do
->     theta <- S.get
->     let ty1' = subst theta ty1
->     let ty2' = subst theta ty2
->     either (errorAt p . typeMismatch what doc m ty1' ty2')
->            (S.modify . compose)
->            (unifyTypes m ty1' ty2')
-
-> unifyTypes :: ModuleIdent -> Type -> Type -> Either Doc TypeSubst
-> unifyTypes _ (TypeVariable tv1) (TypeVariable tv2)
->   | tv1 == tv2 = Right idSubst
->   | otherwise = Right (bindSubst tv1 (TypeVariable tv2) idSubst)
-> unifyTypes m (TypeVariable tv) ty
->   | tv `elem` typeVars ty = Left (recursiveType m tv ty)
->   | otherwise = Right (bindSubst tv ty idSubst)
-> unifyTypes m ty (TypeVariable tv)
->   | tv `elem` typeVars ty = Left (recursiveType m tv ty)
->   | otherwise = Right (bindSubst tv ty idSubst)
-> unifyTypes _ (TypeConstrained tys1 tv1) (TypeConstrained tys2 tv2)
->   | tv1 == tv2 = Right idSubst
->   | tys1 == tys2 = Right (bindSubst tv1 (TypeConstrained tys2 tv2) idSubst)
-> unifyTypes m (TypeConstrained tys tv) ty =
->   foldr (choose . unifyTypes m ty) (Left (incompatibleTypes m ty (head tys)))
->         tys
->   where choose (Left _) theta' = theta'
->         choose (Right theta) _ = Right (bindSubst tv ty theta)
-> unifyTypes m ty (TypeConstrained tys tv) =
->   foldr (choose . unifyTypes m ty) (Left (incompatibleTypes m ty (head tys)))
->         tys
->   where choose (Left _) theta' = theta'
->         choose (Right theta) _ = Right (bindSubst tv ty theta)
-> unifyTypes m (TypeConstructor tc1 tys1) (TypeConstructor tc2 tys2)
->   | tc1 == tc2 = unifyTypeLists m tys1 tys2
-> unifyTypes m (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) =
->   unifyTypeLists m [ty11,ty12] [ty21,ty22]
-> unifyTypes _ (TypeSkolem k1) (TypeSkolem k2)
->   | k1 == k2 = Right idSubst
-> unifyTypes m (TypeRecord fs1 Nothing) tr2@(TypeRecord fs2 Nothing)
->   | length fs1 == length fs2 = unifyTypedLabels m fs1 tr2
-> unifyTypes m tr1@(TypeRecord fs1 Nothing) tr2@(TypeRecord fs2 (Just a2)) =
->   either Left
->          (\res -> either Left 
->	                   (Right . compose res) 
->                          (unifyTypes m (TypeVariable a2) tr1))
->          (unifyTypedLabels m fs2 tr1)
-> unifyTypes m tr1@(TypeRecord _ (Just _)) tr2@(TypeRecord _ Nothing) =
->   unifyTypes m tr2 tr1
-> unifyTypes m (TypeRecord fs1 (Just a1)) tr2@(TypeRecord fs2 (Just a2)) =
->   let (fs1', rs1, rs2) = splitFields fs1 fs2
->   in  either 
->         Left
->         (\res -> 
->           either 
->             Left 
->	      (\res' -> Right (compose res res'))
->	      (unifyTypeLists m [TypeVariable a1,
->			         TypeRecord (fs1 ++ rs2) Nothing]
->	                        [TypeVariable a2,
->			         TypeRecord (fs2 ++ rs1) Nothing]))
->         (unifyTypedLabels m fs1' tr2)
->   where
->   splitFields fs1 fs2 = split' [] [] fs2 fs1
->   split' fs1' rs1 rs2 [] = (fs1',rs1,rs2)
->   split' fs1' rs1 rs2 ((l,ty):fs1) =
->     maybe (split' fs1' ((l,ty):rs1) rs2 fs1)
->           (const (split' ((l,ty):fs1') rs1 (remove l rs2) fs1))
->           (lookup l rs2)
-> unifyTypes m ty1 ty2 = Left (incompatibleTypes m ty1 ty2)
-
-> unifyTypeLists :: ModuleIdent -> [Type] -> [Type] -> Either Doc TypeSubst
-> unifyTypeLists _ [] _ = Right idSubst
-> unifyTypeLists _ _ [] = Right idSubst
-> unifyTypeLists m (ty1:tys1) (ty2:tys2) =
->   either Left (unifyTypesTheta m ty1 ty2) (unifyTypeLists m tys1 tys2)
->   where unifyTypesTheta m ty1 ty2 theta =
->           either Left (Right . flip compose theta)
->                  (unifyTypes m (subst theta ty1) (subst theta ty2))
-
-> unifyTypedLabels :: ModuleIdent -> [(Ident,Type)] -> Type 
->	           -> Either Doc TypeSubst
-> unifyTypedLabels m [] (TypeRecord _ _) = Right idSubst
-> unifyTypedLabels m ((l,ty):fs1) tr@(TypeRecord fs2 _) =
->   either Left
->          (\r -> 
->            maybe (Left (missingLabel m l tr))
->                  (\ty' -> 
->		     either (const (Left (incompatibleLabelTypes m l ty ty')))
->	                    (Right . flip compose r)
->	                    (unifyTypes m ty ty'))
->                  (lookup l fs2))
->          (unifyTypedLabels m fs1 tr)
-> unifyTypedLabels _ _ _ = internalError "unifyTypedLabels"
-
-\end{verbatim}
-For each declaration group, the type checker has to ensure that no
-skolem type escapes its scope.
-\begin{verbatim}
-
-> checkSkolems :: Position -> ModuleIdent -> Doc -> ValueEnv -> Type
->              -> TcState Type
-> checkSkolems p m what tyEnv ty =
->   do
->     theta <- S.lift S.get
->     let ty' = subst theta ty
->         fs = fsEnv (subst theta tyEnv)
->     unless (all (`Set.member` fs) (typeSkolems ty'))
->            (errorAt p (skolemEscapingScope m what ty'))
->     --error (show ty ++ " ## " ++ show (subst theta ty))
->     return ty'
-
-\end{verbatim}
-\paragraph{Instantiation and Generalization}
-We use negative offsets for fresh type variables.
-\begin{verbatim}
-
-> fresh :: (Int -> a) -> TcState a
-> fresh f = liftM f (S.lift (S.lift (S.modify succ >> S.get)))
-
-> freshVar :: (Int -> a) -> TcState a
-> freshVar f = fresh (\n -> f (- n - 1))
-
-> freshTypeVar :: TcState Type
-> freshTypeVar = freshVar TypeVariable
-
-> freshConstrained :: [Type] -> TcState Type
-> freshConstrained tys = freshVar (TypeConstrained tys)
-
-> freshSkolem :: TcState Type
-> freshSkolem = fresh TypeSkolem
-
-> inst :: TypeScheme -> TcState Type
-> inst (ForAll n ty) =
->   do
->     tys <- replicateM n freshTypeVar
->     return (expandAliasType tys ty)
-
-> instExist :: ExistTypeScheme -> TcState Type
-> instExist (ForAllExist n n' ty) =
->   do
->     tys <- replicateM (n + n') freshTypeVar
->     return (expandAliasType tys ty)
-
-> skol :: ExistTypeScheme -> TcState Type
-> skol (ForAllExist n n' ty) =
->   do
->     tys <- replicateM n freshTypeVar
->     tys' <- replicateM n' freshSkolem
->     return (expandAliasType (tys ++ tys') ty)
-
-> gen :: Set.Set Int -> Type -> TypeScheme
-> gen gvs ty =
->   ForAll (length tvs) (subst (foldr2 bindSubst idSubst tvs tvs') ty)
->   where tvs = [tv | tv <- nub (typeVars ty), tv `Set.notMember` gvs]
->         tvs' = map TypeVariable [0..]
-
-\end{verbatim}
-\paragraph{Auxiliary Functions}
-The functions \texttt{constrType}, \texttt{varType}, and
-\texttt{funType} are used to retrieve the type of constructors,
-pattern variables, and variables in expressions, respectively, from
-the type environment. Because the syntactical correctness has already
-been verified by the syntax checker, none of these functions should
-fail.
-
-Note that \texttt{varType} can handle ambiguous identifiers and
-returns the first available type. This function is used for looking up
-the type of an identifier on the left hand side of a rule where it
-unambiguously refers to the local definition.
-\begin{verbatim}
-
-> constrType :: ModuleIdent -> QualIdent -> ValueEnv -> ExistTypeScheme
-> constrType m c tyEnv =
->   case qualLookupValue c tyEnv of
->     [DataConstructor _ sigma] -> sigma
->     [NewtypeConstructor _ sigma] -> sigma
->     _ -> case (qualLookupValue (qualQualify m c) tyEnv) of
->            [DataConstructor _ sigma] -> sigma
->            [NewtypeConstructor _ sigma] -> sigma
->            _ -> internalError ("constrType " ++ show c)
-
-> varType :: Ident -> ValueEnv -> TypeScheme
-> varType v tyEnv =
->   case lookupValue v tyEnv of
->     Value _ sigma : _ -> sigma
->     _ -> internalError ("varType " ++ show v)
-
-> sureVarType :: Ident -> ValueEnv -> Maybe TypeScheme
-> sureVarType v tyEnv =
->   case lookupValue v tyEnv of
->     Value _ sigma : _ -> Just sigma
->     _ -> Nothing
-
-> funType :: ModuleIdent -> QualIdent -> ValueEnv -> TypeScheme
-> funType m f tyEnv =
->   case (qualLookupValue f tyEnv) of
->     [Value _ sigma] -> sigma
->     vs -> case (qualLookupValue (qualQualify m f) tyEnv) of
->             [Value _ sigma] -> sigma
->             _ -> internalError ("funType " ++ show f)
-
-> sureLabelType :: Ident -> ValueEnv -> Maybe TypeScheme
-> sureLabelType l tyEnv =
->   case lookupValue l tyEnv of
->     Label _ _ sigma : _ -> Just sigma
->     _ -> Nothing
-
-
-\end{verbatim}
-The function \texttt{expandType} expands all type synonyms in a type
-and also qualifies all type constructors with the name of the module
-in which the type was defined.
-\begin{verbatim}
-
-> expandMonoType :: ModuleIdent -> TCEnv -> [Ident] -> TypeExpr -> Type
-> expandMonoType m tcEnv tvs ty = expandType m tcEnv (toType tvs ty)
-
-> expandMonoTypes :: ModuleIdent -> TCEnv -> [Ident] -> [TypeExpr] -> [Type]
-> expandMonoTypes m tcEnv tvs tys = map (expandType m tcEnv) (toTypes tvs tys)
-
-> expandPolyType :: ModuleIdent -> TCEnv -> TypeExpr -> TypeScheme
-> expandPolyType m tcEnv ty = 
->     polyType $ normalize $ expandMonoType m tcEnv [] ty
-
-> expandType :: ModuleIdent -> TCEnv -> Type -> Type
-> expandType m tcEnv (TypeConstructor tc tys) =
->   case qualLookupTC tc tcEnv of
->     [DataType tc' _ _] -> TypeConstructor tc' tys'
->     [RenamingType tc' _ _] -> TypeConstructor tc' tys'
->     [AliasType _ _ ty] -> expandAliasType tys' ty
->     _ -> case (qualLookupTC (qualQualify m tc) tcEnv) of
->            [DataType tc' _ _] -> TypeConstructor tc' tys'
->            [RenamingType tc' _ _] -> TypeConstructor tc' tys'
->            [AliasType _ _ ty] -> expandAliasType tys' ty
->            _ -> internalError ("expandType " ++ show tc)
->   where tys' = map (expandType m tcEnv) tys
-> expandType _ _ (TypeVariable tv) = TypeVariable tv
-> expandType _ _ (TypeConstrained tys tv) = TypeConstrained tys tv
-> expandType m tcEnv (TypeArrow ty1 ty2) =
->   TypeArrow (expandType m tcEnv ty1) (expandType m tcEnv ty2)
-> expandType _ tcEnv (TypeSkolem k) = TypeSkolem k
-> expandType m tcEnv (TypeRecord fs rv) =
->   TypeRecord (map (\ (l,ty) -> (l, expandType m tcEnv ty)) fs) rv
-
-\end{verbatim}
-The functions \texttt{fvEnv} and \texttt{fsEnv} compute the set of
-free type variables and free skolems of a type environment,
-respectively. We ignore the types of data constructors here because we
-know that they are closed.
-\begin{verbatim}
-
-> fvEnv :: ValueEnv -> Set.Set Int
-> fvEnv tyEnv =
->   Set.fromList [tv | ty <- localTypes tyEnv, tv <- typeVars ty, tv < 0]
-
-> fsEnv :: ValueEnv -> Set.Set Int
-> fsEnv tyEnv = Set.unions (map (Set.fromList . typeSkolems) (localTypes tyEnv))
-
-> localTypes :: ValueEnv -> [Type]
-> localTypes tyEnv = [ty | (_,Value _ (ForAll _ ty)) <- localBindings tyEnv]
-
-\end{verbatim}
-Miscellaneous functions.
-\begin{verbatim}
-
-> remove :: Eq a => a -> [(a,b)] -> [(a,b)]
-> remove _ [] = []
-> remove k ((k',e):kes) | k == k'   = kes
->		        | otherwise = (k',e):(remove k kes) 
-
-\end{verbatim}
-Error functions.
-\begin{verbatim}
-
-> recursiveTypes :: [Ident] -> (Position,String)
-> recursiveTypes [tc] = 
->     (positionOfIdent tc,
->      "Recursive synonym type " ++ name tc)
-> recursiveTypes (tc:tcs) =
->  (positionOfIdent tc,
->   "Recursive synonym types " ++ name tc ++ types "" tcs)
->   where types comma [tc] = comma ++ " and " ++ name tc ++
->                            showLine (positionOfIdent tc) 
->         types _ (tc:tcs) = ", " ++ name tc ++ 
->                            showLine (positionOfIdent tc) ++ 
->                            types "," tcs
-
-> polymorphicFreeVar :: Ident -> (Position,String)
-> polymorphicFreeVar v =
->  (positionOfIdent v,
->   "Free variable " ++ name v ++ " has a polymorphic type")
-
-> typeSigTooGeneral :: ModuleIdent -> Doc -> TypeExpr -> TypeScheme -> String
-> typeSigTooGeneral m what ty sigma = show $
->   vcat [text "Type signature too general", what,
->         text "Inferred type:" <+> ppTypeScheme m sigma,
->         text "Type signature:" <+> ppTypeExpr 0 ty]
-
-> nonFunctionType :: String -> Doc -> ModuleIdent -> Type -> String
-> nonFunctionType what doc m ty = show $
->   vcat [text "Type error in" <+> text what, doc,
->         text "Type:" <+> ppType m ty,
->         text "Cannot be applied"]
-
-> nonBinaryOp :: String -> Doc -> ModuleIdent -> Type -> String
-> nonBinaryOp what doc m ty = show $
->   vcat [text "Type error in" <+> text what, doc,
->         text "Type:" <+> ppType m ty,
->         text "Cannot be used as binary operator"]
-
-> typeMismatch :: String -> Doc -> ModuleIdent -> Type -> Type -> Doc -> String
-> typeMismatch what doc m ty1 ty2 reason = show $
->   vcat [text "Type error in" <+> text what, doc,
->         text "Inferred type:" <+> ppType m ty2,
->         text "Expected type:" <+> ppType m ty1,
->         reason]
-
-> skolemEscapingScope :: ModuleIdent -> Doc -> Type -> String
-> skolemEscapingScope m what ty = show $
->   vcat [text "Existential type escapes out of its scope", what,
->         text "Type:" <+> ppType m ty]
-
-> recursiveType :: ModuleIdent -> Int -> Type -> Doc
-> recursiveType m tv ty = incompatibleTypes m (TypeVariable tv) ty
-
-> missingLabel :: ModuleIdent -> Ident -> Type -> Doc
-> missingLabel m l rty =
->   sep [text "Missing field for label" <+> ppIdent l,
->        text "in the record type" <+> ppType m rty]
-
-> incompatibleTypes :: ModuleIdent -> Type -> Type -> Doc
-> incompatibleTypes m ty1 ty2 =
->   sep [text "Types" <+> ppType m ty1,
->        nest 2 (text "and" <+> ppType m ty2),
->        text "are incompatible"]
-
-> incompatibleLabelTypes :: ModuleIdent -> Ident -> Type -> Type -> Doc
-> incompatibleLabelTypes m l ty1 ty2 =
->   sep [text "Labeled types" <+> ppIdent l <> text "::" <> ppType m ty1,
->        nest 10 (text "and" <+> ppIdent l <> text "::" <> ppType m ty2),
->        text "are incompatible"]
-
-\end{verbatim}
-
-
-\end{verbatim}
-The following functions implement pretty-printing for types.
-\begin{verbatim}
-
-> ppType :: ModuleIdent -> Type -> Doc
-> ppType m = ppTypeExpr 0 . fromQualType m
-
-> ppTypeScheme :: ModuleIdent -> TypeScheme -> Doc
-> ppTypeScheme m (ForAll _ ty) = ppType m ty
diff --git a/src/TypeSubst.lhs b/src/TypeSubst.lhs
deleted file mode 100644
--- a/src/TypeSubst.lhs
+++ /dev/null
@@ -1,104 +0,0 @@
-
-% $Id: TypeSubst.lhs,v 1.2 2004/02/08 22:14:01 wlux Exp $
-%
-% Copyright (c) 2003, Wolfgang Lux
-% See LICENSE for the full license.
-%
-\nwfilename{TypeSubst.lhs}
-\section{Type Substitutions}
-This module implements substitutions on types.
-\begin{verbatim}
-
-> module TypeSubst(module TypeSubst, idSubst,bindSubst,compose) where
-
-
-> import Data.Maybe
-> import Data.List
-
-> import Types
-
-> import Subst
-> import Base
-> import TopEnv
-
-> type TypeSubst = Subst Int Type
-
-> class SubstType a where
->   subst :: TypeSubst -> a -> a
-
-> bindVar :: Int -> Type -> TypeSubst -> TypeSubst
-> bindVar tv ty = compose (bindSubst tv ty idSubst)
-
-> substVar :: TypeSubst -> Int -> Type
-> substVar = substVar' TypeVariable subst
-
-> instance SubstType Type where
->   subst sigma (TypeConstructor tc tys) =
->     TypeConstructor tc (map (subst sigma) tys)
->   subst sigma (TypeVariable tv) = substVar sigma tv
->   subst sigma (TypeConstrained tys tv) =
->     case substVar sigma tv of
->       TypeVariable tv -> TypeConstrained tys tv
->       ty -> ty
->   subst sigma (TypeArrow ty1 ty2) =
->     TypeArrow (subst sigma ty1) (subst sigma ty2)
->   subst sigma (TypeSkolem k) = TypeSkolem k
->   subst sigma (TypeRecord fs rv)
->     | isJust rv =
->       case substVar sigma (fromJust rv) of
->         TypeVariable tv -> TypeRecord fs' (Just tv)
->         ty -> ty
->     | otherwise = TypeRecord fs' Nothing
->    where fs' = map (\ (l,ty) -> (l, subst sigma ty)) fs
-
-> instance SubstType TypeScheme where
->   subst sigma (ForAll n ty) =
->     ForAll n (subst (foldr unbindSubst sigma [0..n-1]) ty)
-
-> instance SubstType ExistTypeScheme where
->   subst sigma (ForAllExist n n' ty) =
->     ForAllExist n n' (subst (foldr unbindSubst sigma [0..n+n'-1]) ty)
-
-> instance SubstType ValueInfo where
->   subst theta (DataConstructor c ty) = DataConstructor c ty
->   subst theta (NewtypeConstructor c ty) = NewtypeConstructor c ty
->   subst theta (Value v ty) = Value v (subst theta ty)
->   subst theta (Label l r ty) = Label l r (subst theta ty)
-
-> instance SubstType a => SubstType (TopEnv a) where
->   subst = fmap . subst
-
-\end{verbatim}
-The function \texttt{expandAliasType} expands all occurrences of a
-type synonym in a type. After the expansion we have to reassign the
-type indices for all type variables. Otherwise, expanding a type
-synonym like \verb|type Pair' a b = (b,a)| could break the invariant
-that the universally quantified type variables are assigned indices in
-the order of their occurrence. This is handled by the function
-\texttt{normalize}.
-\begin{verbatim}
-
-> expandAliasType :: [Type] -> Type -> Type
-> expandAliasType tys (TypeConstructor tc tys') =
->   TypeConstructor tc (map (expandAliasType tys) tys')
-> expandAliasType tys (TypeVariable n)
->   | n >= 0 = tys !! n
->   | otherwise = TypeVariable n
-> expandAliasType _ (TypeConstrained tys n) = TypeConstrained tys n
-> expandAliasType tys (TypeArrow ty1 ty2) =
->   TypeArrow (expandAliasType tys ty1) (expandAliasType tys ty2)
-> expandAliasType _ (TypeSkolem k) = TypeSkolem k
-> expandAliasType tys (TypeRecord fs rv)
->   | isJust rv =
->     let (TypeVariable tv) = expandAliasType tys (TypeVariable (fromJust rv))
->     in  TypeRecord fs' (Just tv)
->   | otherwise =
->     TypeRecord fs' Nothing
->  where fs' = map (\ (l,ty) -> (l, expandAliasType tys ty)) fs
-
-> normalize :: Type -> Type
-> normalize ty = expandAliasType [TypeVariable (occur tv) | tv <- [0..]] ty
->   where tvs = zip (nub (filter (>= 0) (typeVars ty))) [0..]
->         occur tv = fromJust (lookup tv tvs)
-
-\end{verbatim}
diff --git a/src/Types.lhs b/src/Types.lhs
deleted file mode 100644
--- a/src/Types.lhs
+++ /dev/null
@@ -1,251 +0,0 @@
-% $Id: Types.lhs,v 1.11 2004/02/08 22:14:02 wlux Exp $
-%
-% Copyright (c) 2002, Wolfgang Lux
-% See LICENSE for the full license.
-%
-% Modified by Martin Engelke (men@informatik.uni-kiel.de)
-%
-\nwfilename{Types.lhs}
-\section{Types}
-This module modules provides the definitions for the internal 
-representation of types in the compiler.
-\begin{verbatim}
-
-> module Types where
-
-> import Data.List
-> import Data.Maybe
-
-> import Curry.Base.Ident
-
-\end{verbatim}
-A type is either a type variable, an application of a type constructor
-to a list of arguments, or an arrow type. The \texttt{TypeConstrained}
-case is used for representing type variables that are restricted to a
-particular set of types. At present, this is used for typing guard
-expressions, which are restricted to be either of type \texttt{Bool}
-or of type \texttt{Success}, and integer literals, which are
-restricted to types \texttt{Int} and \texttt{Float}. If the type is
-not restricted it defaults to the first type from the constraint list.
-The case \texttt{TypeSkolem} is used for handling skolem types, which
-result from the use of existentially quantified data constructors.
-
-Type variables are represented with deBruijn style indices. Universally
-quantified type variables are assigned indices in the order of their
-occurrence in the type from left to right. This leads to a canonical
-representation of types where $\alpha$-equivalence of two types
-coincides with equality of the representation.
-
-Note that even though \texttt{TypeConstrained} variables use indices
-as well, these variables must never be quantified.
-\begin{verbatim}
-
-> data Type =
->     TypeConstructor QualIdent [Type]
->   | TypeVariable Int
->   | TypeConstrained [Type] Int
->   | TypeArrow Type Type
->   | TypeSkolem Int
->   | TypeRecord [(Ident,Type)] (Maybe Int)
->   deriving (Show, Eq)
-
-\end{verbatim}
-The function \texttt{isArrowType} checks whether a type is a function
-type $t_1 \rightarrow t_2 \rightarrow \dots \rightarrow t_n$ . The
-function \texttt{arrowArity} computes the arity $n$ of a function type
-and \texttt{arrowBase} returns the type $t_n$.
-\begin{verbatim}
-
-> isArrowType :: Type -> Bool
-> isArrowType (TypeArrow _ _) = True
-> isArrowType _ = False
-
-> arrowArity :: Type -> Int
-> arrowArity (TypeArrow _ ty) = 1 + arrowArity ty
-> arrowArity _ = 0
-
-> arrowArgs :: Type -> [Type]
-> arrowArgs (TypeArrow ty1 ty2) = ty1 : arrowArgs ty2
-> arrowArgs ty = []
-
-> arrowBase :: Type -> Type
-> arrowBase (TypeArrow _ ty) = arrowBase ty
-> arrowBase ty = ty
-
-\end{verbatim}
-The functions \texttt{typeVars}, \texttt{typeConstrs},
-\texttt{typeSkolems} return a list of all type variables, type
-constructors, or skolems occurring in a type $t$, respectively. Note
-that \texttt{TypeConstrained} variables are not included in the set of
-type variables because they cannot be generalized.
-\begin{verbatim}
-
-> typeVars :: Type -> [Int]
-> typeVars ty = vars ty []
->   where vars (TypeConstructor _ tys) tvs = foldr vars tvs tys
->         vars (TypeVariable tv) tvs = tv : tvs
->         vars (TypeConstrained _ _) tvs = tvs
->         vars (TypeArrow ty1 ty2) tvs = vars ty1 (vars ty2 tvs)
->         vars (TypeSkolem _) tvs = tvs
->         vars (TypeRecord fs rtv) tvs =
->             foldr vars (maybe tvs (: tvs) rtv) (map snd fs)
-
-> typeConstrs :: Type -> [QualIdent]
-> typeConstrs ty = types ty []
->   where types (TypeConstructor tc tys) tcs = tc : foldr types tcs tys
->         types (TypeVariable _) tcs = tcs
->         types (TypeConstrained _ _) tcs = tcs
->         types (TypeArrow ty1 ty2) tcs = types ty1 (types ty2 tcs)
->         types (TypeSkolem _) tcs = tcs
->         types (TypeRecord fs _) tcs =
->             foldr types tcs (map snd fs)
-
-> typeSkolems :: Type -> [Int]
-> typeSkolems ty = skolems ty []
->   where skolems (TypeConstructor _ tys) sks = foldr skolems sks tys
->         skolems (TypeVariable _) sks = sks
->         skolems (TypeConstrained _ _) sks = sks
->         skolems (TypeArrow ty1 ty2) sks = skolems ty1 (skolems ty2 sks)
->         skolems (TypeSkolem k) sks = k : sks
->         skolems (TypeRecord fs _) sks =
->             foldr skolems sks (map snd fs)
-
-> equTypes :: Type -> Type -> Bool
-> equTypes t1 t2 = fst (equ [] t1 t2)
->  where 
->  equ is (TypeConstructor qid1 ts1) (TypeConstructor qid2 ts2)
->     | qid1 == qid2 = equs is ts1 ts2
->     | otherwise    = (False, is)
->  equ is (TypeVariable i1) (TypeVariable i2)
->     = maybe (True, (i1,i2):is) 
->             (\ i2' -> (i2 == i2', is))
->             (lookup i1 is)
->  equ is (TypeConstrained ts1 i1) (TypeConstrained ts2 i2)
->     = let (res, is') = equs is ts1 ts2
->       in  maybe (res, (i1,i2):is')
->                 (\ i2' -> (res && i2 == i2', is'))
->                 (lookup i1 is')
->  equ is (TypeArrow tf1 tt1) (TypeArrow tf2 tt2)
->     = let (res1, is1) = equ is tf1 tf2
->           (res2, is2) = equ is1 tt1 tt2
->       in  (res1 && res2, is2)
->  equ is (TypeSkolem i1) (TypeSkolem i2)
->     = maybe (True, (i1,i2):is)
->             (\ i2' -> (i2 == i2', is))
->             (lookup i1 is)
->  equ is (TypeRecord fs1 r1) (TypeRecord fs2 r2)
->     | isJust r1 && isJust r2
->       = let (res1, is1) = equ is (TypeVariable (fromJust r1))
->		                   (TypeVariable (fromJust r2))
->             (res2, is2) = equRecords is1 fs1 fs2
->         in  (res1 && res2, is2)
->     | isNothing r1 && isNothing r2 = equRecords is fs1 fs2
->     | otherwise = (False, is)
->  equ is _ _ = (False, is)
->	
->  equRecords is fs1 fs2 | length fs1 == length fs2 = equrec is fs1 fs2
->		         | otherwise = (False, is)
->    where
->    equrec is [] fs2 = (True, is)
->    equrec is ((l,t):fs1) fs2
->       = let (res1, is1) = maybe (False,is) (equ is t) (lookup l fs2)
->             (res2, is2) = equrec is1 fs1 fs2
->         in  (res1 && res2, is2)
->
->  equs is [] [] = (True, is)
->  equs is (t1:ts1) (t2:ts2)
->     = let (res1, is1) = equ is t1 t2
->           (res2, is2) = equs is1 ts1 ts2
->       in  (res1 && res2, is2)
-
-\end{verbatim}
-We support two kinds of quantifications of types here, universally
-quantified type schemes $\forall\overline{\alpha} .
-\tau(\overline{\alpha})$ and universally and existentially quantified
-type schemes $\forall\overline{\alpha} \exists\overline{\eta} .
-\tau(\overline{\alpha},\overline{\eta})$.  In both, quantified type
-variables are assigned ascending indices starting from 0. Therefore it
-is sufficient to record the numbers of quantified type variables in
-the \texttt{ForAll} and \texttt{ForAllExist} constructors. In case of
-the latter, the first of the two numbers is the number of universally
-quantified variables and the second the number of existentially
-quantified variables.
-\begin{verbatim}
-
-> data TypeScheme = ForAll Int Type deriving (Show, Eq)
-> data ExistTypeScheme = ForAllExist Int Int Type deriving (Show, Eq)
-
-\end{verbatim}
-The functions \texttt{monoType} and \texttt{polyType} translate a type
-$\tau$ into a monomorphic type scheme $\forall.\tau$ and a polymorphic
-type scheme $\forall\overline{\alpha}.\tau$ where $\overline{\alpha} =
-\textrm{fv}(\tau)$, respectively. \texttt{polyType} assumes that all
-universally quantified variables in the type are assigned indices
-starting with 0 and does not renumber the variables.
-\begin{verbatim}
-
-> monoType, polyType :: Type -> TypeScheme
-> monoType ty = ForAll 0 ty
-> polyType ty = ForAll (maximum (-1 : typeVars ty) + 1) ty
-
-\end{verbatim}
-There are a few predefined types:
-\begin{verbatim}
-
-> unitType,boolType,charType,intType,floatType,stringType,successType :: Type
-> unitType = primType unitId []
-> boolType = primType boolId []
-> charType = primType charId []
-> intType = primType intId []
-> floatType = primType floatId []
-> stringType = listType charType
-> successType = primType successId []
-
-> listType,ioType :: Type -> Type
-> listType ty = primType listId [ty]
-> ioType ty = primType ioId [ty]
-
-> tupleType :: [Type] -> Type
-> tupleType tys = primType (tupleId (length tys)) tys
-
-> primType :: Ident -> [Type] -> Type
-> primType = TypeConstructor . qualifyWith preludeMIdent
-
-> typeVar :: Int -> Type
-> typeVar = TypeVariable
-
-\end{verbatim}
-
-
-
-> qualifyType :: ModuleIdent -> Type -> Type
-> qualifyType m (TypeConstructor tc tys)
->   | isTupleId tc' = tupleType tys'
->   | tc' == unitId && n == 0 = unitType
->   | tc' == listId && n == 1 = listType (head tys')
->   | otherwise = TypeConstructor (qualQualify m tc) tys'
->   where n = length tys'
->         tc' = unqualify tc
->         tys' = map (qualifyType m) tys
-> qualifyType _ (TypeVariable tv) = TypeVariable tv
-> qualifyType m (TypeConstrained tys tv) =
->   TypeConstrained (map (qualifyType m) tys) tv
-> qualifyType m (TypeArrow ty1 ty2) =
->   TypeArrow (qualifyType m ty1) (qualifyType m ty2)
-> qualifyType _ (TypeSkolem k) = TypeSkolem k
-> qualifyType m (TypeRecord fs rty) =
->   TypeRecord (map (\ (l,ty) -> (l, qualifyType m ty)) fs) rty
-
-
-> unqualifyType :: ModuleIdent -> Type -> Type
-> unqualifyType m (TypeConstructor tc tys) =
->   TypeConstructor (qualUnqualify m tc) (map (unqualifyType m) tys)
-> unqualifyType _ (TypeVariable tv) = TypeVariable tv
-> unqualifyType m (TypeConstrained tys tv) =
->   TypeConstrained (map (unqualifyType m) tys) tv
-> unqualifyType m (TypeArrow ty1 ty2) =
->   TypeArrow (unqualifyType m ty1) (unqualifyType m ty2)
-> unqualifyType m (TypeSkolem k) = TypeSkolem k
-> unqualifyType m (TypeRecord fs rty) =
->   TypeRecord (map (\ (l,ty) -> (l, unqualifyType m ty)) fs) rty
-
diff --git a/src/Typing.lhs b/src/Typing.lhs
deleted file mode 100644
--- a/src/Typing.lhs
+++ /dev/null
@@ -1,406 +0,0 @@
-
-% $Id: Typing.lhs,v 1.7 2004/02/12 19:13:12 wlux Exp $
-%
-% Copyright (c) 2003-2006, Wolfgang Lux
-% See LICENSE for the full license.
-%
-\nwfilename{Typing.lhs}
-\section{Computing the Type of Curry Expressions}
-\begin{verbatim}
-
-> module Typing(Typeable(..)) where
-
-> import Data.Maybe
-> import Control.Monad
-> import Control.Monad.State as S
-
-> import Curry.Base.Ident
-> import Curry.Syntax
-> import Curry.Syntax.Utils
-
-> import Types
-> import Base
-> import TypeSubst
-> import TopEnv
-> import Utils
-
-
-\end{verbatim}
-During the transformation of Curry source code into the intermediate
-language, the compiler has to recompute the types of expressions. This
-is simpler than type checking because the types of all variables are
-known. Yet, the compiler still must handle functions and constructors
-with polymorphic types and instantiate their type schemes using fresh
-type variables. Since all types computed by \texttt{typeOf} are
-monomorphic, we can use type variables with non-negative offsets for
-the instantiation of type schemes here without risk of name conflicts.
-Using non-negative offsets also makes it easy to distinguish these
-fresh variables from free type variables introduce during type
-inference, which must be regarded as constants here.
-
-However, using non-negative offsets for fresh type variables gives
-rise to two problems when those types are entered back into the type
-environment, e.g., while introducing auxiliary variables during
-desugaring. The first is that those type variables now appear to be
-universally quantified variables, but with indices greater than the
-number of quantified type variables.\footnote{To be precise, this can
-  happen only for auxiliary variables, which have monomorphic types,
-  whereas auxiliary functions will be assigned polymorphic types and
-  these type variables will be properly quantified. However, in this
-  case the assigned types may be too general.} This results in an
-internal error (``Prelude.!!: index too large'') whenever such a type
-is instantiated. The second problem is that there may be inadvertent
-name captures because \texttt{computeType} always uses indices
-starting at 0 for the fresh type variables. In order to avoid these
-problems, \texttt{computeType} renames all type variables with
-non-negative offsets after the final type has been computed, using
-negative indices below the one with the smallest value occurring in
-the type environment. Computing the minimum index of all type
-variables in the type environment seems prohibitively inefficient.
-However, recall that, thanks to laziness, the minimum is computed only
-when the final type contains any type variables with non-negative
-indices. This happens, for instance, 36 times while compiling the
-prelude (for 159 evaluated applications of \texttt{typeOf}) and only
-twice while compiling the standard \texttt{IO} module (for 21
-applications of \texttt{typeOf}).\footnote{These numbers were obtained
-  for version 0.9.9.}
-
-A careful reader will note that inadvertent name captures are still
-possible if one computes the types of two or more auxiliary variables
-before actually entering their types into the environment. Therefore,
-make sure that you enter the types of these auxiliary variables
-immediately into the type environment, unless you are sure that those
-types cannot contain fresh type variables. One such case are the free
-variables of a goal.
-
-\ToDo{In the long run, this module should be made obsolete by adding
-attributes to the abstract syntax tree -- e.g., along the lines of
-Chap.~6 in~\cite{PeytonJonesLester92:Book} -- and returning an
-abstract syntax tree attributed with type information together with
-the type environment from type inference. This also would allow
-getting rid of the identifiers in the representation of integer
-literals, which are used in order to implement overloading of
-integer constants.}
-
-\ToDo{When computing the type of an expression with a type signature
-make use of the annotation instead of recomputing its type. In order
-to do this, we must either ensure that the types are properly
-qualified and expanded or we need access to the type constructor
-environment.}
-\begin{verbatim}
-
-> type TyState a = S.StateT TypeSubst (S.State Int) a
-
-> run :: TyState a -> ValueEnv -> a
-> run m tyEnv = S.evalState (S.evalStateT m idSubst) 0
-
-> class Typeable a where
->   typeOf :: ValueEnv -> a -> Type
-
-> instance Typeable Ident where
->   typeOf = computeType identType
-
-> instance Typeable ConstrTerm where
->   typeOf = computeType argType
-
-> instance Typeable Expression where
->   typeOf = computeType exprType
-
-> instance Typeable Rhs where
->   typeOf = computeType rhsType
-
-> computeType f tyEnv x = normalize (run doComputeType tyEnv)
->   where doComputeType =
->           do
->             ty <- f tyEnv x
->             theta <- S.get
->             return (fixTypeVars tyEnv (subst theta ty))
-
-> fixTypeVars :: ValueEnv -> Type -> Type
-> fixTypeVars tyEnv ty = subst (foldr2 bindSubst idSubst tvs tvs') ty
->   where tvs = filter (>= 0) (typeVars ty)
->         tvs' = map TypeVariable [n - 1,n - 2 ..]
->         n = minimum (0 : concatMap typeVars tys)
->         tys = [ty | (_,Value _ (ForAll _ ty)) <- localBindings tyEnv]
-
-> identType :: ValueEnv -> Ident -> TyState Type
-> identType tyEnv x = instUniv (varType x tyEnv)
-
-> litType :: ValueEnv -> Literal -> TyState Type
-> litType _ (Char _ _)    = return charType
-> litType tyEnv (Int v _) = identType tyEnv v
-> litType _ (Float _ _)   = return floatType
-> litType _ (String _ _)  = return stringType
-
-> argType :: ValueEnv -> ConstrTerm -> TyState Type
-> argType tyEnv (LiteralPattern l) = litType tyEnv l
-> argType tyEnv (NegativePattern _ l) = litType tyEnv l
-> argType tyEnv (VariablePattern v) = identType tyEnv v
-> argType tyEnv (ConstructorPattern c ts) =
->   do
->     ty <- instUnivExist (constrType c tyEnv)
->     tys <- mapM (argType tyEnv) ts
->     unifyList (init (flatten ty)) tys
->     return (last (flatten ty))
->   where flatten (TypeArrow ty1 ty2) = ty1 : flatten ty2
->         flatten ty = [ty]
-> argType tyEnv (InfixPattern t1 op t2) =
->   argType tyEnv (ConstructorPattern op [t1,t2])
-> argType tyEnv (ParenPattern t) = argType tyEnv t
-> argType tyEnv (TuplePattern _ ts)
->   | null ts = return unitType
->   | otherwise = liftM tupleType $ mapM (argType tyEnv) ts
-> argType tyEnv (ListPattern _ ts) = freshTypeVar >>= flip elemType ts
->   where elemType ty [] = return (listType ty)
->         elemType ty (t:ts) =
->           argType tyEnv t >>= unify ty >> elemType ty ts
-> argType tyEnv (AsPattern v _) = argType tyEnv (VariablePattern v)
-> argType tyEnv (LazyPattern _ t) = argType tyEnv t
-> argType tyEnv (FunctionPattern f ts) =
->   do 
->     ty <- instUniv (funType f tyEnv)
->     tys <- mapM (argType tyEnv) ts
->     unifyList (init (flatten ty)) tys
->     return (last (flatten ty))
->   where flatten (TypeArrow ty1 ty2) = ty1 : flatten ty2
->         flatten ty = [ty]
-> argType tyEnv (InfixFuncPattern t1 op t2) =
->   argType tyEnv (FunctionPattern op [t1,t2])
-> argType tyEnv (RecordPattern fs r)
->   | isJust r =
->     do
->       tys <- mapM (fieldPattType tyEnv) fs
->       rty <- argType tyEnv (fromJust r)
->       (TypeVariable i) <- freshTypeVar
->       unify rty (TypeRecord tys (Just i))
->       return rty
->   | otherwise =
->     do
->       tys <- mapM (fieldPattType tyEnv) fs
->       return (TypeRecord tys Nothing)
-
-> fieldPattType :: ValueEnv -> Field ConstrTerm -> TyState (Ident,Type)
-> fieldPattType tyEnv (Field _ l t) =
->   do
->     lty <- instUniv (labelType l tyEnv)
->     ty <- argType tyEnv t
->     unify lty ty
->     return (l,lty)
-
-> exprType :: ValueEnv -> Expression -> TyState Type
-> exprType tyEnv (Literal l) = litType tyEnv l
-> exprType tyEnv (Variable v) = instUniv (funType v tyEnv)
-> exprType tyEnv (Constructor c) = instUnivExist (constrType c tyEnv)
-> exprType tyEnv (Typed e _) = exprType tyEnv e
-> exprType tyEnv (Paren e) = exprType tyEnv e
-> exprType tyEnv (Tuple _ es)
->   | null es = return unitType
->   | otherwise = liftM tupleType $ mapM (exprType tyEnv) es
-> exprType tyEnv (List _ es) = freshTypeVar >>= flip elemType es
->   where elemType ty [] = return (listType ty)
->         elemType ty (e:es) =
->           exprType tyEnv e >>= unify ty >> elemType ty es
-> exprType tyEnv (ListCompr _ e _) = liftM listType $ exprType tyEnv e
-> exprType tyEnv (EnumFrom _) = return (listType intType)
-> exprType tyEnv (EnumFromThen _ _) = return (listType intType)
-> exprType tyEnv (EnumFromTo _ _) = return (listType intType)
-> exprType tyEnv (EnumFromThenTo _ _ _) = return (listType intType)
-> exprType tyEnv (UnaryMinus _ e) = exprType tyEnv e
-> exprType tyEnv (Apply e1 e2) =
->   do
->     (ty1,ty2) <- exprType tyEnv e1 >>= unifyArrow
->     exprType tyEnv e2 >>= unify ty1
->     return ty2
-> exprType tyEnv (InfixApply e1 op e2) =
->   do
->     (ty1,ty2,ty3) <- exprType tyEnv (infixOp op) >>= unifyArrow2
->     exprType tyEnv e1 >>= unify ty1
->     exprType tyEnv e2 >>= unify ty2
->     return ty3
-> exprType tyEnv (LeftSection e op) =
->   do
->     (ty1,ty2,ty3) <- exprType tyEnv (infixOp op) >>= unifyArrow2
->     exprType tyEnv e >>= unify ty1
->     return (TypeArrow ty2 ty3)
-> exprType tyEnv (RightSection op e) =
->   do
->     (ty1,ty2,ty3) <- exprType tyEnv (infixOp op) >>= unifyArrow2
->     exprType tyEnv e >>= unify ty2
->     return (TypeArrow ty1 ty3)
-> exprType tyEnv (Lambda _ args e) =
->   do
->     tys <- mapM (argType tyEnv) args
->     ty <- exprType tyEnv e
->     return (foldr TypeArrow ty tys)
-> exprType tyEnv (Let _ e) = exprType tyEnv e
-> exprType tyEnv (Do _ e) = exprType tyEnv e
-> exprType tyEnv (IfThenElse _ e1 e2 e3) =
->   do
->     exprType tyEnv e1 >>= unify boolType
->     ty2 <- exprType tyEnv e2
->     ty3 <- exprType tyEnv e3
->     unify ty2 ty3
->     return ty3
-> exprType tyEnv (Case _ _ alts) = freshTypeVar >>= flip altType alts
->   where altType ty [] = return ty
->         altType ty (Alt _ _ rhs:alts) =
->           rhsType tyEnv rhs >>= unify ty >> altType ty alts
-> exprType tyEnv (RecordConstr fs) =
->   do 
->     tys <- mapM (fieldExprType tyEnv) fs
->     return (TypeRecord tys Nothing)
-> exprType tyEnv (RecordSelection r l) =
->   do 
->     lty <- instUniv (labelType l tyEnv)
->     rty <- exprType tyEnv r
->     (TypeVariable i) <- freshTypeVar
->     unify rty (TypeRecord [(l,lty)] (Just i))
->     return lty
-> exprType tyEnv (RecordUpdate fs r) =
->   do
->     tys <- mapM (fieldExprType tyEnv) fs
->     rty <- exprType tyEnv r
->     (TypeVariable i) <- freshTypeVar
->     unify rty (TypeRecord tys (Just i))
->     return rty
-
-> rhsType :: ValueEnv -> Rhs -> TyState Type
-> rhsType tyEnv (SimpleRhs _ e _) = exprType tyEnv e
-> rhsType tyEnv (GuardedRhs es _) = freshTypeVar >>= flip condExprType es
->   where condExprType ty [] = return ty
->         condExprType ty (CondExpr _ _ e:es) =
->           exprType tyEnv e >>= unify ty >> condExprType ty es
-
-> fieldExprType :: ValueEnv -> Field Expression -> TyState (Ident,Type)
-> fieldExprType tyEnv (Field _ l e) =
->   do
->     lty <- instUniv (labelType l tyEnv)
->     ty <- exprType tyEnv e
->     unify lty ty
->     return (l,lty)
-
-\end{verbatim}
-In order to avoid name conflicts with non-generalized type variables
-in a type we instantiate quantified type variables using non-negative
-offsets here.
-\begin{verbatim}
-
-> freshTypeVar :: TyState Type
-> freshTypeVar = liftM TypeVariable $ S.lift (S.modify succ >> S.get)
-
-> instType :: Int -> Type -> TyState Type
-> instType n ty =
->   do
->     tys <- sequence (replicate n freshTypeVar)
->     return (expandAliasType tys ty)
-
-> instUniv :: TypeScheme -> TyState Type
-> instUniv (ForAll n ty) = instType n ty
-
-> instUnivExist :: ExistTypeScheme -> TyState Type
-> instUnivExist (ForAllExist n n' ty) = instType (n + n') ty
-
-\end{verbatim}
-When unifying two types, the non-generalized variables, i.e.,
-variables with negative offsets, must not be substituted. Otherwise,
-the unification algorithm is identical to the one used by the type
-checker.
-\begin{verbatim}
-
-> unify :: Type -> Type -> TyState ()
-> unify ty1 ty2 =
->   S.modify (\theta -> unifyTypes (subst theta ty1) (subst theta ty2) theta)
-
-> unifyList :: [Type] -> [Type] -> TyState ()
-> unifyList tys1 tys2 = sequence_ (zipWith unify tys1 tys2)
-
-> unifyArrow :: Type -> TyState (Type,Type)
-> unifyArrow ty =
->   do
->     theta <- S.get
->     case subst theta ty of
->       TypeVariable tv
->         | tv >= 0 ->
->             do
->               ty1 <- freshTypeVar
->               ty2 <- freshTypeVar
->               S.modify (bindVar tv (TypeArrow ty1 ty2))
->               return (ty1,ty2)
->       TypeArrow ty1 ty2 -> return (ty1,ty2)
->       ty' -> internalError ("unifyArrow (" ++ show ty' ++ ")")
-
-> unifyArrow2 :: Type -> TyState (Type,Type,Type)
-> unifyArrow2 ty =
->   do
->     (ty1,ty2) <- unifyArrow ty
->     (ty21,ty22) <- unifyArrow ty2
->     return (ty1,ty21,ty22)
-
-> unifyTypes :: Type -> Type -> TypeSubst -> TypeSubst
-> unifyTypes (TypeVariable tv1) (TypeVariable tv2) theta
->   | tv1 == tv2 = theta
-> unifyTypes (TypeVariable tv) ty theta
->   | tv >= 0 = bindVar tv ty theta
-> unifyTypes ty (TypeVariable tv) theta
->   | tv >= 0 = bindVar tv ty theta
-> unifyTypes (TypeConstructor tc1 tys1) (TypeConstructor tc2 tys2) theta
->   | tc1 == tc2 = foldr2 unifyTypes theta tys1 tys2
-> unifyTypes (TypeConstrained tys1 tv1) (TypeConstrained tys2 tv2) theta
->   | tv1 == tv2 = theta
-> unifyTypes (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) theta =
->   unifyTypes ty11 ty21 (unifyTypes ty12 ty22 theta)
-> unifyTypes (TypeSkolem k1) (TypeSkolem k2) theta
->   | k1 == k2 = theta
-> unifyTypes (TypeRecord fs1 Nothing) (TypeRecord fs2 Nothing) theta
->   | length fs1 == length fs2 = foldr (unifyTypedLabels fs1) theta fs2
-> unifyTypes tr1@(TypeRecord fs1 Nothing) (TypeRecord fs2 (Just a2)) theta =
->   unifyTypes (TypeVariable a2)
->              tr1
->              (foldr (unifyTypedLabels fs1) theta fs2)
-> unifyTypes tr1@(TypeRecord _ (Just _)) tr2@(TypeRecord _ Nothing) theta =
->   unifyTypes tr2 tr1 theta
-> unifyTypes (TypeRecord fs1 (Just a1)) (TypeRecord fs2 (Just a2)) theta =
->   unifyTypes (TypeVariable a1)
->              (TypeVariable a2)
->              (foldr (unifyTypedLabels fs1) theta fs2)
-> unifyTypes ty1 ty2 _ =
->   internalError ("unify: (" ++ show ty1 ++ ") (" ++ show ty2 ++ ")")
-
-> unifyTypedLabels :: [(Ident,Type)] -> (Ident,Type) -> TypeSubst -> TypeSubst
-> unifyTypedLabels fs1 (l,ty) theta =
->   maybe theta (\ty1 -> unifyTypes ty1 ty theta) (lookup l fs1)
-
-\end{verbatim}
-The functions \texttt{constrType}, \texttt{varType}, and
-\texttt{funType} are used for computing the type of constructors,
-pattern variables, and variables.
-
-\ToDo{These functions should be shared with the type checker.}
-\begin{verbatim}
-
-> constrType :: QualIdent -> ValueEnv -> ExistTypeScheme
-> constrType c tyEnv =
->   case qualLookupValue c tyEnv of
->     [DataConstructor _ sigma] -> sigma
->     [NewtypeConstructor _ sigma] -> sigma
->     _ -> internalError ("constrType " ++ show c)
-
-> varType :: Ident -> ValueEnv -> TypeScheme
-> varType v tyEnv =
->   case lookupValue v tyEnv of
->     [Value _ sigma] -> sigma
->     _ -> internalError ("varType " ++ show v)
-
-> funType :: QualIdent -> ValueEnv -> TypeScheme
-> funType f tyEnv =
->   case qualLookupValue f tyEnv of
->     [Value _ sigma] -> sigma
->     _ -> internalError ("funType " ++ show f)
-
-> labelType :: Ident -> ValueEnv -> TypeScheme
-> labelType l tyEnv =
->   case lookupValue l tyEnv of
->     [Label _ _ sigma] -> sigma
->     _ -> internalError ("labelType " ++ show l)
-
-\end{verbatim}
diff --git a/src/Utils.lhs b/src/Utils.lhs
deleted file mode 100644
--- a/src/Utils.lhs
+++ /dev/null
@@ -1,92 +0,0 @@
-% $Id: Utils.lhs,v 1.4 2003/10/04 17:04:38 wlux Exp $
-%
-% Copyright (c) 2001-2003, Wolfgang Lux
-% See LICENSE for the full license.
-%
-\nwfilename{Utils.lhs}
-\section{Utility Functions}
-The module \texttt{Utils} provides a few simple functions that are
-commonly used in the compiler, but not implemented in the Haskell
-\texttt{Prelude} or standard library.
-\begin{verbatim}
-
-> module Utils where
-
-> infixr 5 ++!
-
-\end{verbatim}
-\paragraph{Triples}
-The \texttt{Prelude} does not contain standard functions for
-triples. We provide projection, (un-)currying, and mapping for triples
-here.
-\begin{verbatim}
-
-> fst3 (x,_,_) = x
-> snd3 (_,y,_) = y
-> thd3 (_,_,z) = z
-
-> apFst3 f (x,y,z) = (f x,y,z)
-> apSnd3 f (x,y,z) = (x,f y,z)
-> apThd3 f (x,y,z) = (x,y,f z)
-
-> curry3 f x y z = f (x,y,z)
-> uncurry3 f (x,y,z) = f x y z
-
-\end{verbatim}
-\paragraph{Lists}
-The function \texttt{(++!)} is variant of the list concatenation
-operator \texttt{(++)} that ignores the second argument if the first
-is a non-empty list. When lists are used to encode non-determinism in
-Haskell, this operator has the same effect as the cut operator in
-Prolog, hence the \texttt{!} in the name.
-\begin{verbatim}
-
-> (++!) :: [a] -> [a] -> [a]
-> xs ++! ys = if null xs then ys else xs
-
-\end{verbatim}
-\paragraph{Strict fold}
-The function \texttt{foldl\_strict} is a strict version of
-\texttt{foldl}, i.e., it evaluates the binary applications before
-the recursion. This has the advantage that \texttt{foldl\_strict} does
-not construct a large application which is then evaluated in the base
-case of the recursion.
-\begin{verbatim}
-
-foldl_strict :: (a -> b -> a) -> a -> [b] -> a
-foldl_strict = foldl'
-
-
-\end{verbatim}
-\paragraph{Folding with two lists}
-Fold operations with two arguments lists can be defined using
-\texttt{zip} and \texttt{foldl} or \texttt{foldr}, resp. Our
-definitions are unfolded for efficiency reasons.
-\begin{verbatim}
-
-> foldl2 :: (a -> b -> c -> a) -> a -> [b] -> [c] -> a
-> foldl2 f z []     _      = z
-> foldl2 f z _      []     = z
-> foldl2 f z (x:xs) (y:ys) = foldl2 f (f z x y) xs ys
-
-> foldr2 :: (a -> b -> c -> c) -> c -> [a] -> [b] -> c
-> foldr2 f z []     _      = z
-> foldr2 f z _      []     = z
-> foldr2 f z (x:xs) (y:ys) = f x y (foldr2 f z xs ys)
-
-\end{verbatim}
-\paragraph{Monadic fold with an accumulator}
-The function \texttt{mapAccumM} is a generalization of
-\texttt{mapAccumL} to monads like \texttt{foldM} is for
-\texttt{foldl}.
-\begin{verbatim}
-
-> mapAccumM :: Monad m => (a -> b -> m (a,c)) -> a -> [b] -> m (a,[c])
-> mapAccumM _ s [] = return (s,[])
-> mapAccumM f s (x:xs) =
->   do
->     (s',y) <- f s x
->     (s'',ys) <- mapAccumM f s' xs
->     return (s'',y:ys)
-
-\end{verbatim}
diff --git a/src/WarnCheck.hs b/src/WarnCheck.hs
deleted file mode 100644
--- a/src/WarnCheck.hs
+++ /dev/null
@@ -1,872 +0,0 @@
--------------------------------------------------------------------------------
---
--- WarnCheck - Searches for potentially irregular code and generates
---             warning messages
---                
--- February 2006,
--- Martin Engelke (men@informatik.uni-kiel.de)
---
-module WarnCheck (warnCheck) where
-
-import Control.Monad.State
-import qualified Data.Map as Map
-import Data.List
-
-import Curry.Base.Ident
-import Curry.Base.Position
-import Curry.Base.MessageMonad
-import Curry.Syntax
-
-import Base (ValueEnv, ValueInfo(..), qualLookupValue)
-import TopEnv
-import qualified ScopeEnv
-import ScopeEnv (ScopeEnv)
-
-
--------------------------------------------------------------------------------
-
--- Data type for representing the current state of generating warnings.
--- The monadic representation of the state allows the usage of monadic 
--- syntax (do expression) for dealing easier and safer with its
--- contents.
-
-type CheckState = State CState
-
-data CState = CState {messages  :: [WarnMsg],
-		      scope     :: ScopeEnv QualIdent IdInfo,
-		      values    :: ValueEnv,
-		      moduleId  :: ModuleIdent }
-
--- Runs a 'CheckState' action and returns the list of messages
-run ::  CheckState a -> [WarnMsg]
-run f
-   = reverse (messages (execState f emptyState))
-
-emptyState :: CState
-emptyState = CState {messages  = [],
-		     scope     = ScopeEnv.new,
-		     values    = emptyTopEnv,
-		     moduleId  = mkMIdent []
-		    }
-
--------------------------------------------------------------------------------
-
--- Find potentially incorrect code in a Curry program and generate
--- the following warnings for:
---    - unreferenced variables
---    - shadowing variables
---    - idle case alternatives
---    - overlapping case alternatives
---    - function rules which are not together
-warnCheck :: ModuleIdent -> ValueEnv -> [Decl] -> [Decl] -> [WarnMsg]
-warnCheck mid vals imports decls
-   = run (do addImportedValues vals
-	     addModuleId mid
-	     checkImports imports
-	     foldM' insertDecl decls
-	     foldM' (checkDecl mid) decls
-             checkDeclOccurrences decls
-	 )
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
---
-checkDecl :: ModuleIdent -> Decl -> CheckState ()
-checkDecl mid (DataDecl pos ident params cdecls)
-   = do beginScope
-	foldM' insertTypeVar params
-	foldM' (checkConstrDecl mid) cdecls
-	params' <- filterM isUnrefTypeVar params
-	when (not (null params')) 
-	     (foldM' genWarning' (map unrefTypeVar params'))
-	endScope
-checkDecl mid (TypeDecl _ ident params texpr)
-   = do beginScope
-	foldM' insertTypeVar params
-	checkTypeExpr mid texpr
-	params' <- filterM isUnrefTypeVar params
-	when (not (null params'))
-	     (foldM' genWarning'  (map unrefTypeVar params'))
-	endScope
-checkDecl mid (FunctionDecl pos ident equs)
-   = do beginScope
-	foldM' (checkEquation mid) equs
-	c <- isConsId ident
-	idents' <- returnUnrefVars
-	when (not (c || null idents')) 
-             (foldM' genWarning' (map unrefVar idents'))
-	endScope
-checkDecl mid (PatternDecl _ cterm rhs)
-   = do checkConstrTerm mid cterm
-	checkRhs mid rhs
-checkDecl _ _ = return ()
-
--- Checks locally declared identifiers (i.e. functions and logic variables)
--- for shadowing
-checkLocalDecl :: Decl -> CheckState ()
-checkLocalDecl (FunctionDecl pos ident _)
-   = do s <- isShadowingVar ident
-	when s (genWarning' (shadowingVar ident))
-checkLocalDecl (ExtraVariables pos idents)
-   = do idents' <- filterM isShadowingVar idents
-	when (not (null idents'))
-	     (foldM' genWarning' (map shadowingVar idents'))
-checkLocalDecl (PatternDecl _ constrTerm _)
-   = checkConstrTerm (mkMIdent []) constrTerm
-checkLocalDecl _ = return ()
-
---
-checkConstrDecl :: ModuleIdent -> ConstrDecl -> CheckState ()
-checkConstrDecl mid (ConstrDecl _ _ ident texprs)
-   = do visitId ident
-	foldM' (checkTypeExpr mid) texprs
-checkConstrDecl mid (ConOpDecl _ _ texpr1 ident texpr2)
-   = do visitId ident
-	checkTypeExpr mid texpr1
-	checkTypeExpr mid texpr2
-
-
-checkTypeExpr :: ModuleIdent -> TypeExpr -> CheckState ()
-checkTypeExpr mid (ConstructorType qid texprs)
-   = do maybe (return ()) visitTypeId (localIdent mid qid)
-	foldM' (checkTypeExpr mid ) texprs
-checkTypeExpr mid  (VariableType ident)
-   = visitTypeId ident
-checkTypeExpr mid  (TupleType texprs)
-   = foldM' (checkTypeExpr mid ) texprs
-checkTypeExpr mid  (ListType texpr)
-   = checkTypeExpr mid  texpr
-checkTypeExpr mid  (ArrowType texpr1 texpr2)
-   = do checkTypeExpr mid  texpr1
-	checkTypeExpr mid  texpr2
-checkTypeExpr mid  (RecordType fields restr)
-   = do foldM' (checkTypeExpr mid ) (map snd fields)
-	maybe (return ()) (checkTypeExpr mid ) restr
-
---
-checkEquation :: ModuleIdent -> Equation -> CheckState ()
-checkEquation mid (Equation _ lhs rhs)
-   = do checkLhs mid lhs
-	checkRhs mid rhs
-
---
-checkLhs :: ModuleIdent -> Lhs -> CheckState ()
-checkLhs mid (FunLhs ident cterms)
-   = do visitId ident
-	foldM' (checkConstrTerm mid) cterms
-	foldM' (insertConstrTerm False) cterms
-checkLhs mid (OpLhs cterm1 ident cterm2)
-   = checkLhs mid (FunLhs ident [cterm1, cterm2])
-checkLhs mid (ApLhs lhs cterms)
-   = do checkLhs mid lhs
-	foldM' (checkConstrTerm mid ) cterms
-	foldM' (insertConstrTerm False) cterms
-
---
-checkRhs :: ModuleIdent -> Rhs -> CheckState ()
-checkRhs mid (SimpleRhs _ expr decls)
-   = do beginScope  -- function arguments can be overwritten by local decls
-	foldM' checkLocalDecl decls
-	foldM' insertDecl decls
-	foldM' (checkDecl mid) decls
-	checkDeclOccurrences decls
-	checkExpression mid expr
-	idents' <- returnUnrefVars
-	when (not (null idents'))
-	     (foldM' genWarning' (map unrefVar idents'))
-	endScope
-checkRhs mid (GuardedRhs cexprs decls)
-   = do beginScope
-	foldM' checkLocalDecl decls
-	foldM' insertDecl decls
-	foldM' (checkDecl mid) decls
-	checkDeclOccurrences decls
-	foldM' (checkCondExpr mid) cexprs
-	idents' <- returnUnrefVars
-	when (not (null idents'))
-	     (foldM' genWarning' (map unrefVar idents'))
-	endScope
-
-
---
-checkCondExpr :: ModuleIdent -> CondExpr -> CheckState ()
-checkCondExpr mid (CondExpr _ cond expr)
-   = do checkExpression mid cond
-	checkExpression mid expr
-
--- 
-checkConstrTerm :: ModuleIdent -> ConstrTerm -> CheckState ()
-checkConstrTerm mid (VariablePattern ident)
-   = do s <- isShadowingVar ident
-	when s (genWarning' (shadowingVar ident))
-checkConstrTerm mid (ConstructorPattern _ cterms)
-   = foldM' (checkConstrTerm mid ) cterms
-checkConstrTerm mid (InfixPattern cterm1 qident cterm2)
-   = checkConstrTerm mid (ConstructorPattern qident [cterm1, cterm2])
-checkConstrTerm mid (ParenPattern cterm)
-   = checkConstrTerm mid cterm
-checkConstrTerm mid (TuplePattern _ cterms)
-   = foldM' (checkConstrTerm mid ) cterms
-checkConstrTerm mid (ListPattern _ cterms)
-   = foldM' (checkConstrTerm mid ) cterms
-checkConstrTerm mid (AsPattern ident cterm)
-   = do s <- isShadowingVar ident
-	when s (genWarning' (shadowingVar ident))
-	checkConstrTerm mid cterm
-checkConstrTerm mid (LazyPattern _ cterm)
-   = checkConstrTerm mid cterm
-checkConstrTerm mid (FunctionPattern _ cterms)
-   = foldM' (checkConstrTerm mid ) cterms
-checkConstrTerm mid  (InfixFuncPattern cterm1 qident cterm2)
-   = checkConstrTerm mid  (FunctionPattern qident [cterm1, cterm2])
-checkConstrTerm mid  (RecordPattern fields restr)
-   = do foldM' (checkFieldPattern mid) fields
-	maybe (return ()) (checkConstrTerm mid ) restr
-checkConstrTerm _ _ = return ()
-
---
-checkExpression :: ModuleIdent -> Expression -> CheckState ()
-checkExpression mid (Variable qident)
-   = maybe (return ()) visitId (localIdent mid qident)
-checkExpression mid (Paren expr)
-   = checkExpression mid expr
-checkExpression mid (Typed expr _)
-   = checkExpression mid expr
-checkExpression mid (Tuple _ exprs)
-   = foldM' (checkExpression mid ) exprs
-checkExpression mid (List _ exprs)
-   = foldM' (checkExpression mid ) exprs
-checkExpression mid (ListCompr _ expr stmts)
-   = do beginScope
-	foldM' (checkStatement mid ) stmts
-	checkExpression mid expr
-	idents' <- returnUnrefVars
-	when (not (null idents'))
-	     (foldM' genWarning' (map unrefVar idents'))
-	endScope
-checkExpression mid  (EnumFrom expr)
-   = checkExpression mid  expr
-checkExpression mid  (EnumFromThen expr1 expr2)
-   = foldM' (checkExpression mid ) [expr1, expr2]
-checkExpression mid  (EnumFromTo expr1 expr2)
-   = foldM' (checkExpression mid ) [expr1, expr2]
-checkExpression mid  (EnumFromThenTo expr1 expr2 expr3)
-   = foldM' (checkExpression mid ) [expr1, expr2, expr3]
-checkExpression mid  (UnaryMinus _ expr)
-   = checkExpression mid  expr
-checkExpression mid  (Apply expr1 expr2)
-   = foldM' (checkExpression mid ) [expr1, expr2]
-checkExpression mid  (InfixApply expr1 op expr2)
-   = do maybe (return ()) (visitId) (localIdent mid (opName op))
-	foldM' (checkExpression mid ) [expr1, expr2]
-checkExpression mid  (LeftSection expr _)
-   = checkExpression mid  expr
-checkExpression mid  (RightSection _ expr)
-   = checkExpression mid  expr
-checkExpression mid  (Lambda _ cterms expr)
-   = do beginScope
-	foldM' (checkConstrTerm mid ) cterms
-	foldM' (insertConstrTerm False) cterms
-	checkExpression mid expr
-	idents' <- returnUnrefVars
-	when (not (null idents'))
-	     (foldM' genWarning' (map unrefVar idents'))
-	endScope
-checkExpression mid  (Let decls expr)
-   = do beginScope
-	foldM' checkLocalDecl decls
-	foldM' insertDecl decls
-	foldM' (checkDecl mid) decls
-	checkDeclOccurrences decls
-	checkExpression mid  expr
-	idents' <- returnUnrefVars
-	when (not (null idents'))
-	     (foldM' genWarning' (map unrefVar idents'))
-	endScope
-checkExpression mid  (Do stmts expr)
-   = do beginScope
-	foldM' (checkStatement mid ) stmts
-	checkExpression mid  expr
-	idents' <- returnUnrefVars
-	when (not (null idents'))
-	     (foldM' genWarning' (map unrefVar idents'))
-	endScope
-checkExpression mid  (IfThenElse _ expr1 expr2 expr3)
-   = foldM' (checkExpression mid ) [expr1, expr2, expr3]
-checkExpression mid  (Case _ expr alts)
-   = do checkExpression mid  expr
-	foldM' (checkAlt mid) alts
-	checkCaseAlternatives mid alts
-checkExpression mid (RecordConstr fields)
-   = foldM' (checkFieldExpression mid) fields
-checkExpression mid (RecordSelection expr ident)
-   = checkExpression mid expr -- Hier auch "visitId ident" ?
-checkExpression mid (RecordUpdate fields expr)
-   = do foldM' (checkFieldExpression mid) fields
-	checkExpression mid expr
-checkExpression _ _  = return ()
-
---
-checkStatement :: ModuleIdent -> Statement -> CheckState ()
-checkStatement mid (StmtExpr _ expr)
-   = checkExpression mid expr
-checkStatement mid (StmtDecl decls)
-   = do foldM' checkLocalDecl decls
-	foldM' insertDecl decls
-	foldM' (checkDecl mid) decls
-	checkDeclOccurrences decls
-checkStatement mid (StmtBind _ cterm expr)
-   = do checkConstrTerm mid cterm
-	insertConstrTerm False cterm
-	checkExpression mid expr
-
---
-checkAlt :: ModuleIdent -> Alt -> CheckState ()
-checkAlt mid (Alt pos cterm rhs)
-   = do beginScope 
-	checkConstrTerm mid  cterm
-	insertConstrTerm False cterm
-	checkRhs mid rhs
-	idents' <-  returnUnrefVars
-	when (not (null idents'))
-	     (foldM' genWarning' (map unrefVar idents'))
-	endScope
-
---
-checkFieldExpression :: ModuleIdent -> Field Expression -> CheckState ()
-checkFieldExpression mid (Field _ ident expr)
-   = checkExpression mid expr -- Hier auch "visitId ident" ?
-
---
-checkFieldPattern :: ModuleIdent -> Field ConstrTerm -> CheckState ()
-checkFieldPattern mid (Field _ ident cterm)
-   = checkConstrTerm mid  cterm
-
--- Check for idle and overlapping case alternatives
-checkCaseAlternatives :: ModuleIdent -> [Alt] -> CheckState ()
-checkCaseAlternatives mid alts
-   = do checkIdleAlts mid alts
-	checkOverlappingAlts mid alts
-
---
--- FIXME this looks buggy: is alts' required to be non-null or not? (hsi)
-checkIdleAlts :: ModuleIdent -> [Alt] -> CheckState ()
-checkIdleAlts mid alts
-   = do alts' <- dropUnless' isVarAlt alts
-	let idles = tail_ [] alts'
-	    (Alt pos _ _) = head idles
-	unless (null idles) (genWarning pos idleCaseAlts)
- where
- isVarAlt (Alt _ (VariablePattern id) _) 
-    = isVarId id
- isVarAlt (Alt _ (ParenPattern (VariablePattern id)) _) 
-    = isVarId id
- isVarAlt (Alt _ (AsPattern _ (VariablePattern id)) _)
-    = isVarId id
- isVarAlt _ = return False
-
---
-checkOverlappingAlts :: ModuleIdent -> [Alt] -> CheckState ()
-checkOverlappingAlts mid [] = return ()
-checkOverlappingAlts mid (alt:alts)
-   = do (altsr, alts') <- partition' (equalAlts alt) alts
-        mapM_ (\ (Alt pos _ _) -> genWarning pos overlappingCaseAlt) altsr
-	checkOverlappingAlts mid alts'
- where
- equalAlts (Alt _ cterm1 _) (Alt _ cterm2 _) = equalConstrTerms cterm1 cterm2
-
- equalConstrTerms (LiteralPattern l1) (LiteralPattern l2)
-    = return (l1 == l2)
- equalConstrTerms (NegativePattern id1 l1) (NegativePattern id2 l2) 
-    = return (id1 == id2 && l1 == l2)
- equalConstrTerms (VariablePattern id1) (VariablePattern id2)
-    = do p <- isConsId id1 
-	 return (p && id1 == id2)
- equalConstrTerms (ConstructorPattern qid1 cs1)
-		  (ConstructorPattern qid2 cs2)
-    = if qid1 == qid2
-      then all' (\ (c1,c2) -> equalConstrTerms c1 c2) (zip cs1 cs2)
-      else return False
- equalConstrTerms (InfixPattern lcs1 qid1 rcs1)
-		  (InfixPattern lcs2 qid2 rcs2)
-    = equalConstrTerms (ConstructorPattern qid1 [lcs1, rcs1])
-                       (ConstructorPattern qid2 [lcs2, rcs2])
- equalConstrTerms (ParenPattern cterm1) (ParenPattern cterm2)
-    = equalConstrTerms cterm1 cterm2
- equalConstrTerms (TuplePattern _ cs1) (TuplePattern _ cs2)
-    = equalConstrTerms (ConstructorPattern (qTupleId 2) cs1)
-                       (ConstructorPattern (qTupleId 2) cs2)
- equalConstrTerms (ListPattern _ cs1) (ListPattern _ cs2)
-    = cmpListM equalConstrTerms cs1 cs2
- equalConstrTerms (AsPattern id1 cterm1) (AsPattern id2 cterm2)
-    = equalConstrTerms cterm1 cterm2
- equalConstrTerms (LazyPattern _ cterm1) (LazyPattern _ cterm2)
-    = equalConstrTerms cterm1 cterm2
- equalConstrTerms _ _ = return False
-
-
--- Find function rules which are not together
-checkDeclOccurrences :: [Decl] -> CheckState ()
-checkDeclOccurrences decls = checkDO (mkIdent "") Map.empty decls
- where
- checkDO prevId env [] = return ()
- checkDO prevId env ((FunctionDecl pos ident _):decls)
-    = do c <- isConsId ident
-	 if not (c || prevId == ident)
-          then (maybe (checkDO ident (Map.insert ident pos env) decls)
-	              (\pos' -> genWarning' (rulesNotTogether ident pos')
-		                >> checkDO ident env decls)
-	              (Map.lookup ident env))
-	  else checkDO ident env decls
- checkDO _ env (_:decls) 
-    = checkDO (mkIdent "") env decls
-
-
--- check import declarations for multiply imported modules
-checkImports :: [Decl] -> CheckState ()
-checkImports imps = checkImps Map.empty imps
- where
- checkImps env [] = return ()
- checkImps env ((ImportDecl pos mid _ _ spec):imps)
-    | mid /= preludeMIdent
-      = maybe (checkImps (Map.insert mid (fromImpSpec spec) env) imps)
-              (\ishs -> checkImpSpec env pos mid ishs spec
-	                >>= (\env' -> checkImps env' imps))
-	      (Map.lookup mid env)
-    | otherwise
-      = checkImps env imps
- checkImps env (_:imps) = checkImps env imps
-
- checkImpSpec env pos mid (is,hs) Nothing
-    = genWarning' (multiplyImportedModule mid) >> return env
- checkImpSpec env pos mid (is,hs) (Just (Importing _ is'))
-    | null is && any (\i' -> notElem i' hs) is'
-      = do genWarning' (multiplyImportedModule mid)
-	   return (Map.insert mid (is',hs) env)
-    | null iis
-      = return (Map.insert mid (is' ++ is,hs) env)
-    | otherwise
-      = do foldM' genWarning'
-		  (map ((multiplyImportedSymbol mid) . impName) iis)
-	   return (Map.insert mid (unionBy cmpImport is' is,hs) env)
-  where iis = intersectBy cmpImport is' is
- checkImpSpec env pos mid (is,hs) (Just (Hiding _ hs'))
-    | null ihs
-      = return (Map.insert mid (is,hs' ++ hs) env)
-    | otherwise
-      = do foldM' genWarning' 
-		  (map ((multiplyHiddenSymbol mid) . impName) ihs)
-	   return (Map.insert mid (is,unionBy cmpImport hs' hs) env)
-  where ihs = intersectBy cmpImport hs' hs
-
- cmpImport (ImportTypeWith id1 cs1) (ImportTypeWith id2 cs2)
-    = id1 == id2 && null (intersect cs1 cs2)
- cmpImport i1 i2 = (impName i1) == (impName i2)
-
- impName (Import id)           = id
- impName (ImportTypeAll id)    = id
- impName (ImportTypeWith id _) = id
-
- fromImpSpec Nothing                 = ([],[])
- fromImpSpec (Just (Importing _ is)) = (is,[])
- fromImpSpec (Just (Hiding _ hs))    = ([],hs)
-
-
--------------------------------------------------------------------------------
--- For detecting unreferenced variables, the following functions updates the 
--- current check state by adding identifiers occuring in declaration left hand 
--- sides.
-
---
-insertDecl :: Decl -> CheckState ()
-insertDecl (DataDecl _ ident _ cdecls)
-   = do insertTypeConsId ident
-	foldM' insertConstrDecl cdecls
-insertDecl (TypeDecl _ ident _ texpr)
-   = do insertTypeConsId ident
-	insertTypeExpr texpr
-insertDecl (FunctionDecl _ ident _)
-   = do c <- isConsId ident
-	unless c (insertVar ident)
-insertDecl (ExternalDecl _ _ _ ident _)
-   = insertVar ident
-insertDecl (FlatExternalDecl _ idents)
-   = foldM' insertVar idents
-insertDecl (PatternDecl _ cterm _)
-   = insertConstrTerm False cterm
-insertDecl (ExtraVariables _ idents)
-   = foldM' insertVar idents
-insertDecl _ = return ()
-
---
-insertTypeExpr :: TypeExpr -> CheckState ()
-insertTypeExpr (VariableType _) = return ()
-insertTypeExpr (ConstructorType _ texprs)
-   = foldM' insertTypeExpr texprs
-insertTypeExpr (TupleType texprs)
-   = foldM' insertTypeExpr texprs
-insertTypeExpr (ListType texpr)
-   = insertTypeExpr texpr
-insertTypeExpr (ArrowType texpr1 texpr2)
-   = foldM' insertTypeExpr [texpr1,texpr2]
-insertTypeExpr (RecordType fields restr)
-   = do --foldM' insertVar (concatMap fst fields)
-	maybe (return ()) insertTypeExpr restr
-
---
-insertConstrDecl :: ConstrDecl -> CheckState ()
-insertConstrDecl (ConstrDecl _ _ ident _)
-   = insertConsId ident
-insertConstrDecl (ConOpDecl _ _ _ ident _)
-   = insertConsId ident
-
--- Notes: 
---    - 'fp' indicates whether 'checkConstrTerm' deals with the arguments
---      of a function pattern or not.
---    - Since function patterns are not recognized before syntax check, it is
---      necessary to determine, whether a constructor pattern represents a
---      constructor or a function. 
-insertConstrTerm :: Bool -> ConstrTerm -> CheckState ()
-insertConstrTerm fp (VariablePattern ident)
-   | fp        = do c <- isConsId ident
-		    v <- isVarId ident
-		    unless c (if (name ident) /= "_" && v
-			         then visitId ident
-			         else insertVar ident)
-   | otherwise = do c <- isConsId ident
-	            unless c (insertVar ident)
-insertConstrTerm fp (ConstructorPattern qident cterms)
-   = do c <- isQualConsId qident
-	if c then foldM' (insertConstrTerm fp) cterms
-	     else foldM' (insertConstrTerm True) cterms
-insertConstrTerm fp (InfixPattern cterm1 qident cterm2)
-   = insertConstrTerm fp (ConstructorPattern qident [cterm1, cterm2])
-insertConstrTerm fp (ParenPattern cterm)
-   = insertConstrTerm fp cterm
-insertConstrTerm fp (TuplePattern _ cterms)
-   = foldM' (insertConstrTerm fp) cterms
-insertConstrTerm fp (ListPattern _ cterms)
-   = foldM' (insertConstrTerm fp) cterms
-insertConstrTerm fp (AsPattern ident cterm)
-   = do insertVar ident
-	insertConstrTerm fp cterm
-insertConstrTerm fp (LazyPattern _ cterm)
-   = insertConstrTerm fp cterm
-insertConstrTerm _ (FunctionPattern _ cterms)
-   = foldM' (insertConstrTerm True) cterms
-insertConstrTerm _ (InfixFuncPattern cterm1 qident cterm2)
-   = insertConstrTerm True (FunctionPattern qident [cterm1, cterm2])
-insertConstrTerm fp (RecordPattern fields restr)
-   = do foldM' (insertFieldPattern fp) fields
-	maybe (return ()) (insertConstrTerm fp) restr
-insertConstrTerm _ _ = return ()
-
---
-insertFieldPattern :: Bool -> Field ConstrTerm -> CheckState ()
-insertFieldPattern fp (Field _ _ cterm)
-   = insertConstrTerm fp cterm
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
--- Data type for distinguishing identifiers as either (type) constructors or
--- (type) variables (including functions).
--- The Boolean flag in 'VarInfo' is used to mark variables when they are used 
--- within expressions.
-data IdInfo = ConsInfo | VarInfo Bool deriving Show
-
---
-isVariable :: IdInfo -> Bool
-isVariable (VarInfo _) = True
-isVariable _           = False
-
---
-isConstructor :: IdInfo -> Bool
-isConstructor ConsInfo = True
-isConstructor _        = False
-
---
-variableVisited :: IdInfo -> Bool
-variableVisited (VarInfo v) = v
-variableVisited _           = True
-
---
-visitVariable :: IdInfo -> IdInfo
-visitVariable info = case info of
-		       VarInfo _ -> VarInfo True
-		       _         -> info
-
-
---
-modifyScope :: (ScopeEnv QualIdent IdInfo -> ScopeEnv QualIdent IdInfo)
-	       -> CState -> CState
-modifyScope f state = state{ scope = f (scope state) }
-
-
---
-genWarning :: Position -> String -> CheckState ()
-genWarning pos msg
-   = modify (\state -> state{ messages = warnMsg:(messages state) })
- where warnMsg = WarnMsg (Just pos) msg
- 
-genWarning' :: (Position, String) -> CheckState ()
-genWarning' (pos, msg)
-   = modify (\state -> state{ messages = warnMsg:(messages state) })
-    where warnMsg = WarnMsg (Just pos) msg 
-
---
-insertVar :: Ident -> CheckState ()
-insertVar id 
-   | isAnnonId id = return ()
-   | otherwise
-     = modify 
-         (\state -> modifyScope 
-	              (ScopeEnv.insert (commonId id) (VarInfo False)) state)
-
---
-insertTypeVar :: Ident -> CheckState ()
-insertTypeVar id
-   | isAnnonId id = return ()
-   | otherwise    
-     = modify 
-         (\state -> modifyScope 
-	              (ScopeEnv.insert (typeId id) (VarInfo False)) state)
-
---
-insertConsId :: Ident -> CheckState ()
-insertConsId id
-   = modify 
-       (\state -> modifyScope (ScopeEnv.insert (commonId id) ConsInfo) state)
-
---
-insertTypeConsId :: Ident -> CheckState ()
-insertTypeConsId id
-   = modify 
-       (\state -> modifyScope (ScopeEnv.insert (typeId id) ConsInfo) state)
-
---
-isVarId :: Ident -> CheckState Bool
-isVarId id
-   = gets (\state -> isVar state (commonId id))
-
---
-isConsId :: Ident -> CheckState Bool
-isConsId id 
-   = gets (\state -> isCons state (qualify id))
-
---
-isQualConsId :: QualIdent -> CheckState Bool
-isQualConsId qid
-   = gets (\state -> isCons state qid)
-
---
-isShadowingVar :: Ident -> CheckState Bool
-isShadowingVar id 
-   = gets (\state -> isShadowing state (commonId id))
-
---
-visitId :: Ident -> CheckState ()
-visitId id 
-   = modify 
-       (\state -> modifyScope 
-	            (ScopeEnv.modify visitVariable (commonId id)) state)
-
---
-visitTypeId :: Ident -> CheckState ()
-visitTypeId id 
-   = modify 
-       (\state -> modifyScope 
-	            (ScopeEnv.modify visitVariable (typeId id)) state)
-
---
-isUnrefTypeVar :: Ident -> CheckState Bool
-isUnrefTypeVar id
-   = gets (\state -> isUnref state (typeId id))
-
---
-returnUnrefVars :: CheckState [Ident]
-returnUnrefVars 
-   = gets (\state -> 
-	   	    let ids    = map fst (ScopeEnv.toLevelList (scope state))
-                        unrefs = filter (isUnref state) ids
-	            in  map unqualify unrefs )
-
---
-addModuleId :: ModuleIdent -> CheckState ()
-addModuleId mid = modify (\state -> state{ moduleId = mid })
-
---
-
-withScope :: CheckState a -> CheckState ()
-withScope m = beginScope >> m >> endScope
-
---
-beginScope :: CheckState ()
-beginScope = modify (\state -> modifyScope ScopeEnv.beginScope state)
-
---
-endScope :: CheckState ()
-endScope = modify (\state -> modifyScope ScopeEnv.endScopeUp state)
-
-
--- Adds the content of a value environment to the state
-addImportedValues :: ValueEnv -> CheckState ()
-addImportedValues vals = modify (\state -> state{ values = vals })
-
---
-foldM' :: (a -> CheckState ()) -> [a] -> CheckState ()
-foldM' f [] = return ()
-foldM' f (x:xs) = f x >> foldM' f xs
-
---
-dropUnless' :: (a -> CheckState Bool) -> [a] -> CheckState [a]
-dropUnless' mpred [] = return []
-dropUnless' mpred (x:xs)
-   = do p <- mpred x
-	if p then return (x:xs) else dropUnless' mpred xs
-
---
-partition' :: (a -> CheckState Bool) -> [a] -> CheckState ([a],[a])
-partition' mpred xs = part mpred [] [] xs
- where
- part mpred ts fs [] = return (reverse ts, reverse fs)
- part mpred ts fs (x:xs)
-   = do p <- mpred x
-	if p then part mpred (x:ts) fs xs
-	     else part mpred ts (x:fs) xs
-
---
-all' :: (a -> CheckState Bool) -> [a] -> CheckState Bool
-all' mpred [] = return True
-all' mpred (x:xs)
-   = do p <- mpred x
-	if p then all' mpred xs else return False
-
-
-
--------------------------------------------------------------------------------
-
---
-isShadowing :: CState -> QualIdent -> Bool
-isShadowing state qid
-   = let sc = scope state
-     in  maybe False isVariable (ScopeEnv.lookup qid sc)
-	 && ScopeEnv.level qid sc < ScopeEnv.currentLevel sc
-
---
-isUnref :: CState -> QualIdent -> Bool
-isUnref state qid 
-   = let sc = scope state
-     in  maybe False (not . variableVisited) (ScopeEnv.lookup qid sc)
-         && ScopeEnv.level qid sc == ScopeEnv.currentLevel sc
-
---
-isVar :: CState -> QualIdent -> Bool
-isVar state qid = maybe (isAnnonId (unqualify qid)) 
-	           isVariable 
-		   (ScopeEnv.lookup qid (scope state))
-
---
-isCons :: CState -> QualIdent -> Bool
-isCons state qid = maybe (isImportedCons state qid)
-		         isConstructor
-			 (ScopeEnv.lookup qid (scope state))
- where
- isImportedCons state qid
-    = case (qualLookupValue qid (values state)) of
-        (DataConstructor _ _):_    -> True
-        (NewtypeConstructor _ _):_ -> True
-        _                          -> False
-
-
---
-isAnnonId :: Ident -> Bool
-isAnnonId id = (name id) == "_"
-
-
--- Since type identifiers and normal identifiers (e.g. functions, variables
--- or constructors) don't share the same namespace, it is necessary
--- to distinguish them in the scope environment of the check state.
--- For this reason type identifiers are annotated with 1 and normal
--- identifiers are annotated with 0.
---
-commonId :: Ident -> QualIdent
-commonId id = qualify (unRenameIdent id)
-
---
-typeId :: Ident -> QualIdent
-typeId id = qualify (renameIdent id 1)
-
-
--------------------------------------------------------------------------------
--- Warnings...
-
-unrefTypeVar :: Ident -> (Position, String)
-unrefTypeVar id = 
-  (positionOfIdent id,
-   "unreferenced type variable \"" ++ show id ++ "\"")
-
-unrefVar :: Ident -> (Position, String)
-unrefVar id = 
-  (positionOfIdent id,
-   "unused declaration of variable \"" ++ show id ++ "\"")
-
-shadowingVar :: Ident -> (Position, String)
-shadowingVar id = 
-  (positionOfIdent id,
-   "shadowing symbol \"" ++ show id ++ "\"")
-
-idleCaseAlts :: String
-idleCaseAlts = "idle case alternative(s)"
-
-overlappingCaseAlt :: String
-overlappingCaseAlt = "redundant overlapping case alternative"
-
-rulesNotTogether :: Ident -> Position -> (Position, String)
-rulesNotTogether id pos
-  = (positionOfIdent id,
-     "rules for function \"" ++ show id ++ "\" "    
-     ++ "are not together "
-     ++ "(first occurrence at " 
-     ++ show (line pos) ++ "." ++ show (column pos) ++ ")")
-
-multiplyImportedModule :: ModuleIdent -> (Position, String)
-multiplyImportedModule mid 
-  = (positionOfModuleIdent mid,
-     "module \"" ++ show mid ++ "\" was imported more than once")
-
-multiplyImportedSymbol :: ModuleIdent -> Ident -> (Position, String)
-multiplyImportedSymbol mid ident
-  = (positionOfIdent ident,
-     "symbol \"" ++ show ident ++ "\" was imported from module \""
-     ++ show mid ++ "\" more than once")
-
-multiplyHiddenSymbol :: ModuleIdent -> Ident -> (Position, String)
-multiplyHiddenSymbol mid ident
-  = (positionOfIdent ident,
-     "symbol \"" ++ show ident ++ "\" from module \"" ++ show mid
-     ++ "\" was hidden more than once")
-
-
--------------------------------------------------------------------------------
--- Miscellaneous
-
--- safer versions of 'tail' and 'head'
-tail_ :: [a] -> [a] -> [a]
-tail_ alt []     = alt
-tail_ _   (_:xs) = xs
-
-
---
-cmpListM :: Monad m => (a -> a -> m Bool) -> [a] -> [a] -> m Bool
-cmpListM cmpM []     []     = return True
-cmpListM cmpM (x:xs) (y:ys) = do c <- cmpM x y
-				 if c then cmpListM cmpM xs ys 
-				      else return False
-cmpListM cmpM _      _      = return False
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
diff --git a/src/currydoc.css b/src/currydoc.css
deleted file mode 100644
--- a/src/currydoc.css
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Use monospace fonts for typewriter styles */
-pre, tt, code { font-family: monospace }
-
-/* Use always white background */
-body { background: white; color: black }
-
-/* Show hyperlinks without underscore */
-a:visited, a:link, a:active { text-decoration: none }
-
-.keyword { color:blue }
-.constructorname_constrpattern { color : #FF00FF }
-.constructorname_constrcall { color : #FF00FF }
-.constructorname_constrdecla { color : #FF00FF }
-.constructorname_otherconstrkind { color : #FF00FF }
-.typeconstructor_typedecla  { color : #ff7f50 }
-.typeconstructor_typeuse  { color : #ff7f50 }
-.typeconstructor_typeexport  { color : #ff7f50 }
-.function_infixfunction  { color : #800080 }
-.function_typsig  { color : #800080 }
-.function_fundecl  { color : #800080 }
-.function_functioncall  { color : #800080 }
-.function_otherfunctionkind  { color : #800080 }
-.moduleName  { color : #800000 }
-.commentary  { color : green }
-.numberCode  { color : #008080 }
-.stringCode  { color : #800000 }
-.charCode  { color : #800000 }
-.symbol  { color : #C0C0C0 }
-.identifier_iddecl   { color : black }
-.identifier_idoccur   { color : black }
-.identifier_unknownid   { color : black }
-.codeWarning  {font-weight: bold;font-style:italic; color : red }
-.codeError  { font-style:italic; color : #a52a2a }
-.notParsed  { font-style:italic; color : #C0C0C0 }
diff --git a/src/cymake.hs b/src/cymake.hs
deleted file mode 100644
--- a/src/cymake.hs
+++ /dev/null
@@ -1,97 +0,0 @@
--- -----------------------------------------------------------------------------
--- |
--- cymake - The Curry builder
---
---          Command line tool for generating Curry representations (e.g.
---          FlatCurry, AbstractCurry) for a Curry source file including
---          all imported modules.
---
--- September 2005, Martin Engelke (men@informatik.uni-kiel.de)
---
--- -----------------------------------------------------------------------------
-
-module Main(main) where
-
-import Data.List
-import Data.Maybe
-import System.Console.GetOpt
-import System.Environment(getArgs, getProgName)
-import System.Exit(ExitCode(..), exitWith)
-import System.IO
-import Control.Monad (unless)
-
-import CurryBuilder(buildCurry)
-import CurryCompilerOpts
-import CurryHtml
-import Curry.Files.CymakePath (cymakeVersion)
-
-
--- | The command line tool cymake
-main :: IO ()
-main = do
-  prog <- getProgName
-  args <- getArgs
-  cymake prog args
-
--- | Checks the command line arguments and invokes the curry builder
-cymake :: String -> [String] -> IO ()
-cymake prog args
-  | elem Help opts = printUsage prog
-  | null files     = badUsage prog ["no files"]
-  | null errs'
-    && not (elem Html opts) = do
-      unless (noVerb options')
-        (putStrLn $ "This is cymake, version " ++ cymakeVersion)
-      mapM_ (buildCurry options') files
-  | null errs'     = do
-                     let importFiles = nub $ importPaths opts'
-                         outputFile  = maybe "" id (output opts')
-                     mapM_ (source2html importFiles outputFile) files
-  | otherwise      = badUsage prog errs'
-  where
-  (opts, files, errs) = getOpt Permute options args
-  opts'               = foldr selectOption defaultOpts opts
-  options'            = if flat opts' || flatXml opts' || abstract opts'
-                        || untypedAbstract opts' || parseOnly opts'
-                          then  opts'
-                          else  opts'{ flat = True }
-  errs'               = errs ++ check options' files
-
--- | Prints usage information of the command line tool.
-printUsage :: String -> IO ()
-printUsage prog = do
-  putStrLn (usageInfo header options)
-  exitWith ExitSuccess
-  where header = "usage: " ++ prog ++ " [OPTION] ... MODULE ..."
-
--- | Prints errors
-badUsage :: String -> [String] -> IO ()
-badUsage prog errs = do
-  putErrsLn $ map (\err -> prog ++ ": " ++ err) errs
-  abortWith ["Try '" ++ prog ++ " -" ++ "-help' for more information"]
-
--- | Checks options and files and return a list of error messages
-check :: Options -> [String] -> [String]
-check opts files
-   | null files
-     = ["no files"]
-   | isJust (output opts) && length files > 1
-     = ["cannot specify -o with multiple targets"]
-   | otherwise
-     = []
-
--- | Prints an error message on 'stderr'
-putErrLn :: String -> IO ()
-putErrLn = hPutStrLn stderr
-
--- | Prints a list of error messages on 'stderr'
-putErrsLn :: [String] -> IO ()
-putErrsLn = mapM_ putErrLn
-
--- | Prints a list of error messages on 'stderr' and aborts the program with
---   exit code 1
-abortWith :: [String] -> IO a
-abortWith errs = putErrsLn errs >> exitWith (ExitFailure 1)
-
--- -----------------------------------------------------------------------------
--- -----------------------------------------------------------------------------
diff --git a/test/TestFrontend.hs b/test/TestFrontend.hs
new file mode 100644
--- /dev/null
+++ b/test/TestFrontend.hs
@@ -0,0 +1,359 @@
+--------------------------------------------------------------------------------
+-- Test Suite for the Curry Frontend
+--------------------------------------------------------------------------------
+--
+-- This Test Suite supports three kinds of tests:
+--
+-- 1) tests which should pass
+-- 2) tests which should pass with a specific warning
+-- 3) tests which should fail yielding a specific error message
+--
+-- In order to add a test to this suite, proceed as follows:
+--
+-- 1) Store your test code in a file (please use descriptive names) and put it
+--    in the corresponding subfolder (i.e. test/pass for passing tests,
+--    test/fail for failing tests and test/warning for passing tests producing
+--    warnings)
+-- 2) Extend the corresponding test information list (there is one for each test
+--    group at the end of this file) with the required information (i.e. name of
+--    the Curry module to be tested and expected warning/failure message(s))
+-- 3) Run 'cabal test'
+
+{-# LANGUAGE CPP #-}
+module TestFrontend (tests) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative    ((<$>))
+#endif
+import qualified Control.Exception as E (SomeException, catch)
+
+import           Data.List              (isInfixOf, sort)
+import qualified Data.Map as Map        (insert)
+import           Distribution.TestSuite ( Test (..), TestInstance (..)
+                                        , Progress (..), Result (..)
+                                        , OptionDescr)
+import           System.FilePath        (FilePath, (</>), (<.>))
+
+import           Curry.Base.Message     (Message, message, ppMessages, ppError)
+import           Curry.Base.Monad       (CYIO, runCYIO)
+import           Curry.Base.Pretty      (text)
+import qualified CompilerOpts as CO     ( Options (..), WarnOpts (..)
+                                        , WarnFlag (..), Verbosity (VerbQuiet)
+                                        , CppOpts (..)
+                                        , defaultOptions)
+import CurryBuilder                     (buildCurry)
+
+tests :: IO [Test]
+tests = return [failingTests, passingTests, warningTests]
+
+runSecure :: CYIO a -> IO (Either [Message] (a, [Message]))
+runSecure act = runCYIO act `E.catch` handler
+  where handler e = return (Left [message $ text $ show (e :: E.SomeException)])
+
+-- Execute a test by calling cymake
+runTest :: CO.Options -> String -> [String] -> IO Progress
+runTest opts test errorMsgs =
+  if null errorMsgs
+    then passOrFail <$> runSecure (buildCurry opts' test)
+    else catchE     <$> runSecure (buildCurry opts' test)
+  where
+    cppOpts       = CO.optCppOpts opts
+    cppDefs       = Map.insert "__PAKCS__" 3 (CO.cppDefinitions cppOpts)
+    wOpts         = CO.optWarnOpts opts
+    wFlags        =   CO.WarnUnusedBindings
+                    : CO.WarnUnusedGlobalBindings
+                    : CO.wnWarnFlags wOpts
+    opts'         = opts { CO.optForce    = True
+                         , CO.optWarnOpts = wOpts
+                            { CO.wnWarnFlags    = wFlags  }
+                         , CO.optCppOpts  = cppOpts
+                            { CO.cppDefinitions = cppDefs }
+                         }
+    passOrFail    = Finished . either fail (const Pass)
+    catchE        = Finished . either pass (pass . snd)
+    fail msgs
+      | null msgs = Pass
+      | otherwise = Fail $ "An unexpected failure occurred: " ++
+                           showMessages msgs
+    pass msgs
+      | null otherMsgs = Pass
+      | otherwise      = Fail $ "Expected warnings/failures did not occur: " ++
+                                unwords otherMsgs
+      where
+        errorStr  = showMessages msgs
+        otherMsgs = filter (not . flip isInfixOf errorStr) errorMsgs
+
+showMessages :: [Message] -> String
+showMessages = show . ppMessages ppError . sort
+
+-- group of test which should fail yielding a specific error message
+failingTests :: Test
+failingTests = Group { groupName    = "Failing Tests"
+, concurrently = False
+, groupTests   = map (mkTest "test/fail/") failInfos
+}
+
+-- group of tests which should pass
+passingTests :: Test
+passingTests = Group { groupName    = "Passing Tests"
+                     , concurrently = False
+                     , groupTests   = map (mkTest "test/pass/") passInfos
+                     }
+
+-- group of tests which should pass producing a specific warning message
+warningTests :: Test
+warningTests = Group { groupName    = "Warning Tests"
+                     , concurrently = False
+                     , groupTests   = map (mkTest "test/warning/") warnInfos
+                     }
+
+-- create a new test
+mkTest :: FilePath -> TestInfo -> Test
+mkTest path (testName, testTags, testOpts, mSetOpts, errorMsgs) =
+  let file = path </> testName <.> "curry"
+      opts = CO.defaultOptions { CO.optVerbosity   = CO.VerbQuiet
+                               , CO.optImportPaths = [path]
+                               }
+      test = TestInstance
+        { run       = runTest opts file errorMsgs
+        , name      = testName
+        , tags      = testTags
+        , options   = testOpts
+        , setOption = maybe (\_ _ -> Right test) id mSetOpts
+        }
+  in Test test
+
+-- Information for a test instance:
+-- * name of test
+-- * tags to classify a test
+-- * options
+-- * function to set options
+-- * optional warning/error message which should be thrown on execution of test
+type TestInfo = (String, [String], [OptionDescr], Maybe SetOption, [String])
+
+type SetOption = String -> String -> Either String TestInstance
+
+--------------------------------------------------------------------------------
+-- Definition of failing tests
+--------------------------------------------------------------------------------
+
+-- generate a simple failing test
+mkFailTest :: String -> [String] -> TestInfo
+mkFailTest name errorMsgs = (name, [], [], Nothing, errorMsgs)
+
+-- To add a failing test to the test suite simply add the module name of the
+-- test code and the expected error message(s) to the following list
+failInfos :: [TestInfo]
+failInfos = map (uncurry mkFailTest)
+  [ ("DataFail",
+      [ "Missing instance for Prelude.Data Test1"
+      , "Missing instance for Prelude.Data (Test2"
+      , "Missing instance for Prelude.Data (Test2"
+      , "Missing instance for Prelude.Data Test1"
+      ]
+    )
+  , ("ErrorMultipleSignature", ["More than one type signature for `f'"])
+  , ("ErrorMultipleSignature", ["More than one type signature for `f'"])
+  , ("ExportCheck/AmbiguousName", ["Ambiguous name `not'"])
+  , ("ExportCheck/AmbiguousType", ["Ambiguous type `Bool'"])
+  , ("ExportCheck/ModuleNotImported", ["Module `Foo' not imported"])
+  , ("ExportCheck/MultipleName", ["Multiple exports of name `not'"])
+  , ("ExportCheck/MultipleType", ["Multiple exports of type `Bool'"])
+  , ("ExportCheck/NoDataType", ["`Foo' is not a data type"])
+  , ("ExportCheck/OutsideTypeConstructor", ["Data constructor `False' outside type export in export list"])
+  , ("ExportCheck/OutsideTypeLabel", ["Label `value' outside type export in export list"])
+  , ("ExportCheck/UndefinedElement", ["`foo' is not a constructor or label of type `Bool'"])
+  , ("ExportCheck/UndefinedName", ["Undefined name `foo' in export list"])
+  , ("ExportCheck/UndefinedType", ["Undefined type or class `Foo' in export list"])
+  , ("FP_Cyclic", ["Function `g' used in functional pattern depends on `f'  causing a cyclic dependency"])
+  , ("FP_Restrictions",
+      [ "Functional patterns are not supported inside a case expression"
+      , "Functional patterns are not supported inside a case expression"
+      , "Functional patterns are not supported inside a list comprehension"
+      , "Functional patterns are not supported inside a do sequence"
+      ]
+    )
+  , ("HaskellRecordsFail", ["Unexpected token `,'"])
+  , ("FP_NonGlobal", ["Function `f1' in functional pattern is not global"])
+  , ("ImportError",
+      [ "Module Prelude does not export foo"
+      , "Module Prelude does not export bar"
+      ]
+    )
+  , ("KindCheck",
+      [ "Type variable a occurs more than once in left hand side of type declaration"
+      , "Type variable b occurs more than once in left hand side of type declaration"
+      ]
+    )
+  , ("MissingLabelInUpdate",
+      ["Undefined record label `l1'"] )
+  , ("MultipleArities", ["Equations for `test' have different arities"])
+  , ("MultipleDefinitions",
+      ["Multiple definitions for data/record constructor `Rec'"]
+    )
+  , ("MultiplePrecedence",
+      ["More than one fixity declaration for `f'"]
+    )
+  , ("PatternRestrictions",
+      [ "Lazy patterns are not supported inside a functional pattern"]
+    )
+  , ("PragmaError", ["Unknown language extension"])
+  , ("PrecedenceRange", ["Precedence out of range"])
+  , ("RecordLabelIDs", ["Multiple declarations of `RecordLabelIDs.id'"])
+  , ("RecursiveTypeSyn", ["Mutually recursive synonym and/or renaming types A and B (line 12.6)"])
+  , ("SyntaxError", ["Type error in application"])
+  , ("TypedFreeVariables",
+      ["Variable x has a polymorphic type", "Type error in equation"]
+    )
+  , ("TypeError1", ["Type error in explicitly typed expression"])
+  , ("TypeError2", ["Missing instance for Prelude.Num Prelude.Bool"])
+  , ("TypeSigTooGeneral",
+      [ "Type signature too general"
+      , "Function: h"
+      , "Type signature too general"
+      , "Function: g'"
+      , "Type signature too general"
+      , "Function: n"
+      ]
+    )
+  , ("UnboundTypeVariable",
+      [ "Unbound type variable b"
+      , "Unbound type variable c"
+      ]
+    )
+  ]
+
+--------------------------------------------------------------------------------
+-- Definition of passing tests
+--------------------------------------------------------------------------------
+
+-- generate a simple passing test
+mkPassTest :: String -> TestInfo
+mkPassTest = flip mkFailTest []
+
+-- To add a passing test to the test suite simply add the module name of the
+-- test code to the following list
+passInfos :: [TestInfo]
+passInfos = map mkPassTest
+  [ "AbstractCurryBug"
+  , "ACVisibility"
+  , "AnonymVar"
+  , "CaseComplete"
+  , "DataPass"
+  , "DefaultPrecedence"
+  , "Dequeue"
+  , "EmptyWhere"
+  , "ExplicitLayout"
+  , "FCase"
+  , "FP_Lifting"
+  , "FP_NonCyclic"
+  , "FP_NonLinearity"
+  , "FunctionalPatterns"
+  , "HaskellRecords"
+  , "HaskellRecordsPass"
+  , "Hierarchical"
+  , "ImportRestricted"
+  , "ImportRestricted2"
+  , "Infix"
+  , "Inline"
+  , "Lambda"
+  , "Maybe"
+  , "NegLit"
+  , "Newtype1"
+  , "Newtype2"
+  , "NonLinearLHS"
+  , "OperatorDefinition"
+  , "PatDecl"
+  , "Prelude"
+  , "Pretty"
+  , "RecordsPolymorphism"
+  , "RecordTest1"
+  , "RecordTest2"
+  , "RecordTest3"
+  , "ReexportTest"
+  , "SelfExport"
+  , "SpaceLeak"
+  , "TyConsTest"
+  , "TypedExpr"
+  , "UntypedAcy"
+  , "Unzip"
+  , "WhereAfterDo"
+  ]
+
+--------------------------------------------------------------------------------
+-- Definition of warning tests
+--------------------------------------------------------------------------------
+
+-- To add a warning test to the test suite simply add the module name of the
+-- test code and the expected warning message(s) to the following list
+warnInfos :: [TestInfo]
+warnInfos = map (uncurry mkFailTest)
+  [
+    ("AliasClash",
+      [ "The module alias `AliasClash' overlaps with the current module name"
+      , "Overlapping module aliases"
+      , "Module List is imported more than once"
+      ]
+    )
+  , ("Case1", ["Pattern matches are non-exhaustive", "In an equation for `h'"])
+  , ("Case2",
+      [ "An fcase expression is potentially non-deterministic due to overlapping rules"
+      , "Pattern matches are non-exhaustive", "In an fcase alternative"
+      , "In a case alternative", "In an equation for `fp'"
+      , "Pattern matches are potentially unreachable"
+      , "Function `fp' is potentially non-deterministic due to overlapping rules"
+      , "Pattern matches are non-exhaustive"
+      ]
+    )
+  , ("CaseModeH",
+      [ "Wrong case mode in symbol `B' due to selected case mode `haskell`, try renaming to b instead"
+      , "Wrong case mode in symbol `B' due to selected case mode `haskell`, try renaming to b instead"
+      , "Wrong case mode in symbol `Xs' due to selected case mode `haskell`, try renaming to xs instead"
+      , "Wrong case mode in symbol `c' due to selected case mode `haskell`, try renaming to C instead"
+      , "Wrong case mode in symbol `f' due to selected case mode `haskell`, try renaming to F instead"
+      ]
+    )
+  , ("CaseModeP",
+      [ "Wrong case mode in symbol `a' due to selected case mode `prolog`, try renaming to A instead"
+      , "Wrong case mode in symbol `a' due to selected case mode `prolog`, try renaming to A instead"
+      , "Wrong case mode in symbol `mf' due to selected case mode `prolog`, try renaming to Mf instead"
+      , "Wrong case mode in symbol `E' due to selected case mode `prolog`, try renaming to e instead"
+      ]
+    )
+  , ("CheckSignature",
+      [ "Top-level binding with no type signature: hw"
+      , "Top-level binding with no type signature: f"
+      , "Unused declaration of variable `answer'"
+      ]
+    )
+  , ("NonExhaustivePattern",
+      [ "Pattern matches are non-exhaustive", "In a case alternative"
+      , "In an equation for `test2'", "In an equation for `and'"
+      , "In an equation for `plus'", "In an equation for `len2'"
+      , "In an equation for `tuple'", "In an equation for `tuple2'"
+      , "In an equation for `g'", "In an equation for `rec'"]
+    )
+  , ("NoRedundant", [])
+  , ("OverlappingPatterns",
+      [ "Pattern matches are potentially unreachable", "In a case alternative"
+      , "An fcase expression is potentially non-deterministic due to overlapping rules"
+      , "Function `i' is potentially non-deterministic due to overlapping rules"
+      , "Function `j' is potentially non-deterministic due to overlapping rules"
+      , "Function `k' is potentially non-deterministic due to overlapping rules"
+      ]
+    )
+  , ("QualRedundant",
+      [ "Redundant context in type signature for function `f': 'P.Eq a'"]
+    )
+  , ("Redundant",
+      [ "Redundant context in type signature for function `f': 'Eq a'"]
+    )
+  , ("ShadowingSymbols",
+      [ "Unused declaration of variable `x'", "Shadowing symbol `x'"])
+  , ("TabCharacter",
+      [ "Tab character"])
+  , ("UnexportedFunction",
+      [ "Unused declaration of variable `q'"
+      , "Unused declaration of variable `g'" ]
+    )
+  ]
