diff --git a/quasar.cabal b/quasar.cabal
index 1c0f83fbda8c223989a019a0e06a38eb0d884939..a339ef314020b05c12b0ec22fe0bbaf51b662de0 100644
--- a/quasar.cabal
+++ b/quasar.cabal
@@ -15,6 +15,7 @@ common shared-properties
   default-extensions:
     AllowAmbiguousTypes
     BangPatterns
+    ConstraintKinds
     DataKinds
     DefaultSignatures
     DeriveAnyClass
@@ -33,6 +34,7 @@ common shared-properties
     NamedFieldPuns
     NoImplicitPrelude
     OverloadedStrings
+    PolyKinds
     RankNTypes
     ScopedTypeVariables
     StandaloneDeriving
@@ -48,6 +50,7 @@ common shared-properties
     hashable,
     microlens-platform,
     mtl,
+    record-hasfield,
     template-haskell,
     transformers,
     unordered-containers,
diff --git a/src/Quasar/Prelude.hs b/src/Quasar/Prelude.hs
index ada83ca5edf0c3c93bb59cded9febe4dd9a9404d..edcaccf177797faecae877c170434fb4824bba4f 100644
--- a/src/Quasar/Prelude.hs
+++ b/src/Quasar/Prelude.hs
@@ -1,13 +1,12 @@
-{-# LANGUAGE PackageImports #-}
-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE PolyKinds #-}
-
 module Quasar.Prelude
-  ( module BasePrelude,
+  ( module Prelude,
     module Quasar.PreludeExtras,
     (>=>),
     (<=<),
     Control.Applicative.liftA2,
+    module Control.Concurrent.MVar,
+    Control.Exception.Exception,
+    Control.Exception.SomeException,
     Control.Exception.throwIO,
     Control.Monad.forever,
     Control.Monad.unless,
@@ -16,15 +15,25 @@ module Quasar.Prelude
     Control.Monad.forM,
     Control.Monad.forM_,
     Control.Monad.join,
+    Data.Unique.Unique,
+    Data.Unique.newUnique,
     Data.Void.Void,
     Hashable.Hashable,
     GHC.Generics.Generic,
     MonadIO,
     liftIO,
-    Maybe.catMaybes,
-    Maybe.fromMaybe,
-    Maybe.listToMaybe,
-    Maybe.maybeToList,
+    Data.Maybe.catMaybes,
+    Data.Maybe.fromMaybe,
+    Data.Maybe.listToMaybe,
+    Data.Maybe.maybeToList,
+    Data.Int.Int8,
+    Data.Int.Int16,
+    Data.Int.Int32,
+    Data.Int.Int64,
+    Data.Word.Word8,
+    Data.Word.Word16,
+    Data.Word.Word32,
+    Data.Word.Word64,
     error,
     errorWithoutStackTrace,
     head,
@@ -43,26 +52,34 @@ module Quasar.Prelude
   )
 where
 
-import "base" Prelude as BasePrelude hiding
+import Prelude hiding
   ( error,
     errorWithoutStackTrace,
     head,
     last,
     read,
+    -- Due to the accepted "monad of no return" proposal, return becomes an
+    -- alias for pure. Return can be a pitfall for newcomers, so we decided to
+    -- use pure instead.
+    return,
     undefined,
   )
-import qualified "base" Prelude as P
+import qualified Prelude as P
 
 import Quasar.PreludeExtras
 
 import qualified Control.Applicative
+import Control.Concurrent.MVar
 import qualified Control.Exception
 import qualified Control.Monad
-import qualified Data.Void
 import Control.Monad ((>=>), (<=<))
 import Control.Monad.IO.Class (MonadIO, liftIO)
 import qualified Data.Hashable as Hashable
-import qualified Data.Maybe as Maybe
+import qualified Data.Int
+import qualified Data.Maybe
+import qualified Data.Unique
+import qualified Data.Void
+import qualified Data.Word
 import qualified Debug.Trace as Trace
 import qualified GHC.Generics
 import qualified GHC.Stack.Types
diff --git a/src/Quasar/PreludeExtras.hs b/src/Quasar/PreludeExtras.hs
index 377efab622232334e494a76c7934530101a773f1..9489b5af89174e39d7b5a9d50e6368ed258f9b33 100644
--- a/src/Quasar/PreludeExtras.hs
+++ b/src/Quasar/PreludeExtras.hs
@@ -1,14 +1,12 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE PackageImports #-}
-
 module Quasar.PreludeExtras where
 
 -- Use prelude from `base` to prevent module import cycle.
-import "base" Prelude
+import Prelude
 
 import Quasar.Utils.ExtraT
 
 import Control.Applicative (liftA2)
+import Control.Concurrent (threadDelay)
 import Control.Monad.State.Lazy as State
 import qualified Data.Char as Char
 import qualified Data.Hashable as Hashable
@@ -16,7 +14,10 @@ import qualified Data.HashMap.Strict as HM
 import qualified Data.HashSet as HS
 import qualified Data.List as List
 import qualified Data.Maybe as Maybe
+import GHC.Records.Compat (HasField, getField, setField)
 import qualified GHC.Stack.Types
+import GHC.TypeLits (Symbol)
+import Lens.Micro.Platform (Lens', lens)
 
 impossibleCodePath :: GHC.Stack.Types.HasCallStack => a
 impossibleCodePath = error "Code path marked as impossible was reached"
@@ -51,6 +52,7 @@ leftToMaybe :: Either a b -> Maybe a
 leftToMaybe (Left x) = Just x
 leftToMaybe (Right _) = Nothing
 
+-- | Returns all duplicate elements in a list. The order of the produced list is unspecified.
 duplicates :: forall a. (Eq a, Hashable.Hashable a) => [a] -> [a]
 duplicates = HS.toList . duplicates' HS.empty
   where
@@ -87,3 +89,19 @@ infixr 6 <<>>
 
 dup :: a -> (a, a)
 dup x = (x, x)
+
+-- | Enumerate all values of an 'Enum'
+enumerate :: (Enum a, Bounded a) => [a]
+enumerate = [minBound..maxBound]
+
+-- | Splits a list using a predicate. The separator is removed. The opposite of `intercalate`.
+splitOn :: (a -> Bool) -> [a] -> [[a]]
+splitOn p s = case break p s of
+  (w, []) -> [w]
+  (w, _:r) -> w : splitOn p r
+
+fieldLens :: forall (x :: Symbol) r a. HasField x r a => Lens' r a
+fieldLens = lens (getField @x) (setField @x)
+
+sleepForever :: IO a
+sleepForever = forever $ threadDelay 1000000000000