diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2017-2018, Herbert Valerio Riedel
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Herbert Valerio Riedel nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Prelude.cabal b/Prelude.cabal
new file mode 100644
--- /dev/null
+++ b/Prelude.cabal
@@ -0,0 +1,67 @@
+cabal-version:       >=1.10
+name:                Prelude
+version:             0.1.0.0
+
+license:             BSD3
+license-file:        LICENSE
+author:              Herbert Valerio Riedel
+copyright:           2017-2018 Herbert Valerio Riedel
+maintainer:          hvr@gnu.org
+bug-reports:         https://github.com/hvr/Prelude/issues
+category:            Prelude
+build-type:          Simple
+synopsis:            A Prelude module replacement
+description:
+  This package provides a "Prelude" module drop-in replacement for [base](https://hackage.haskell.org/package/base)'s @Prelude@ module.
+  .
+  Goals of this package include:
+  .
+  * Be reasonably modest and remain close in spirit to the @base@ package's scope
+  .
+  * Depend only on @base@ (via @base-noprelude@) for recent GHC versions
+  .
+  * Avoid partial functions being in scope by default; redefine common partial functions such as @read@ or @head@ to be 'Maybe'-valued
+  .
+  * Provide a uniform "Prelude" across multiple GHC releases (currently GHC 7.0 and newer supported) to the extent possible given typeclass restructurings such as AMP or FTP
+  .
+  * Reduce @import@ clutter by reexporting common verbs from modules such as @Control.Monad@ and @Control.Applicative@
+  .
+  === Versioning and Usage
+  .
+  This package is intended to be used in combination with [base-noprelude](https://hackage.haskell.org/package/base-noprelude) and
+  possibly [base-orphans](https://hackage.haskell.org/package/base-orphans). @Prelude@ strives to be faithful to
+  the [PVP](https://pvp.haskell.org/); however, for technical reasons @Prelude@'s API is not fully determined by its version due to changes in core typeclasses and consequently it's strongly advised to declare a dependency on @Prelude@ always in conjunction with a dependency on @base-noprelude@.
+  .
+  For instance, all you need to do in order to use this package if you were previously depending on [base](https://hackage.haskell.org/package/base) via
+  .
+  > build-depends:
+  >     base ^>= 4.10.0.0 || ^>= 4.11.0.0
+  .
+  is to replace @base@ by @base-noprelude@ and also add a dependency on @Prelude@ like so
+  .
+  > build-depends:
+  >     Prelude ^>= 0.1.0.0
+  >   , base-noprelude ^>= 4.10.0.0 || ^>= 4.11.0.0
+  .
+  and this will effectively replace the implicit "Prelude" module.
+
+source-repository head
+  type: git
+  location: https://github.com/hvr/Prelude.git
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Prelude
+
+  default-language:    Haskell2010
+  other-extensions:    BangPatterns CPP NoImplicitPrelude
+
+  build-depends:       base-noprelude >=4.3 && <4.13
+
+  if !impl(ghc >= 8.0)
+    build-depends: semigroups >= 0.18.5 && < 0.19
+                 , fail == 4.9.*
+                 , transformers >= 0.3.0.0 && < 0.6
+
+  if impl(ghc == 7.4.*)
+    build-depends: ghc-prim == 0.2.*
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/src/Prelude.hs b/src/Prelude.hs
new file mode 100644
--- /dev/null
+++ b/src/Prelude.hs
@@ -0,0 +1,321 @@
+{-# LANGUAGE BangPatterns      #-}
+{-# LANGUAGE CPP               #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+#if __GLASGOW_HASKELL__ >= 702
+{-# LANGUAGE Trustworthy       #-}
+#endif
+
+{-# OPTIONS_GHC -Wall #-}
+
+-- |
+-- Copyright: © Herbert Valerio Riedel 2017-2018
+-- SPDX-License-Identifier: BSD-3-Clause
+--
+-- This module is implicitly imported in all modules unless @{-\# LANGUAGE NoImplicitPrelude \#-}@ is in effect.
+--
+module Prelude (
+    -- ** 'Char'
+    Char, String, IsString(fromString)
+
+    -- ** 'Bool'
+  , Bool(False, True)
+  , (&&), (||), not, otherwise, bool
+
+    -- ** 'Maybe'
+  , Maybe(Nothing, Just)
+  , maybe, fromMaybe, isJust, isNothing, mapMaybe, catMaybes, listToMaybe, maybeToList
+
+    -- ** 'Either'
+  , Either(Left, Right)
+  , either, fromLeft, fromRight, isLeft, isRight, lefts, rights, partitionEithers
+
+    -- ** 'Eq' and 'Ord'
+  , Ordering(LT, EQ, GT)
+  , Eq((==), (/=))
+  , Ord(compare, (<), (<=), (>=), (>), max, min)
+  , comparing
+
+    -- ** 'Enum'
+  , Enum(fromEnum, enumFrom, enumFromThen, enumFromTo, enumFromThenTo)
+
+    -- ** 'Bounded'
+  , Bounded(minBound, maxBound)
+
+    -- ** 2-tuples
+  , fst, snd, curry, uncurry
+
+    -- ** 'Num'eric types, classes, and helpers
+  , Integer
+  , Int, Int8, Int16, Int32, Int64
+  , Word, Word8, Word16, Word32, Word64
+  , Float, Double, Rational
+
+  , Num((+), (-), (*), negate, abs, signum, fromInteger)
+  , Real(toRational)
+  , Integral(quot, rem, div, mod, quotRem, divMod, toInteger)
+  , Fractional((/), recip, fromRational)
+  , Floating(pi, exp, log, sqrt, (**), logBase, sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh)
+  , RealFrac(properFraction, truncate, round, ceiling, floor)
+  , RealFloat(floatRadix, floatDigits, floatRange, decodeFloat, encodeFloat, exponent, significand, scaleFloat, isNaN, isInfinite, isDenormalized, isIEEE, isNegativeZero, atan2)
+
+  , subtract, even, odd, gcd, lcm, (^), (^^)
+  , fromIntegral, realToFrac
+
+    -- ** 'Semigroup' and 'Monoid'
+  , Semigroup((<>)), sconcat
+  , Monoid(mempty, mappend, mconcat)
+
+    -- ** 'Functor', 'Applicative', 'Monad', and 'Alternative'
+  , Fun.Functor(fmap, (<$)), (<$>)
+  , Applicative(pure, (<*>), (*>), (<*))
+  , Monad((>>=), (>>), return)
+  , Alternative(empty, (<|>), some, many)
+  , MonadFail
+  , MonadPlus(mzero,mplus)
+  , guard, ($>), Trav.forM, F.forM_, F.mapM_, F.sequence_, (=<<), when, unless, void, F.msum, replicateM, replicateM_, forever, (>=>), (<=<), foldM, foldM_, join
+  , liftM, liftM2, liftM3, liftM4, liftM5
+  , liftA, liftA2, liftA3, liftA4, liftA5
+
+    -- ** 'Foldable' and 'Traversable'
+  , F.Foldable(foldMap, fold, foldr, foldl), F.foldr', F.foldl', F.elem, product, sum, F.toList, F.find
+
+  , Traversable(traverse, sequenceA, mapM, sequence)
+  , F.and, F.or, F.any, F.all, F.concat, F.concatMap, F.asum, F.sequenceA_, F.traverse_, F.notElem
+
+  , null, length
+
+    -- ** 'Data', 'Typeable', and 'Generic'
+
+  , Data
+  , Typeable
+#if MIN_VERSION_base_noprelude(4,5,0)
+  , Generic
+#endif
+
+    -- ** List operations
+  , Prelude.head
+  , Prelude.last
+  , Prelude.init
+  , Prelude.tail
+  , List.inits
+  , List.tails
+  , uncons
+
+  , List.drop
+  , List.dropWhile
+  , List.take
+  , List.takeWhile
+
+  , List.break
+  , List.span
+  , List.splitAt
+
+  , List.filter
+  , List.iterate
+  , List.lookup
+  , List.partition
+  , List.repeat
+  , List.replicate
+  , List.reverse
+  , List.groupBy
+  , List.intersperse
+  , List.intercalate
+
+  , List.scanl
+  , List.scanl1
+  , List.scanr
+  , List.scanr1
+
+    -- *** Zipping
+  , List.zip
+  , List.zip3
+  , List.zip4
+  , List.zip5
+  , List.zip6
+  , List.zip7
+  , List.zipWith
+  , List.zipWith3
+  , List.zipWith4
+  , List.zipWith5
+  , List.zipWith6
+  , List.zipWith7
+  , List.unzip
+  , List.unzip3
+  , List.unzip4
+  , List.unzip5
+  , List.unzip6
+  , List.unzip7
+
+    -- ** 'NonEmpty' lists
+  , NonEmpty((:|))
+
+    -- ** 'Read' and 'Show'
+  , Show(showsPrec, showList, show)
+  , ShowS, shows, showChar, showString, showParen
+
+  , Read(readsPrec, readList)
+  , ReadS, reads, readParen, Prelude.read
+
+    -- ** 'IO' and 'MonadIO'
+  , IO
+  , MonadIO(liftIO)
+
+    -- *** Standard input/output
+  , putChar, putStr, putStrLn, print
+  , getChar, getLine, getContents
+
+    -- *** 'FilePath'
+  , FilePath
+  , readFile, writeFile, appendFile
+
+
+    -- ** Common miscellaneous verbs
+  , id, const, (.), flip, ($), ($!), (&), until, asTypeOf, seq, on
+
+    -- *** Intentionally partial functions
+  , error, errorWithoutStackTrace, undefined
+
+  ) where
+
+import           Control.Applicative          as App
+import           Control.Monad
+import           Control.Monad.Fail
+import           Control.Monad.IO.Class
+import           Data.Bool
+import           Data.Data                    (Data)
+import           Data.Either
+import           Data.Foldable                as F
+import           Data.Function
+import           Data.Functor                 as Fun
+import           Data.Int
+import qualified Data.List                    as List
+import           Data.List.NonEmpty           (NonEmpty (..))
+import           Data.Maybe
+import           Data.Ord
+import           Data.Semigroup
+import           Data.String
+import           Data.Traversable             as Trav
+import           Data.Tuple
+import           Data.Typeable                (Typeable)
+import           Data.Word
+import           System.IO
+import           Text.Read
+
+import           GHC.Base
+import           GHC.Enum
+import           GHC.Float
+#if MIN_VERSION_base_noprelude(4,5,0)
+import           GHC.Generics                 (Generic)
+#endif
+import           GHC.Num
+import           GHC.Real
+import           GHC.Show
+
+#if MIN_VERSION_base_noprelude(4,8,0)
+import           Data.List                    (uncons)
+#endif
+
+#if !MIN_VERSION_base_noprelude(4,7,0)
+import           GHC.Err                      (undefined)
+#endif
+
+#if !MIN_VERSION_base_noprelude(4,6,0)
+import           Text.ParserCombinators.ReadP as P
+#endif
+
+-- | Last element of a list.
+last :: [a] -> Maybe a
+last [] = Nothing
+last xs = Just (List.last xs)
+
+-- | First element of a list.
+head :: [a] -> Maybe a
+head []    = Nothing
+head (x:_) = Just x
+
+-- | List with the last element removed.
+init :: [a] -> Maybe [a]
+init [] = Nothing
+init xs = Just (List.init xs)
+
+-- | List with the first element removed.
+tail :: [a] -> Maybe [a]
+tail []     = Nothing
+tail (_:xs) = Just xs
+
+-- | Lift a 4-ary function to actions.
+liftA4 :: Applicative f => (a -> b -> c -> d -> e) -> f a -> f b -> f c -> f d -> f e
+liftA4 f a b c d = liftA3 f a b c <*> d
+
+-- | Lift a 5-ary function to actions.
+liftA5 :: Applicative f => (a -> b -> c -> d -> e -> g) -> f a -> f b -> f c -> f d -> f e -> f g
+liftA5 f a b c d e = liftA4 f a b c d <*> e
+
+
+#if !MIN_VERSION_base_noprelude(4,10,0)
+fromLeft :: a -> Either a b -> a
+fromLeft _ (Left a) = a
+fromLeft a _        = a
+
+fromRight :: b -> Either a b -> b
+fromRight _ (Right b) = b
+fromRight b _         = b
+#endif
+
+#if !MIN_VERSION_base_noprelude(4,9,0)
+errorWithoutStackTrace :: String -> a
+errorWithoutStackTrace = error
+#endif
+
+#if !MIN_VERSION_base_noprelude(4,8,0)
+infixl 1 &
+
+(&) :: a -> (a -> b) -> b
+x & f = f x
+
+null :: Foldable f => f a -> Bool
+null = List.null . F.toList
+
+length :: Foldable f => f a -> Int
+length = List.length . F.toList
+
+infixr 0 $!
+
+($!)    :: (a -> b) -> a -> b
+f $! x  = let !vx = x in f vx
+
+uncons :: [a] -> Maybe (a, [a])
+uncons []     = Nothing
+uncons (x:xs) = Just (x, xs)
+#endif
+
+#if !MIN_VERSION_base_noprelude(4,7,0)
+isRight, isLeft :: Either a b -> Bool
+isRight (Left  _) = False
+isRight (Right _) = True
+isLeft  (Left  _) = True
+isLeft  (Right _) = False
+
+bool :: a -> a -> Bool -> a
+bool f _ False = f
+bool _ t True  = t
+
+infixl 4 $>
+($>) :: Functor f => f a -> b -> f b
+x $> y = y <$ x
+#endif
+
+-- | Parse using the 'Read' instance. Succeeds if there's a unique valid parse; returns 'Nothing' otherwise.
+read :: Read a => String -> Maybe a
+#if !MIN_VERSION_base_noprelude(4,6,0)
+read s = case [ x | (x,"") <- readPrec_to_S read' minPrec s ] of
+           [x] -> Just x
+           _   -> Nothing
+ where
+  read' = do x <- readPrec
+             lift P.skipSpaces
+             return x
+#else
+read = readMaybe
+#endif
