diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+1
+
+- Move to use `Distribution.SPDX` (from `Cabal`) types.
+
 0.2.2.0
 
 - Update license list to v2.6
diff --git a/bench/Bench.hs b/bench/Bench.hs
new file mode 100644
--- /dev/null
+++ b/bench/Bench.hs
@@ -0,0 +1,39 @@
+module Main (main) where
+
+import Generators
+import Test.QuickCheck
+import Test.QuickCheck.Random (mkQCGen)
+
+import Distribution.SPDX
+import Distribution.SPDX.Extra
+
+main :: IO ()
+main = quickCheckWith args $
+    forAll (scaleGen (`div` 3) exprGen) $ \e' -> case e' of
+        NONE      -> True
+        License e -> isOsiApprovedExpr e == isOsiApprovedExpr' e
+  where
+    args = stdArgs
+        { replay = Just (mkQCGen 1337, 0)
+        , maxSuccess = 500
+        }
+
+osiLicenseIds :: [LicenseId]
+osiLicenseIds = filter licenseIsOsiApproved [minBound .. maxBound]
+
+osiLicenseExpr :: LicenseExpression
+osiLicenseExpr = foldr1 EAnd $ map (\l -> ELicense (ELicenseId l) Nothing) osiLicenseIds
+
+isOsiApprovedExpr :: LicenseExpression -> Bool
+isOsiApprovedExpr (ELicense _ (Just _)) = False
+isOsiApprovedExpr (ELicense sl Nothing) = simple sl
+isOsiApprovedExpr (EAnd e1 e2)          = isOsiApprovedExpr e1 && isOsiApprovedExpr e2
+isOsiApprovedExpr (EOr e1 e2)           = isOsiApprovedExpr e1 || isOsiApprovedExpr e2
+
+simple :: SimpleLicenseExpression -> Bool
+simple (ELicenseId i)     = licenseIsOsiApproved i
+simple (ELicenseIdPlus _) = False -- we don't know ranges
+simple (ELicenseRef _)    = False
+
+isOsiApprovedExpr' :: LicenseExpression -> Bool
+isOsiApprovedExpr' e = License e `satisfies` License osiLicenseExpr
diff --git a/spdx.cabal b/spdx.cabal
--- a/spdx.cabal
+++ b/spdx.cabal
@@ -1,24 +1,28 @@
+cabal-version:       2.2
 name:                spdx
-version:             0.2.2.0
-synopsis:            SPDX license expression language
-description:         Implementation of <http://spdx.org/sites/spdx/files/SPDX-2.0.pdf SPDX> related functionality.
+version:             1
+
+synopsis:            SPDX license expression language, Extras
+category:            Data
+description:         Cabal provides SPDX types. This package provides some extras.
+
 homepage:            https://github.com/phadej/spdx
-license:             BSD3
+license:             BSD-3-Clause
 license-file:        LICENSE
 author:              Oleg Grenrus <oleg.grenrus@iki.fi>
 maintainer:          Oleg Grenrus <oleg.grenrus@iki.fi>
-copyright:           (c) 2015 Oleg Grenrus
-category:            Data
+copyright:           (c) 2015-2018 Oleg Grenrus
 build-type:          Simple
+
 extra-source-files:  README.md CHANGELOG.md
-cabal-version:       >=1.10
 tested-with:
-  GHC==7.4.2,
-  GHC==7.6.3,
-  GHC==7.8.4,
-  GHC==7.10.3,
-  GHC==8.0.2,
-  GHC==8.2.1
+  GHC ==7.6.3
+   || ==7.8.4
+   || ==7.10.3
+   || ==8.0.2
+   || ==8.2.2
+   || ==8.4.4
+   || ==8.6.1
 
 source-repository head
   type: git
@@ -26,27 +30,22 @@
 
 library
   default-language:    Haskell98
-  exposed-modules:     Data.SPDX,
-                       Data.SPDX.LatticeSyntax
-  other-modules:       Data.SPDX.Licenses,
-                       Data.SPDX.Types,
-                       Data.SPDX.Parser,
-                       Data.SPDX.Pretty,
-                       Data.SPDX.Ranges
-  other-extensions:    CPP
-                       DeriveFunctor,
-                       DeriveFoldable,
-                       DeriveTraversable,
-                       DeriveDataTypeable
-  if impl(ghc >=7.2)
-    other-extensions:  DeriveGeneric
+  exposed-modules:
+    Distribution.SPDX.Extra
+    Distribution.SPDX.Extra.Internal
+  other-extensions:
+    CPP
+    DeriveFunctor,
+    DeriveFoldable,
+    DeriveTraversable,
+    DeriveDataTypeable
   hs-source-dirs:      src/
   ghc-options:         -Wall
-  build-depends:       base              >=4.2 && <4.11,
-                       transformers      >=0.3 && <0.6
-  if impl(ghc >=7.2 && <7.5)
-    build-depends: ghc-prim
-
+  build-depends:
+    , base              >=4.3.0.0 && <4.13
+    , Cabal             >=2.4.0.1 && <2.5
+    , containers        >=0.5.0.0 && <0.7
+    , transformers      >=0.3     && <0.6
 
 test-suite test
   type:                exitcode-stdio-1.0
@@ -55,7 +54,25 @@
   default-language:    Haskell98
   hs-source-dirs:      tests
   ghc-options:         -Wall
