diff --git a/crdt.cabal b/crdt.cabal
--- a/crdt.cabal
+++ b/crdt.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: db0538f8b628af11f30af67edf7178b1305f42a56a99e2fa5e60a6c941a47ce8
+-- hash: c7858c1e62913fddff18ba02c93949c604e502f20eced23a4b1d57b0c89d199b
 
 name:           crdt
-version:        4.1
+version:        4.2
 synopsis:       Conflict-free replicated data types
 description:    Definitions of CmRDT and CvRDT. Implementations for some classic CRDTs.
 category:       Distributed Systems
diff --git a/lib/CRDT/LWW.hs b/lib/CRDT/LWW.hs
--- a/lib/CRDT/LWW.hs
+++ b/lib/CRDT/LWW.hs
@@ -16,7 +16,8 @@
 import           Data.Semilattice (Semilattice)
 
 import           CRDT.Cm (CausalOrd (..), CmRDT (..))
-import           CRDT.LamportClock (LamportTime, Process, advance, getTime)
+import           CRDT.LamportClock (Clock, LamportTime (LamportTime), advance,
+                                    getTime)
 
 -- | Last write wins. Assuming timestamp is unique.
 -- This type is both 'CmRDT' and 'CvRDT'.
@@ -46,12 +47,12 @@
 instance Eq a => Semilattice (LWW a)
 
 -- | Initialize state
-initial :: a -> Process (LWW a)
+initial :: Clock m => a -> m (LWW a)
 initial value = LWW value <$> getTime
 
 -- | Change state as CvRDT operation.
 -- Current value is ignored, because new timestamp is always greater.
-assign :: a -> LWW a -> Process (LWW a)
+assign :: Clock m => a -> LWW a -> m (LWW a)
 assign value old = do
     advanceFromLWW old
     initial value
@@ -74,5 +75,5 @@
 
     apply = (<>)
 
-advanceFromLWW :: LWW a -> Process ()
-advanceFromLWW LWW{time} = advance time
+advanceFromLWW :: Clock m => LWW a -> m ()
+advanceFromLWW LWW{time = LamportTime time _} = advance time
diff --git a/lib/CRDT/LamportClock.hs b/lib/CRDT/LamportClock.hs
--- a/lib/CRDT/LamportClock.hs
+++ b/lib/CRDT/LamportClock.hs
@@ -3,10 +3,9 @@
 module CRDT.LamportClock
     ( Pid (..)
     -- * Lamport timestamp (for a single process)
+    , Clock (..)
     , LamportTime (..)
     , getRealLamportTime
-    , getTime
-    , advance
     -- * Lamport clock (for a whole multi-process system)
     , LamportClock (..)
     , runLamportClock
@@ -54,12 +53,6 @@
 getPid :: Process Pid
 getPid = Process ask
 
-getTime :: Process LamportTime
-getTime = Process $ do
-    pid <- ask
-    time <- lift $ preIncrementAt pid
-    pure $ LamportTime time pid
-
 runLamportClock :: LamportClock a -> a
 runLamportClock (LamportClock action) = evalState action mempty
 
@@ -72,11 +65,6 @@
         lt' = succ . fromMaybe 0 $ Map.lookup pid m
         in (lt', Map.insert pid lt' m)
 
-advance :: LamportTime -> Process ()
-advance (LamportTime time _) = Process $ do
-    pid <- ask
-    lift . LamportClock . modify $ Map.insertWith max pid time
-
 getRealLocalTime :: IO LocalTime
 getRealLocalTime = round . utcTimeToPOSIXSeconds <$> getCurrentTime
 
@@ -96,3 +84,16 @@
     decodeMac :: MAC -> Word64
     decodeMac (MAC b5 b4 b3 b2 b1 b0) =
         decode $ BSL.pack [0, 0, b5, b4, b3, b2, b1, b0]
+
+class Monad m => Clock m where
+    getTime :: m LamportTime
+    advance :: LocalTime -> m ()
+
+instance Clock Process where
+    getTime = Process $ do
+        pid <- ask
+        time <- lift $ preIncrementAt pid
+        pure $ LamportTime time pid
+    advance time = Process $ do
+        pid <- ask
+        lift . LamportClock . modify $ Map.insertWith max pid time
