diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # dickinson
 
+## 1.1.0.2
+
+  * Support `prettyprinter` ≥ 1.7.0
+
 ## 1.1.0.1
 
   * Read `DCK_PATH` variable when searching for files.
diff --git a/bench/Bench.hs b/bench/Bench.hs
--- a/bench/Bench.hs
+++ b/bench/Bench.hs
@@ -53,9 +53,10 @@
                     [ bench "bench/data/multiple.dck" $ nf (decode :: BSL.ByteString -> Dickinson ()) e
                     , bench "examples/shakespeare.dck" $ nf (decode :: BSL.ByteString -> Dickinson ()) es
                     ]
-                , env multiParsed $ \ ~(Dickinson _ p) ->
+                , env checkEnv $ \ ~(Dickinson _ p, Dickinson _ p') ->
                   bgroup "check"
                     [ bench "bench/data/multiple.dck" $ nf checkMultiple p
+                    , bench "lib/adjectives.dck" $ nf checkMultiple p'
                     , bench "bench/data/multiple.dck" $ nf checkDuplicates p -- TODO: better example
                     ]
                 , bgroup "pipeline"
@@ -96,6 +97,7 @@
           parses = (,) <$> libFile <*> shakespeare
           libParsed = either throw id . parseWithMax <$> BSL.readFile "bench/data/nestLet.dck"
           multiParsed = either throw id . parse <$> BSL.readFile "bench/data/multiple.dck"
+          libText = either throw id . parse <$> BSL.readFile "lib/adjectives.dck"
           encoded = encode . void <$> multiParsed
           encodeShakespeare = encode . void . either throw id . parse <$> shakespeare
           encodeEnv = (,) <$> encoded <*> encodeShakespeare
@@ -107,6 +109,9 @@
           amalComplex = (,)
             <$> amalgamateRename [] "test/examples/declension.dck"
             <*> amalgamateRename [] "test/data/refractory.dck"
+          checkEnv = (,)
+            <$> multiParsed
+            <*> libText
 
 plainExpr :: (UniqueCtx, Dickinson a) -> Dickinson a
 plainExpr = fst . uncurry renameDickinson
diff --git a/language-dickinson.cabal b/language-dickinson.cabal
--- a/language-dickinson.cabal
+++ b/language-dickinson.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.0
 name:               language-dickinson
-version:            1.1.0.1
+version:            1.1.0.2
 license:            BSD3
 license-file:       LICENSE
 copyright:          Copyright: (c) 2020 Vanessa McHale
@@ -131,7 +131,7 @@
         transformers -any,
         containers -any,
         random -any,
-        prettyprinter -any,
+        prettyprinter >=1.7.0,
         deepseq -any,
         microlens -any,
         microlens-mtl -any,
@@ -219,8 +219,9 @@
     main-is:          Spec.hs
     hs-source-dirs:   test
     other-modules:
-        Golden
         Eval
+        Golden
+        Roundtrip.Compare
         TypeCheck
         TH
 
diff --git a/lib/noun.dck b/lib/noun.dck
--- a/lib/noun.dck
+++ b/lib/noun.dck
@@ -42,6 +42,7 @@
       (| "apothegm")
       (| "satori")
       (| "ardor")
+      (| "palaver")
       (| "theogeny")
       (| "curio")
       (| "tonsure")
diff --git a/run/REPL.hs b/run/REPL.hs
--- a/run/REPL.hs
+++ b/run/REPL.hs
@@ -4,45 +4,45 @@
 module REPL ( dickinsonRepl
             ) where
 
-import           Control.Monad                         (void)
-import           Control.Monad.Except                  (ExceptT, runExceptT)
-import           Control.Monad.IO.Class                (liftIO)
-import           Control.Monad.State.Lazy              (MonadState, StateT, evalStateT, get, gets, lift, put)
-import qualified Data.ByteString.Lazy                  as BSL
-import           Data.Foldable                         (traverse_)
-import qualified Data.IntMap                           as IM
-import qualified Data.IntSet                           as IS
-import qualified Data.Map                              as M
-import           Data.Maybe                            (fromJust)
-import           Data.Semigroup                        ((<>))
-import qualified Data.Text                             as T
-import qualified Data.Text.IO                          as TIO
-import qualified Data.Text.Lazy                        as TL
-import           Data.Text.Lazy.Encoding               (encodeUtf8)
-import           Data.Text.Prettyprint.Doc             (Pretty (pretty), hardline)
-import           Data.Text.Prettyprint.Doc.Ext         (prettyText)
-import           Data.Text.Prettyprint.Doc.Render.Text (putDoc)
-import           Data.Tuple.Ext                        (fst4)
+import           Control.Monad                  (void)
+import           Control.Monad.Except           (ExceptT, runExceptT)
+import           Control.Monad.IO.Class         (liftIO)
+import           Control.Monad.State.Lazy       (MonadState, StateT, evalStateT, get, gets, lift, put)
+import qualified Data.ByteString.Lazy           as BSL
+import           Data.Foldable                  (traverse_)
+import qualified Data.IntMap                    as IM
+import qualified Data.IntSet                    as IS
+import qualified Data.Map                       as M
+import           Data.Maybe                     (fromJust)
+import           Data.Semigroup                 ((<>))
+import qualified Data.Text                      as T
+import qualified Data.Text.IO                   as TIO
+import qualified Data.Text.Lazy                 as TL
+import           Data.Text.Lazy.Encoding        (encodeUtf8)
+import           Data.Text.Prettyprint.Doc.Ext  (prettyText)
+import           Data.Tuple.Ext                 (fst4)
 import           Language.Dickinson.Check.Scope
 import           Language.Dickinson.Error
 import           Language.Dickinson.Eval
 import           Language.Dickinson.File
-import           Language.Dickinson.Lexer              (AlexPosn, AlexUserState, alexInitUserState)
+import           Language.Dickinson.Lexer       (AlexPosn, AlexUserState, alexInitUserState)
 import           Language.Dickinson.Lib
 import           Language.Dickinson.Parser
 import           Language.Dickinson.Rename
 import           Language.Dickinson.Type
 import           Language.Dickinson.TypeCheck
 import           Language.Dickinson.Unique
-import           Lens.Micro                            (_1)
-import           Lens.Micro.Mtl                        (use, (.=))
+import           Lens.Micro                     (_1)
+import           Lens.Micro.Mtl                 (use, (.=))
+import           Prettyprinter                  (Pretty (pretty), hardline)
+import           Prettyprinter.Render.Text      (putDoc)
 import           REPL.Completions
 import           REPL.Save
-import           System.Console.Haskeline              (InputT, completeFilename, defaultSettings, fallbackCompletion,
-                                                        getInputLine, historyFile, runInputT, setComplete)
-import           System.Directory                      (getHomeDirectory)
-import           System.FilePath                       ((</>))
-import           System.Random                         (newStdGen, randoms)
+import           System.Console.Haskeline       (InputT, completeFilename, defaultSettings, fallbackCompletion,
+                                                 getInputLine, historyFile, runInputT, setComplete)
+import           System.Directory               (getHomeDirectory)
+import           System.FilePath                ((</>))
+import           System.Random                  (newStdGen, randoms)
 
 dickinsonRepl :: [FilePath] -> IO ()
 dickinsonRepl fps = runRepl (traverse_ loadFile fps *> loop)
diff --git a/src/Data/Text/Prettyprint/Doc/Ext.hs b/src/Data/Text/Prettyprint/Doc/Ext.hs
--- a/src/Data/Text/Prettyprint/Doc/Ext.hs
+++ b/src/Data/Text/Prettyprint/Doc/Ext.hs
@@ -8,6 +8,8 @@
                                      , intercalate
                                      , hardSep
                                      , prettyDumpBinds
+                                     -- * Debug class
+                                     , Debug (..)
                                      -- * Operators
                                      , (<#>)
                                      , (<:>)
@@ -15,21 +17,23 @@
                                      , (<#*>)
                                      ) where
 
-import qualified Data.IntMap                           as IM
-import           Data.List                             (intersperse)
-import           Data.Semigroup                        ((<>))
-import qualified Data.Text                             as T
-import qualified Data.Text.Lazy                        as TL
-import           Data.Text.Prettyprint.Doc             (Doc, LayoutOptions (LayoutOptions),
-                                                        PageWidth (AvailablePerLine), Pretty (pretty), SimpleDocStream,
-                                                        concatWith, flatAlt, hardline, indent,
-                                                        layoutSmart, softline, vsep, (<+>))
-import           Data.Text.Prettyprint.Doc.Render.Text (renderLazy, renderStrict)
+import qualified Data.IntMap               as IM
+import           Data.List                 (intersperse)
+import           Data.Semigroup            ((<>))
+import qualified Data.Text                 as T
+import qualified Data.Text.Lazy            as TL
+import           Prettyprinter             (Doc, LayoutOptions (LayoutOptions), PageWidth (AvailablePerLine),
+                                            Pretty (pretty), SimpleDocStream, concatWith, flatAlt, hardline, indent,
+                                            layoutSmart, softline, vsep, (<+>))
+import           Prettyprinter.Render.Text (renderLazy, renderStrict)
 
 infixr 6 <#>
 infixr 6 <:>
 infixr 6 <^>
 
+class Debug a where
+    debug :: a -> Doc b
+
 (<#>) :: Doc a -> Doc a -> Doc a
 (<#>) x y = x <> hardline <> y
 
@@ -56,6 +60,8 @@
 
 dickinsonLayoutOptions :: LayoutOptions
 dickinsonLayoutOptions = LayoutOptions (AvailablePerLine 160 0.8)
+
+-- TODO: use layoutCompact for errors?
 
 smartDickinson :: Doc a -> SimpleDocStream a
 smartDickinson = layoutSmart dickinsonLayoutOptions
diff --git a/src/Language/Dickinson/Check/Duplicate.hs b/src/Language/Dickinson/Check/Duplicate.hs
--- a/src/Language/Dickinson/Check/Duplicate.hs
+++ b/src/Language/Dickinson/Check/Duplicate.hs
@@ -12,6 +12,7 @@
 import           Language.Dickinson.Type
 
 -- TODO: duplicate check better? hm
+-- FIXME: HashSet or whatever?
 
 checkNames :: [(a, T.Text)] -> Maybe (DickinsonWarning a)
 checkNames ns = foldMapAlternative announce (groupBy ((==) `on` snd) $ sortBy (compare `on` snd) ns)
diff --git a/src/Language/Dickinson/Error.hs b/src/Language/Dickinson/Error.hs
--- a/src/Language/Dickinson/Error.hs
+++ b/src/Language/Dickinson/Error.hs
@@ -12,12 +12,12 @@
 import           Control.Monad.Except      (MonadError, throwError)
 import           Data.Semigroup            ((<>))
 import qualified Data.Text                 as T
-import           Data.Text.Prettyprint.Doc (Pretty (pretty), dquotes, squotes, (<+>))
 import           Data.Typeable             (Typeable)
 import           GHC.Generics              (Generic)
 import           Language.Dickinson.Name
 import           Language.Dickinson.Parser
 import           Language.Dickinson.Type
+import           Prettyprinter             (Pretty (pretty), dquotes, squotes, (<+>))
 
 data DickinsonError a = UnfoundName a (Name a)
                       | NoText T.Text -- separate from UnfoundName since there is no loc
diff --git a/src/Language/Dickinson/Eval.hs b/src/Language/Dickinson/Eval.hs
--- a/src/Language/Dickinson/Eval.hs
+++ b/src/Language/Dickinson/Eval.hs
@@ -27,7 +27,6 @@
 import qualified Data.List.NonEmpty            as NE
 import qualified Data.Map                      as M
 import qualified Data.Text                     as T
-import           Data.Text.Prettyprint.Doc     (Doc, Pretty (..), vsep, (<+>))
 import           Data.Text.Prettyprint.Doc.Ext
 import           Language.Dickinson.Error
 import           Language.Dickinson.Lexer
@@ -39,6 +38,7 @@
 import           Language.Dickinson.Unique
 import           Lens.Micro                    (Lens', over, set, _1)
 import           Lens.Micro.Mtl                (use, (.=))
+import           Prettyprinter                 (Doc, Pretty (..), vsep, (<+>))
 
 -- | The state during evaluation
 data EvalSt a = EvalSt
diff --git a/src/Language/Dickinson/Lexer.x b/src/Language/Dickinson/Lexer.x
--- a/src/Language/Dickinson/Lexer.x
+++ b/src/Language/Dickinson/Lexer.x
@@ -36,7 +36,7 @@
 import Data.Semigroup ((<>))
 import qualified Data.Text as T
 import Data.Text.Encoding (decodeUtf8)
-import Data.Text.Prettyprint.Doc (Pretty (pretty), pipe, lparen, rparen, rbrace, rbracket, lbracket, colon, squotes, dquotes, dquote, rangle, comma, (<+>))
+import Prettyprinter (Pretty (pretty), pipe, lparen, rparen, rbrace, rbracket, lbracket, colon, squotes, dquotes, dquote, rangle, comma, (<+>))
 import GHC.Generics (Generic)
 import Language.Dickinson.Name
 import Language.Dickinson.Unique
diff --git a/src/Language/Dickinson/Name.hs b/src/Language/Dickinson/Name.hs
--- a/src/Language/Dickinson/Name.hs
+++ b/src/Language/Dickinson/Name.hs
@@ -16,11 +16,12 @@
 import           Data.Foldable                 (toList)
 import qualified Data.IntMap                   as IM
 import           Data.List.NonEmpty            (NonEmpty (..))
+import           Data.Semigroup                ((<>))
 import qualified Data.Text                     as T
-import           Data.Text.Prettyprint.Doc     (Pretty (pretty))
-import           Data.Text.Prettyprint.Doc.Ext (intercalate)
+import           Data.Text.Prettyprint.Doc.Ext (Debug (..), intercalate)
 import           GHC.Generics                  (Generic)
 import           Language.Dickinson.Unique
+import           Prettyprinter                 (Pretty (pretty))
 
 type TyName a = Name a
 
@@ -45,5 +46,8 @@
 
 instance Pretty (Name a) where
     pretty (Name t _ _) = intercalate "." (toList (pretty <$> t))
+
+instance Debug (Name a) where
+    debug (Name t u _) = intercalate "." (toList (pretty <$> t)) <> pretty u
 
 type NameEnv a = IM.IntMap (Name a)
diff --git a/src/Language/Dickinson/Parser.y b/src/Language/Dickinson/Parser.y
--- a/src/Language/Dickinson/Parser.y
+++ b/src/Language/Dickinson/Parser.y
@@ -26,7 +26,7 @@
 import Data.Semigroup ((<>))
 import qualified Data.Text as T
 import Data.Text.Encoding (decodeUtf8)
-import Data.Text.Prettyprint.Doc (Pretty (pretty), (<+>))
+import Prettyprinter (Pretty (pretty), (<+>))
 import Data.Tuple.Ext (fst4)
 import Data.Typeable (Typeable)
 import GHC.Generics (Generic)
@@ -184,9 +184,14 @@
 countSpaces :: T.Text -> Int
 countSpaces = T.length . T.takeWhile (== ' ')
 
+dropDoubleNewlines :: [T.Text] -> [T.Text]
+dropDoubleNewlines ("":t:ts) | " " `T.isPrefixOf` t = dropDoubleNewlines (t:ts)
+dropDoubleNewlines (t:ts)                           = t : dropDoubleNewlines ts
+dropDoubleNewlines []                               = []
+
 -- minimum indentation (relevant in a string containing newline characters)
 minIndent :: T.Text -> Int
-minIndent t = minimum (maxBound : fmap countSpaces (T.lines t))
+minIndent t = minimum (maxBound : fmap countSpaces (dropDoubleNewlines $ T.lines t)) -- reduce duplicates
 
 minIndentExpr :: Expression a -> Maybe Int
 minIndentExpr (StrChunk _ t) | "\n" `T.isInfixOf` t  = Just $ minIndent $ T.tail $ T.dropWhile (/= '\n') t -- tail because T.lines "\n   hello" is ["", "    hello"]
diff --git a/src/Language/Dickinson/Rename.hs b/src/Language/Dickinson/Rename.hs
--- a/src/Language/Dickinson/Rename.hs
+++ b/src/Language/Dickinson/Rename.hs
@@ -26,7 +26,6 @@
 import qualified Data.IntMap                   as IM
 import qualified Data.List.NonEmpty            as NE
 import           Data.Semigroup                (Semigroup (..))
-import           Data.Text.Prettyprint.Doc     (Pretty (..), (<+>))
 import           Data.Text.Prettyprint.Doc.Ext
 import           GHC.Generics                  (Generic)
 import           Language.Dickinson.Name
@@ -34,6 +33,7 @@
 import           Language.Dickinson.Unique
 import           Lens.Micro                    (Lens')
 import           Lens.Micro.Mtl                (modifying, use, (%=), (.=))
+import           Prettyprinter                 (Pretty (..), (<+>))
 
 -- | Renamer state passed between various stages of compilation
 data Renames = Renames { max_ :: Int, bound :: IM.IntMap Int }
diff --git a/src/Language/Dickinson/Type.hs b/src/Language/Dickinson/Type.hs
--- a/src/Language/Dickinson/Type.hs
+++ b/src/Language/Dickinson/Type.hs
@@ -14,22 +14,22 @@
                                , defExprM
                                ) where
 
-import           Control.DeepSeq                    (NFData)
-import           Data.Binary                        (Binary)
-import           Data.Data                          (Data)
-import           Data.Foldable                      (toList)
-import           Data.List.NonEmpty                 (NonEmpty (..))
-import qualified Data.List.NonEmpty                 as NE
-import           Data.Semigroup                     ((<>))
-import qualified Data.Text                          as T
-import           Data.Text.Prettyprint.Doc          (Doc, Pretty (pretty), align, brackets, colon, concatWith, dquotes,
-                                                     encloseSep, group, hardline, hsep, indent, lparen, parens, pipe,
-                                                     rangle, rparen, tupled, vsep, (<+>))
-import           Data.Text.Prettyprint.Doc.Ext      (hardSep, (<#*>), (<#>), (<^>))
-import           Data.Text.Prettyprint.Doc.Internal (unsafeTextWithoutNewlines)
-import           GHC.Generics                       (Generic)
+import           Control.DeepSeq               (NFData)
+import           Data.Binary                   (Binary)
+import           Data.Data                     (Data)
+import           Data.Foldable                 (toList)
+import           Data.List.NonEmpty            (NonEmpty (..))
+import qualified Data.List.NonEmpty            as NE
+import           Data.Semigroup                ((<>))
+import qualified Data.Text                     as T
+import           Data.Text.Prettyprint.Doc.Ext (Debug (..), hardSep, (<#*>), (<#>), (<^>))
+import           GHC.Generics                  (Generic)
 import           Language.Dickinson.Lexer
 import           Language.Dickinson.Name
+import           Prettyprinter                 (Doc, Pretty (pretty), align, brackets, colon, concatWith, dquotes,
+                                                encloseSep, group, hardline, hsep, indent, lparen, parens, pipe, rangle,
+                                                rparen, tupled, vsep, (<+>))
+import           Prettyprinter.Internal        (unsafeTextWithoutNewlines)
 
 data Dickinson a = Dickinson { modImports :: [Import a]
                              , modDefs    :: [Declaration a]
@@ -112,8 +112,11 @@
     pretty (TyDecl _ n cs) = "tydecl" <+> pretty n <+> "=" <+> concatWith (\x y -> x <+> pipe <+> y) (toList (pretty <$> cs))
 
 instance Pretty (Import a) where
-    pretty (Import _ n)   = parens (":include" <+> pretty n)
+    pretty = prettyImport pretty
 
+prettyImport :: (Name a -> Doc b) -> Import a -> Doc b
+prettyImport pn (Import _ n) = parens (":include" <+> pn n)
+
 instance Pretty (Dickinson a) where
     pretty (Dickinson is ds) = concatWith (\x y -> x <> hardline <> hardline <> y) (fmap pretty is <> ["%-"] <> fmap pretty ds)
 
@@ -141,12 +144,18 @@
 textHard = concatWith (<#>) . map unsafeTextWithoutNewlines . T.splitOn "\n"
 
 instance Pretty (Pattern a) where
-    pretty (PatternVar _ n)    = pretty n
-    pretty (PatternTuple _ ps) = tupled (toList (pretty <$> ps))
-    pretty Wildcard{}          = "_"
-    pretty (PatternCons _ c)   = pretty c
-    pretty (OrPattern _ ps)    = group (encloseSep lparen rparen pipe (toList $ fmap pretty ps))
+    pretty = prettyPattern pretty
 
+instance Debug (Pattern a) where
+    debug = prettyPattern debug
+
+prettyPattern :: (Name a -> Doc b) -> Pattern a -> Doc b
+prettyPattern pn (PatternVar _ n)    = pn n
+prettyPattern pn (PatternTuple _ ps) = tupled (toList (prettyPattern pn <$> ps))
+prettyPattern _ Wildcard{}           = "_"
+prettyPattern pn (PatternCons _ c)   = pn c
+prettyPattern pn (OrPattern _ ps)    = group (encloseSep lparen rparen pipe (toList $ fmap (prettyPattern pn) ps))
+
 escReplace :: T.Text -> T.Text
 escReplace =
       T.replace "\"" "\\\""
@@ -180,10 +189,13 @@
     pretty (BuiltinFn _ b)    = pretty b
 
 instance Pretty (DickinsonTy a) where
-    pretty TyText{}       = "text"
-    pretty (TyFun _ t t') = parens ("⟶" <+> pretty t <+> pretty t')
-    pretty (TyTuple _ ts) = tupled (toList (pretty <$> ts))
-    pretty (TyNamed _ n)  = pretty n
+    pretty = prettyType pretty
+
+prettyType :: (Name a -> Doc b) -> DickinsonTy a -> Doc b
+prettyType _ TyText{}        = "text"
+prettyType pn (TyFun _ t t') = parens ("⟶" <+> prettyType pn t <+> prettyType pn t')
+prettyType pn (TyTuple _ ts) = tupled (toList (prettyType pn <$> ts))
+prettyType pn (TyNamed _ n)  = pn n
 
 defExprM :: Declaration a -> Maybe (Expression a)
 defExprM (Define _ _ e) = Just e
diff --git a/src/Language/Dickinson/Unique.hs b/src/Language/Dickinson/Unique.hs
--- a/src/Language/Dickinson/Unique.hs
+++ b/src/Language/Dickinson/Unique.hs
@@ -6,10 +6,10 @@
                                  , dummyUnique
                                  ) where
 
-import           Control.DeepSeq           (NFData)
-import           Data.Binary               (Binary (..))
-import           Data.Data                 (Data)
-import           Data.Text.Prettyprint.Doc (Pretty)
+import           Control.DeepSeq (NFData)
+import           Data.Binary     (Binary (..))
+import           Data.Data       (Data)
+import           Prettyprinter   (Pretty)
 
 -- | For interning identifiers.
 newtype Unique = Unique { unUnique :: Int }
diff --git a/test/Eval.hs b/test/Eval.hs
--- a/test/Eval.hs
+++ b/test/Eval.hs
@@ -30,6 +30,7 @@
     , resultCase "test/data/refractory.dck"
     , resultCase "test/examples/lambda.dck"
     , resultCase "test/examples/library.dck"
+    , testCase "Escapes even stripped multiline strings" cowsayEval
     ]
 
 forceResult :: a -> Assertion
@@ -75,3 +76,8 @@
 
 orPatternEval :: Assertion
 orPatternEval = evalTo "test/data/orPattern.dck" "hit"
+
+cowsayEval :: Assertion
+cowsayEval = do
+    res <- evalFile ["lib"] "test/eval/cowrun.dck"
+    res @?= "\nHello!\n------\n      \\   ^__^\n       \\  (oo)\\_______\n          (__)\\       )\\/\\\n              ||----w |\n              ||     ||"
diff --git a/test/Golden.hs b/test/Golden.hs
--- a/test/Golden.hs
+++ b/test/Golden.hs
@@ -5,11 +5,11 @@
 import qualified Data.ByteString.Lazy          as BSL
 import           Data.Functor                  (void)
 import           Data.Text.Lazy.Encoding       (encodeUtf8)
-import           Data.Text.Prettyprint.Doc     (pretty)
 import           Data.Text.Prettyprint.Doc.Ext
 import           Language.Dickinson.Parser
 import           Language.Dickinson.Rename
 import           Language.Dickinson.Type
+import           Prettyprinter                 (pretty)
 import           System.FilePath               ((-<.>))
 import           Test.Tasty                    (TestTree, testGroup)
 import           Test.Tasty.Golden             (goldenVsString)
diff --git a/test/Roundtrip/Compare.hs b/test/Roundtrip/Compare.hs
new file mode 100644
--- /dev/null
+++ b/test/Roundtrip/Compare.hs
@@ -0,0 +1,64 @@
+module Roundtrip.Compare ( compareDickinson
+                         ) where
+
+import           Data.List.NonEmpty      (NonEmpty (..))
+import           Language.Dickinson.Name
+import           Language.Dickinson.Type
+
+compareDickinson :: Dickinson a -> Dickinson a -> Bool
+compareDickinson (Dickinson is ds) (Dickinson is' ds') =
+    compareList compareImport is is'
+        && compareList compareDeclaration ds ds'
+
+compareDeclaration :: Declaration a -> Declaration a -> Bool
+compareDeclaration (TyDecl _ n tns) (TyDecl _ n' tns') = compareName n n' && compareNonEmpty compareName tns tns'
+compareDeclaration (Define _ n e) (Define _ n' e')     = compareName n n' && compareExpression e e'
+compareDeclaration _ _                                 = False
+
+compareType :: DickinsonTy a -> DickinsonTy a -> Bool
+compareType TyText{} TyText{}                     = True
+compareType (TyFun _ ty ty') (TyFun _ ty'' ty''') = compareType ty ty'' && compareType ty' ty'''
+compareType (TyNamed _ n) (TyNamed _ n')          = compareName n n'
+compareType (TyTuple _ tys) (TyTuple _ tys')      = compareNonEmpty compareType tys tys'
+compareType _ _                                   = False
+
+compareExpression :: Expression a -> Expression a -> Bool
+compareExpression (Literal _ t) (Literal _ t')           = t == t'
+compareExpression (StrChunk _ t) (StrChunk _ t')         = t == t'
+compareExpression (Choice _ brs) (Choice _ brs')         = compareNonEmpty (\(p, e) (p', e') -> p == p' && compareExpression e e') brs brs'
+compareExpression (Let _ ls e) (Let _ ls' e')            = compareExpression e e' && compareNonEmpty (\(n, e'') (n', e''') -> compareName n n' && compareExpression e'' e''') ls ls'
+compareExpression (Var _ n) (Var _ n')                   = compareName n n'
+compareExpression (Interp _ es) (Interp _ es')           = compareList compareExpression es es'
+compareExpression (MultiInterp _ es) (MultiInterp _ es') = compareList compareExpression es es'
+compareExpression (Lambda _ n ty e) (Lambda _ n' ty' e') = compareName n n' && compareType ty ty' && compareExpression e e'
+compareExpression (Apply _ e e') (Apply _ e'' e''')      = compareExpression e e'' && compareExpression e' e'''
+compareExpression (Concat _ es) (Concat _ es')           = compareList compareExpression es es'
+compareExpression (Tuple _ es) (Tuple _ es')             = compareNonEmpty compareExpression es es'
+compareExpression (Match _ e br) (Match _ e' br')        = compareExpression e e' && compareNonEmpty (\(p, e'') (p', e''') -> comparePattern p p' && compareExpression e'' e''') br br'
+compareExpression (Flatten _ e) (Flatten _ e')           = compareExpression e e'
+compareExpression (Annot _ e ty) (Annot _ e' ty')        = compareExpression e e' && compareType ty ty'
+compareExpression (Constructor _ tn) (Constructor _ tn') = compareName tn tn'
+compareExpression (BuiltinFn _ b) (BuiltinFn _ b')       = b == b'
+compareExpression _ _                                    = False
+
+compareImport :: Import a -> Import a -> Bool
+compareImport (Import _ n) (Import _ n') = compareName n n'
+
+comparePattern :: Pattern a -> Pattern a -> Bool
+comparePattern (PatternVar _ n) (PatternVar _ n')       = compareName n n'
+comparePattern (PatternTuple _ ps) (PatternTuple _ ps') = compareNonEmpty comparePattern ps ps'
+comparePattern (PatternCons _ tn) (PatternCons _ tn')   = compareName tn tn'
+comparePattern Wildcard{} Wildcard{}                    = True
+comparePattern (OrPattern _ ps) (OrPattern _ ps')       = compareNonEmpty comparePattern ps ps'
+comparePattern _ _                                      = False
+
+compareNonEmpty :: (a -> a -> Bool) -> NonEmpty a -> NonEmpty a -> Bool
+compareNonEmpty eq (x :| xs) (y :| ys) = x `eq` y && compareList eq xs ys
+
+compareList :: (a -> a -> Bool) -> [a] -> [a] -> Bool
+compareList _ [] []          = True
+compareList eq (x:xs) (y:ys) = x `eq` y && compareList eq xs ys
+compareList _ _ _            = False
+
+compareName :: Name a -> Name a -> Bool
+compareName (Name n _ _) (Name n' _ _) = n == n'
diff --git a/test/data/lambdaMultiQuote.pretty b/test/data/lambdaMultiQuote.pretty
--- a/test/data/lambdaMultiQuote.pretty
+++ b/test/data/lambdaMultiQuote.pretty
@@ -3,7 +3,7 @@
 (:def cowsay
   (:lambda txt text
     '''
-    
+
     ${txt}
     ------
           \   ^__^
diff --git a/test/eval/cowrun.dck b/test/eval/cowrun.dck
new file mode 100644
--- /dev/null
+++ b/test/eval/cowrun.dck
@@ -0,0 +1,6 @@
+(:include cowsay)
+
+%-
+
+(:def main
+  $ cowsay "Hello!")