-  build-depends:       base              >=4.5  && <4.11,
-                       tasty             >=0.10 && <0.12,
-                       tasty-quickcheck  >=0.8  && <0.10,
-                       spdx
+  build-depends:
+    , base
+    , base-compat       ^>=0.10.5
+    , Cabal
+    , spdx
+    , tasty             ^>=1.1.0.4
+    , tasty-quickcheck  ^>=0.10
+
+benchmark bench
+  type:                exitcode-stdio-1.0
+  main-is:             Bench.hs
+  other-modules:       Generators
+  default-language:    Haskell98
+  hs-source-dirs:      tests bench
+  ghc-options:         -Wall
+  build-depends:
+    , base
+    , base-compat       ^>=0.10.5
+    , Cabal
+    , spdx
+    , QuickCheck       ^>=2.12.6.1
+    , tasty-quickcheck ^>=0.10
diff --git a/src/Data/SPDX.hs b/src/Data/SPDX.hs
deleted file mode 100644
--- a/src/Data/SPDX.hs
+++ /dev/null
@@ -1,93 +0,0 @@
-{-# LANGUAGE CPP #-}
-#if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE Safe #-}
-#endif
--- |
--- Module      : Data.SPDX
--- Description : SPDX licenses and expression language
--- Copyright   : (c) 2015 Oleg Grenrus
--- License     : BSD3
--- Maintainer  : Oleg Grenrus <oleg.grenrus@iki.fi>
---
-module Data.SPDX (
-  -- * Types
-    LicenseId
-  , getLicenseId
-  , LicenseExceptionId
-  , getLicenseExceptionId
-  , LicenseRef(..)
-  , LicenseExpression(..)
-  -- * Data
-  , licenses
-  , licenseIdentifiers
-  , mkLicenseId
-  , isOsiApproved
-  , licenseExceptions
-  -- ** Ranges
-  , licenseRanges
-  , lookupLicenseRange
-  -- * Parsing
-  , parseExpression
-  , unsafeParseExpr
-  -- * Prettifying
-  -- | Inverse of parsing
-  , prettyLicenseId
-  , prettyLicenseExceptionId
-  , prettyLicenseRef
-  , prettyLicenseExpression
-  -- * Logic
-  , satisfies
-  , equivalent
-  ) where
-
-import Data.SPDX.LatticeSyntax (LatticeSyntax(..))
-import qualified Data.SPDX.LatticeSyntax as LS
-import           Data.SPDX.Licenses
-import           Data.SPDX.Parser
-import           Data.SPDX.Pretty
-import           Data.SPDX.Ranges
-import           Data.SPDX.Types
-
-data Lic = Lic (Either LicenseRef LicenseId) (Maybe LicenseExceptionId)
-  deriving (Eq, Ord, Show, Read)
-
-exprToLSLic :: LicenseExpression -> LatticeSyntax Lic
-exprToLSLic (ELicense False l e) = LVar (Lic l e)
-exprToLSLic (ELicense True (Right l) e) = foldr1 LJoin $ map (\l' -> LVar $ Lic (Right l') e) $ lookupLicenseRange l
--- We don't know anything about newer license references
-exprToLSLic (ELicense True (Left l) e) = LVar (Lic (Left l) e)
-exprToLSLic (EConjunction a b) = LMeet (exprToLSLic a) (exprToLSLic b)
-exprToLSLic (EDisjunction a b) = LJoin (exprToLSLic a) (exprToLSLic b)
-
--- |
---
--- @⟦ satisfies a b ⟧ ≡ a ≥ b ≡ a ∧ b = b @
---
--- >>> unsafeParseExpr "GPL-3.0" `satisfies` unsafeParseExpr "ISC AND MIT"
--- False
---
--- >>> unsafeParseExpr "Zlib" `satisfies` unsafeParseExpr "ISC AND MIT AND Zlib"
--- True
---
--- >>> unsafeParseExpr "(MIT OR GPL-2.0)" `satisfies` unsafeParseExpr "(ISC AND MIT)"
--- True
---
--- >>> unsafeParseExpr "(MIT AND GPL-2.0)" `satisfies` unsafeParseExpr "(MIT AND GPL-2.0)"
--- True
---
--- >>> unsafeParseExpr "(MIT AND GPL-2.0)" `satisfies` unsafeParseExpr "(ISC AND GPL-2.0)"
--- False
-satisfies :: LicenseExpression -- ^ package license
-          -> LicenseExpression -- ^ license policy
-          -> Bool
-satisfies a b = exprToLSLic b `LS.preorder` exprToLSLic a
-
--- | Check wheather two 'LicenseExpression' are equivalent.
---
--- >>> unsafeParseExpr "(MIT AND GPL-2.0)" `equivalent` unsafeParseExpr "(GPL-2.0 AND MIT)"
--- True
---
--- >>> unsafeParseExpr "MIT" `equivalent` unsafeParseExpr "MIT OR BSD-3-Clause"
--- False
-equivalent :: LicenseExpression -> LicenseExpression -> Bool
-equivalent a b = exprToLSLic a `LS.equivalent` exprToLSLic b
diff --git a/src/Data/SPDX/LatticeSyntax.hs b/src/Data/SPDX/LatticeSyntax.hs
deleted file mode 100644
--- a/src/Data/SPDX/LatticeSyntax.hs
+++ /dev/null
@@ -1,151 +0,0 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE DeriveFoldable #-}
-{-# LANGUAGE DeriveTraversable #-}
-{-# LANGUAGE DeriveDataTypeable #-}
-#if __GLASGOW_HASKELL__ >= 701
-#if __GLASGOW_HASKELL__ >= 703
-{-# LANGUAGE Safe #-}
-#else
-{-# LANGUAGE Trustworthy #-}
-#endif
-#endif
--- |
--- Module      : Data.SPDX.LatticeSyntax
--- Description : General lattice tools
--- Copyright   : (c) 2015 Oleg Grenrus
--- License     : BSD3
--- Maintainer  : Oleg Grenrus <oleg.grenrus@iki.fi>
---
--- Inspired by <http://www.well-typed.com/blog/2014/12/simple-smt-solver/ Simple SMT Solver>.
---
--- In future this module will probably be moved into separate package.
-module Data.SPDX.LatticeSyntax (LatticeSyntax(..), dual, freeVars, equivalent, preorder, satisfiable) where
-
-import Control.Applicative
-import Control.Monad
-import Control.Monad.Trans.State
-import Data.Data
-import Data.Foldable
-import Data.Traversable
-import Prelude hiding (all, or)
-
-data LatticeSyntax a = LVar a
-                     | LBound Bool
-                     | LJoin (LatticeSyntax a) (LatticeSyntax a)
-                     | LMeet (LatticeSyntax a) (LatticeSyntax a)
-  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable, Typeable, Data)
-
-instance Applicative LatticeSyntax where
-  pure  = return
-  (<*>) = ap
-
-instance Monad LatticeSyntax where
-  return = LVar
-  LVar x    >>= f = f x
-  LBound b  >>= _ = LBound b
-  LJoin a b >>= f = LJoin (a >>= f) (b >>= f)
-  LMeet a b >>= f = LMeet (a >>= f) (b >>= f)
-
-freeVars :: LatticeSyntax a -> [a]
-freeVars = toList
-
-dual :: LatticeSyntax a -> LatticeSyntax a
-dual (LVar v) = LVar v
-dual (LBound t) = LBound $ not t
-dual (LJoin a b) = LMeet (dual a) (dual b)
-dual (LMeet a b) = LJoin (dual a) (dual b)
-
--- | Test for equivalence.
---
--- >>> equivalent (LMeet (LVar 'a') (LVar 'b')) (LMeet (LVar 'b') (LVar 'a'))
--- True
---
--- >>> equivalent (LVar 'a') (LMeet (LVar 'a') (LVar 'a'))
--- True
---
--- >>> equivalent (LMeet (LVar 'a') (LVar 'b')) (LMeet (LVar 'b') (LVar 'b'))
--- False
-equivalent :: Eq a => LatticeSyntax a -> LatticeSyntax a -> Bool
-equivalent a b = all (uncurry (==)) . runEval $ p
-  where p = (,) <$> evalLattice a <*> evalLattice b
-
--- | Test for preorder.
---
--- @ a ≤ b ⇔ a ∨ b ≡ b ⇔ a ≡ a ∧ b @
---
--- >>> preorder (LVar 'a' `LMeet` LVar 'b') (LVar 'a')
--- True
---
--- >>> preorder (LVar 'a') (LVar 'a' `LMeet` LVar 'b')
--- False
-preorder :: Eq a => LatticeSyntax a -> LatticeSyntax a -> Bool
-preorder a b = (a `LJoin` b) `equivalent` b
-
--- | Return `True` if for some variable assigment expression evaluates to `True`.
-satisfiable :: Eq a => LatticeSyntax a -> Bool
-satisfiable = or . runEval . evalLattice
-
-newtype Eval v a = Eval { unEval :: StateT [(v, Bool)] [] a }
-
-instance Functor (Eval v) where
-  fmap = liftM
-
-instance Applicative (Eval v) where
-  pure = return
-  (<*>) = ap
-
-instance Alternative (Eval v) where
-  empty = mzero
-  (<|>) = mplus
-
-instance Monad (Eval v) where
-  return = Eval . return
-  Eval m >>= k = Eval $ m >>= unEval . k
-
-instance MonadPlus (Eval v) where
-  mzero = Eval mzero
-  Eval a `mplus` Eval b = Eval $ a `mplus` b
-
-runEval :: Eval v a -> [a]
-runEval act = evalStateT (unEval act) []
-
-evalLattice :: Eq v => LatticeSyntax v -> Eval v Bool
-evalLattice (LVar v)    = guess v
-evalLattice (LBound b)  = return b
-evalLattice (LJoin a b) = evalLattice a ||^ evalLattice b
-evalLattice (LMeet a b) = evalLattice a &&^ evalLattice b
-
-guess :: Eq v => v -> Eval v Bool
-guess v = Eval $ do
-  st <- get
-  let remember b = put ((v, b) : st) >> return b
-  case lookup v st of
-    Just b  -> return b
-    Nothing -> remember True <|> remember False
-
--- From Control.Monad.Extra of extra
-
--- | Like @if@, but where the test can be monadic.
-ifM :: Monad m => m Bool -> m a -> m a -> m a
-ifM b t f = do b' <- b; if b' then t else f
-
--- | The lazy '||' operator lifted to a monad. If the first
---   argument evaluates to 'True' the second argument will not
---   be evaluated.
---
--- > Just True  ||^ undefined  == Just True
--- > Just False ||^ Just True  == Just True
--- > Just False ||^ Just False == Just False
-(||^) :: Monad m => m Bool -> m Bool -> m Bool
-(||^) a b = ifM a (return True) b
-
--- | The lazy '&&' operator lifted to a monad. If the first
---   argument evaluates to 'False' the second argument will not
---   be evaluated.
---
--- > Just False &&^ undefined  == Just False
--- > Just True  &&^ Just True  == Just True
--- > Just True  &&^ Just False == Just False
-(&&^) :: Monad m => m Bool -> m Bool -> m Bool
-(&&^) a b = ifM a b (return False)
diff --git a/src/Data/SPDX/Licenses.hs b/src/Data/SPDX/Licenses.hs
deleted file mode 100644
--- a/src/Data/SPDX/Licenses.hs
+++ /dev/null
@@ -1,404 +0,0 @@
-{-# LANGUAGE CPP #-}
-#if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE Safe #-}
-#endif
-module Data.SPDX.Licenses (
-    licenses
-  , licenseIdentifiers
-  , mkLicenseId
-  , isOsiApproved
-  , licenseExceptions
-  ) where
-
-import Data.Foldable
-import Data.Maybe
-
-import Data.SPDX.Types
-
-licenseExceptions :: [LicenseExceptionId]
-licenseExceptions = map LicenseExceptionId
-    [ "389-exception"
-    , "Autoconf-exception-2.0"
-    , "Autoconf-exception-3.0"
-    , "Bison-exception-2.2"
-    , "Classpath-exception-2.0"
-    , "CLISP-exception-2.0"
-    , "DigiRule-FOSS-exception"
-    , "eCos-exception-2.0"
-    , "Fawkes-Runtime-exception"
-    , "FLTK-exception"
-    , "Font-exception-2.0"
-    , "freertos-exception-2.0"
-    , "GCC-exception-2.0"
-    , "GCC-exception-3.1"
-    , "gnu-javamail-exception"
-    , "i2p-gpl-java-exception"
-    , "Libtool-exception"
-    , "LZMA-exception"
-    , "mif-exception"
-    , "Nokia-Qt-exception-1.1"
-    , "OCCT-exception-1.0"
-    , "openvpn-openssl-exception"
-    , "Qwt-exception-1.0"
-    , "u-boot-exception-2.0"
-    , "WxWindows-exception-3.1"
-    ]
-
--- | A list of SPDX licenses identifiers.
---
--- See <http://spdx.org/licenses/>.
-licenseIdentifiers :: [LicenseId]
-licenseIdentifiers = map fstOf3 licenses
-
-fstOf3 :: (a, b, c) -> a
-fstOf3 (x,_,_) = x
-
---sndOf3 :: (a, b, c) -> b
---sndOf3 (_,x,_) = x
-
-trdOf3 :: (a, b, c) -> c
-trdOf3 (_,_,x) = x
-
--- | Lookup `LicenseId` by string representation
-mkLicenseId :: String -> Maybe LicenseId
-mkLicenseId str = find ((== str) . getLicenseId) licenseIdentifiers
-
--- | Whether license is OSI approved
---
--- See <http://opensource.org/licenses/alphabetical>
-isOsiApproved :: LicenseId -> Bool
-isOsiApproved l = trdOf3 $ fromJust $ find ((==l) . fstOf3) licenses
-
--- | A list of `LicenseId`, license name and whether the license is OSI approved.
---
--- See <http://spdx.org/licenses/>.
-licenses :: [(LicenseId, String, Bool)]
-licenses =
-  [ (LicenseId "0BSD", "BSD Zero Clause License", True)
-  , (LicenseId "AAL", "Attribution Assurance License", True)
-  , (LicenseId "ADSL", "Amazon Digital Services License", False)
-  , (LicenseId "AFL-1.1", "Academic Free License v1.1", True)
-  , (LicenseId "AFL-1.2", "Academic Free License v1.2", True)
-  , (LicenseId "AFL-2.0", "Academic Free License v2.0", True)
-  , (LicenseId "AFL-2.1", "Academic Free License v2.1", True)
-  , (LicenseId "AFL-3.0", "Academic Free License v3.0", True)
-  , (LicenseId "AGPL-1.0", "Affero General Public License v1.0", False)
-  , (LicenseId "AGPL-3.0", "GNU Affero General Public License v3.0", True)
-  , (LicenseId "AMDPLPA", "AMD's plpa_map.c License", False)
-  , (LicenseId "AML", "Apple MIT License", False)
-  , (LicenseId "AMPAS", "Academy of Motion Picture Arts and Sciences BSD", False)
-  , (LicenseId "ANTLR-PD", "ANTLR Software Rights Notice", False)
-  , (LicenseId "APAFML", "Adobe Postscript AFM License", False)
-  , (LicenseId "APL-1.0", "Adaptive Public License 1.0", True)
-  , (LicenseId "APSL-1.0", "Apple Public Source License 1.0", True)
-  , (LicenseId "APSL-1.1", "Apple Public Source License 1.1", True)
-  , (LicenseId "APSL-1.2", "Apple Public Source License 1.2", True)
-  , (LicenseId "APSL-2.0", "Apple Public Source License 2.0", True)
-  , (LicenseId "Abstyles", "Abstyles License", False)
-  , (LicenseId "Adobe-2006", "Adobe Systems Incorporated Source Code License Agreement", False)
-  , (LicenseId "Adobe-Glyph", "Adobe Glyph List License", False)
-  , (LicenseId "Afmparse", "Afmparse License", False)
-  , (LicenseId "Aladdin", "Aladdin Free Public License", False)
-  , (LicenseId "Apache-1.0", "Apache License 1.0", False)
-  , (LicenseId "Apache-1.1", "Apache License 1.1", True)
-  , (LicenseId "Apache-2.0", "Apache License 2.0", True)
-  , (LicenseId "Artistic-1.0", "Artistic License 1.0", True)
-  , (LicenseId "Artistic-1.0-Perl", "Artistic License 1.0 (Perl)", True)
-  , (LicenseId "Artistic-1.0-cl8", "Artistic License 1.0 w/clause 8", True)
-  , (LicenseId "Artistic-2.0", "Artistic License 2.0", True)
-  , (LicenseId "BSD-2-Clause", "BSD 2-clause \"Simplified\" License", True)
-  , (LicenseId "BSD-2-Clause-FreeBSD", "BSD 2-clause FreeBSD License", False)
-  , (LicenseId "BSD-2-Clause-NetBSD", "BSD 2-clause NetBSD License", False)
-  , (LicenseId "BSD-3-Clause", "BSD 3-clause \"New\" or \"Revised\" License", True)
-  , (LicenseId "BSD-3-Clause-Attribution", "BSD with attribution", False)
-  , (LicenseId "BSD-3-Clause-Clear", "BSD 3-clause Clear License", False)
-  , (LicenseId "BSD-3-Clause-LBNL", "Lawrence Berkeley National Labs BSD variant license", False)
-  , (LicenseId "BSD-3-Clause-No-Nuclear-License", "BSD 3-Clause No Nuclear License", False)
-  , (LicenseId "BSD-3-Clause-No-Nuclear-License-2014", "BSD 3-Clause No Nuclear License 2014", False)
-  , (LicenseId "BSD-3-Clause-No-Nuclear-Warranty", "BSD 3-Clause No Nuclear Warranty", False)
-  , (LicenseId "BSD-4-Clause", "BSD 4-clause \"Original\" or \"Old\" License", False)
-  , (LicenseId "BSD-4-Clause-UC", "BSD-4-Clause (University of California-Specific)", False)
-  , (LicenseId "BSD-Protection", "BSD Protection License", False)
-  , (LicenseId "BSD-Source-Code", "BSD Source Code Attribution", False)
-  , (LicenseId "BSL-1.0", "Boost Software License 1.0", True)
-  , (LicenseId "Bahyph", "Bahyph License", False)
-  , (LicenseId "Barr", "Barr License", False)
-  , (LicenseId "Beerware", "Beerware License", False)
-  , (LicenseId "BitTorrent-1.0", "BitTorrent Open Source License v1.0", False)
-  , (LicenseId "BitTorrent-1.1", "BitTorrent Open Source License v1.1", False)
-  , (LicenseId "Borceux", "Borceux license", False)
-  , (LicenseId "CATOSL-1.1", "Computer Associates Trusted Open Source License 1.1", True)
-  , (LicenseId "CC-BY-1.0", "Creative Commons Attribution 1.0", False)
-  , (LicenseId "CC-BY-2.0", "Creative Commons Attribution 2.0", False)
-  , (LicenseId "CC-BY-2.5", "Creative Commons Attribution 2.5", False)
-  , (LicenseId "CC-BY-3.0", "Creative Commons Attribution 3.0", False)
-  , (LicenseId "CC-BY-4.0", "Creative Commons Attribution 4.0", False)
-  , (LicenseId "CC-BY-NC-1.0", "Creative Commons Attribution Non Commercial 1.0", False)
-  , (LicenseId "CC-BY-NC-2.0", "Creative Commons Attribution Non Commercial 2.0", False)
-  , (LicenseId "CC-BY-NC-2.5", "Creative Commons Attribution Non Commercial 2.5", False)
-  , (LicenseId "CC-BY-NC-3.0", "Creative Commons Attribution Non Commercial 3.0", False)
-  , (LicenseId "CC-BY-NC-4.0", "Creative Commons Attribution Non Commercial 4.0", False)
-  , (LicenseId "CC-BY-NC-ND-1.0", "Creative Commons Attribution Non Commercial No Derivatives 1.0", False)
-  , (LicenseId "CC-BY-NC-ND-2.0", "Creative Commons Attribution Non Commercial No Derivatives 2.0", False)
-  , (LicenseId "CC-BY-NC-ND-2.5", "Creative Commons Attribution Non Commercial No Derivatives 2.5", False)
-  , (LicenseId "CC-BY-NC-ND-3.0", "Creative Commons Attribution Non Commercial No Derivatives 3.0", False)
-  , (LicenseId "CC-BY-NC-ND-4.0", "Creative Commons Attribution Non Commercial No Derivatives 4.0", False)
-  , (LicenseId "CC-BY-NC-SA-1.0", "Creative Commons Attribution Non Commercial Share Alike 1.0", False)
-  , (LicenseId "CC-BY-NC-SA-2.0", "Creative Commons Attribution Non Commercial Share Alike 2.0", False)
-  , (LicenseId "CC-BY-NC-SA-2.5", "Creative Commons Attribution Non Commercial Share Alike 2.5", False)
-  , (LicenseId "CC-BY-NC-SA-3.0", "Creative Commons Attribution Non Commercial Share Alike 3.0", False)
-  , (LicenseId "CC-BY-NC-SA-4.0", "Creative Commons Attribution Non Commercial Share Alike 4.0", False)
-  , (LicenseId "CC-BY-ND-1.0", "Creative Commons Attribution No Derivatives 1.0", False)
-  , (LicenseId "CC-BY-ND-2.0", "Creative Commons Attribution No Derivatives 2.0", False)
-  , (LicenseId "CC-BY-ND-2.5", "Creative Commons Attribution No Derivatives 2.5", False)
-  , (LicenseId "CC-BY-ND-3.0", "Creative Commons Attribution No Derivatives 3.0", False)
-  , (LicenseId "CC-BY-ND-4.0", "Creative Commons Attribution No Derivatives 4.0", False)
-  , (LicenseId "CC-BY-SA-1.0", "Creative Commons Attribution Share Alike 1.0", False)
-  , (LicenseId "CC-BY-SA-2.0", "Creative Commons Attribution Share Alike 2.0", False)
-  , (LicenseId "CC-BY-SA-2.5", "Creative Commons Attribution Share Alike 2.5", False)
-  , (LicenseId "CC-BY-SA-3.0", "Creative Commons Attribution Share Alike 3.0", False)
-  , (LicenseId "CC-BY-SA-4.0", "Creative Commons Attribution Share Alike 4.0", False)
-  , (LicenseId "CC0-1.0", "Creative Commons Zero v1.0 Universal", False)
-  , (LicenseId "CDDL-1.0", "Common Development and Distribution License 1.0", True)
-  , (LicenseId "CDDL-1.1", "Common Development and Distribution License 1.1", False)
-  , (LicenseId "CECILL-1.0", "CeCILL Free Software License Agreement v1.0", False)
-  , (LicenseId "CECILL-1.1", "CeCILL Free Software License Agreement v1.1", False)
-  , (LicenseId "CECILL-2.0", "CeCILL Free Software License Agreement v2.0", False)
-  , (LicenseId "CECILL-2.1", "CeCILL Free Software License Agreement v2.1", True)
-  , (LicenseId "CECILL-B", "CeCILL-B Free Software License Agreement", False)
-  , (LicenseId "CECILL-C", "CeCILL-C Free Software License Agreement", False)
-  , (LicenseId "CNRI-Jython", "CNRI Jython License", False)
-  , (LicenseId "CNRI-Python", "CNRI Python License", True)
-  , (LicenseId "CNRI-Python-GPL-Compatible", "CNRI Python Open Source GPL Compatible License Agreement", False)
-  , (LicenseId "CPAL-1.0", "Common Public Attribution License 1.0", True)
-  , (LicenseId "CPL-1.0", "Common Public License 1.0", True)
-  , (LicenseId "CPOL-1.02", "Code Project Open License 1.02", False)
-  , (LicenseId "CUA-OPL-1.0", "CUA Office Public License v1.0", True)
-  , (LicenseId "Caldera", "Caldera License", False)
-  , (LicenseId "ClArtistic", "Clarified Artistic License", False)
-  , (LicenseId "Condor-1.1", "Condor Public License v1.1", False)
-  , (LicenseId "Crossword", "Crossword License", False)
-  , (LicenseId "CrystalStacker", "CrystalStacker License", False)
-  , (LicenseId "Cube", "Cube License", False)
-  , (LicenseId "D-FSL-1.0", "Deutsche Freie Software Lizenz", False)
-  , (LicenseId "DOC", "DOC License", False)
-  , (LicenseId "DSDP", "DSDP License", False)
-  , (LicenseId "Dotseqn", "Dotseqn License", False)
-  , (LicenseId "ECL-1.0", "Educational Community License v1.0", True)
-  , (LicenseId "ECL-2.0", "Educational Community License v2.0", True)
-  , (LicenseId "EFL-1.0", "Eiffel Forum License v1.0", True)
-  , (LicenseId "EFL-2.0", "Eiffel Forum License v2.0", True)
-  , (LicenseId "EPL-1.0", "Eclipse Public License 1.0", True)
-  , (LicenseId "EUDatagrid", "EU DataGrid Software License", True)
-  , (LicenseId "EUPL-1.0", "European Union Public License 1.0", False)
-  , (LicenseId "EUPL-1.1", "European Union Public License 1.1", True)
-  , (LicenseId "Entessa", "Entessa Public License v1.0", True)
-  , (LicenseId "ErlPL-1.1", "Erlang Public License v1.1", False)
-  , (LicenseId "Eurosym", "Eurosym License", False)
-  , (LicenseId "FSFAP", "FSF All Permissive License", False)
-  , (LicenseId "FSFUL", "FSF Unlimited License", False)
-  , (LicenseId "FSFULLR", "FSF Unlimited License (with License Retention)", False)
-  , (LicenseId "FTL", "Freetype Project License", False)
-  , (LicenseId "Fair", "Fair License", True)
-  , (LicenseId "Frameworx-1.0", "Frameworx Open License 1.0", True)
-  , (LicenseId "FreeImage", "FreeImage Public License v1.0", False)
-  , (LicenseId "GFDL-1.1", "GNU Free Documentation License v1.1", False)
-  , (LicenseId "GFDL-1.2", "GNU Free Documentation License v1.2", False)
-  , (LicenseId "GFDL-1.3", "GNU Free Documentation License v1.3", False)
-  , (LicenseId "GL2PS", "GL2PS License", False)
-  , (LicenseId "GPL-1.0", "GNU General Public License v1.0 only", False)
-  , (LicenseId "GPL-2.0", "GNU General Public License v2.0 only", True)
-  , (LicenseId "GPL-3.0", "GNU General Public License v3.0 only", True)
-  , (LicenseId "Giftware", "Giftware License", False)
-  , (LicenseId "Glide", "3dfx Glide License", False)
-  , (LicenseId "Glulxe", "Glulxe License", False)
-  , (LicenseId "HPND", "Historic Permission Notice and Disclaimer", True)
-  , (LicenseId "HaskellReport", "Haskell Language Report License", False)
-  , (LicenseId "IBM-pibs", "IBM PowerPC Initialization and Boot Software", False)
-  , (LicenseId "ICU", "ICU License", False)
-  , (LicenseId "IJG", "Independent JPEG Group License", False)
-  , (LicenseId "IPA", "IPA Font License", True)
-  , (LicenseId "IPL-1.0", "IBM Public License v1.0", True)
-  , (LicenseId "ISC", "ISC License", True)
-  , (LicenseId "ImageMagick", "ImageMagick License", False)
-  , (LicenseId "Imlib2", "Imlib2 License", False)
-  , (LicenseId "Info-ZIP", "Info-ZIP License", False)
-  , (LicenseId "Intel", "Intel Open Source License", True)
-  , (LicenseId "Intel-ACPI", "Intel ACPI Software License Agreement", False)
-  , (LicenseId "Interbase-1.0", "Interbase Public License v1.0", False)
-  , (LicenseId "JSON", "JSON License", False)
-  , (LicenseId "JasPer-2.0", "JasPer License", False)
-  , (LicenseId "LAL-1.2", "Licence Art Libre 1.2", False)
-  , (LicenseId "LAL-1.3", "Licence Art Libre 1.3", False)
-  , (LicenseId "LGPL-2.0", "GNU Library General Public License v2 only", True)
-  , (LicenseId "LGPL-2.1", "GNU Lesser General Public License v2.1 only", True)
-  , (LicenseId "LGPL-3.0", "GNU Lesser General Public License v3.0 only", True)
-  , (LicenseId "LGPLLR", "Lesser General Public License For Linguistic Resources", False)
-  , (LicenseId "LPL-1.0", "Lucent Public License Version 1.0", True)
-  , (LicenseId "LPL-1.02", "Lucent Public License v1.02", True)
-  , (LicenseId "LPPL-1.0", "LaTeX Project Public License v1.0", False)
-  , (LicenseId "LPPL-1.1", "LaTeX Project Public License v1.1", False)
-  , (LicenseId "LPPL-1.2", "LaTeX Project Public License v1.2", False)
-  , (LicenseId "LPPL-1.3a", "LaTeX Project Public License v1.3a", False)
-  , (LicenseId "LPPL-1.3c", "LaTeX Project Public License v1.3c", True)
-  , (LicenseId "Latex2e", "Latex2e License", False)
-  , (LicenseId "Leptonica", "Leptonica License", False)
-  , (LicenseId "LiLiQ-P-1.1", "Licence Libre du Qu\233bec \8211 Permissive version 1.1", True)
-  , (LicenseId "LiLiQ-R-1.1", "Licence Libre du Qu\233bec \8211 R\233ciprocit\233 version 1.1", True)
-  , (LicenseId "LiLiQ-Rplus-1.1", "Licence Libre du Qu\233bec \8211 R\233ciprocit\233 forte version 1.1", True)
-  , (LicenseId "Libpng", "libpng License", False)
-  , (LicenseId "MIT", "MIT License", True)
-  , (LicenseId "MIT-CMU", "CMU License", False)
-  , (LicenseId "MIT-advertising", "Enlightenment License (e16)", False)
-  , (LicenseId "MIT-enna", "enna License", False)
-  , (LicenseId "MIT-feh", "feh License", False)
-  , (LicenseId "MITNFA", "MIT +no-false-attribs license", False)
-  , (LicenseId "MPL-1.0", "Mozilla Public License 1.0", True)
-  , (LicenseId "MPL-1.1", "Mozilla Public License 1.1", True)
-  , (LicenseId "MPL-2.0", "Mozilla Public License 2.0", True)
-  , (LicenseId "MPL-2.0-no-copyleft-exception", "Mozilla Public License 2.0 (no copyleft exception)", True)
-  , (LicenseId "MS-PL", "Microsoft Public License", True)
-  , (LicenseId "MS-RL", "Microsoft Reciprocal License", True)
-  , (LicenseId "MTLL", "Matrix Template Library License", False)
-  , (LicenseId "MakeIndex", "MakeIndex License", False)
-  , (LicenseId "MirOS", "MirOS Licence", True)
-  , (LicenseId "Motosoto", "Motosoto License", True)
-  , (LicenseId "Multics", "Multics License", True)
-  , (LicenseId "Mup", "Mup License", False)
-  , (LicenseId "NASA-1.3", "NASA Open Source Agreement 1.3", True)
-  , (LicenseId "NBPL-1.0", "Net Boolean Public License v1", False)
-  , (LicenseId "NCSA", "University of Illinois/NCSA Open Source License", True)
-  , (LicenseId "NGPL", "Nethack General Public License", True)
-  , (LicenseId "NLOD-1.0", "Norwegian Licence for Open Government Data", False)
-  , (LicenseId "NLPL", "No Limit Public License", False)
-  , (LicenseId "NOSL", "Netizen Open Source License", False)
-  , (LicenseId "NPL-1.0", "Netscape Public License v1.0", False)
-  , (LicenseId "NPL-1.1", "Netscape Public License v1.1", False)
-  , (LicenseId "NPOSL-3.0", "Non-Profit Open Software License 3.0", True)
-  , (LicenseId "NRL", "NRL License", False)
-  , (LicenseId "NTP", "NTP License", True)
-  , (LicenseId "Naumen", "Naumen Public License", True)
-  , (LicenseId "Net-SNMP", "Net-SNMP License", False)
-  , (LicenseId "NetCDF", "NetCDF license", False)
-  , (LicenseId "Newsletr", "Newsletr License", False)
-  , (LicenseId "Nokia", "Nokia Open Source License", True)
-  , (LicenseId "Noweb", "Noweb License", False)
-  , (LicenseId "Nunit", "Nunit License", False)
-  , (LicenseId "OCCT-PL", "Open CASCADE Technology Public License", False)
-  , (LicenseId "OCLC-2.0", "OCLC Research Public License 2.0", True)
-  , (LicenseId "ODbL-1.0", "ODC Open Database License v1.0", False)
-  , (LicenseId "OFL-1.0", "SIL Open Font License 1.0", False)
-  , (LicenseId "OFL-1.1", "SIL Open Font License 1.1", True)
-  , (LicenseId "OGTSL", "Open Group Test Suite License", True)
-  , (LicenseId "OLDAP-1.1", "Open LDAP Public License v1.1", False)
-  , (LicenseId "OLDAP-1.2", "Open LDAP Public License v1.2", False)
-  , (LicenseId "OLDAP-1.3", "Open LDAP Public License v1.3", False)
-  , (LicenseId "OLDAP-1.4", "Open LDAP Public License v1.4", False)
-  , (LicenseId "OLDAP-2.0", "Open LDAP Public License v2.0 (or possibly 2.0A and 2.0B)", False)
-  , (LicenseId "OLDAP-2.0.1", "Open LDAP Public License v2.0.1", False)
-  , (LicenseId "OLDAP-2.1", "Open LDAP Public License v2.1", False)
-  , (LicenseId "OLDAP-2.2", "Open LDAP Public License v2.2", False)
-  , (LicenseId "OLDAP-2.2.1", "Open LDAP Public License v2.2.1", False)
-  , (LicenseId "OLDAP-2.2.2", "Open LDAP Public License  2.2.2", False)
-  , (LicenseId "OLDAP-2.3", "Open LDAP Public License v2.3", False)
-  , (LicenseId "OLDAP-2.4", "Open LDAP Public License v2.4", False)
-  , (LicenseId "OLDAP-2.5", "Open LDAP Public License v2.5", False)
-  , (LicenseId "OLDAP-2.6", "Open LDAP Public License v2.6", False)
-  , (LicenseId "OLDAP-2.7", "Open LDAP Public License v2.7", False)
-  , (LicenseId "OLDAP-2.8", "Open LDAP Public License v2.8", False)
-  , (LicenseId "OML", "Open Market License", False)
-  , (LicenseId "OPL-1.0", "Open Public License v1.0", False)
-  , (LicenseId "OSET-PL-2.1", "OSET Public License version 2.1", True)
-  , (LicenseId "OSL-1.0", "Open Software License 1.0", True)
-  , (LicenseId "OSL-1.1", "Open Software License 1.1", False)
-  , (LicenseId "OSL-2.0", "Open Software License 2.0", True)
-  , (LicenseId "OSL-2.1", "Open Software License 2.1", True)
-  , (LicenseId "OSL-3.0", "Open Software License 3.0", True)
-  , (LicenseId "OpenSSL", "OpenSSL License", False)
-  , (LicenseId "PDDL-1.0", "ODC Public Domain Dedication & License 1.0", False)
-  , (LicenseId "PHP-3.0", "PHP License v3.0", True)
-  , (LicenseId "PHP-3.01", "PHP License v3.01", False)
-  , (LicenseId "Plexus", "Plexus Classworlds License", False)
-  , (LicenseId "PostgreSQL", "PostgreSQL License", True)
-  , (LicenseId "Python-2.0", "Python License 2.0", True)
-  , (LicenseId "QPL-1.0", "Q Public License 1.0", True)
-  , (LicenseId "Qhull", "Qhull License", False)
-  , (LicenseId "RHeCos-1.1", "Red Hat eCos Public License v1.1", False)
-  , (LicenseId "RPL-1.1", "Reciprocal Public License 1.1", True)
-  , (LicenseId "RPL-1.5", "Reciprocal Public License 1.5", True)
-  , (LicenseId "RPSL-1.0", "RealNetworks Public Source License v1.0", True)
-  , (LicenseId "RSA-MD", "RSA Message-Digest License ", False)
-  , (LicenseId "RSCPL", "Ricoh Source Code Public License", True)
-  , (LicenseId "Rdisc", "Rdisc License", False)
-  , (LicenseId "Ruby", "Ruby License", False)
-  , (LicenseId "SAX-PD", "Sax Public Domain Notice", False)
-  , (LicenseId "SCEA", "SCEA Shared Source License", False)
-  , (LicenseId "SGI-B-1.0", "SGI Free Software License B v1.0", False)
-  , (LicenseId "SGI-B-1.1", "SGI Free Software License B v1.1", False)
-  , (LicenseId "SGI-B-2.0", "SGI Free Software License B v2.0", False)
-  , (LicenseId "SISSL", "Sun Industry Standards Source License v1.1", True)
-  , (LicenseId "SISSL-1.2", "Sun Industry Standards Source License v1.2", False)
-  , (LicenseId "SMLNJ", "Standard ML of New Jersey License", False)
-  , (LicenseId "SMPPL", "Secure Messaging Protocol Public License", False)
-  , (LicenseId "SNIA", "SNIA Public License 1.1", False)
-  , (LicenseId "SPL-1.0", "Sun Public License v1.0", True)
-  , (LicenseId "SWL", "Scheme Widget Library (SWL) Software License Agreement", False)
-  , (LicenseId "Saxpath", "Saxpath License", False)
-  , (LicenseId "Sendmail", "Sendmail License", False)
-  , (LicenseId "SimPL-2.0", "Simple Public License 2.0", True)
-  , (LicenseId "Sleepycat", "Sleepycat License", True)
-  , (LicenseId "Spencer-86", "Spencer License 86", False)
-  , (LicenseId "Spencer-94", "Spencer License 94", False)
-  , (LicenseId "Spencer-99", "Spencer License 99", False)
-  , (LicenseId "SugarCRM-1.1.3", "SugarCRM Public License v1.1.3", False)
-  , (LicenseId "TCL", "TCL/TK License", False)
-  , (LicenseId "TCP-wrappers", "TCP Wrappers License", False)
-  , (LicenseId "TMate", "TMate Open Source License", False)
-  , (LicenseId "TORQUE-1.1", "TORQUE v2.5+ Software License v1.1", False)
-  , (LicenseId "TOSL", "Trusster Open Source License", False)
-  , (LicenseId "UPL-1.0", "Universal Permissive License v1.0", True)
-  , (LicenseId "Unicode-DFS-2015", "Unicode License Agreement - Data Files and Software (2015)", False)
-  , (LicenseId "Unicode-DFS-2016", "Unicode License Agreement - Data Files and Software (2016)", False)
-  , (LicenseId "Unicode-TOU", "Unicode Terms of Use", False)
-  , (LicenseId "Unlicense", "The Unlicense", False)
-  , (LicenseId "VOSTROM", "VOSTROM Public License for Open Source", False)
-  , (LicenseId "VSL-1.0", "Vovida Software License v1.0", True)
-  , (LicenseId "Vim", "Vim License", False)
-  , (LicenseId "W3C", "W3C Software Notice and License (2002-12-31)", True)
-  , (LicenseId "W3C-19980720", "W3C Software Notice and License (1998-07-20)", False)
-  , (LicenseId "W3C-20150513", "W3C Software Notice and Document License (2015-05-13)", False)
-  , (LicenseId "WTFPL", "Do What The F*ck You Want To Public License", False)
-  , (LicenseId "Watcom-1.0", "Sybase Open Watcom Public License 1.0", True)
-  , (LicenseId "Wsuipa", "Wsuipa License", False)
-  , (LicenseId "X11", "X11 License", False)
-  , (LicenseId "XFree86-1.1", "XFree86 License 1.1", False)
-  , (LicenseId "XSkat", "XSkat License", False)
-  , (LicenseId "Xerox", "Xerox License", False)
-  , (LicenseId "Xnet", "X.Net License", True)
-  , (LicenseId "YPL-1.0", "Yahoo! Public License v1.0", False)
-  , (LicenseId "YPL-1.1", "Yahoo! Public License v1.1", False)
-  , (LicenseId "ZPL-1.1", "Zope Public License 1.1", False)
-  , (LicenseId "ZPL-2.0", "Zope Public License 2.0", True)
-  , (LicenseId "ZPL-2.1", "Zope Public License 2.1", False)
-  , (LicenseId "Zed", "Zed License", False)
-  , (LicenseId "Zend-2.0", "Zend License v2.0", False)
-  , (LicenseId "Zimbra-1.3", "Zimbra Public License v1.3", False)
-  , (LicenseId "Zimbra-1.4", "Zimbra Public License v1.4", False)
-  , (LicenseId "Zlib", "zlib License", True)
-  , (LicenseId "bzip2-1.0.5", "bzip2 and libbzip2 License v1.0.5", False)
-  , (LicenseId "bzip2-1.0.6", "bzip2 and libbzip2 License v1.0.6", False)
-  , (LicenseId "curl", "curl License", False)
-  , (LicenseId "diffmark", "diffmark license", False)
-  , (LicenseId "dvipdfm", "dvipdfm License", False)
-  , (LicenseId "eGenix", "eGenix.com Public License 1.1.0", False)
-  , (LicenseId "gSOAP-1.3b", "gSOAP Public License v1.3b", False)
-  , (LicenseId "gnuplot", "gnuplot License", False)
-  , (LicenseId "iMatix", "iMatix Standard Function Library Agreement", False)
-  , (LicenseId "libtiff", "libtiff License", False)
-  , (LicenseId "mpich2", "mpich2 License", False)
-  , (LicenseId "psfrag", "psfrag License", False)
-  , (LicenseId "psutils", "psutils License", False)
-  , (LicenseId "xinetd", "xinetd License", False)
-  , (LicenseId "xpp", "XPP License", False)
-  , (LicenseId "zlib-acknowledgement", "zlib/libpng License with Acknowledgement", False)
-  ]
diff --git a/src/Data/SPDX/Parser.hs b/src/Data/SPDX/Parser.hs
deleted file mode 100644
--- a/src/Data/SPDX/Parser.hs
+++ /dev/null
@@ -1,99 +0,0 @@
-{-# LANGUAGE CPP #-}
-#if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE Safe #-}
-#endif
-module Data.SPDX.Parser (parseExpression, unsafeParseExpr) where
-
-#ifndef MIN_VERSION_base
-#define MIN_VERSION_base(x,y,z) 0
-#endif
-
-#if !MIN_VERSION_base(4,8,0)
-import Control.Applicative
-#endif
-
-import Control.Monad
-import Data.Char
-import Text.ParserCombinators.ReadP
-
-import Data.SPDX.Types
-import Data.SPDX.Licenses (licenseIdentifiers, licenseExceptions)
-
-infixl 4 `ap'`
-
--- ReadP isn't Applicative in old enough base
-ap' :: Monad m => m (a -> b) -> m a -> m b
-ap' = ap
-
-(<<) :: Monad m => m a -> m b -> m a
-ma << mb = do
-  a <- ma
-  _ <- mb
-  return a
-
-license :: ReadP LicenseId
-license = choice (map f licenseIdentifiers)
-  where f l = l <$ string (getLicenseId l)
-
-licenseException :: ReadP LicenseExceptionId
-licenseException = choice (map f licenseExceptions)
-  where f l = l <$ string (getLicenseExceptionId l)
-
-licenseRef :: ReadP LicenseRef
-licenseRef = l `mplus` d
-  where l = LicenseRef Nothing <$ string "LicenseRef-" `ap'` idString
-        d = (\docId licId -> LicenseRef (Just docId) licId) <$ string "DocumentRef-" `ap'` idString << char ':' << string "LicenseRef-" `ap'` idString
-
-mkLicense ::  ReadP (Either LicenseRef LicenseId) -> ReadP LicenseExpression
-mkLicense p = choice
-  [ (\l   -> ELicense False l Nothing)  <$> p
-  , (\l e -> ELicense False l (Just e)) <$> p << skipSpaces1 << string "WITH" << skipSpaces1 `ap'` licenseException
-  , (\l   -> ELicense True  l Nothing)  <$> p << char '+'
-  , (\l e -> ELicense True  l (Just e)) <$> p << char '+' << string " WITH " `ap'` licenseException
-  ]
-
-elicense :: ReadP LicenseExpression
-elicense = mkLicense (Right <$> license)
-
-elicenseRef :: ReadP LicenseExpression
-elicenseRef = mkLicense (Left <$> licenseRef)
-
-idString :: ReadP String
-idString = munch1 p
-  where p '.' = True
-        p '-' = True
-        p c   = isAlphaNum c
-
-skipSpaces1 :: ReadP ()
-skipSpaces1 = () <$ char ' ' << skipSpaces
-
-parens :: ReadP a -> ReadP a
-parens = between (char '(') (skipSpaces << char ')')
-
-terminal :: ReadP LicenseExpression
-terminal = choice [ elicense
-                  , elicenseRef
-                  , parens expression
-                  ]
-
-conjunction :: ReadP LicenseExpression
-conjunction = chainr1 terminal (EConjunction <$ skipSpaces1 << string "AND" << skipSpaces1)
-
-disjunction :: ReadP LicenseExpression
-disjunction = chainr1 conjunction (EDisjunction <$ skipSpaces1 << string "OR" << skipSpaces1)
-
-expression :: ReadP LicenseExpression
-expression = skipSpaces >> disjunction
-
--- | Parse SPDX License Expression
---
--- >>> parseExpression "LGPL-2.1 OR MIT"
--- [EDisjunction (ELicense False (Right (LicenseId "LGPL-2.1")) Nothing) (ELicense False (Right (LicenseId "MIT")) Nothing)]
-parseExpression :: String -> [LicenseExpression]
-parseExpression = map fst . readP_to_S (expression << skipSpaces << eof)
-
-unsafeParseExpr :: String -> LicenseExpression
-unsafeParseExpr s = f . parseExpression $ s
-  where f []      = error $ "Failed parse of license expression: " ++ s
-        f [l]     = l
-        f (_:_:_) = error $ "Ambigious parse of license expression: " ++ s
diff --git a/src/Data/SPDX/Pretty.hs b/src/Data/SPDX/Pretty.hs
deleted file mode 100644
--- a/src/Data/SPDX/Pretty.hs
+++ /dev/null
@@ -1,43 +0,0 @@
-{-# LANGUAGE CPP #-}
-#if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE Safe #-}
-#endif
--- | Parser inverse.
-module Data.SPDX.Pretty
-  ( prettyLicenseId
-  , prettyLicenseExceptionId
-  , prettyLicenseRef
-  , prettyLicenseExpression
-  ) where
-
-import Data.SPDX.Types
-
-prettyLicenseId :: LicenseId -> String
-prettyLicenseId = getLicenseId
-
-prettyLicenseExceptionId :: LicenseExceptionId -> String
-prettyLicenseExceptionId = getLicenseExceptionId
-
-prettyLicenseRef :: LicenseRef -> String
-prettyLicenseRef (LicenseRef Nothing r)  = "LicenseRef-" ++ r
-prettyLicenseRef (LicenseRef (Just d) r) = "DocumentRef-" ++ d ++ ":LicenseRef-" ++ r
-
-prettyLicenseExpression :: LicenseExpression -> String
-prettyLicenseExpression = pprExpr 1
-
-pprLicense :: Either LicenseRef LicenseId -> String
-pprLicense (Left ref) = prettyLicenseRef ref
-pprLicense (Right i)  = prettyLicenseId i
-
-pprExpr :: Int -> LicenseExpression -> String
-pprExpr _ (ELicense newer lic exc) = pprLicense lic ++ n ++ e
-  where n = if newer then "+" else ""
-        e = case exc of
-              Just exc' -> " WITH " ++ prettyLicenseExceptionId exc'
-              Nothing   -> ""
-pprExpr d (EConjunction e1 e2)     = parens (d < 0) $ pprExpr 0 e1 ++ " AND " ++ pprExpr 0 e2
-pprExpr d (EDisjunction e1 e2)     = parens (d < 1) $ pprExpr 1 e1 ++ " OR " ++ pprExpr 1 e2
-
-parens :: Bool -> String -> String
-parens False s = s
-parens True  s  = "(" ++ s ++ ")"
diff --git a/src/Data/SPDX/Ranges.hs b/src/Data/SPDX/Ranges.hs
deleted file mode 100644
--- a/src/Data/SPDX/Ranges.hs
+++ /dev/null
@@ -1,51 +0,0 @@
-{-# LANGUAGE CPP #-}
-#if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE Safe #-}
-#endif
-module Data.SPDX.Ranges (licenseRanges, lookupLicenseRange) where
-
-import Data.Char
-import Data.List
-import Data.Maybe
-
-import Data.SPDX.Types
-import Data.SPDX.Licenses
-
-licenseRanges :: [[LicenseId]]
-licenseRanges = filter longerThanSingleton . map f $ prefixes
-  where f p = filter (\l -> p `isPrefixOf` getLicenseId l && restIsNumber (getLicenseId l) p) licenseIdentifiers
-
--- | Lookup newer licenses we know about
---
--- >>> lookupLicenseRange $ fromJust $ mkLicenseId "MIT"
--- [LicenseId "MIT"]
---
--- >>> lookupLicenseRange $ fromJust $ mkLicenseId "GPL-2.0"
--- [LicenseId "GPL-2.0",LicenseId "GPL-3.0"]
---
--- >>> lookupLicenseRange $ fromJust $ mkLicenseId "LGPL-2.0"
--- [LicenseId "LGPL-2.0",LicenseId "LGPL-2.1",LicenseId "LGPL-3.0"]
-lookupLicenseRange :: LicenseId -> [LicenseId]
-lookupLicenseRange l = fromMaybe [l] $ lookup l ranges'
-
-ranges' :: [(LicenseId, [LicenseId])]
-ranges' = map (\r -> (head r, r)) . filter (not . nullOrSingleton) . concatMap tails $ licenseRanges
-
-nullOrSingleton :: [a] -> Bool
-nullOrSingleton []      = True
-nullOrSingleton [_]     = True
-nullOrSingleton (_:_:_) = False
-
-restIsNumber :: String -> String -> Bool
-restIsNumber l p = all (\c -> isDigit c || c == 'a' || c == 'b' || c == 'c' || c == '.') (drop (length p) l)
-
-pref :: String -> String
-pref = reverse . dropWhile (/= '-') . reverse
-
-prefixes :: [String]
-prefixes = nub (filter (not . null) $ map (pref . getLicenseId) licenseIdentifiers)
-
-longerThanSingleton :: [a] -> Bool
-longerThanSingleton []      = False
-longerThanSingleton [_]     = False
-longerThanSingleton (_:_:_) = True
diff --git a/src/Data/SPDX/Types.hs b/src/Data/SPDX/Types.hs
deleted file mode 100644
--- a/src/Data/SPDX/Types.hs
+++ /dev/null
@@ -1,69 +0,0 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE DeriveDataTypeable #-}
-
-#if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE DeriveGeneric #-}
-#endif
-
-#if __GLASGOW_HASKELL__ >= 701
-#if __GLASGOW_HASKELL__ >= 703
-{-# LANGUAGE Safe #-}
-#else
-{-# LANGUAGE Trustworthy #-}
-#endif
-#endif
-module Data.SPDX.Types (
-    LicenseId(..)
-  , getLicenseId
-  , LicenseExceptionId(..)
-  , getLicenseExceptionId
-  , LicenseRef(..)
-  , LicenseExpression(..)
-  ) where
-
-import Data.Data
-
-#if __GLASGOW_HASKELL__ >= 701
-import GHC.Generics
-#endif
-
-data LicenseRef = LicenseRef
-  { lrDocument :: !(Maybe String)
-  , lrLicense  :: !String
-  }
-  deriving (Eq, Ord, Show, Read, Typeable, Data
-#if __GLASGOW_HASKELL__ >= 701
-           , Generic
-#endif
-           )
-
--- | Opaque license identifier type.
-newtype LicenseId = LicenseId String
-  deriving (Eq, Ord, Show, Read, Typeable, Data
-#if __GLASGOW_HASKELL__ >= 701
-           , Generic
-#endif
-           )
-
-getLicenseId :: LicenseId -> String
-getLicenseId (LicenseId l) = l
-
--- | Opaque license exception identifier type.
-newtype LicenseExceptionId = LicenseExceptionId String
-  deriving (Eq, Ord, Show, Read, Typeable, Data
-#if __GLASGOW_HASKELL__ >= 701
-           , Generic
-#endif
-           )
-
-getLicenseExceptionId :: LicenseExceptionId -> String
-getLicenseExceptionId (LicenseExceptionId l) = l
-
-data LicenseExpression = ELicense !Bool !(Either LicenseRef LicenseId) !(Maybe LicenseExceptionId)
-                       | EConjunction !LicenseExpression !LicenseExpression
-                       | EDisjunction !LicenseExpression !LicenseExpression
-  deriving (Eq, Ord, Show, Read, Typeable, Data
-#if __GLASGOW_HASKELL__ >= 701
-           , Generic
-#endif
-           )
diff --git a/src/Distribution/SPDX/Extra.hs b/src/Distribution/SPDX/Extra.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/SPDX/Extra.hs
@@ -0,0 +1,77 @@
+-- |
+--
+module Distribution.SPDX.Extra (
+  -- * Types
+  -- | We don't export the constructors, as they change with Cabal version.
+  License,
+  LicenseExpression,
+  SimpleLicenseExpression,
+  LicenseId,
+  LicenseExceptionId,
+
+  -- * Logic
+  satisfies,
+  equivalent,
+  ) where
+
+import Distribution.SPDX
+       (License (..), LicenseExceptionId, LicenseExpression (..), LicenseId,
+       SimpleLicenseExpression (..))
+import Distribution.SPDX.Extra.Internal (LatticeSyntax (..))
+
+import qualified Distribution.SPDX.Extra.Internal as LS
+
+-- |
+--
+-- @⟦ satisfies a b ⟧ ≡ a ≥ b ≡ a ∧ b = b @
+--
+-- >>> unsafeParseExpr "GPL-3.0-only" `satisfies` unsafeParseExpr "ISC AND MIT"
+-- False
+--
+-- >>> unsafeParseExpr "Zlib" `satisfies` unsafeParseExpr "ISC AND MIT AND Zlib"
+-- True
+--
+-- >>> unsafeParseExpr "(MIT OR GPL-2.0-only)" `satisfies` unsafeParseExpr "(ISC AND MIT)"
+-- True
+--
+-- >>> unsafeParseExpr "(MIT AND GPL-2.0-only)" `satisfies` unsafeParseExpr "(MIT AND GPL-2.0-only)"
+-- True
+--
+-- >>> unsafeParseExpr "(MIT AND GPL-2.0-only)" `satisfies` unsafeParseExpr "(ISC AND GPL-2.0-only)"
+-- False
+--
+satisfies :: License -- ^ package license
+          -> License -- ^ license policy
+          -> Bool
+satisfies a b = exprToLSLic b `LS.preorder` exprToLSLic a
+
+-- | Check wheather two 'LicenseExpression' are equivalent.
+--
+-- >>> unsafeParseExpr "(MIT AND GPL-2.0-only)" `equivalent` unsafeParseExpr "(GPL-2.0-only AND MIT)"
+-- True
+--
+-- >>> unsafeParseExpr "MIT" `equivalent` unsafeParseExpr "MIT OR BSD-3-Clause"
+-- False
+--
+equivalent :: License -> License -> Bool
+equivalent a b = exprToLSLic a `LS.equivalent` exprToLSLic b
+
+-------------------------------------------------------------------------------
+-- internal
+-------------------------------------------------------------------------------
+
+data Lic = Lic !SimpleLicenseExpression !(Maybe LicenseExceptionId)
+  deriving (Eq, Ord)
+
+exprToLSLic :: License -> LatticeSyntax Lic
+exprToLSLic NONE          = LBound False
+exprToLSLic (License lic) = licTo lic
+
+licTo :: LicenseExpression -> LatticeSyntax Lic
+licTo (ELicense lic exc) = LVar (Lic lic exc)
+licTo (EAnd a b)         = LMeet (licTo a) (licTo b)
+licTo (EOr a b)          = LJoin (licTo a) (licTo b)
+
+-- $setup
+-- >>> import Distribution.Parsec.Class (simpleParsec)
+-- >>> let unsafeParseExpr e = maybe (error $ "invalid: " ++ e) (id :: License -> License) (simpleParsec e)
diff --git a/src/Distribution/SPDX/Extra/Internal.hs b/src/Distribution/SPDX/Extra/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/SPDX/Extra/Internal.hs
@@ -0,0 +1,142 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE DeriveFoldable #-}
+{-# LANGUAGE DeriveTraversable #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+-- |
+--
+-- Inspired by <http://www.well-typed.com/blog/2014/12/simple-smt-solver/ Simple SMT Solver>.
+--
+-- In future this module will probably be moved into separate package.
+module Distribution.SPDX.Extra.Internal
+  (LatticeSyntax(..), dual, freeVars, equivalent, preorder, satisfiable) where
+
+import Control.Applicative
+import Control.Monad
+import Control.Monad.Trans.State.Strict
+import Data.Data
+import Data.Foldable
+import Data.Traversable
+import Prelude hiding (all, or)
+
+import qualified Data.Map.Strict as Map
+
+data LatticeSyntax a = LVar a
+                     | LBound Bool
+                     | LJoin (LatticeSyntax a) (LatticeSyntax a)
+                     | LMeet (LatticeSyntax a) (LatticeSyntax a)
+  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable, Typeable, Data)
+
+instance Applicative LatticeSyntax where
+  pure  = return
+  (<*>) = ap
+
+instance Monad LatticeSyntax where
+  return = LVar
+  LVar x    >>= f = f x
+  LBound b  >>= _ = LBound b
+  LJoin a b >>= f = LJoin (a >>= f) (b >>= f)
+  LMeet a b >>= f = LMeet (a >>= f) (b >>= f)
+
+freeVars :: LatticeSyntax a -> [a]
+freeVars = toList
+
+dual :: LatticeSyntax a -> LatticeSyntax a
+dual (LVar v) = LVar v
+dual (LBound t) = LBound $ not t
+dual (LJoin a b) = LMeet (dual a) (dual b)
+dual (LMeet a b) = LJoin (dual a) (dual b)
+
+-- | Test for equivalence.
+--
+-- >>> equivalent (LMeet (LVar 'a') (LVar 'b')) (LMeet (LVar 'b') (LVar 'a'))
+-- True
+--
+-- >>> equivalent (LVar 'a') (LMeet (LVar 'a') (LVar 'a'))
+-- True
+--
+-- >>> equivalent (LMeet (LVar 'a') (LVar 'b')) (LMeet (LVar 'b') (LVar 'b'))
+-- False
+equivalent :: Ord a => LatticeSyntax a -> LatticeSyntax a -> Bool
+equivalent a b = all (uncurry (==)) . runEval $ p
+  where p = (,) <$> evalLattice a <*> evalLattice b
+
+-- | Test for preorder.
+--
+-- @ a ≤ b ⇔ a ∨ b ≡ b ⇔ a ≡ a ∧ b @
+--
+-- >>> preorder (LVar 'a' `LMeet` LVar 'b') (LVar 'a')
+-- True
+--
+-- >>> preorder (LVar 'a') (LVar 'a' `LMeet` LVar 'b')
+-- False
+preorder :: Ord a => LatticeSyntax a -> LatticeSyntax a -> Bool
+preorder a b = (a `LJoin` b) `equivalent` b
+
+-- | Return `True` if for some variable assigment expression evaluates to `True`.
+satisfiable :: Ord a => LatticeSyntax a -> Bool
+satisfiable = or . runEval . evalLattice
+
+newtype Eval v a = Eval { unEval :: StateT (Map.Map v Bool) [] a }
+
+instance Functor (Eval v) where
+  fmap = liftM
+
+instance Applicative (Eval v) where
+  pure = return
+  (<*>) = ap
+
+instance Alternative (Eval v) where
+  empty = mzero
+  (<|>) = mplus
+
+instance Monad (Eval v) where
+  return = Eval . return
+  Eval m >>= k = Eval $ m >>= unEval . k
+
+instance MonadPlus (Eval v) where
+  mzero = Eval mzero
+  Eval a `mplus` Eval b = Eval $ a `mplus` b
+
+runEval :: Eval v a -> [a]
+runEval act = evalStateT (unEval act) Map.empty
+
+evalLattice :: Ord v => LatticeSyntax v -> Eval v Bool
+evalLattice (LVar v)    = guess v
+evalLattice (LBound b)  = return b
+evalLattice (LJoin a b) = evalLattice a ||^ evalLattice b
+evalLattice (LMeet a b) = evalLattice a &&^ evalLattice b
+
+guess :: Ord v => v -> Eval v Bool
+guess v = Eval $ do
+  st <- get
+  let remember b = put (Map.insert v b st) >> return b
+  case Map.lookup v st of
+    Just b  -> return b
+    Nothing -> remember True <|> remember False
+
+-- From Control.Monad.Extra of extra
+
+-- | Like @if@, but where the test can be monadic.
+ifM :: Monad m => m Bool -> m a -> m a -> m a
+ifM b t f = do b' <- b; if b' then t else f
+
+-- | The lazy '||' operator lifted to a monad. If the first
+--   argument evaluates to 'True' the second argument will not
+--   be evaluated.
+--
+-- > Just True  ||^ undefined  == Just True
+-- > Just False ||^ Just True  == Just True
+-- > Just False ||^ Just False == Just False
+(||^) :: Monad m => m Bool -> m Bool -> m Bool
+(||^) a b = ifM a (return True) b
+
+-- | The lazy '&&' operator lifted to a monad. If the first
+--   argument evaluates to 'False' the second argument will not
+--   be evaluated.
+--
+-- > Just False &&^ undefined  == Just False
+-- > Just True  &&^ Just True  == Just True
+-- > Just True  &&^ Just False == Just False
+(&&^) :: Monad m => m Bool -> m Bool -> m Bool
+(&&^) a b = ifM a b (return False)
diff --git a/tests/Generators.hs b/tests/Generators.hs
--- a/tests/Generators.hs
+++ b/tests/Generators.hs
@@ -11,20 +11,17 @@
 
 import           Test.Tasty.QuickCheck as QC
 
-import           Data.SPDX
-import           Data.SPDX.LatticeSyntax (LatticeSyntax(..))
+import           Distribution.SPDX
+import           Distribution.SPDX.Extra.Internal (LatticeSyntax(..))
 
 licenseIdGen :: Gen LicenseId
-licenseIdGen = elements licenseIdentifiers
+licenseIdGen = elements $ licenseIdList LicenseListVersion_3_2
 
 licenseExceptionGen :: Gen LicenseExceptionId
-licenseExceptionGen = elements licenseExceptions
-
-maybeGen :: Gen a -> Gen (Maybe a)
-maybeGen g = oneof [ pure Nothing, Just <$> g]
+licenseExceptionGen = elements $ licenseExceptionIdList LicenseListVersion_3_2
 
 licenseRefGen :: Gen LicenseRef
-licenseRefGen = LicenseRef <$> maybeGen idStringGen <*> idStringGen
+licenseRefGen = mkLicenseRef' <$> liftArbitrary idStringGen <*> idStringGen
 
 idStringGen :: Gen String
 idStringGen = elements ["foo", "bar", "baz", "AllRightsReserved"]
@@ -39,29 +36,32 @@
                       ]
           where gen' = gen (n `div` 2)
 
-mkExprGen :: Gen LicenseExpression -> Gen LicenseExpression
-mkExprGen licGen = sized gen
-  where gen 0 = licGen
-        gen n = oneof [ licGen
-                      , EDisjunction <$> gen' <*> gen'
-                      , EConjunction <$> gen' <*> gen'
-                      ]
-          where gen' = gen (n `div` 2)
+mkExprGen :: Gen LicenseExpression -> Gen License
+mkExprGen licGen = License <$> sized gen where
+    gen 0 = licGen
+    gen n = oneof [ licGen
+                  , EOr <$> gen' <*> gen'
+                  , EAnd <$> gen' <*> gen'
+                  ]
+      where gen' = gen (n `div` 2)
 
-exprGen :: Gen LicenseExpression
-exprGen = mkExprGen $ ELicense <$> arbitrary <*> (Right <$> licenseIdGen) <*> (pure Nothing)
+exprGen :: Gen License
+exprGen = mkExprGen $ ELicense <$> simpleLicenseExprGen <*> pure Nothing
 
 -- | 'exprGen' which contains also LicenseRefs and exceptions
-exprGen' :: Gen LicenseExpression
-exprGen' = mkExprGen $ ELicense <$> arbitrary <*> eitherLicenseIdRefGen <*> maybeGen licenseExceptionGen
+exprGen' :: Gen License
+exprGen' = mkExprGen $ ELicense <$> simpleLicenseExprGen <*> liftArbitrary licenseExceptionGen
 
-eitherLicenseIdRefGen :: Gen (Either LicenseRef LicenseId)
-eitherLicenseIdRefGen = oneof [Right <$> licenseIdGen, Left <$> licenseRefGen]
+simpleLicenseExprGen :: Gen SimpleLicenseExpression
+simpleLicenseExprGen = oneof [ELicenseId <$> licenseIdGen, ELicenseRef <$> licenseRefGen]
 
-exprShrink :: LicenseExpression -> [LicenseExpression]
-exprShrink (ELicense _ _ _)   = []
-exprShrink (EDisjunction a b) = a : b : ((a `EDisjunction`) <$> exprShrink b) ++ ((`EDisjunction` b) <$> exprShrink a)
-exprShrink (EConjunction a b) = a : b : ((a `EConjunction`) <$> exprShrink b) ++ ((`EConjunction` b) <$> exprShrink a)
+exprShrink :: License -> [License]
+exprShrink NONE        = []
+exprShrink (License e) = map License (go e) where
+    go :: LicenseExpression -> [LicenseExpression]
+    go (ELicense _ _) = []
+    go (EOr a b)      = a : b : map (uncurry EOr)  (liftShrink2 go go (a, b))
+    go (EAnd a b)     = a : b : map (uncurry EAnd) (liftShrink2 go go (a, b))
 
 scaleGen :: (Int -> Int) -> Gen a -> Gen a
 scaleGen f g = sized (\n -> resize (f n) g)
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -1,14 +1,18 @@
 module Main (main) where
 
-import           Data.List
-import           Test.Tasty
-import           Test.Tasty.QuickCheck as QC
-
-import           Data.SPDX
-import           Data.SPDX.LatticeSyntax (LatticeSyntax(..))
-import qualified Data.SPDX.LatticeSyntax as LS
+import Data.Maybe                       (isJust)
+import Distribution.Parsec.Class
+import Distribution.Pretty
+import Distribution.SPDX
+import Distribution.SPDX.Extra
+import Distribution.SPDX.Extra.Internal (LatticeSyntax (..))
+import Generators
+import Prelude ()
+import Prelude.Compat
+import Test.Tasty
+import Test.Tasty.QuickCheck            as QC
 
-import           Generators
+import qualified Distribution.SPDX.Extra.Internal as LS
 
 main :: IO ()
 main = defaultMain tests
@@ -20,10 +24,10 @@
 properties = testGroup "Properties" [qcProps]
 
 up :: String -> LicenseExpression
-up = unsafeParseExpr
+up = maybe (error "invalid expr") id . simpleParsec
 
 valid :: String -> Bool
-valid = (==1) . length . parseExpression
+valid s = isJust (simpleParsec s :: Maybe License)
 
 validExpr :: TestName -> TestTree
 validExpr str = QC.testProperty str $ once $ property $ valid str
@@ -34,19 +38,19 @@
 units :: TestTree
 units = testGroup "Unit tests" [ simpleUnits
                                , compositeUnits
-                               , rangeUnit
                                ]
 
+
 -- | Like `equivalent`, but prints a counterexample when it fails.
-equivalentProp :: [LicenseExpression] -> [LicenseExpression] -> Property
-equivalentProp x y =
-  counterexample (show x ++ " /= " ++ show y) $ length x == length y && (and $ zipWith equivalent x y)
+equivalentProp :: Maybe License -> Maybe License -> Property
+equivalentProp x y = counterexample (show x ++ " /= " ++ show y) $
+    length x == length y && (and $ equivalent <$> x <*> y)
 
 simpleUnits :: TestTree
 simpleUnits = testGroup "Simple License Expressions"
   [ invalidExpr "Invalid-Identifier"
-  , validExpr "GPL-2.0"
-  , validExpr "GPL-2.0+"
+  , validExpr "GPL-2.0-only"
+  , validExpr "GPL-2.0-or-later"
   , validExpr "LicenseRef-23"
   , validExpr "LicenseRef-MIT-Style-1"
   , validExpr "DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2"
@@ -54,18 +58,15 @@
 
 compositeUnits :: TestTree
 compositeUnits = testGroup "Composite License Expressions"
-  [ validExpr "LGPL-2.1 OR MIT"
-  , validExpr "LGPL-2.1 OR MIT OR BSD-3-Clause"
-  , validExpr "LGPL-2.1 AND MIT"
-  , validExpr "LGPL-2.1 AND MIT AND BSD-2-Clause"
-  , validExpr "GPL-2.0+ WITH Bison-exception-2.2"
+  [ validExpr "LGPL-2.1-only OR MIT"
+  , validExpr "LGPL-2.1-only OR MIT OR BSD-3-Clause"
+  , validExpr "LGPL-2.1-only AND MIT"
+  , validExpr "LGPL-2.1-only AND MIT AND BSD-2-Clause"
+  , validExpr "GPL-2.0-or-later WITH Bison-exception-2.2"
   , QC.testProperty "Order of Precedence and Parentheses" $ once $ property $
-    up "LGPL-2.1 OR BSD-3-Clause AND MIT" == EDisjunction (up "LGPL-2.1") (EConjunction (up "BSD-3-Clause") (up "MIT"))
+    up "LGPL-2.1-only OR BSD-3-Clause AND MIT" == EOr (up "LGPL-2.1-only") (EAnd (up "BSD-3-Clause") (up "MIT"))
   ]
 
-rangeUnit :: TestTree
-rangeUnit = QC.testProperty "calculated license ranges" $ once $ sort (map (map getLicenseId) licenseRanges) === sort ranges
-
 lsProps :: TestTree
 lsProps = testGroup "LatticeSyntax"
   [ QC.testProperty "a ≤ b ⇔ a ∨ b ≡ b ⇔ a ≡ a ∧ b" $ forAll latticeSyntaxGen $ \a -> forAll latticeSyntaxGen $ \b ->
@@ -76,77 +77,20 @@
   , QC.testProperty "preorder reflexive" $ forAll latticeSyntaxGen $ \a -> a `LS.preorder` a
   ]
 
-osiLicenseIds :: [LicenseId]
-osiLicenseIds = filter isOsiApproved licenseIdentifiers
-
-osiLicenseExpr :: LicenseExpression
-osiLicenseExpr = foldr1 EConjunction $ map (\l -> ELicense False (Right l) Nothing) osiLicenseIds
-
-isOsiApprovedExpr :: LicenseExpression -> Bool
-isOsiApprovedExpr (ELicense _ (Left _) _) = False
-isOsiApprovedExpr (ELicense _ _ (Just _)) = False
-isOsiApprovedExpr (ELicense False (Right e) Nothing) = isOsiApproved e
-isOsiApprovedExpr (ELicense True (Right e2) Nothing) = any isOsiApproved $ lookupLicenseRange e2
-isOsiApprovedExpr (EConjunction e1 e2) = isOsiApprovedExpr e1 && isOsiApprovedExpr e2
-isOsiApprovedExpr (EDisjunction e1 e2) = isOsiApprovedExpr e1 || isOsiApprovedExpr e2
-
-isOsiApprovedExpr' :: LicenseExpression -> Bool
-isOsiApprovedExpr' e = e `satisfies` osiLicenseExpr
-
 qcProps :: TestTree
 qcProps = testGroup "By Quickcheck"
-  [ QC.testProperty "licence identifiers are valid licenses" $ forAll licenseIdGen $ valid . getLicenseId
-  , QC.testProperty "satisfies osi checked" $ forAll (scaleGen (`div` 3) exprGen) $
-      \e -> isOsiApprovedExpr e == isOsiApprovedExpr' e -- Skip
+  [ QC.testProperty "licence identifiers are valid licenses" $ forAll licenseIdGen $ valid . prettyShow
   , lsProps
   , parsePrettyProps
   ]
 
 parsePrettyProps :: TestTree
 parsePrettyProps = testGroup "parse . pretty"
-  [ QC.testProperty "LicenseId" $ forAll licenseIdGen $ \i -> mkLicenseId (prettyLicenseId i) === Just i
-  , QC.testProperty "LicenseExpression"  $ forAllShrink (scaleGen (`div` 3) exprGen)  exprShrink $ \e -> parseExpression (prettyLicenseExpression e) `equivalentProp` [e]
-  , QC.testProperty "LicenseExpression'" $ forAllShrink (scaleGen (`div` 3) exprGen') exprShrink $ \e -> parseExpression (prettyLicenseExpression e) `equivalentProp` [e]
+  [ QC.testProperty "LicenseId" $ forAll licenseIdGen $ \i -> mkLicenseId LicenseListVersion_3_2 (prettyShow i) === Just i
+  , QC.testProperty "LicenseExpression"  $ forAllShrink (scaleGen (`div` 3) exprGen)  exprShrink $ \e ->
+      let p = prettyShow e
+      in counterexample p $ simpleParsec p `equivalentProp` Just e
+  , QC.testProperty "LicenseExpression'" $ forAllShrink (scaleGen (`div` 3) exprGen') exprShrink $ \e ->
+      let p = prettyShow e
+      in counterexample p $ simpleParsec p `equivalentProp` Just e
   ]
-
-ranges :: [[String]]
-ranges =
-    [ ["AFL-1.1","AFL-1.2","AFL-2.0","AFL-2.1","AFL-3.0"]
-    , ["AGPL-1.0","AGPL-3.0"]
-    , ["APSL-1.0","APSL-1.1","APSL-1.2","APSL-2.0"]
-    , ["Apache-1.0","Apache-1.1","Apache-2.0"]
-    , ["Artistic-1.0","Artistic-2.0"]
-    , ["BitTorrent-1.0","BitTorrent-1.1"]
-    , ["CC-BY-1.0","CC-BY-2.0","CC-BY-2.5","CC-BY-3.0","CC-BY-4.0"]
-    , ["CC-BY-NC-1.0","CC-BY-NC-2.0","CC-BY-NC-2.5","CC-BY-NC-3.0","CC-BY-NC-4.0"]
-    , ["CC-BY-NC-ND-1.0","CC-BY-NC-ND-2.0","CC-BY-NC-ND-2.5","CC-BY-NC-ND-3.0","CC-BY-NC-ND-4.0"]
-    , ["CC-BY-NC-SA-1.0","CC-BY-NC-SA-2.0","CC-BY-NC-SA-2.5","CC-BY-NC-SA-3.0","CC-BY-NC-SA-4.0"]
-    , ["CC-BY-ND-1.0","CC-BY-ND-2.0","CC-BY-ND-2.5","CC-BY-ND-3.0","CC-BY-ND-4.0"]
-    , ["CC-BY-SA-1.0","CC-BY-SA-2.0","CC-BY-SA-2.5","CC-BY-SA-3.0","CC-BY-SA-4.0"]
-    , ["CDDL-1.0","CDDL-1.1"]
-    , ["CECILL-1.0","CECILL-1.1","CECILL-2.0","CECILL-2.1"]
-    , ["ECL-1.0","ECL-2.0"]
-    , ["EFL-1.0","EFL-2.0"]
-    , ["EUPL-1.0","EUPL-1.1"]
-    , ["GFDL-1.1","GFDL-1.2","GFDL-1.3"]
-    , ["GPL-1.0","GPL-2.0","GPL-3.0"]
-    , ["LAL-1.2","LAL-1.3"]
-    , ["LGPL-2.0","LGPL-2.1","LGPL-3.0"]
-    , ["LPL-1.0","LPL-1.02"]
-    , ["LPPL-1.0","LPPL-1.1","LPPL-1.2","LPPL-1.3a","LPPL-1.3c"]
-    , ["MPL-1.0","MPL-1.1","MPL-2.0"]
-    , ["NPL-1.0","NPL-1.1"]
-    , ["OFL-1.0","OFL-1.1"]
-    , ["OLDAP-1.1","OLDAP-1.2","OLDAP-1.3","OLDAP-1.4","OLDAP-2.0","OLDAP-2.0.1","OLDAP-2.1","OLDAP-2.2","OLDAP-2.2.1","OLDAP-2.2.2","OLDAP-2.3","OLDAP-2.4","OLDAP-2.5","OLDAP-2.6","OLDAP-2.7","OLDAP-2.8"]
-    , ["OSL-1.0","OSL-1.1","OSL-2.0","OSL-2.1","OSL-3.0"]
-    , ["PHP-3.0","PHP-3.01"]
-    , ["RPL-1.1","RPL-1.5"]
-    , ["SGI-B-1.0","SGI-B-1.1","SGI-B-2.0"]
-    , ["Spencer-86","Spencer-94","Spencer-99"]
-    , ["Unicode-DFS-2015","Unicode-DFS-2016"]
-    , ["W3C-19980720","W3C-20150513"]
-    , ["YPL-1.0","YPL-1.1"]
-    , ["ZPL-1.1","ZPL-2.0","ZPL-2.1"]
-    , ["Zimbra-1.3","Zimbra-1.4"]
-    , ["bzip2-1.0.5","bzip2-1.0.6"]
-    ]
