diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+1.7.0.0 [2026-07-21]
+--------------------
+* Mini.Transformers.MaybeT: Replace 'anticipate' with 'maybeT'
+* Mini.Transformers.EitherT: Replace 'anticipate' with 'eitherT'
+* Hash.Class: Add class 'Hash'
+  * Rework Murmur32 for the new Hash class
+
 1.6.5.0 [2026-07-20]
 --------------------
 * Mini.Transformers.MaybeT: Add 'just'
diff --git a/mini.cabal b/mini.cabal
--- a/mini.cabal
+++ b/mini.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               mini
-version:            1.6.5.0
+version:            1.7.0.0
 license:            MIT
 license-file:       LICENSE
 author:             Victor Wallsten <victor.wallsten@protonmail.com>
diff --git a/src/Mini/Hash/Class.hs b/src/Mini/Hash/Class.hs
--- a/src/Mini/Hash/Class.hs
+++ b/src/Mini/Hash/Class.hs
@@ -1,6 +1,12 @@
--- | The class of hashable types
+{-# LANGUAGE FunctionalDependencies #-}
+
+-- | Hash functions and hashable types
 module Mini.Hash.Class (
-  -- * Class
+  -- * Classes
+  Hash (
+    hash,
+    digest
+  ),
   Hashable (
     toBytes
   ),
@@ -42,7 +48,14 @@
   (.),
  )
 
--- Class
+-- Classes
+
+-- | The class of hash functions
+class Hash h s d | h -> s d where
+  -- | Make a hash value from a hashable value and a seed
+  hash :: (Hashable a) => a -> s -> h
+  -- | Extract the digest of a hash value
+  digest :: h -> d
 
 -- | Instances should use little-endian byte order
 class Hashable a where
diff --git a/src/Mini/Hash/Murmur32.hs b/src/Mini/Hash/Murmur32.hs
--- a/src/Mini/Hash/Murmur32.hs
+++ b/src/Mini/Hash/Murmur32.hs
@@ -1,14 +1,9 @@
--- | An implementation of MurmurHash3_x86_32 supporting incremental addition
+{-# LANGUAGE MultiParamTypeClasses #-}
+
+-- | An implementation of MurmurHash3_x86_32
 module Mini.Hash.Murmur32 (
   -- * Type
-  Hash32,
-
-  -- * Construction
-  seed,
-
-  -- * Operations
-  add,
-  digest,
+  Murmur32,
 ) where
 
 import Data.Bits (
@@ -16,9 +11,7 @@
   shiftL,
   shiftR,
   xor,
- )
-import Data.Function (
-  on,
+  (.&.),
  )
 import Data.Word (
   Word32,
@@ -26,10 +19,11 @@
  )
 import Mini.Data.Recursion (
   bool,
-  uncurry3,
  )
 import Mini.Hash.Class (
-  Hashable,
+  Hash,
+  digest,
+  hash,
   toBytes,
  )
 import Numeric (
@@ -39,79 +33,69 @@
   Eq,
   Ord,
   Show,
-  compare,
-  foldr,
   fromIntegral,
-  null,
   showsPrec,
   ($),
   (*),
   (+),
   (.),
-  (<>),
-  (==),
+  (/=),
  )
 
 -- Type
 
 -- | Abstract representation of a 32-bit hash value
-data Hash32 = Hash32 Word32 Word32 [Word8]
-
-instance Eq Hash32 where
-  (==) = (==) `on` digest
-
-instance Ord Hash32 where
-  compare = compare `on` digest
+newtype Murmur32 = Murmur32 Word32
+  deriving (Eq, Ord)
 
-instance Show Hash32 where
+instance Show Murmur32 where
   showsPrec _ = showHex . digest
 
--- Construction
-
--- | Make a hash from a seed
-seed :: Word32 -> Hash32
-seed s = Hash32 s 0 []
-
--- Operations
-
--- | Add a hashable type to a hash
-add :: (Hashable a) => a -> Hash32 -> Hash32
-add a = addBytes $ toBytes a
-
--- | Get the digest of a hash
-digest :: Hash32 -> Word32
-digest (Hash32 h1 len t) =
-  let (k0, tlen) =
-        foldr
-          (\a (b, n) -> (fromIntegral a `xor` (b `shiftL` 8), n + 1))
-          (0, 0)
-          t
-      len' = len + tlen
-      k1 = k0 * 0xcc9e2d51
-      k2 = k1 `rotateL` 15
-      k3 = k2 * 0x1b873593
-      h2 = h1 `xor` k3
-   in mix
-        . bool
-          (h2 `xor` len')
-          (h1 `xor` len)
-        $ null t
+instance Hash Murmur32 Word32 Word32 where
+  hash a s =
+    let bs = toBytes a
+        (len, h, k) = body s bs
+     in Murmur32 . final len $ tail len h k
+  digest (Murmur32 d) = d
 
 -- Helpers
 
-addBytes :: [Word8] -> Hash32 -> Hash32
-addBytes new (Hash32 h0 len0 old) = uncurry3 Hash32 $ go h0 len0 (old <> new)
+body :: Word32 -> [Word8] -> (Word32, Word32, Word32)
+body h0 bs = go 0 h0 bs
  where
-  go h len (a : b : c : d : rest) =
+  go len h (a : b : c : d : rest) =
     let d' = fromIntegral d `shiftL` 24
         c' = fromIntegral c `shiftL` 16
         b' = fromIntegral b `shiftL` 8
         a' = fromIntegral a
-        w = a' `xor` b' `xor` c' `xor` d'
-        h' = murmur w h
-        len' = len + 4
-     in go h' len' rest
-  go h len bs = (h, len, bs)
+        k = a' `xor` b' `xor` c' `xor` d'
+     in go (len + 4) (murmur k h) rest
+  go len h (a : b : c : _) =
+    let c' = fromIntegral c `shiftL` 16
+        b' = fromIntegral b `shiftL` 8
+        a' = fromIntegral a
+        k = a' `xor` b' `xor` c'
+     in (len + 3, h, k)
+  go len h (a : b : _) =
+    let b' = fromIntegral b `shiftL` 8
+        a' = fromIntegral a
+        k = a' `xor` b'
+     in (len + 2, h, k)
+  go len h (a : _) = (len + 1, h, fromIntegral a)
+  go len h _ = (len, h, 0)
+
+
+
+tail :: Word32 -> Word32 -> Word32 -> Word32
+tail len h0 k0 =
+    let k1 = k0 * 0xcc9e2d51
+        k2 = k1 `rotateL` 15
+        k3 = k2 * 0x1b873593
+        h1 = h0 `xor` k3
+     in bool h0 h1 $ len .&. 3 /= 0
+
+final :: Word32 -> Word32 -> Word32
+final len h = mix $ h `xor` len
 
 murmur :: Word32 -> Word32 -> Word32
 murmur k1 h1 =
diff --git a/src/Mini/Random/Class.hs b/src/Mini/Random/Class.hs
--- a/src/Mini/Random/Class.hs
+++ b/src/Mini/Random/Class.hs
@@ -23,7 +23,6 @@
   shiftL,
   shiftR,
   (.&.),
-  (.|.),
  )
 import Data.Int (
   Int16,
@@ -41,11 +40,6 @@
   Word64,
   Word8,
  )
-import Mini.Hash.Murmur32 (
-  Hash32,
-  add,
-  digest,
- )
 import Mini.Random.SplitMix (
   SplitMix,
  )
@@ -78,15 +72,6 @@
   nextWord32 :: g -> (Word32, g)
   nextWord32 = first fromIntegral . nextWord64
   nextWord64 :: g -> (Word64, g)
-
-instance Generator Hash32 where
-  nextWord32 h = let d = digest h in (d, add d h)
-  nextWord64 h =
-    let (lo, g) = nextWord32 h
-        (hi, g') = nextWord32 g
-        lo' = fromIntegral lo
-        hi' = fromIntegral hi `shiftL` 32
-     in (lo' .|. hi', g')
 
 instance Generator SplitMix where
   nextWord32 = SplitMix.nextWord32
diff --git a/src/Mini/Transformers/EitherT.hs b/src/Mini/Transformers/EitherT.hs
--- a/src/Mini/Transformers/EitherT.hs
+++ b/src/Mini/Transformers/EitherT.hs
@@ -7,7 +7,7 @@
   runEitherT,
 
   -- * Operations
-  anticipate,
+  eitherT,
   left,
   right,
 ) where
@@ -47,7 +47,6 @@
   pure,
   ($),
   (.),
-  (<$>),
   (<*>),
   (>>=),
  )
@@ -69,20 +68,10 @@
 
 instance (Monad m, Monoid e) => Alternative (EitherT e m) where
   empty = left mempty
-  m <|> n =
-    EitherT $
-      runEitherT m
-        >>= either
-          (\e -> either (Left . mappend e) Right <$> runEitherT n)
-          (pure . Right)
+  m <|> n = eitherT (\e -> eitherT (left . mappend e) right n) right m
 
 instance (Monad m) => Monad (EitherT e m) where
-  m >>= k =
-    EitherT $
-      runEitherT m
-        >>= either
-          (pure . Left)
-          (runEitherT . k)
+  m >>= k = eitherT left k m
 
 instance MonadTrans (EitherT e) where
   lift = EitherT . fmap Right
@@ -95,9 +84,14 @@
 
 -- Operations
 
--- | Run a computation and get its result
-anticipate :: (Monad m) => EitherT e m a -> EitherT e m (Either e a)
-anticipate = lift . runEitherT
+-- | Case analysis on the result of a computation
+eitherT
+  :: (Monad m)
+  => (e -> EitherT e' m b) -- ^ Function applied in case of @Left e@
+  -> (a -> EitherT e' m b) -- ^ Function applied in case of @Right a@
+  -> EitherT e m a -- ^ Object of the case analysis
+  -> EitherT e' m b
+eitherT l r m = EitherT $ runEitherT m >>= runEitherT . either l r
 
 -- | Terminate the computation with a value
 left :: (Applicative m) => e -> EitherT e m a
diff --git a/src/Mini/Transformers/MaybeT.hs b/src/Mini/Transformers/MaybeT.hs
--- a/src/Mini/Transformers/MaybeT.hs
+++ b/src/Mini/Transformers/MaybeT.hs
@@ -7,7 +7,7 @@
   runMaybeT,
 
   -- * Operations
-  anticipate,
+  maybeT,
   nothing,
   just,
 ) where
@@ -66,20 +66,10 @@
 
 instance (Monad m) => Alternative (MaybeT m) where
   empty = nothing
-  m <|> n =
-    MaybeT $
-      runMaybeT m
-        >>= maybe
-          (runMaybeT n)
-          (pure . Just)
+  m <|> n = maybeT n just m
 
 instance (Monad m) => Monad (MaybeT m) where
-  m >>= k =
-    MaybeT $
-      runMaybeT m
-        >>= maybe
-          (pure Nothing)
-          (runMaybeT . k)
+  m >>= k = maybeT nothing k m
 
 instance MonadTrans MaybeT where
   lift = MaybeT . fmap Just
@@ -92,9 +82,14 @@
 
 -- Operations
 
--- | Run a computation and get its result
-anticipate :: (Monad m) => MaybeT m a -> MaybeT m (Maybe a)
-anticipate = lift . runMaybeT
+-- | Case analysis on the result of a computation
+maybeT
+  :: (Monad m)
+  => MaybeT m b -- ^ Computation in case of @Nothing@
+  -> (a -> MaybeT m b) -- ^ Function applied in case of @Just a@
+  -> MaybeT m a -- ^ Object of the case analysis
+  -> MaybeT m b
+maybeT n j m = MaybeT $ runMaybeT m >>= runMaybeT . maybe n j
 
 -- | Terminate the computation without a value
 nothing :: (Applicative m) => MaybeT m a
