diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,41 @@
 # Change Log
 
+## [v0.8.1](https://github.com/tweag/linear-base/tree/v0.8.1) (2026-06-24)
+
+[Full Changelog](https://github.com/tweag/linear-base/compare/v0.8.0...v0.8.1)
+
+### Headline changes
+
+- Restore compatibility with GHC 9.2: Import Multiplicity from GHC.Types [\#509](https://github.com/tweag/linear-base/pull/509) ([tomsmeding](https://github.com/tomsmeding))
+
+## [v0.8.0](https://github.com/tweag/linear-base/tree/v0.8.0) (2026-05-12)
+
+[Full Changelog](https://github.com/tweag/linear-base/compare/v0.7.0...v0.8.0)
+
+### Headline changes
+
+- Add MonadIO instances for StateT and ReaderT [\#506](https://github.com/tweag/linear-base/pull/506) ([dcastro](https://github.com/dcastro))
+- Coerce `System.IO` and `Linear.IO` into `RIO` [\#505](https://github.com/tweag/linear-base/pull/505) ([dcastro](https://github.com/dcastro))
+
+## [v0.7.0](https://github.com/tweag/linear-base/tree/v0.7.0) (2026-02-27)
+
+[Full Changelog](https://github.com/tweag/linear-base/compare/v0.6.0...v0.7.0)
+
+### Headline changes
+
+- Add instance Consumable/Dupable/Movable for ByteString, ShortByteString and Text [\#501](https://github.com/tweag/linear-base/pull/501) ([Bodigrim](https://github.com/Bodigrim))
+- feat: Adds missing instances for `NonEmpty` and adds some Linear counterpart of `Data.List.NonEmpty` [\#495](https://github.com/tweag/linear-base/pull/495) ([konn](https://github.com/konn))
+- use Unsatisfiable for banned instances \(unrestricted Monoid / Semigroup for linear containers\) [\#494](https://github.com/tweag/linear-base/pull/494) ([konn](https://github.com/konn))
+- Control Monad instance for linear arrows [\#493](https://github.com/tweag/linear-base/pull/493) ([konn](https://github.com/konn))
+
+## [v0.6.0](https://github.com/tweag/linear-base/tree/v0.6.0) (2025-11-18)
+
+[Full Changelog](https://github.com/tweag/linear-base/compare/v0.5.0...v0.6.0)
+
+### Headline changes
+
+- Make List.zipWith as lazy as expected [\#492](https://github.com/tweag/linear-base/pull/492) ([aspiwack](https://github.com/aspiwack))
+
 ## [v0.5.0](https://github.com/tweag/linear-base/tree/v0.5.0) (2025-04-07)
 
 [Full Changelog](https://github.com/tweag/linear-base/compare/v0.4.0...v0.5.0)
diff --git a/bench/Data/Mutable/HashMap.hs b/bench/Data/Mutable/HashMap.hs
--- a/bench/Data/Mutable/HashMap.hs
+++ b/bench/Data/Mutable/HashMap.hs
@@ -22,7 +22,7 @@
 import qualified Data.HashTable.ST.Basic as BasicST
 import qualified Data.HashTable.ST.Cuckoo as CuckooST
 import Data.Hashable (Hashable (..), hashWithSalt)
-import Data.List (foldl')
+import qualified Data.List as List
 import qualified Data.Unrestricted.Linear as Linear
 import GHC.Generics (Generic)
 import qualified Prelude.Linear as Linear
@@ -199,7 +199,7 @@
       bench (descriptions !! n) $ nf (\xs -> f xs Map.empty) kvs
 
     foldlx :: (b -> a -> b) -> [a] -> b -> b
-    foldlx f xs b = foldl' f b xs
+    foldlx f xs b = List.foldl' f b xs
 
     look :: Map.HashMap Key Int -> Key -> Map.HashMap Key Int
     look m k = case m Map.!? k of
@@ -208,7 +208,7 @@
 
     bench1 :: Benchmark
     bench1 = mkBench 0 $
-      \xs hm -> foldl' (\m (k, v) -> Map.delete k (Map.insert k v m)) hm xs
+      \xs hm -> List.foldl' (\m (k, v) -> Map.delete k (Map.insert k v m)) hm xs
 
     bench2 :: Benchmark
     bench2 = mkBench 1 $
diff --git a/linear-base.cabal b/linear-base.cabal
--- a/linear-base.cabal
+++ b/linear-base.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               linear-base
-version:            0.5.0
+version:            0.8.1
 license:            MIT
 license-file:       LICENSE
 copyright:          (c) Tweag Holding and affiliates
@@ -79,6 +79,7 @@
         Data.HashMap.Mutable.Linear
         Data.HashMap.Mutable.Linear.Internal
         Data.List.Linear
+        Data.List.NonEmpty.Linear
         Data.Maybe.Linear
         Data.Monoid.Linear
         Data.Monoid.Linear.Internal.Monoid
@@ -134,6 +135,7 @@
     default-language: Haskell2010
     build-depends:
         base >=4.16 && <5,
+        bytestring,
         containers,
         ghc-prim,
         ghc-bignum,
diff --git a/src/Control/Functor/Linear/Internal/Reader.hs b/src/Control/Functor/Linear/Internal/Reader.hs
--- a/src/Control/Functor/Linear/Internal/Reader.hs
+++ b/src/Control/Functor/Linear/Internal/Reader.hs
@@ -1,5 +1,9 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DerivingVia #-}
+{-# LANGUAGE FlexibleInstances #-}
 {-# OPTIONS -Wno-orphans #-}
 {-# LANGUAGE LinearTypes #-}
+{-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE NoImplicitPrelude #-}
 {-# OPTIONS_HADDOCK hide #-}
 
@@ -28,8 +32,10 @@
 import Data.Functor.Identity
 import qualified Data.Functor.Linear.Internal.Applicative as Data
 import qualified Data.Functor.Linear.Internal.Functor as Data
+import Data.Kind (FUN)
 import Data.Unrestricted.Linear.Internal.Consumable
 import Data.Unrestricted.Linear.Internal.Dupable
+import GHC.Types (Multiplicity (..))
 import Prelude.Linear.Internal (runIdentity', ($), (.))
 
 -- # Linear ReaderT
@@ -119,3 +125,9 @@
 
 instance MonadTrans (NonLinear.ReaderT r) where
   lift x = NonLinear.ReaderT (\_ -> x)
+
+deriving via Reader r instance (Dupable r) => Data.Applicative (FUN 'One r)
+
+deriving via Reader r instance (Dupable r) => Applicative (FUN 'One r)
+
+deriving via Reader r instance (Dupable r) => Monad (FUN 'One r)
diff --git a/src/Control/Monad/IO/Class/Linear.hs b/src/Control/Monad/IO/Class/Linear.hs
--- a/src/Control/Monad/IO/Class/Linear.hs
+++ b/src/Control/Monad/IO/Class/Linear.hs
@@ -7,6 +7,8 @@
 import Prelude.Linear
 import qualified System.IO as System
 import qualified System.IO.Linear as Linear
+import System.IO.Resource.Linear (RIO)
+import qualified System.IO.Resource.Linear as RIO
 
 -- | Like 'NonLinear.MonadIO' but allows to lift both linear
 -- and non-linear 'IO' actions into a linear monad.
@@ -19,3 +21,12 @@
 
 instance MonadIO Linear.IO where
   liftIO = id
+
+instance MonadIO RIO where
+  liftIO = RIO.fromIO
+
+instance (MonadIO m) => MonadIO (Linear.StateT s m) where
+  liftIO = Linear.lift . liftIO
+
+instance (MonadIO m, Dupable r) => MonadIO (Linear.ReaderT r m) where
+  liftIO = Linear.lift . liftIO
diff --git a/src/Data/Functor/Linear/Internal/Functor.hs b/src/Data/Functor/Linear/Internal/Functor.hs
--- a/src/Data/Functor/Linear/Internal/Functor.hs
+++ b/src/Data/Functor/Linear/Internal/Functor.hs
@@ -32,6 +32,7 @@
 import Data.Functor.Product
 import Data.Functor.Sum
 import Data.Kind (FUN)
+import Data.List.NonEmpty (NonEmpty)
 import Data.Unrestricted.Linear.Internal.Consumable
 import Data.Unrestricted.Linear.Internal.Ur
 import GHC.Types (Multiplicity (..))
@@ -75,6 +76,11 @@
       go :: [a] %1 -> [b]
       go [] = []
       go (a : as) = f a : go as
+
+deriving via
+  Generically1 NonEmpty
+  instance
+    Functor NonEmpty
 
 deriving via
   Generically1 (Const x)
diff --git a/src/Data/Functor/Linear/Internal/Traversable.hs b/src/Data/Functor/Linear/Internal/Traversable.hs
--- a/src/Data/Functor/Linear/Internal/Traversable.hs
+++ b/src/Data/Functor/Linear/Internal/Traversable.hs
@@ -34,6 +34,7 @@
 import Data.Functor.Const
 import qualified Data.Functor.Linear.Internal.Applicative as Data
 import qualified Data.Functor.Linear.Internal.Functor as Data
+import Data.List.NonEmpty (NonEmpty (..))
 import GHC.Types (Multiplicity (..))
 import Generics.Linear
 import Prelude.Linear.Internal
@@ -130,6 +131,12 @@
     where
       go [] = Control.pure []
       go (x : xs) = Control.liftA2 (:) (f x) (go xs)
+
+instance Traversable NonEmpty where
+  -- We define traverse explicitly both to allow specialization
+  -- to the appropriate Applicative and to allow specialization to
+  -- the passed function. The generic definition allows neither, sadly.
+  traverse f (x :| xs) = (:|) Control.<$> f x Control.<*> traverse f xs
 
 instance Traversable ((,) a) where
   traverse = genericTraverse
diff --git a/src/Data/HashMap/Mutable/Linear/Internal.hs b/src/Data/HashMap/Mutable/Linear/Internal.hs
--- a/src/Data/HashMap/Mutable/Linear/Internal.hs
+++ b/src/Data/HashMap/Mutable/Linear/Internal.hs
@@ -1,5 +1,7 @@
 {-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE InstanceSigs #-}
@@ -25,7 +27,9 @@
 import Data.Hashable
 import qualified Data.Maybe as NonLinear
 import Data.Unrestricted.Linear
+import GHC.TypeLits (ErrorMessage (..))
 import Prelude.Linear hiding (filter, insert, lookup, mapMaybe, read, (+))
+import Prelude.Linear.Unsatisfiable (Unsatisfiable, unsatisfiable)
 import Unsafe.Coerce (unsafeCoerce)
 import qualified Unsafe.Linear as Unsafe
 import Prelude ((+))
@@ -481,8 +485,8 @@
         )
         arr
 
-instance Prelude.Semigroup (HashMap k v) where
-  (<>) = error "Prelude.<>: invariant violation, unrestricted HashMap"
+instance (Unsatisfiable ('Text "Using Prelude's Semigroup methods on a Data.HashMap.Mutable.Linear is vacuous as there can't be an unrestricted such Hashmap")) => Prelude.Semigroup (HashMap k v) where
+  (<>) = unsatisfiable
 
 instance (Keyed k) => Semigroup (HashMap k v) where
   (<>) = union
diff --git a/src/Data/List/Linear.hs b/src/Data/List/Linear.hs
--- a/src/Data/List/Linear.hs
+++ b/src/Data/List/Linear.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE LinearTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE NoImplicitPrelude #-}
@@ -80,6 +80,7 @@
     zip3,
     zipWith,
     zipWith',
+    zipFold,
     zipWith3,
     unzip,
     unzip3,
@@ -354,18 +355,53 @@
 zip3 = zipWith3 (,,)
 
 zipWith :: (Consumable a, Consumable b) => (a %1 -> b %1 -> c) -> [a] %1 -> [b] %1 -> [c]
-zipWith f xs ys =
-  zipWith' f xs ys & \(ret, leftovers) ->
-    leftovers `lseq` ret
+zipWith f =
+  zipFold (\a b cs -> f a b : cs) [] consume2 consume2
+  where
+    consume2 :: forall x y z. (Consumable x, Consumable y) => x %1 -> y %1 -> [z]
+    consume2 x y = x `lseq` y `lseq` []
 
 -- | Same as 'zipWith', but returns the leftovers instead of consuming them.
+-- Because the leftovers are returned at toplevel, @zipWith'@ is pretty strict:
+-- forcing the first cons cell of the returned list forces all the recursive
+-- calls.
 zipWith' :: (a %1 -> b %1 -> c) -> [a] %1 -> [b] %1 -> ([c], Maybe (Either (NonEmpty a) (NonEmpty b)))
-zipWith' _ [] [] = ([], Nothing)
-zipWith' _ (a : as) [] = ([], Just (Left (a :| as)))
-zipWith' _ [] (b : bs) = ([], Just (Right (b :| bs)))
-zipWith' f (a : as) (b : bs) =
-  case zipWith' f as bs of
-    (cs, rest) -> (f a b : cs, rest)
+zipWith' f =
+  zipFold
+    (\a b !(cs, rest) -> ((f a b : cs), rest))
+    ([], Nothing)
+    (\a as -> ([], Just (Left (a :| as))))
+    (\b bs -> ([], Just (Right (b :| bs))))
+
+-- | A function which combines zipping and 'foldr'. It's more general than all
+-- the zip-family functions ('zip', 'zip'', 'zipWith', 'zipWith'').
+--
+-- If @k < n@, then
+--
+-- * @'zipFold' cons nil lefta leftb [a₁, a₂, …, aₙ] [b₁, b₂, …, bₖ] = cons a₁ b₁ (cons a₂ b₂ (… (cons aₖ bₖ (lefta aₖ₊₁ [aₖ₊₂, …, aₙ]))))@
+-- * @'zipFold' cons nil lefta leftb [a₁, a₂, …, aₖ] [b₁, b₂, …, bₙ] = cons a₁ b₁ (cons a₂ b₂ (… (cons aₖ bₖ (leftb bₖ₊₁ [bₖ₊₂, …, bₙ]))))@
+-- * @'zipFold' cons nil lefta leftb [a₁, a₂, …, aₖ] [b₁, b₂, …, bₖ] = cons a₁ b₁ (cons a₂ b₂ (… (cons aₖ bₖ nil)))@
+zipFold ::
+  forall r a b.
+  -- | Combines elements at the same index
+  (a %1 -> b %1 -> r %1 -> r) ->
+  -- | Starting value if both lists have the same length
+  r ->
+  -- | Starting value if the first list is longer
+  (a %1 -> [a] %1 -> r) ->
+  -- | Starting value if the second list is longer
+  (b %1 -> [b] %1 -> r) ->
+  [a] %1 ->
+  [b] %1 ->
+  r
+zipFold cons nil lefta leftb =
+  go
+  where
+    go :: [a] %1 -> [b] %1 -> r
+    go [] [] = nil
+    go (a : as) [] = lefta a as
+    go [] (b : bs) = leftb b bs
+    go (a : as) (b : bs) = cons a b (go as bs)
 
 zipWith3 :: forall a b c d. (Consumable a, Consumable b, Consumable c) => (a %1 -> b %1 -> c %1 -> d) -> [a] %1 -> [b] %1 -> [c] %1 -> [d]
 zipWith3 _ [] ys zs = (ys, zs) `lseq` []
diff --git a/src/Data/List/NonEmpty/Linear.hs b/src/Data/List/NonEmpty/Linear.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/List/NonEmpty/Linear.hs
@@ -0,0 +1,211 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE LinearTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# OPTIONS_GHC -Wno-name-shadowing #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+-- |
+-- Linear versions of 'NonEmpty' functions.
+--
+-- This module only contains minimal amount of documentation; consult the
+-- original "Data.List.NonEmpty" module for more detailed information.
+module Data.List.NonEmpty.Linear
+  ( -- * Non-empty stream transformations
+    NonEmpty (..),
+    map,
+    intersperse,
+    scanl,
+    scanr,
+    scanl1,
+    scanr1,
+    transpose,
+    NonLinear.sortBy,
+    NonLinear.sortWith,
+
+    -- * Basic functions
+    length,
+    NonLinear.head,
+    NonLinear.tail,
+    NonLinear.last,
+    NonLinear.init,
+    singleton,
+    (<|),
+    cons,
+    uncons,
+    unfoldr,
+    NonLinear.sort,
+    reverse,
+    append,
+    appendList,
+    prependList,
+
+    -- * Extracting sublists
+    take,
+    drop,
+    splitAt,
+    takeWhile,
+    dropWhile,
+    span,
+    break,
+    filter,
+    partition,
+
+    -- * Zipping and unzipping streams
+    zip,
+    zipWith,
+    zip',
+    zipWith',
+    unzip,
+    unzip3,
+
+    -- * Converting to and from a list
+    fromList,
+    toList,
+    nonEmpty,
+    xor,
+  )
+where
+
+import qualified Data.List.Linear as List
+import Data.List.NonEmpty (NonEmpty (..))
+import qualified Data.List.NonEmpty as NonLinear
+import Data.Vector.Internal.Check (HasCallStack)
+import Prelude.Linear hiding (drop, dropWhile, filter, intersperse, length, map, partition, reverse, scanl, scanl1, scanr, scanr1, span, splitAt, take, takeWhile, transpose, uncons, unfoldr, unzip, unzip3, zip, zip', zipWith, zipWith')
+import qualified Unsafe.Linear as Unsafe
+import qualified Prelude as Prelude
+
+map :: (a %1 -> b) -> NonEmpty a %1 -> NonEmpty b
+map f (x :| xs) = f x :| List.map f xs
+
+intersperse :: a -> NonEmpty a %1 -> NonEmpty a
+intersperse a = Unsafe.toLinear (NonLinear.intersperse a)
+
+reverse :: NonEmpty a %1 -> NonEmpty a
+reverse = Unsafe.toLinear NonLinear.reverse
+
+scanl :: (Dupable b) => (b %1 -> a %1 -> b) -> b %1 -> NonEmpty a %1 -> NonEmpty b
+scanl f z = fromList . List.scanl f z . toList
+
+scanr :: (Dupable b) => (a %1 -> b %1 -> b) -> b %1 -> NonEmpty a %1 -> NonEmpty b
+scanr f z = fromList . List.scanr f z . toList
+
+scanl1 :: (Dupable a) => (a %1 -> a %1 -> a) -> NonEmpty a %1 -> NonEmpty a
+scanl1 f (x :| xs) = fromList $ List.scanl f x xs
+
+scanr1 :: (Dupable a) => (a %1 -> a %1 -> a) -> NonEmpty a %1 -> NonEmpty a
+scanr1 f (x :| xs) = fromList $ List.scanr1 f (x : xs)
+
+transpose :: NonEmpty (NonEmpty a) %1 -> NonEmpty (NonEmpty a)
+transpose = Unsafe.toLinear NonLinear.transpose
+
+singleton :: a %1 -> NonEmpty a
+singleton = (:| [])
+
+infixr 5 <|
+
+(<|) :: a %1 -> NonEmpty a %1 -> NonEmpty a
+a <| bs = a :| toList bs
+
+cons :: a %1 -> NonEmpty a %1 -> NonEmpty a
+cons = (<|)
+
+uncons :: NonEmpty a %1 -> (a, Maybe (NonEmpty a))
+uncons (x :| xs) = (x, nonEmpty xs)
+
+unfoldr :: (a %1 -> (b, Maybe a)) -> a %1 -> NonEmpty b
+unfoldr f a = case f a of
+  (b, mc) -> b :| maybe [] go mc
+  where
+    go c = case f c of
+      (d, me) -> d : maybe [] go me
+
+append :: NonEmpty a %1 -> NonEmpty a %1 -> NonEmpty a
+append = (<>)
+
+appendList :: NonEmpty a %1 -> [a] %1 -> NonEmpty a
+appendList (x :| xs) ys = x :| (xs <> ys)
+
+prependList :: [a] %1 -> NonEmpty a %1 -> NonEmpty a
+prependList ls ne = case ls of
+  [] -> ne
+  (y : ys) -> y :| (ys <> toList ne)
+
+-- | __NOTE__: This does not short-circuit and always traverses the
+-- entire list to consume the rest of the elements.
+take :: (Consumable a) => Int -> NonEmpty a %1 -> [a]
+take n = List.take n . toList
+
+drop :: (Consumable a) => Int -> NonEmpty a %1 -> [a]
+drop n = List.drop n . toList
+
+splitAt :: (Consumable a) => Int -> NonEmpty a %1 -> ([a], [a])
+splitAt n = List.splitAt n . toList
+
+-- | __NOTE__: This does not short-circuit and always traverses the
+-- entire list to consume the rest of the elements.
+takeWhile :: (Dupable a) => (a %1 -> Bool) -> NonEmpty a %1 -> [a]
+takeWhile p = List.takeWhile p . toList
+
+dropWhile :: (Dupable a) => (a %1 -> Bool) -> NonEmpty a %1 -> [a]
+dropWhile p = List.dropWhile p . toList
+
+span :: (Dupable a) => (a %1 -> Bool) -> NonEmpty a %1 -> ([a], [a])
+span p = List.span p . toList
+
+break :: (Dupable a) => (a %1 -> Bool) -> NonEmpty a %1 -> ([a], [a])
+break p = span (not . p)
+
+filter :: (Dupable a) => (a %1 -> Bool) -> NonEmpty a %1 -> [a]
+filter p = List.filter p . toList
+
+partition :: (Dupable a) => (a %1 -> Bool) -> NonEmpty a %1 -> ([a], [a])
+partition p = List.partition p . toList
+
+-- | Return the length of the given list alongside with the list itself.
+length :: NonEmpty a %1 -> (Ur Int, NonEmpty a)
+length = Unsafe.toLinear $ \xs ->
+  (Ur (NonLinear.length xs), xs)
+
+fromList :: (HasCallStack) => [a] %1 -> (NonEmpty a)
+fromList (x : xs) = x :| xs
+fromList [] = Prelude.error "NonEmpty.Linear.fromList: empty list"
+
+toList :: NonEmpty a %1 -> [a]
+toList (x :| xs) = x : xs
+
+nonEmpty :: [a] %1 -> Maybe (NonEmpty a)
+nonEmpty (x : xs) = Just (x :| xs)
+nonEmpty [] = Nothing
+
+xor :: NonEmpty Bool %1 -> Bool
+xor = Unsafe.toLinear NonLinear.xor
+
+zip :: (Consumable a, Consumable b) => NonEmpty a %1 -> NonEmpty b %1 -> NonEmpty (a, b)
+zip = zipWith (,)
+
+zipWith :: (Consumable a, Consumable b) => (a %1 -> b %1 -> c) -> NonEmpty a %1 -> NonEmpty b %1 -> NonEmpty c
+zipWith f (a :| as) (b :| bs) = f a b :| List.zipWith f as bs
+
+-- | Same as 'zipWith', but returns the leftovers instead of consuming them.
+-- Because the leftovers are returned at toplevel, @zipWith'@ is pretty strict:
+-- forcing the second cons cell of the returned list forces all the recursive
+-- calls.
+zipWith' :: (a %1 -> b %1 -> c) -> NonEmpty a %1 -> NonEmpty b %1 -> (NonEmpty c, Maybe (Either (NonEmpty a) (NonEmpty b)))
+zipWith' f (a :| as) (b :| bs) =
+  case List.zipWith' f as bs of
+    (cs, may) -> (f a b :| cs, may)
+
+-- | Same as 'zip', but returns the leftovers instead of consuming them.
+zip' :: NonEmpty a %1 -> NonEmpty b %1 -> (NonEmpty (a, b), Maybe (Either (NonEmpty a) (NonEmpty b)))
+zip' = zipWith' (,)
+
+unzip :: NonEmpty (a, b) %1 -> (NonEmpty a, NonEmpty b)
+unzip ((a, b) :| asbs) =
+  List.unzip asbs & \(as, bs) ->
+    (a :| as, b :| bs)
+
+unzip3 :: NonEmpty (a, b, c) %1 -> (NonEmpty a, NonEmpty b, NonEmpty c)
+unzip3 ((a, b, c) :| abs) =
+  List.unzip3 abs & \(as, bs, cs) ->
+    (a :| as, b :| bs, c :| cs)
diff --git a/src/Data/Monoid/Linear/Internal/Semigroup.hs b/src/Data/Monoid/Linear/Internal/Semigroup.hs
--- a/src/Data/Monoid/Linear/Internal/Semigroup.hs
+++ b/src/Data/Monoid/Linear/Internal/Semigroup.hs
@@ -11,6 +11,7 @@
 module Data.Monoid.Linear.Internal.Semigroup
   ( -- * Semigroup
     Semigroup (..),
+    sconcat,
 
     -- * Endo
     Endo (..),
@@ -34,6 +35,7 @@
 import Data.Functor.Const (Const (..))
 import Data.Functor.Identity (Identity (..))
 import qualified Data.Functor.Product as Functor
+import Data.List.NonEmpty (NonEmpty (..))
 import qualified Data.Monoid as Monoid
 import Data.Ord (Down (..))
 import Data.Proxy (Proxy (..))
@@ -64,6 +66,13 @@
 class Semigroup a where
   (<>) :: a %1 -> a %1 -> a
   infixr 6 <> -- same fixity as base.<>
+
+sconcat :: (Semigroup a) => NonEmpty a %1 -> a
+sconcat (x :| xs :: NonEmpty a) = go x xs
+  where
+    go :: a %1 -> [a] %1 -> a
+    go acc [] = acc
+    go acc (x' : xs') = go (acc <> x') xs'
 
 -- | An @'Endo' a@ is just a linear function of type @a %1-> a@.
 -- This has a classic monoid definition with 'id' and '(.)'.
diff --git a/src/Data/Ord/Linear/Internal/Eq.hs b/src/Data/Ord/Linear/Internal/Eq.hs
--- a/src/Data/Ord/Linear/Internal/Eq.hs
+++ b/src/Data/Ord/Linear/Internal/Eq.hs
@@ -13,6 +13,7 @@
 
 import Data.Bool.Linear
 import Data.Int (Int16, Int32, Int64, Int8)
+import Data.List.NonEmpty (NonEmpty (..))
 import Data.Unrestricted.Linear
 import Data.Word (Word16, Word32, Word64, Word8)
 import Prelude.Linear.Internal
@@ -46,6 +47,9 @@
   [] == [] = True
   (x : xs) == (y : ys) = x == y && xs == ys
   xs == ys = (xs, ys) `lseq` False
+
+instance (Consumable a, Eq a) => Eq (NonEmpty a) where
+  (x :| xs) == (y :| ys) = x == y && xs == ys
 
 instance (Consumable a, Eq a) => Eq (Prelude.Maybe a) where
   Prelude.Nothing == Prelude.Nothing = True
diff --git a/src/Data/Ord/Linear/Internal/Ord.hs b/src/Data/Ord/Linear/Internal/Ord.hs
--- a/src/Data/Ord/Linear/Internal/Ord.hs
+++ b/src/Data/Ord/Linear/Internal/Ord.hs
@@ -15,6 +15,7 @@
 
 import Data.Bool.Linear (Bool (..), not)
 import Data.Int (Int16, Int32, Int64, Int8)
+import Data.List.NonEmpty (NonEmpty (..))
 import Data.Monoid.Linear
 import Data.Ord (Ordering (..))
 import Data.Ord.Linear.Internal.Eq
@@ -118,6 +119,10 @@
     case compare x y of
       EQ -> compare xs ys
       res -> (xs, ys) `lseq` res
+
+instance (Consumable a, Ord a) => Ord (NonEmpty a) where
+  compare (x :| xs) (y :| ys) =
+    compare x y <> compare xs ys
 
 instance (Ord a, Ord b) => Ord (a, b) where
   (a, b) `compare` (a', b') =
diff --git a/src/Data/Set/Mutable/Linear/Internal.hs b/src/Data/Set/Mutable/Linear/Internal.hs
--- a/src/Data/Set/Mutable/Linear/Internal.hs
+++ b/src/Data/Set/Mutable/Linear/Internal.hs
@@ -1,10 +1,13 @@
 {-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE LinearTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE StrictData #-}
 {-# LANGUAGE TupleSections #-}
+{-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE NoImplicitPrelude #-}
 {-# OPTIONS_GHC -Wno-name-shadowing #-}
 {-# OPTIONS_HADDOCK hide #-}
@@ -14,7 +17,9 @@
 import qualified Data.HashMap.Mutable.Linear as Linear
 import Data.Monoid.Linear
 import Data.Unrestricted.Linear
+import GHC.TypeLits (ErrorMessage (..))
 import qualified Prelude.Linear as Linear hiding (insert)
+import Prelude.Linear.Unsatisfiable (Unsatisfiable, unsatisfiable)
 import Prelude (Bool, Int)
 import qualified Prelude
 
@@ -70,8 +75,11 @@
 -- # Typeclass Instances
 -------------------------------------------------------------------------------
 
-instance Prelude.Semigroup (Set a) where
-  (<>) = Prelude.error "Prelude.(<>): invariant violation, unrestricted Set"
+instance
+  (Unsatisfiable ('Text "Using Prelude's Semigroup methods on a Data.Set.Mutable.Linear is vacuous as there can't be an unrestricted such Set")) =>
+  Prelude.Semigroup (Set a)
+  where
+  (<>) = unsatisfiable
 
 instance (Keyed a) => Semigroup (Set a) where
   (<>) = union
diff --git a/src/Data/Unrestricted/Linear/Internal/Instances.hs b/src/Data/Unrestricted/Linear/Internal/Instances.hs
--- a/src/Data/Unrestricted/Linear/Internal/Instances.hs
+++ b/src/Data/Unrestricted/Linear/Internal/Instances.hs
@@ -21,10 +21,13 @@
 -- other classes (for cleanness) in this module to avoid this dependence.
 module Data.Unrestricted.Linear.Internal.Instances where
 
+import Data.ByteString (ByteString)
+import Data.ByteString.Short (ShortByteString)
 import qualified Data.Functor.Linear.Internal.Applicative as Data
 import qualified Data.Functor.Linear.Internal.Functor as Data
 import Data.Monoid.Linear
 import Data.Replicator.Linear.Internal.Instances ()
+import qualified Data.Text
 import Data.Unrestricted.Linear.Internal.Consumable
 import Data.Unrestricted.Linear.Internal.Dupable
 import Data.Unrestricted.Linear.Internal.Movable
@@ -189,6 +192,27 @@
     V
       . Unsafe.toLinear (Vector.fromListN (V.theLength @n))
       Data.<$> dupR (Unsafe.toLinear Vector.toList xs)
+
+instance Movable ByteString where
+  move = Unsafe.toLinear $ \s -> s `seq` Ur s
+
+deriving via (AsMovable ByteString) instance Consumable ByteString
+
+deriving via (AsMovable ByteString) instance Dupable ByteString
+
+instance Movable ShortByteString where
+  move = Unsafe.toLinear $ \s -> s `seq` Ur s
+
+deriving via (AsMovable ShortByteString) instance Consumable ShortByteString
+
+deriving via (AsMovable ShortByteString) instance Dupable ShortByteString
+
+instance Movable Data.Text.Text where
+  move = Unsafe.toLinear $ \s -> s `seq` Ur s
+
+deriving via (AsMovable Data.Text.Text) instance Consumable Data.Text.Text
+
+deriving via (AsMovable Data.Text.Text) instance Dupable Data.Text.Text
 
 -- Some stock instances
 
diff --git a/src/Streaming/Linear/Internal/Consume.hs b/src/Streaming/Linear/Internal/Consume.hs
--- a/src/Streaming/Linear/Internal/Consume.hs
+++ b/src/Streaming/Linear/Internal/Consume.hs
@@ -62,6 +62,7 @@
 where
 
 import qualified Control.Functor.Linear as Control
+import Control.Monad.IO.Class.Linear (liftSystemIO)
 import qualified Data.Bool.Linear as Linear
 import Data.Functor.Identity
 import Data.Text (Text)
@@ -116,7 +117,7 @@
         Return r -> Control.return r
         Effect ms -> ms Control.>>= stdoutLn'
         Step (str :> stream) -> Control.do
-          fromSystemIO $ Text.putStrLn str
+          liftSystemIO $ Text.putStrLn str
           stdoutLn' stream
 {-# INLINEABLE stdoutLn' #-}
 
diff --git a/src/Streaming/Linear/Internal/Produce.hs b/src/Streaming/Linear/Internal/Produce.hs
--- a/src/Streaming/Linear/Internal/Produce.hs
+++ b/src/Streaming/Linear/Internal/Produce.hs
@@ -45,6 +45,7 @@
 where
 
 import qualified Control.Functor.Linear as Control
+import Control.Monad.IO.Class.Linear (liftSystemIOU)
 import Data.Text (Text)
 import qualified Data.Text as Text
 import Data.Unrestricted.Linear
@@ -344,7 +345,7 @@
   where
     getALine :: () %1 -> IO (Either (Of Text ()) ())
     getALine () = Control.do
-      Ur line <- fromSystemIOU System.getLine
+      Ur line <- liftSystemIOU System.getLine
       Control.return $ Left (Text.pack line :> ())
 
 -- | An affine stream of reading lines, crashing on failed parse.
@@ -353,7 +354,7 @@
   where
     readALine :: (Read a) => () %1 -> IO (Either (Of a ()) ())
     readALine () = Control.do
-      Ur line <- fromSystemIOU System.getLine
+      Ur line <- liftSystemIOU System.getLine
       Control.return $ Left (Prelude.read line :> ())
 
 -- | An affine stream iterating an initial state forever.
diff --git a/src/System/IO/Resource/Linear.hs b/src/System/IO/Resource/Linear.hs
--- a/src/System/IO/Resource/Linear.hs
+++ b/src/System/IO/Resource/Linear.hs
@@ -32,6 +32,11 @@
     RIO,
     run,
 
+    -- * Interfacing with IO
+    fromIO,
+    fromSystemIO,
+    fromSystemIOU,
+
     -- * Using Resource Handles
     -- $monad
     -- $files
diff --git a/src/System/IO/Resource/Linear/Internal.hs b/src/System/IO/Resource/Linear/Internal.hs
--- a/src/System/IO/Resource/Linear/Internal.hs
+++ b/src/System/IO/Resource/Linear/Internal.hs
@@ -88,10 +88,24 @@
       result <- action'
       Control.return $ move result
 
--- | Should not be applied to a function that acquires or releases resources.
-unsafeFromSystemIO :: System.IO a %1 -> RIO a
-unsafeFromSystemIO action = RIO (\_ -> Linear.fromSystemIO action)
+-- | Coerces a linear IO action into a 'RIO' action.
+fromIO :: Linear.IO a %1 -> RIO a
+fromIO action = RIO (\_ -> action)
 
+-- | Coerces a standard IO action into a 'RIO' action.
+-- Note that the value @a@ must be used linearly in the 'RIO' monad.
+fromSystemIO :: System.IO a %1 -> RIO a
+fromSystemIO action =
+  -- Should not be applied to a function that acquires or releases resources.
+  fromIO (Linear.fromSystemIO action)
+
+-- | Coerces a standard IO action into a 'RIO' action, allowing you to use
+-- the result of type @a@ in a non-linear manner by wrapping it inside
+-- 'Ur'.
+fromSystemIOU :: System.IO a -> RIO (Ur a)
+fromSystemIOU action =
+  fromIO (Linear.fromSystemIOU action)
+
 -- monad
 
 instance Control.Functor RIO where
@@ -235,7 +249,7 @@
   (a -> System.IO b) ->
   (Resource a %1 -> RIO (Ur b, Resource a))
 unsafeFromSystemIOResource action (UnsafeResource key resource) =
-  unsafeFromSystemIO
+  fromSystemIO
     ( do
         c <- action resource
         Prelude.return (Ur c, UnsafeResource key resource)
diff --git a/test/Test/Data/List.hs b/test/Test/Data/List.hs
--- a/test/Test/Data/List.hs
+++ b/test/Test/Data/List.hs
@@ -1,9 +1,11 @@
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE NoImplicitPrelude #-}
+{-# OPTIONS_GHC -Wno-x-partial #-}
 
 module Test.Data.List (listTests) where
 
 import qualified Data.List.Linear as List
+import qualified Data.Num.Linear as Num
 import Hedgehog
 import qualified Hedgehog.Gen as Gen
 import qualified Hedgehog.Range as Range
@@ -17,7 +19,9 @@
   testGroup
     "List tests"
     [ testPropertyNamed "take n ++ drop n = id" "take_drop" take_drop,
-      testPropertyNamed "length . take n = const n" "take_length" take_length
+      testPropertyNamed "length . take n = const n" "take_length" take_length,
+      testPropertyNamed "zipWith is lazy" "zipWith_lazy" zipWith_lazy,
+      testPropertyNamed "zipWith3 is lazy" "zipWith3_lazy" zipWith3_lazy
     ]
 
 take_drop :: Property
@@ -41,3 +45,22 @@
     False -> do
       annotate "Prelude.length xs < n"
       Prelude.length (List.take n xs) === Prelude.length xs
+
+zipWith_lazy :: Property
+zipWith_lazy = property $ do
+  lgth <- forAll $ Gen.word (Range.linear 0 50)
+  _ <- eval $ Prelude.head (xs lgth)
+  Prelude.return ()
+  where
+    xs :: Word -> [Word]
+    xs lgth = List.zipWith (Num.+) (0 : error "bottom") [0 .. lgth]
+
+zipWith3_lazy :: Property
+zipWith3_lazy = property $ do
+  lgth1 <- forAll $ Gen.word (Range.linear 0 50)
+  lgth2 <- forAll $ Gen.word (Range.linear 0 50)
+  _ <- eval $ Prelude.head (xs lgth1 lgth2)
+  Prelude.return ()
+  where
+    xs :: Word -> Word -> [Word]
+    xs lgth1 lgth2 = List.zipWith3 (\x y z -> x Num.+ y Num.+ z) (0 : error "bottom") [0 .. lgth1] [0 .. lgth2]
