diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
 # TidalCycles log of changes
 
+## 1.4.0 - Padley Gorge
+
+* fix representation to handle continuous and analog events properly @yaxu
+
+## 1.3.0 - rolled back to 1.1.2
+
+## 1.2.0 - Hunters Bar
+
+* Simplify <* and *>, removing any distinction between analogue and digital patterns
+
 ## 1.1.2 - Eccy Road
 
 * Usability fix for `binary` / `binaryN` (use squeezeJoin on input pattern)
diff --git a/src/Sound/Tidal/Carabiner.hs b/src/Sound/Tidal/Carabiner.hs
--- a/src/Sound/Tidal/Carabiner.hs
+++ b/src/Sound/Tidal/Carabiner.hs
@@ -1,9 +1,10 @@
+{-# OPTIONS_GHC -fno-warn-dodgy-imports -fno-warn-name-shadowing #-}
 module Sound.Tidal.Carabiner where
 
 import Network.Socket hiding (send, sendTo, recv, recvFrom)
 import Network.Socket.ByteString (send, recv)
 import qualified Data.ByteString.Char8 as B8
-import Control.Concurrent (forkIO, threadDelay, takeMVar, putMVar)
+import Control.Concurrent (forkIO, takeMVar, putMVar)
 import qualified Sound.Tidal.Stream as S
 import Sound.Tidal.Tempo
 import System.Clock
@@ -12,9 +13,6 @@
 import Data.Maybe (isJust, fromJust)
 import qualified Sound.OSC.FD as O
 
-port :: Int
-port = 17000
-
 carabiner :: S.Stream -> Int -> Double -> IO Socket
 carabiner tidal bpc latency = do sock <- client tidal bpc latency "127.0.0.1" 17000
                                  sendMsg sock "status\n"
@@ -53,7 +51,7 @@
              d = nowO - m
              start' = ((fromIntegral $ fromJust start) / 1000000)
              startO = start' + d
-             cyc = toRational $ (fromJust beat) / (fromIntegral bpc)
+             -- cyc = toRational $ (fromJust beat) / (fromIntegral bpc)
          tempo <- takeMVar (S.sTempoMV tidal)
          let tempo' = tempo {atTime = startO + latency,
                              atCycle = 0,
@@ -63,5 +61,5 @@
 act _ _ _ name _ = putStr $ "Unhandled thingie " ++ name
 
 sendMsg :: Socket -> String -> IO ()
-sendMsg sock msg = do send sock $ B8.pack msg
+sendMsg sock msg = do _ <- send sock $ B8.pack msg
                       return ()
diff --git a/src/Sound/Tidal/Control.hs b/src/Sound/Tidal/Control.hs
--- a/src/Sound/Tidal/Control.hs
+++ b/src/Sound/Tidal/Control.hs
@@ -65,7 +65,9 @@
 _chop n = withEvents (concatMap chopEvent)
   where -- for each part,
         chopEvent :: Event ControlMap -> [Event ControlMap]
-        chopEvent (Event w p' v) = map (chomp v (length $ chopArc w n)) $ arcs w p'
+        chopEvent (Event (Just w) p' v) = map (chomp v (length $ chopArc w n)) $ arcs w p'
+        -- ignoring 'analog' events (those without wholes),
+        chopEvent _ = []
         -- cut whole into n bits, and number them
         arcs w' p' = numberedArcs p' $ chopArc w' n
         -- each bit is a new whole, with part that's the intersection of old part and new whole
@@ -77,7 +79,7 @@
         -- begin and end values by the old difference (end-begin), and
         -- add the old begin
         chomp :: ControlMap -> Int -> (Int, (Arc, Arc)) -> Event ControlMap
-        chomp v n' (i, (w,p')) = Event w p' (Map.insert "begin" (VF b') $ Map.insert "end" (VF e') v)
+        chomp v n' (i, (w,p')) = Event (Just w) p' (Map.insert "begin" (VF b') $ Map.insert "end" (VF e') v)
           where b = fromMaybe 0 $ do v' <- Map.lookup "begin" v
                                      getF v'
                 e = fromMaybe 1 $ do v' <- Map.lookup "end" v
@@ -368,12 +370,12 @@
 msec p = ((realToFrac . (/1000)) <$> cF 1 "_cps") *| p
 
 _trigger :: Show a => Bool -> a -> Pattern b -> Pattern b
-_trigger quantise k pat = pat {query = q}
+_trigger quant k pat = pat {query = q}
   where q st = query ((offset st) ~> pat) st
-        f | quantise = fromIntegral . round
+        f | quant = (fromIntegral :: Int -> Rational) . round
           | otherwise = id
-        offset st = fromMaybe (pure 0) $ do pat <- Map.lookup ctrl (controls st)
-                                            return $ ((f . fromMaybe 0 . getR) <$> pat)
+        offset st = fromMaybe (pure 0) $ do p <- Map.lookup ctrl (controls st)
+                                            return $ ((f . fromMaybe 0 . getR) <$> p)
         ctrl = "_t_" ++ show k
 
 trigger :: Show a => a -> Pattern b -> Pattern b
@@ -392,10 +394,10 @@
 _getP d f pat = (fromMaybe d . f) <$> pat
 
 _cX :: a -> (Value -> Maybe a) -> String -> Pattern a
-_cX d f s = Pattern Analog $ \(State a m) -> queryArc (maybe (pure d) (_getP d f) $ Map.lookup s m) a
+_cX d f s = Pattern $ \(State a m) -> queryArc (maybe (pure d) (_getP d f) $ Map.lookup s m) a
 
 _cX_ :: (Value -> Maybe a) -> String -> Pattern a
-_cX_ f s = Pattern Analog $ \(State a m) -> queryArc (maybe silence (_getP_ f) $ Map.lookup s m) a
+_cX_ f s = Pattern $ \(State a m) -> queryArc (maybe silence (_getP_ f) $ Map.lookup s m) a
 
 cF :: Double -> String -> Pattern Double
 cF d = _cX d getF
@@ -439,7 +441,7 @@
 cS0 :: String -> Pattern String
 cS0 = _cX "" getS
 
-cP :: String -> Pattern String
+cP :: (Enumerable a, Parseable a) => String -> Pattern a
 cP s = innerJoin $ parseBP_E <$> (_cX_ getS s)
 
 -- Default controller inputs (for MIDI)
diff --git a/src/Sound/Tidal/Core.hs b/src/Sound/Tidal/Core.hs
--- a/src/Sound/Tidal/Core.hs
+++ b/src/Sound/Tidal/Core.hs
@@ -17,10 +17,10 @@
 
 -- | Takes a function from time to values, and turns it into a 'Pattern'.
 sig :: (Time -> a) -> Pattern a
-sig f = Pattern Analog q
+sig f = Pattern q
   where q (State (Arc s e) _)
           | s > e = []
-          | otherwise = [Event (Arc s e) (Arc s e) (f (s+((e-s)/2)))]
+          | otherwise = [Event Nothing (Arc s e) (f (s+((e-s)/2)))]
 
 -- | @sine@ returns a 'Pattern' of continuous 'Fractional' values following a
 -- sinewave with frequency of one cycle, and amplitude from 0 to 1.
@@ -190,8 +190,7 @@
 -- in turn, then the second cycle from each, and so on.
 cat :: [Pattern a] -> Pattern a
 cat [] = silence
--- TODO I *guess* it would be digital..
-cat ps = Pattern Digital q
+cat ps = Pattern $ q
   where n = length ps
         q st = concatMap (f st) $ arcCyclesZW (arc st)
         f st a = query (withResultTime (+offset) p) $ st {arc = Arc (subtract offset (start a)) (subtract offset (stop a))}
@@ -234,10 +233,7 @@
 -- | 'overlay' combines two 'Pattern's into a new pattern, so that
 -- their events are combined over time. 
 overlay :: Pattern a -> Pattern a -> Pattern a
--- Analog if they're both analog
-overlay !p@(Pattern Analog _) !p'@(Pattern Analog _) = Pattern Analog $ \st -> query p st ++ query p' st
--- Otherwise digital. Won't really work to have a mixture.. Hmm
-overlay !p !p' = Pattern Digital $ \st -> query p st ++ query p' st
+overlay !p !p' = Pattern $ \st -> query p st ++ query p' st
 
 -- | An infix alias of @overlay@
 (<>) :: Pattern a -> Pattern a -> Pattern a
@@ -307,11 +303,13 @@
         })
     }
   where makeWholeRelative :: Event a -> Event a
-        makeWholeRelative (Event (Arc s e) p'@(Arc s' e') v) =
-          Event (Arc (s'-s) (e'-e)) p' v
+        makeWholeRelative (e@(Event Nothing _ _)) = e
+        makeWholeRelative (Event (Just (Arc s e)) p'@(Arc s' e') v) =
+          Event (Just $ Arc (s'-s) (e-e')) p' v
         makeWholeAbsolute :: Event a -> Event a
-        makeWholeAbsolute (Event (Arc s e) p'@(Arc s' e') v) =
-          Event (Arc (s'-e) (e'+s)) p' v
+        makeWholeAbsolute (e@(Event Nothing _ _)) = e
+        makeWholeAbsolute (Event (Just (Arc s e)) p'@(Arc s' e') v) =
+          Event (Just $ Arc (s'-e) (e'+s)) p' v
         midCycle :: Arc -> Time
         midCycle (Arc s _) = sam s + 0.5
         mapParts :: (Arc -> Arc) -> [Event a] -> [Event a]
diff --git a/src/Sound/Tidal/Pattern.hs b/src/Sound/Tidal/Pattern.hs
--- a/src/Sound/Tidal/Pattern.hs
+++ b/src/Sound/Tidal/Pattern.hs
@@ -7,7 +7,7 @@
 import           Prelude hiding ((<*), (*>))
 
 import           Control.Applicative (liftA2)
-import           Data.Bifunctor (Bifunctor(..))
+--import           Data.Bifunctor (Bifunctor(..))
 import           Data.Data (Data) -- toConstr
 import           Data.List (delete, findIndex, sort, intercalate)
 import qualified Data.Map.Strict as Map
@@ -86,6 +86,11 @@
   | otherwise = Nothing
   where (Arc s'' e'') = sect a b
 
+subMaybeArc :: Maybe Arc -> Maybe Arc -> Maybe (Maybe Arc)
+subMaybeArc (Just a) (Just b) = do sa <- subArc a b
+                                   return $ Just sa
+subMaybeArc _ _ = Just Nothing
+
 instance Applicative ArcF where
   pure t = Arc t t
   (<*>) (Arc sf ef) (Arc sx ex) = Arc (sf sx) (ef ex)
@@ -131,11 +136,10 @@
 isIn :: Arc -> Time -> Bool
 isIn (Arc s e) t = t >= s && t < e
 
--- | An event is a value that's active during a timespan
--- The part should be equal to or fit inside the
--- whole
+-- | An event is a value that's active during a timespan. If a whole
+-- is present, the part should be equal to or fit inside it.
 data EventF a b = Event
-  { whole :: a
+  { whole :: Maybe a
   , part :: a
   , value :: b
   } deriving (Eq, Ord, Functor)
@@ -146,17 +150,27 @@
   NFData (EventF a b) where 
     rnf (Event w p v) = rnf w `seq` rnf p `seq` rnf v
 
-instance Bifunctor EventF where
+{-instance Bifunctor EventF where
   bimap f g (Event w p e) = Event (f w) (f p) (g e)
+-}
 
 instance {-# OVERLAPPING #-} Show a => Show (Event a) where
-  show (Event (Arc ws we) a@(Arc ps pe) e) =
+  show (Event (Just (Arc ws we)) a@(Arc ps pe) e) =
     h ++ "(" ++ show a ++ ")" ++ t ++ "|" ++ show e
     where h | ws == ps = ""
             | otherwise = prettyRat ws ++ "-"
           t | we == pe = ""
             | otherwise = "-" ++ prettyRat we
+  show (Event Nothing a e) =
+    "~" ++ show a ++ "~|" ++ show e
 
+isAnalog :: Event a -> Bool
+isAnalog (Event {whole = Nothing}) = True
+isAnalog _ = False
+
+isDigital :: Event a -> Bool
+isDigital = not . isAnalog
+
 -- | `True` if an `Event`'s starts is within given `Arc`
 onsetIn :: Arc -> Event a -> Bool
 onsetIn a e = isIn a (wholeStart e)
@@ -186,13 +200,17 @@
                       (stop (part e') == start (part e))
                      )
 
+wholeOrPart :: Event a -> Arc
+wholeOrPart (Event {whole = Just a}) = a
+wholeOrPart e = part e
+
 -- | Get the onset of an event's 'whole'
 wholeStart :: Event a -> Time
-wholeStart = start . whole
+wholeStart = start . wholeOrPart
 
 -- | Get the offset of an event's 'whole'
 wholeStop :: Event a -> Time
-wholeStop = stop . whole
+wholeStop = stop . wholeOrPart
 
 -- | Get the onset of an event's 'whole'
 eventPartStart :: Event a -> Time
@@ -210,10 +228,12 @@
 eventValue = value
 
 eventHasOnset :: Event a -> Bool
-eventHasOnset e = start (whole e) == start (part e)
+eventHasOnset e | isAnalog e = False
+                | otherwise = start (fromJust $ whole e) == start (part e)
 
+-- TODO - Is this used anywhere? Just tests, it seems
 toEvent :: (((Time, Time), (Time, Time)), a) -> Event a
-toEvent (((ws, we), (ps, pe)), v) = Event (Arc ws we) (Arc ps pe) v
+toEvent (((ws, we), (ps, pe)), v) = Event (Just $ Arc ws we) (Arc ps pe) v
 
 -- | an Arc and some named control values
 data State = State {arc :: Arc,
@@ -223,13 +243,8 @@
 -- | A function that represents events taking place over time
 type Query a = (State -> [Event a])
 
--- | Also known as Continuous vs Discrete/Amorphous vs Pulsating etc.
-data Nature = Analog | Digital
-            deriving (Eq, Show)
-
--- | A datatype that's basically a query, plus a hint about whether its events
--- are Analogue or Digital by nature
-data Pattern a = Pattern {nature :: Nature, query :: Query a}
+-- | A datatype that's basically a query
+data Pattern a = Pattern {query :: Query a}
 
 data Value = VS { svalue :: String }
            | VF { fvalue :: Double }
@@ -306,96 +321,73 @@
 
 instance NFData a => 
   NFData (Pattern a) where 
-    rnf (Pattern _ q) = rnf $ \s -> q s
+    rnf (Pattern q) = rnf $ \s -> q s
 
 instance Functor Pattern where
   -- | apply a function to all the values in a pattern
   fmap f p = p {query = fmap (fmap f) . query p}
 
-instance Applicative Pattern where
-  -- | Repeat the given value once per cycle, forever
-  pure v = Pattern Digital $ \(State a _) ->
-    map (\a' -> Event a' (sect a a') v) $ cycleArcsInArc a
-
-  (<*>) pf@(Pattern Digital _) px@(Pattern Digital _) = Pattern Digital q
+applyPatToPat :: (Maybe Arc -> Maybe Arc -> Maybe (Maybe Arc)) -> Pattern (a -> b) -> Pattern a -> Pattern b
+applyPatToPat combineWholes pf px = Pattern q
     where q st = catMaybes $ concatMap match $ query pf st
             where
-              match (Event fWhole fPart f) =
+              match (ef@(Event _ fPart f)) =
                 map
-                (\(Event xWhole xPart x) ->
-                  do whole' <- subArc xWhole fWhole
+                (\ex@(Event _ xPart x) ->
+                  do whole' <- combineWholes (whole ef) (whole ex)
                      part' <- subArc fPart xPart
                      return (Event whole' part' (f x))
                 )
-                (query px $ st {arc = fPart})
-  (<*>) pf@(Pattern Digital _) px@(Pattern Analog _) = Pattern Digital q
-    where q st = concatMap match $ query pf st
+                (query px $ st {arc = (wholeOrPart ef)})
+
+instance Applicative Pattern where
+  -- | Repeat the given value once per cycle, forever
+  pure v = Pattern $ \(State a _) ->
+    map (\a' -> Event (Just a') (sect a a') v) $ cycleArcsInArc a
+
+  (<*>) = applyPatToPatBoth
+
+applyPatToPatBoth :: Pattern (a -> b) -> Pattern a -> Pattern b
+applyPatToPatBoth pf px = Pattern q
+    where q st = catMaybes $ (concatMap match $ query pf st) ++ (concatMap matchX $ query (filterAnalog px) st)
             where
-              match (Event fWhole fPart f) =
-                map
-                (Event fWhole fPart . f . value)
-                (query px $ st {arc = pure (start fPart)})
+              -- match analog events from pf with all events from px
+              match ef@(Event Nothing fPart _)   = map (withFX ef) (query px $ st {arc = fPart}) -- analog
+              -- match digital events from pf with digital events from px
+              match ef@(Event (Just fWhole) _ _) = map (withFX ef) (query (filterDigital px) $ st {arc = fWhole}) -- digital
+              -- match analog events from px (constrained above) with digital events from px
+              matchX ex@(Event Nothing fPart _)  = map (\ef -> withFX ef ex) (query (filterDigital pf) $ st {arc = fPart}) -- digital
+              matchX _ = error "can't happen"
+              withFX ef ex = do whole' <- subMaybeArc (whole ef) (whole ex)
+                                part' <- subArc (part ef) (part ex)
+                                return (Event whole' part' (value ef $ value ex))
 
-  (<*>) pf@(Pattern Analog _) px@(Pattern Digital _) = Pattern Digital q
-    where q st = concatMap match $ query px st
+applyPatToPatLeft :: Pattern (a -> b) -> Pattern a -> Pattern b
+applyPatToPatLeft pf px = Pattern q
+    where q st = catMaybes $ (concatMap match $ query pf st)
             where
-              match (Event xWhole xPart x) =
-                map
-                (\e -> Event xWhole xPart (value e x))
-                (query pf st {arc = pure (start xPart)})
+              match ef = map (withFX ef) (query px $ st {arc = wholeOrPart ef})
+              withFX ef ex = do let whole' = whole ef
+                                part' <- subArc (part ef) (part ex)
+                                return (Event whole' part' (value ef $ value ex))
 
-  (<*>) pf px = Pattern Analog q
-    where q st = concatMap match $ query pf st
+applyPatToPatRight :: Pattern (a -> b) -> Pattern a -> Pattern b
+applyPatToPatRight pf px = Pattern q
+    where q st = catMaybes $ (concatMap match $ query px st)
             where
-              match ef =
-                map
-                (Event (arc st) (arc st) . value ef . value)
-                (query px st)
+              match ex = map (\ef -> withFX ef ex) (query pf $ st {arc = wholeOrPart ex})
+              withFX ef ex = do let whole' = whole ex
+                                part' <- subArc (part ef) (part ex)
+                                return (Event whole' part' (value ef $ value ex))
 
--- | Like <*>, but the structure only comes from the left
-(<*) :: Pattern (a -> b) -> Pattern a -> Pattern b
-(<*) pf@(Pattern Analog _) px@(Pattern Analog _) = Pattern Analog q
-  where q st = concatMap match $ query pf st
-          where
-            match (Event fWhole fPart f) =
-              map
-              (Event fWhole fPart . f . value) $
-              query px st -- for continuous events, use the original query
 
--- If one of the patterns is digital, treat both as digital.. (TODO - needs extra thought)
-(<*) pf px = Pattern Digital q
-    where q st = catMaybes $ concatMap match $ query pf st
-            where
-              match (Event fWhole fPart f) =
-                map
-                (\(Event _ xPart x) ->
-                  do let whole' = fWhole
-                     part' <- subArc fPart xPart
-                     return (Event whole' part' (f x))
-                )
-                (query px $ st {arc = fPart})
+-- | Like <*>, but the 'wholes' come from the left
+(<*) :: Pattern (a -> b) -> Pattern a -> Pattern b
+(<*) = applyPatToPatLeft
 
--- | Like <*>, but the structure only comes from the right
+-- | Like <*>, but the 'wholes' come from the right
 (*>) :: Pattern (a -> b) -> Pattern a -> Pattern b
-(*>) pf@(Pattern Analog _) px@(Pattern Analog _) = Pattern Analog q
-  where q st = concatMap match $ query px st
-          where
-            match (Event xWhole xPart x) =
-              map
-              (\e -> Event xWhole xPart (value e x)) $
-              query pf st -- for continuous events, use the original query
-
-(*>) pf px = Pattern Digital q
-    where q st = catMaybes $ concatMap match $ query pf st
-            where
-              match (Event _ fPart f) =
-                map
-                (\(Event xWhole xPart x) ->
-                  do let whole' = xWhole
-                     part' <- subArc fPart xPart
-                     return (Event whole' part' (f x))
-                )
-                (query px $ st {arc = fPart})
+(*>) = applyPatToPatRight
 
 infixl 4 <*, *>
 
@@ -421,7 +413,7 @@
           (query pp st)
         munge ow op (Event iw ip v') =
           do
-            w' <- subArc ow iw
+            w' <- subMaybeArc ow iw
             p' <- subArc op ip
             return (Event w' p' v')
 
@@ -444,8 +436,8 @@
 outerJoin :: Pattern (Pattern a) -> Pattern a
 outerJoin pp = pp {query = q}
   where q st = concatMap
-          (\(Event w p v) ->
-             mapMaybe (munge w p) $ query v st {arc = pure (start w)}
+          (\e ->
+             mapMaybe (munge (whole e) (part e)) $ query (value e) st {arc = pure (start $ wholeOrPart e)}
           )
           (query pp st)
           where munge ow op (Event _ _ v') =
@@ -459,12 +451,12 @@
 squeezeJoin :: Pattern (Pattern a) -> Pattern a
 squeezeJoin pp = pp {query = q}
   where q st = concatMap
-          (\(Event w p v) ->
-             mapMaybe (munge w p) $ query (compressArc (cycleArc w) v) st {arc = p}
+          (\e@(Event w p v) ->
+             mapMaybe (munge w p) $ query (compressArc (cycleArc $ wholeOrPart e) v) st {arc = p}
           )
           (query pp st)
         munge oWhole oPart (Event iWhole iPart v) =
-          do w' <- subArc oWhole iWhole
+          do w' <- subMaybeArc oWhole iWhole
              p' <- subArc oPart iPart
              return (Event w' p' v)
 
@@ -659,17 +651,11 @@
 -- * Internal functions
 
 empty :: Pattern a
-empty = Pattern {nature = Digital, query = const []}
+empty = Pattern {query = const []}
 
 queryArc :: Pattern a -> Arc -> [Event a]
 queryArc p a = query p $ State a Map.empty 
 
-isDigital :: Pattern a -> Bool
-isDigital = (== Digital) . nature
-
-isAnalog :: Pattern a -> Bool
-isAnalog = not . isDigital
-
 -- | Splits queries that span cycles. For example `query p (0.5, 1.5)` would be
 -- turned into two queries, `(0.5,1)` and `(1,1.5)`, and the results
 -- combined. Being able to assume queries don't span cycles often
@@ -680,7 +666,7 @@
 -- | Apply a function to the arcs/timespans (both whole and parts) of the result
 withResultArc :: (Arc -> Arc) -> Pattern a -> Pattern a
 withResultArc f pat = pat
-  { query = map (\(Event w p e) -> Event (f w) (f p) e) . query pat}
+  { query = map (\(Event w p e) -> Event (f <$> w) (f p) e) . query pat}
 
 -- | Apply a function to the time (both start and end of the timespans
 -- of both whole and parts) of the result
@@ -798,8 +784,17 @@
 filterWhen test p = p {query = filter (test . wholeStart) . query p}
 
 filterOnsets :: Pattern a -> Pattern a
-filterOnsets p = p {query = filter (\e -> eventPartStart e == wholeStart e) . query p}
+filterOnsets p = p {query = filter (\e -> eventPartStart e == wholeStart e) . query (filterDigital p)}
 
+filterEvents :: (Event a -> Bool) -> Pattern a -> Pattern a
+filterEvents f p = p {query = filter f . query p}
+
+filterDigital :: Pattern a -> Pattern a
+filterDigital = filterEvents isDigital
+
+filterAnalog :: Pattern a -> Pattern a
+filterAnalog = filterEvents isAnalog
+
 playFor :: Time -> Time -> Pattern a -> Pattern a
 playFor s e = filterWhen (\t -> (t >= s) && (t < e))
 
@@ -823,7 +818,7 @@
 matchManyToOne f pa pb = pa {query = q}
   where q st = map match $ query pb st
           where
-            match (Event xWhole xPart x) =
-              Event xWhole xPart (any (f x) (as $ start xWhole), x)
+            match (ex@(Event xWhole xPart x)) =
+              Event xWhole xPart (any (f x) (as $ start $ wholeOrPart ex), x)
             as s = map value $ query pa $ fQuery s
             fQuery s = st {arc = Arc s s}
diff --git a/src/Sound/Tidal/Simple.hs b/src/Sound/Tidal/Simple.hs
--- a/src/Sound/Tidal/Simple.hs
+++ b/src/Sound/Tidal/Simple.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module Sound.Tidal.Simple where
 
diff --git a/src/Sound/Tidal/Stream.hs b/src/Sound/Tidal/Stream.hs
--- a/src/Sound/Tidal/Stream.hs
+++ b/src/Sound/Tidal/Stream.hs
@@ -148,12 +148,12 @@
 toMessage :: Config -> Double -> OSCTarget -> T.Tempo -> Event (Map.Map String Value) -> Maybe O.Message
 toMessage config t target tempo e = do vs <- toData target addExtra
                                        return $ O.Message (oPath target) $ oPreamble target ++ vs
-  where on = sched tempo $ start $ whole e
-        off = sched tempo $ stop $ whole e
-        identifier = ((if (start $ whole e) == (start $ part e) then "X" else ">")
-                      ++ show (start $ whole e)
+  where on = sched tempo $ start $ wholeOrPart e
+        off = sched tempo $ stop $ wholeOrPart e
+        identifier = ((if (start $ wholeOrPart e) == (start $ part e) then "X" else ">")
+                      ++ show (start $ wholeOrPart e)
                       ++ "-"
-                      ++ show (stop $ whole e)
+                      ++ show (stop $ wholeOrPart e)
                       ++ "-"
                       ++ getString "n"
                       ++ "-"
@@ -177,7 +177,7 @@
                       | otherwise = id
         extra False = addIdentifier [("cps", (VF $ T.cps tempo)),
                                      ("delta", VF delta),
-                                     ("cycle", VF (fromRational $ start $ whole e))
+                                     ("cycle", VF (fromRational $ start $ wholeOrPart e))
                                     ]
         extra True = timestamp ++ (extra False)
         timestamp = [("sec", VI sec),
@@ -202,10 +202,11 @@
      tempo <- readMVar tempoMV
      now <- O.time
      let sMap' = Map.insert "_cps" (pure $ VF $ T.cps tempo) sMap
-         es = filterEvents $ query p (State {arc = T.nowArc st, controls = sMap'})
-         filterEvents | cSendParts config = id
-                      | otherwise = filter eventHasOnset
-         on e = (sched tempo $ start $ whole e) + eventNudge e
+         es = filterOns $ query p (State {arc = T.nowArc st, controls = sMap'})
+         filterOns | cSendParts config = id
+                   | otherwise = filter eventHasOnset
+           -- there should always be a whole (due to the eventHasOnset filter)
+         on e = (sched tempo $ start $ wholeOrPart e) + eventNudge e
          eventNudge e = fromJust $ getF $ fromMaybe (VF 0) $ Map.lookup "nudge" $ value e
          messages target = catMaybes $ map (\e -> do m <- toMessage config (on e + latency target) target tempo e
                                                      return $ (on e, m)
@@ -309,8 +310,10 @@
                                                        controls = sMap'
                                                       }
                                                )
-           at e = sched fakeTempo $ start $ whole e
-           on e = sched tempo $ start $ whole e
+           -- there should always be a whole (due to the eventHasOnset filter)
+           at e = sched fakeTempo $ start $ wholeOrPart e
+           -- there should always be a whole (due to the eventHasOnset filter)
+           on e = sched tempo $ start $ wholeOrPart e
            cpsChanges = map (\e -> (on e - now, Map.lookup "cps" $ value e)) es
            config = sConfig st
            messages target =
diff --git a/src/Sound/Tidal/UI.hs b/src/Sound/Tidal/UI.hs
--- a/src/Sound/Tidal/UI.hs
+++ b/src/Sound/Tidal/UI.hs
@@ -9,6 +9,7 @@
 -- import           System.Random (randoms, mkStdGen)
 import           System.Random.MWC
 import           Control.Monad.ST
+import           Control.Monad.Primitive (PrimState, PrimMonad)
 import qualified Data.Vector as V
 import           Data.Word (Word32)
 import           Data.Ratio ((%),numerator,denominator)
@@ -28,7 +29,7 @@
 -- * UI
 
 -- | Randomisation
-
+timeToSeed :: (PrimMonad m, Real a) => a -> m (Gen (PrimState m))
 timeToSeed x = do
   let x' = toRational (x*x) / 1000000
   let n' = fromIntegral $ numerator x'
@@ -79,7 +80,7 @@
 @
 -}
 rand :: Fractional a => Pattern a
-rand = Pattern Analog (\(State a@(Arc s e) _) -> [Event a a (realToFrac $ timeToRand $ (e + s)/2)])
+rand = Pattern (\(State a@(Arc s e) _) -> [Event Nothing a (realToFrac $ timeToRand $ (e + s)/2)])
 
 {- | Just like `rand` but for whole numbers, `irand n` generates a pattern of (pseudo-) random whole numbers between `0` to `n-1` inclusive. Notably used to pick a random
 samples from a folder:
@@ -196,16 +197,16 @@
 degradeBy = tParam _degradeBy
 
 _degradeBy :: Double -> Pattern a -> Pattern a
-_degradeBy x p = fmap fst $ filterValues ((> x) . snd) $ (,) <$> p <*> rand
+_degradeBy x p = fmap fst $ filterValues ((> x) . snd) $ (,) <$> p <* rand
 
 unDegradeBy :: Pattern Double -> Pattern a -> Pattern a
 unDegradeBy = tParam _unDegradeBy
 
 _unDegradeBy :: Double -> Pattern a -> Pattern a
-_unDegradeBy x p = fmap fst $ filterValues ((<= x) . snd) $ (,) <$> p <*> rand
+_unDegradeBy x p = fmap fst $ filterValues ((<= x) . snd) $ (,) <$> p <* rand
 
 degradeOverBy :: Int -> Pattern Double -> Pattern a -> Pattern a
-degradeOverBy i tx p = unwrap $ (\x -> fmap fst $ filterValues ((> x) . snd) $ (,) <$> p <*> fastRepeatCycles i rand) <$> slow (fromIntegral i) tx
+degradeOverBy i tx p = unwrap $ (\x -> fmap fst $ filterValues ((> x) . snd) $ (,) <$> p <* fastRepeatCycles i rand) <$> slow (fromIntegral i) tx
 
 
 {- | Use @sometimesBy@ to apply a given function "sometimes". For example, the
@@ -969,7 +970,7 @@
 substruct :: Pattern String -> Pattern b -> Pattern b
 substruct s p = p {query = f}
   where f st =
-          concatMap ((\a' -> queryArc (compressArcTo a' p) a') . whole) (query s st)
+          concatMap ((\a' -> queryArc (compressArcTo a' p) a') . fromJust . whole) $ filter isDigital $ (query s st)
 
 randArcs :: Int -> Pattern [Arc]
 randArcs n =
@@ -987,8 +988,8 @@
 
 -- TODO - what does this do? Something for @stripe@ ..
 randStruct :: Int -> Pattern Int
-randStruct n = splitQueries $ Pattern {nature = Digital, query = f}
-  where f st = map (\(a,b,c) -> Event a (fromJust b) c) $ filter (\(_,x,_) -> isJust x) as
+randStruct n = splitQueries $ Pattern {query = f}
+  where f st = map (\(a,b,c) -> Event (Just a) (fromJust b) c) $ filter (\(_,x,_) -> isJust x) as
           where as = map (\(i, Arc s' e') ->
                     (Arc (s' + sam s) (e' + sam s),
                        subArc (Arc s e) (Arc (s' + sam s) (e' + sam s)), i)) $
@@ -998,7 +999,10 @@
 
 -- TODO - what does this do?
 substruct' :: Pattern Int -> Pattern a -> Pattern a
-substruct' s p = p {query = \st -> concatMap (\(Event a' _ i) -> queryArc (compressArcTo a' (inside (pure $ 1/toRational(length (queryArc s (Arc (sam (start $ arc st)) (nextSam (start $ arc st)))))) (rotR (toRational i)) p)) a') (query s st)}
+substruct' s p = p {query = \st -> concatMap (f st) (query s st)}
+  where f st (Event (Just a') _ i) = queryArc (compressArcTo a' (inside (pure $ 1/toRational(length (queryArc s (Arc (sam (start $ arc st)) (nextSam (start $ arc st)))))) (rotR (toRational i)) p)) a'
+        -- Ignore analog events (ones without wholes)
+        f _ _ = []
 
 -- | @stripe n p@: repeats pattern @p@, @n@ times per cycle. So
 -- similar to @fast@, but with random durations. The repetitions will
@@ -1064,10 +1068,10 @@
 transition probability from state 0->0 is 2/5, 0->1 is 3/5, 1->0 is 1/4, and 
 1->1 is 3/4.  -}
 runMarkov :: Int -> [[Double]] -> Int -> Time -> [Int]
-runMarkov n tp xi seed = reverse $ (iterate (markovStep $ renorm tp) [xi])!! (n-1) where
-  markovStep tp xs = (fromJust $ findIndex (r <=) $ scanl1 (+) (tp!!(head xs))) : xs where
+runMarkov n tp xi seed = reverse $ (iterate (markovStep $ renorm) [xi])!! (n-1) where
+  markovStep tp' xs = (fromJust $ findIndex (r <=) $ scanl1 (+) (tp'!!(head xs))) : xs where
     r = timeToRand $ seed + (fromIntegral . length) xs / fromIntegral n
-  renorm tp = [ map (/ sum x) x | x <- tp ]
+  renorm = [ map (/ sum x) x | x <- tp ]
 
 {- @markovPat n xi tp@ generates a one-cycle pattern of @n@ steps in a Markov
 chain starting from state @xi@ with transition matrix @tp@. Each row of the
@@ -1088,7 +1092,7 @@
 markovPat = tParam2 _markovPat
 
 _markovPat :: Int -> Int -> [[Double]] -> Pattern Int
-_markovPat n xi tp = splitQueries $ Pattern Digital (\(State a@(Arc s e) _) -> 
+_markovPat n xi tp = splitQueries $ Pattern (\(State a@(Arc s _) _) -> 
   queryArc (listToPat $ runMarkov n tp xi (sam s)) a)
 
 {-|
@@ -1138,7 +1142,7 @@
 stretch :: Pattern a -> Pattern a
 -- TODO - should that be whole or part?
 stretch p = splitQueries $ p {query = q}
-  where q st = query (zoomArc (cycleArc $ enclosingArc $ map whole $ query p (st {arc = Arc (sam s) (nextSam s)})) p) st
+  where q st = query (zoomArc (cycleArc $ enclosingArc $ map wholeOrPart $ query p (st {arc = Arc (sam s) (nextSam s)})) p) st
           where s = start $ arc st
 
 {- | `fit'` is a generalization of `fit`, where the list is instead constructed by using another integer pattern to slice up a given pattern.  The first argument is the number of cycles of that latter pattern to use when slicing.  It's easier to understand this with a few examples:
@@ -1203,7 +1207,7 @@
 loopFirst p = splitQueries $ p {query = f}
   where f st = map
           (\(Event w p' v) ->
-             Event (plus w) (plus p') v) $
+             Event (plus <$> w) (plus p') v) $
           query p (st {arc = minus $ arc st})
           where minus = fmap (subtract (sam s))
                 plus = fmap (+ sam s)
@@ -1281,14 +1285,14 @@
 randrun :: Int -> Pattern Int
 randrun 0 = silence
 randrun n' =
-  splitQueries $ Pattern Digital (\(State a@(Arc s _) _) -> events a $ sam s)
+  splitQueries $ Pattern (\(State a@(Arc s _) _) -> events a $ sam s)
   where events a seed = mapMaybe toEv $ zip arcs shuffled
           where shuffled = map snd $ sortOn fst $ zip rs [0 .. (n'-1)]
                 rs = timeToRands seed n'
                 arcs = zipWith Arc fractions (tail fractions)
                 fractions = map (+ (sam $ start a)) [0, 1 / fromIntegral n' .. 1]
                 toEv (a',v) = do a'' <- subArc a a'
-                                 return $ Event a' a'' v
+                                 return $ Event (Just a') a'' v
 
 ur :: Time -> Pattern String -> [(String, Pattern a)] -> [(String, Pattern a -> Pattern a)] -> Pattern a
 ur t outer_p ps fs = _slow t $ unwrap $ adjust <$> timedValues (getPat . split <$> outer_p)
@@ -1303,7 +1307,7 @@
         transform _ _ = id
         transform' str (Arc s e) p = s `rotR` inside (pure $ 1/(e-s)) (matchF str) p
         matchF str = fromMaybe id $ lookup str fs
-        timedValues = withEvent (\(Event a a' v) -> Event a a' (a,v))
+        timedValues = withEvent (\(Event (Just a) a' v) -> Event (Just a) a' (a,v)) . filterDigital
 
 inhabit :: [(String, Pattern a)] -> Pattern String -> Pattern a
 inhabit ps p = squeezeJoin $ (\s -> fromMaybe silence $ lookup s ps) <$> p
@@ -1341,13 +1345,15 @@
 arpWith f p = withEvents munge p
   where munge es = concatMap (spreadOut . f) (groupBy (\a b -> whole a == whole b) $ sortOn whole es)
         spreadOut xs = mapMaybe (\(n, x) -> shiftIt n (length xs) x) $ enumerate xs
-        shiftIt n d (Event (Arc s e) a' v) =
+        shiftIt n d (Event (Just (Arc s e)) a' v) =
           do
             a'' <- subArc (Arc newS newE) a'
-            return (Event (Arc newS newE) a'' v)
+            return (Event (Just $ Arc newS newE) a'' v)
           where newS = s + (dur * fromIntegral n)
                 newE = newS + dur
                 dur = (e - s) / fromIntegral d
+        -- TODO ignoring analog events.. Should we just leave them as-is?
+        shiftIt _ _ _ = Nothing
 
 arp :: Pattern String -> Pattern a -> Pattern a
 arp = tParam _arp
@@ -1412,10 +1418,10 @@
 -- Uses the first (binary) pattern to switch between the following two
 -- patterns.
 sew :: Pattern Bool -> Pattern a -> Pattern a -> Pattern a
-sew stitch a b = overlay (mask stitch a)  (mask (inv stitch) b)
+sew pb a b = overlay (mask pb a) (mask (inv pb) b)
 
 stitch :: Pattern Bool -> Pattern a -> Pattern a -> Pattern a
-stitch bool a b = overlay (struct bool a)  (struct (inv bool) b)
+stitch pb a b = overlay (struct pb a)  (struct (inv pb) b)
 
 stutter :: Integral i => i -> Time -> Pattern a -> Pattern a
 stutter n t p = stack $ map (\i -> (t * fromIntegral i) `rotR` p) [0 .. (n-1)]
@@ -1643,7 +1649,7 @@
 
 -- | chooses between a list of functions, using a pattern of integers
 pickF :: Pattern Int -> [Pattern a -> Pattern a] -> Pattern a -> Pattern a
-pickF pi fs pat = innerJoin $ (\i -> _pickF i fs pat) <$> pi
+pickF pInt fs pat = innerJoin $ (\i -> _pickF i fs pat) <$> pInt
 
 _pickF :: Int -> [Pattern a -> Pattern a] -> Pattern a -> Pattern a
 _pickF i fs p =  (fs !!! i) p
@@ -1718,16 +1724,17 @@
 -- | Serialises a pattern so there's only one event playing at any one
 -- time, making it 'monophonic'. Events which start/end earlier are given priority.
 mono :: Pattern a -> Pattern a
-mono p = Pattern Digital $ \(State a cm) -> flatten $ query p (State a cm) where
+mono p = Pattern $ \(State a cm) -> flatten $ query p (State a cm) where
   flatten :: [Event a] -> [Event a]
   flatten = mapMaybe constrainPart . truncateOverlaps . sortOn whole
   truncateOverlaps [] = []
   truncateOverlaps (e:es) = e : truncateOverlaps (mapMaybe (snip e) es)
-  snip a b | start (whole b) >= stop (whole a) = Just b
-           | stop (whole b) <= stop (whole a) = Nothing
-           | otherwise = Just b {whole = Arc (stop $ whole a) (stop $ whole b)}
+  -- TODO - decide what to do about analog events..
+  snip a b | start (wholeOrPart b) >= stop (wholeOrPart a) = Just b
+           | stop (wholeOrPart b) <= stop (wholeOrPart a) = Nothing
+           | otherwise = Just b {whole = Just $ Arc (stop $ wholeOrPart a) (stop $ wholeOrPart b)}
   constrainPart :: Event a -> Maybe (Event a)
-  constrainPart e = do a <- subArc (whole e) (part e)
+  constrainPart e = do a <- subArc (wholeOrPart e) (part e)
                        return $ e {part = a}
 
 -- serialize the given pattern
@@ -1738,24 +1745,25 @@
 -- if there is, check where we are in the 'whole' of the event, and use that to tween between the values of the event and the next event
 -- smooth :: Pattern Double -> Pattern Double
 
+-- TODO - test this with analog events
 smooth :: Fractional a => Pattern a -> Pattern a
-smooth p = Pattern Analog $ \st@(State a cm) -> tween st a $ query monoP (State (midArc a) cm)
+smooth p = Pattern $ \st@(State a cm) -> tween st a $ query monoP (State (midArc a) cm)
   where
     midArc a = Arc (mid (start a, stop a)) (mid (start a, stop a))
     tween _ _ [] = []
-    tween st queryA (e:_) = maybe [e {whole = queryA, part = queryA}] (tween' queryA) (nextV st)
+    tween st queryA (e:_) = maybe [e {whole = Just queryA, part = queryA}] (tween' queryA) (nextV st)
       where aStop = Arc (wholeStop e) (wholeStop e)
             nextEs st' = query monoP (st' {arc = aStop})
             nextV st' | null (nextEs st') = Nothing
                       | otherwise = Just $ value (head (nextEs st'))
             tween' queryA' v =
               [ Event
-                { whole = queryA'
+                { whole = Just queryA'
                 , part = queryA'
                 , value = value e + ((v - value e) * pc)}
               ]
-            pc | delta' (whole e) == 0 = 0
-               | otherwise = fromRational $ (eventPartStart e - wholeStart e) / delta' (whole e)
+            pc | delta' (wholeOrPart e) == 0 = 0
+               | otherwise = fromRational $ (eventPartStart e - wholeStart e) / delta' (wholeOrPart e)
             delta' a = stop a - start a
     monoP = mono p
 
@@ -1818,15 +1826,16 @@
 
 squeezeJoinUp :: Pattern (ControlPattern) -> ControlPattern
 squeezeJoinUp pp = pp {query = q}
-  where q st = concatMap
-          (\(Event w p v) ->
-             mapMaybe (munge w p) $ query (compressArc (cycleArc w) (v |* P.speed (pure $ fromRational $ 1/(stop w - start w)))) st {arc = p}
-          )
-          (query pp st)
-        munge oWhole oPart (Event iWhole iPart v) =
+  where q st = concatMap (f st) (query (filterDigital pp) st)
+        f st (Event (Just w) p v) =
+          mapMaybe (munge w p) $ query (compressArc (cycleArc w) (v |* P.speed (pure $ fromRational $ 1/(stop w - start w)))) st {arc = p}
+        -- already ignoring analog events, but for completeness..
+        f _ _ = []
+        munge oWhole oPart (Event (Just iWhole) iPart v) =
           do w' <- subArc oWhole iWhole
              p' <- subArc oPart iPart
-             return (Event w' p' v)
+             return (Event (Just w') p' v)
+        munge _ _ _ = Nothing
 
 chew :: Int -> Pattern Int -> ControlPattern  -> ControlPattern
 chew n ipat pat = (squeezeJoinUp $ zoompat <$> ipat) |/ P.speed (pure $ fromIntegral n)
diff --git a/src/Sound/Tidal/Version.hs b/src/Sound/Tidal/Version.hs
--- a/src/Sound/Tidal/Version.hs
+++ b/src/Sound/Tidal/Version.hs
@@ -1,4 +1,4 @@
 module Sound.Tidal.Version where
 
 tidal_version :: String
-tidal_version = "1.3.0"
+tidal_version = "1.4.0"
diff --git a/test/Sound/Tidal/CoreTest.hs b/test/Sound/Tidal/CoreTest.hs
--- a/test/Sound/Tidal/CoreTest.hs
+++ b/test/Sound/Tidal/CoreTest.hs
@@ -94,36 +94,36 @@
     describe "saw" $ do
       it "goes from 0 up to 1 every cycle" $ do
         it "0" $
-          (queryArc saw (Arc 0 0))    `shouldBe` fmap toEvent [(((0,0), (0,0)),    0 :: Float)]
+          (queryArc saw (Arc 0 0)) `shouldBe` [(Event Nothing (Arc 0 0) 0)]
         it "0.25" $
-          (queryArc saw (Arc 0.25 0.25)) `shouldBe` fmap toEvent [(((0.25,0.25), (0.25,0.25)), 0.25 :: Float)]
+          (queryArc saw (Arc 0.25 0.25)) `shouldBe` [(Event Nothing (Arc 0.25 0.25) 0.25)]
         it "0.5" $
-          (queryArc saw (Arc 0.5 0.5))  `shouldBe` fmap toEvent [(((0.5,0.5), (0.5,0.5) ), 0.5 :: Float)]
+          (queryArc saw (Arc 0.5 0.5))  `shouldBe` [(Event Nothing (Arc 0.5 0.5) 0.5)]
         it "0.75" $
-          (queryArc saw (Arc 0.75 0.75)) `shouldBe` fmap toEvent [(((0.75,0.75), (0.75,0.75)), 0.75 :: Float)]
+          (queryArc saw (Arc 0.75 0.75)) `shouldBe` [(Event Nothing (Arc 0.75 0.75) 0.75)]
       it "can be added to" $ do
         (map value $ queryArc ((+1) <$> saw) (Arc 0.5 0.5)) `shouldBe` [1.5 :: Float]
       it "works on the left of <*>" $ do
         (queryArc ((+) <$> saw <*> pure 3) (Arc 0 1))
-          `shouldBe` fmap toEvent [(((0,1), (0,1)), 3 :: Float)]
+          `shouldBe` [Event Nothing (Arc 0 1) 3.5]
       it "works on the right of <*>" $ do
         (queryArc ((fast 4 $ pure (+3)) <*> saw) (Arc 0 1))
-          `shouldBe` fmap toEvent
-          [(((0,0.25), (0,0.25)), 3 :: Float),
-            (((0.25,0.5), (0.25,0.5)), 3.25),
-            (((0.5,0.75), (0.5,0.75)), 3.5),
-            (((0.75,1), (0.75,1)), 3.75)
+          `shouldBe` 
+          [Event Nothing (Arc 0 0.25) 3.5,
+           Event Nothing (Arc 0.25 0.5) 3.5,
+           Event Nothing (Arc 0.5 0.75) 3.5,
+           Event Nothing (Arc 0.75 1) 3.5
           ]
       it "can be reversed" $ do
         it "works with whole cycles" $
           (queryArc (rev saw) (Arc 0 1))
-            `shouldBe` fmap toEvent [(((0,1), (0,1)), 0.5 :: Float)]
+            `shouldBe` [(Event Nothing (Arc 0 1) 0.5)]
         it "works with half cycles" $
           (queryArc (rev saw) (Arc 0 0.5))
-            `shouldBe` fmap toEvent [(((0,0.5), (0,0.5)), 0.75 :: Float)]
+            `shouldBe` [(Event Nothing (Arc 0 0.5) 0.75)]
         it "works with inset points" $
           (queryArc (rev saw) (Arc 0.25 0.25))
-            `shouldBe` fmap toEvent [(((0.25,0.25), (0.25,0.25)), 0.75 :: Float)]
+            `shouldBe` [(Event Nothing (Arc 0.25 0.25) 0.75)]
 
     describe "tri" $ do
       it "goes from 0 up to 1 and back every cycle" $ do
diff --git a/test/Sound/Tidal/PatternTest.hs b/test/Sound/Tidal/PatternTest.hs
--- a/test/Sound/Tidal/PatternTest.hs
+++ b/test/Sound/Tidal/PatternTest.hs
@@ -25,53 +25,54 @@
         let res = fmap (+1) (Arc 3 5)
         property $ ((Arc 4 6) :: Arc) === res
 
+  {-
     describe "Event" $ do
       it "(Bifunctor) first: Apply a function to the Arc elements: whole and part" $ do
-        let res = Event (Arc 1 2) (Arc 3 4) 5 :: Event Int
+        let res = Event (Just $ Arc 1 2) (Arc 3 4) 5 :: Event Int
             f = (+1)
         property $
           first f res ===
-          Event (Arc 2 3) (Arc 4 5) 5
+          Event (Just $ Arc 2 3) (Arc 4 5) 5
       it "(Bifunctor) second: Apply a function to the event element" $ do
-        let res = Event (Arc 1 2) (Arc 3 4) 5 :: Event Int
+        let res = Event (Just $ Arc 1 2) (Arc 3 4) 5 :: Event Int
             f = (+1)
         property $
           second f res ===
-          Event (Arc 1 2) (Arc 3 4) 6
+          Event (Just $ Arc 1 2) (Arc 3 4) 6-}
 
     describe "whole" $ do
       it "returns the whole Arc in an Event" $ do
-        property $ Arc 1 2 === whole (Event (Arc 1 2) (Arc 3 4) 5 :: Event Int)
+        property $ (Just $ Arc 1 2) === whole (Event (Just $ Arc 1 2) (Arc 3 4) 5 :: Event Int)
 
     describe "part" $ do
       it "returns the part Arc in an Event" $ do
-        property $ Arc 3 4 === part (Event (Arc 1 2) (Arc 3 4) 5 :: Event Int)
+        property $ (Arc 3 4) === part (Event (Just $ Arc 1 2) (Arc 3 4) 5 :: Event Int)
 
     describe "value" $ do
       it "returns the event value in an Event" $ do
-        property $ 5 === value (Event (Arc 1 2 :: Arc) (Arc 3 4) ( 5 :: Int))
+        property $ 5 === value (Event (Just $ Arc 1 2) (Arc 3 4) ( 5 :: Int))
 
     describe "wholeStart" $ do 
       it "retrieve the onset of an event: the start of the whole Arc" $ do 
-        property $ 1 === wholeStart (Event (Arc 1 2) (Arc 3 4) (5 :: Int))
+        property $ 1 === wholeStart (Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int))
 
     describe "eventHasOnset" $ do 
       it "return True when the start values of the two arcs in an event are equal" $ do 
-        let ev = (Event (Arc 1 2) (Arc 1 3) (4 :: Int)) 
+        let ev = (Event (Just $ Arc 1 2) (Arc 1 3) (4 :: Int)) 
         property $ True === eventHasOnset ev 
       it "return False when the start values of the two arcs in an event are not equal" $ do 
-        let ev = (Event (Arc 1 2) (Arc 3 4) (5 :: Int)) 
+        let ev = (Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) 
         property $ False === eventHasOnset ev
 
     describe "pure" $ do
       it "fills a whole cycle" $ do
-        property $ queryArc (pure 0) (Arc 0 1) === [(Event (Arc 0 1) (Arc 0 1) (0 :: Int))]
+        property $ queryArc (pure 0) (Arc 0 1) === [(Event (Just $ Arc 0 1) (Arc 0 1) (0 :: Int))]
       it "returns the part of an pure that you ask for, preserving the whole" $ do
-        property $ queryArc (pure 0) (Arc 0.25 0.75) === [(Event (Arc 0 1) (Arc 0.25 0.75) (0 :: Int))]
+        property $ queryArc (pure 0) (Arc 0.25 0.75) === [(Event (Just $ Arc 0 1) (Arc 0.25 0.75) (0 :: Int))]
       it "gives correct fragments when you go over cycle boundaries" $ do
         property $ queryArc (pure 0) (Arc 0.25 1.25) ===
-          [ (Event (Arc 0 1) (Arc 0.25 1) (0 :: Int)),
-            (Event (Arc 1 2) (Arc 1 1.25) 0)
+          [ (Event (Just $ Arc 0 1) (Arc 0.25 1) (0 :: Int)),
+            (Event (Just $ Arc 1 2) (Arc 1 1.25) 0)
           ]
       it "works with zero-length queries" $ do
         it "0" $
@@ -85,8 +86,8 @@
       it "copes with cross-cycle queries" $ do
         (queryArc(_fastGap 2 $ fastCat [pure "a", pure "b"]) (Arc 0.5 1.5))
           `shouldBe`
-          [(Event (Arc (1 % 1) (5 % 4)) (Arc (1 % 1) (5 % 4)) ("a" :: String)),
-           (Event (Arc (5 % 4) (3 % 2)) (Arc (5 % 4) (3 % 2)) "b")
+          [(Event (Just $ Arc (1 % 1) (5 % 4)) (Arc (1 % 1) (5 % 4)) ("a" :: String)),
+           (Event (Just $ Arc (5 % 4) (3 % 2)) (Arc (5 % 4) (3 % 2)) "b")
           ]
       it "does not return events outside of the query" $ do
         (queryArc(_fastGap 2 $ fastCat [pure "a", pure ("b" :: String)]) (Arc 0.5 0.9))
@@ -191,9 +192,9 @@
             b = fastCat [pure "c", pure "d", pure "e"]
             pp = fastCat [pure a, pure b]
         queryArc (unwrap pp) (Arc 0 1)
-          `shouldBe` [(Event (Arc (0 % 1) (1 % 2)) (Arc (0 % 1) (1 % 2)) ("a" :: String)),
-                      (Event (Arc (1 % 2) (2 % 3)) (Arc (1 % 2) (2 % 3)) "d"),
-                      (Event (Arc (2 % 3) (1 % 1)) (Arc (2 % 3) (1 % 1)) "e")
+          `shouldBe` [(Event (Just $ Arc (0 % 1) (1 % 2)) (Arc (0 % 1) (1 % 2)) ("a" :: String)),
+                      (Event (Just $ Arc (1 % 2) (2 % 3)) (Arc (1 % 2) (2 % 3)) "d"),
+                      (Event (Just $ Arc (2 % 3) (1 % 1)) (Arc (2 % 3) (1 % 1)) "e")
                      ]
 
     describe "squeezeJoin" $ do
@@ -202,11 +203,11 @@
             b = fastCat [pure "c", pure "d", pure "e"]
             pp = fastCat [pure a, pure b]
         queryArc (squeezeJoin pp) (Arc 0 1)
-          `shouldBe` [(Event (Arc (0 % 1) (1 % 4)) (Arc (0 % 1) (1 % 4)) ("a" :: String)),
-                      (Event (Arc (1 % 4) (1 % 2)) (Arc (1 % 4) (1 % 2)) "b"),
-                      (Event (Arc (1 % 2) (2 % 3)) (Arc (1 % 2) (2 % 3)) "c"),
-                      (Event (Arc (2 % 3) (5 % 6)) (Arc (2 % 3) (5 % 6)) "d"),
-                      (Event (Arc (5 % 6) (1 % 1)) (Arc (5 % 6) (1 % 1)) "e")
+          `shouldBe` [(Event (Just $ Arc (0 % 1) (1 % 4)) (Arc (0 % 1) (1 % 4)) ("a" :: String)),
+                      (Event (Just $ Arc (1 % 4) (1 % 2)) (Arc (1 % 4) (1 % 2)) "b"),
+                      (Event (Just $ Arc (1 % 2) (2 % 3)) (Arc (1 % 2) (2 % 3)) "c"),
+                      (Event (Just $ Arc (2 % 3) (5 % 6)) (Arc (2 % 3) (5 % 6)) "d"),
+                      (Event (Just $ Arc (5 % 6) (1 % 1)) (Arc (5 % 6) (1 % 1)) "e")
                      ]
 
     describe ">>=" $ do
@@ -251,38 +252,38 @@
     describe "controlI" $ do
       it "can retrieve values from state" $
        (query (pure 3 + cF_ "hello") $ State (Arc 0 1) (Map.singleton "hello" (pure $ VF 0.5)))
-       `shouldBe` [(Event (Arc (0 % 1) (1 % 1)) (Arc (0 % 1) (1 % 1)) 3.5)]
+       `shouldBe` [(Event (Just $ Arc (0 % 1) (1 % 1)) (Arc (0 % 1) (1 % 1)) 3.5)]
 
     describe "wholeStart" $ do 
       it "retrieve first element of a tuple, inside first element of a tuple, inside the first of another" $ do 
-        property $ 1 === wholeStart (Event (Arc 1 2) (Arc 3 4) (5 :: Int))
+        property $ 1 === wholeStart (Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int))
 
     describe "wholeStop" $ do
       it "retrieve the end time from the first Arc in an Event" $ do
-        property $ 2 === wholeStop (Event (Arc 1 2) (Arc 3 4) (5 :: Int))
+        property $ 2 === wholeStop (Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int))
 
     describe "eventPartStart" $ do 
       it "retrieve the start time of the second Arc in an Event" $ do 
-        property $ 3 === eventPartStart (Event (Arc 1 2) (Arc 3 4) (5 :: Int))
+        property $ 3 === eventPartStart (Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int))
 
     describe "eventPartStop" $ do 
       it "retrieve the end time of the second Arc in an Event" $ do 
-        property $ 4 === eventPartStop (Event (Arc 1 2) (Arc 3 4) (5 :: Int))
+        property $ 4 === eventPartStop (Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int))
     
     describe "eventPart" $ do 
       it "retrieve the second Arc in an Event" $ do 
-        property $ Arc 3 4 === eventPart (Event (Arc 1 2) (Arc 3 4) (5 :: Int))
+        property $ Arc 3 4 === eventPart (Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int))
     
     describe "eventValue" $ do
       it "retrieve the second value from a tuple" $ do 
-        property $ 5 === eventValue (Event (Arc 1 2) (Arc 3 4) (5 :: Int))
+        property $ 5 === eventValue (Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int))
 
     describe "eventHasOnset" $ do 
       it "return True when the start values of the two arcs in an event are equal" $ do 
-        let ev = (Event (Arc 1 2) (Arc 1 3) (4 :: Int)) 
+        let ev = (Event (Just $ Arc 1 2) (Arc 1 3) (4 :: Int)) 
         property $ True === eventHasOnset ev 
       it "return False when the start values of the two arcs in an event are not equal" $ do 
-        let ev = (Event (Arc 1 2) (Arc 3 4) (5 :: Int)) 
+        let ev = (Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) 
         property $ False === eventHasOnset ev
 
     describe "sam" $ do
@@ -360,16 +361,16 @@
 
     describe "onsetIn" $ do
       it "If the beginning of an Event is within a given Arc, same rules as 'isIn'" $ do 
-         let res = onsetIn (Arc 2.0 2.8) (Event (Arc 2.2 2.7) (Arc 3.3 3.8) (5 :: Int))
+         let res = onsetIn (Arc 2.0 2.8) (Event (Just $ Arc 2.2 2.7) (Arc 3.3 3.8) (5 :: Int))
          property $ True === res 
       it "Beginning of Event is equal to beggining of given Arc" $ do 
-         let res = onsetIn (Arc 2.0 2.8) (Event (Arc 2.0 2.7) (Arc 3.3 3.8) (5 :: Int))
+         let res = onsetIn (Arc 2.0 2.8) (Event (Just $ Arc 2.0 2.7) (Arc 3.3 3.8) (5 :: Int))
          property $ True === res 
       it "Beginning of an Event is less than the start of the Arc" $ do 
-         let res = onsetIn (Arc 2.0 2.8) (Event (Arc 1.2 1.7) (Arc 3.3 3.8) (5 :: Int))
+         let res = onsetIn (Arc 2.0 2.8) (Event (Just $ Arc 1.2 1.7) (Arc 3.3 3.8) (5 :: Int))
          property $ False === res
       it "Start of Event is greater than the start of the given Arc" $ do 
-         let res = onsetIn (Arc 2.0 2.8) (Event (Arc 3.1 3.5) (Arc 4.0 4.6) (5 :: Int))
+         let res = onsetIn (Arc 2.0 2.8) (Event (Just $ Arc 3.1 3.5) (Arc 4.0 4.6) (5 :: Int))
          property $ False === res
 
     describe "subArc" $ do
@@ -403,16 +404,16 @@
 
     describe "isAdjacent" $ do
       it "if the given Events are adjacent parts of the same whole" $ do 
-        let res = isAdjacent (Event (Arc 1 2) (Arc 3 4) 5) (Event (Arc 1 2) (Arc 4 3) (5 :: Int))
+        let res = isAdjacent (Event (Just $ Arc 1 2) (Arc 3 4) 5) (Event (Just $ Arc 1 2) (Arc 4 3) (5 :: Int))
         property $ True === res 
       it "if first Arc of of first Event is not equal to first Arc of second Event" $ do
-        let res = isAdjacent (Event (Arc 1 2) (Arc 3 4) 5) (Event (Arc 7 8) (Arc 4 3) (5 :: Int))
+        let res = isAdjacent (Event (Just $ Arc 1 2) (Arc 3 4) 5) (Event (Just $ Arc 7 8) (Arc 4 3) (5 :: Int))
         property $ False === res  
       it "if the value of the first Event does not equal the value of the second Event" $ do 
-        let res = isAdjacent (Event (Arc 1 2) (Arc 3 4) 5) (Event (Arc 1 2) (Arc 4 3) (6 :: Int))
+        let res = isAdjacent (Event (Just $ Arc 1 2) (Arc 3 4) 5) (Event (Just $ Arc 1 2) (Arc 4 3) (6 :: Int))
         property $ False === res 
       it "second value of second Arc of first Event not equal to first value of second Arc in second Event..." $ do
-        let res = isAdjacent (Event (Arc 1 2) (Arc 3 4) 5) (Event (Arc 1 2) (Arc 3 4) (5 :: Int))
+        let res = isAdjacent (Event (Just $ Arc 1 2) (Arc 3 4) 5) (Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int))
         property $ False === res 
 
     describe "defragParts" $ do 
@@ -420,24 +421,24 @@
         let res = defragParts ([] :: [Event Int]) 
         property $ [] === res
       it "if list consists of only one Event return it as is" $ do 
-        let res = defragParts [(Event (Arc 1 2) (Arc 3 4) (5 :: Int))]
-        property $ [Event (Arc 1 2) (Arc 3 4) (5 :: Int)] === res 
+        let res = defragParts [(Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int))]
+        property $ [Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)] === res 
       it "if list contains adjacent Events return list with Parts combined" $ do 
-        let res = defragParts [(Event (Arc 1 2) (Arc 3 4) (5 :: Int)), (Event (Arc 1 2) (Arc 4 3) (5 :: Int))]
-        property $ [(Event (Arc 1 2) (Arc 3 4) 5)] === res
+        let res = defragParts [(Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)), (Event (Just $ Arc 1 2) (Arc 4 3) (5 :: Int))]
+        property $ [(Event (Just $ Arc 1 2) (Arc 3 4) 5)] === res
       it "if list contains more than one Event none of which are adjacent, return List as is" $ do 
-        let res = defragParts [(Event (Arc 1 2) (Arc 3 4) 5), (Event (Arc 7 8) (Arc 4 3) (5 :: Int))]
-        property $ [Event (Arc 1 2) (Arc 3 4) 5, Event (Arc 7 8) (Arc 4 3) (5 :: Int)] === res
+        let res = defragParts [(Event (Just $ Arc 1 2) (Arc 3 4) 5), (Event (Just $ Arc 7 8) (Arc 4 3) (5 :: Int))]
+        property $ [Event (Just $ Arc 1 2) (Arc 3 4) 5, Event (Just $ Arc 7 8) (Arc 4 3) (5 :: Int)] === res
 
     describe "compareDefrag" $ do 
       it "compare list with Events with empty list of Events" $ do
-        let res = compareDefrag [Event (Arc 1 2) (Arc 3 4) (5 :: Int), Event (Arc 1 2) (Arc 4 3) (5 :: Int)] []
+        let res = compareDefrag [Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int), Event (Just $ Arc 1 2) (Arc 4 3) (5 :: Int)] []
         property $ False === res 
       it "compare lists containing same Events but of different length" $ do 
-        let res = compareDefrag [Event (Arc 1 2) (Arc 3 4) (5 :: Int), Event (Arc 1 2) (Arc 4 3) 5] [Event (Arc 1 2) (Arc 3 4) (5 :: Int)]
+        let res = compareDefrag [Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int), Event (Just $ Arc 1 2) (Arc 4 3) 5] [Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)]
         property $ True === res
       it "compare lists of same length with same Events" $ do 
-        let res = compareDefrag [Event (Arc 1 2) (Arc 3 4) (5 :: Int)] [Event (Arc 1 2) (Arc 3 4) (5 :: Int)]
+        let res = compareDefrag [Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)] [Event (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)]
         property $ True === res 
 
     describe "sect" $ do 
@@ -549,8 +550,8 @@
 
     -- pending "Sound.Tidal.Pattern.eventL" $ do
     --  it "succeeds if the first event 'whole' is shorter" $ do
-    --    property $ eventL (Event (Arc 0,0),(Arc 0 1)),"x") (((0 0) (Arc 0 1.1)) "x")
+    --    property $ eventL (Event (Just $ Arc 0,0),(Arc 0 1)),"x") (((0 0) (Arc 0 1.1)) "x")
     --  it "fails if the events are the same length" $ do
-    --    property $ not $ eventL (Event (Arc 0,0),(Arc 0 1)),"x") (((0 0) (Arc 0 1)) "x")
+    --    property $ not $ eventL (Event (Just $ Arc 0,0),(Arc 0 1)),"x") (((0 0) (Arc 0 1)) "x")
     --  it "fails if the second event is shorter" $ do
-    --    property $ not $ eventL (Event (Arc 0,0),(Arc 0 1)),"x") (((0 0) (Arc 0 0.5)) "x")
+    --    property $ not $ eventL (Event (Just $ Arc 0,0),(Arc 0 1)),"x") (((0 0) (Arc 0 0.5)) "x")
diff --git a/test/Sound/Tidal/UITest.hs b/test/Sound/Tidal/UITest.hs
--- a/test/Sound/Tidal/UITest.hs
+++ b/test/Sound/Tidal/UITest.hs
@@ -44,7 +44,7 @@
       it "can hold a value over multiple cycles" $ do
         comparePD (Arc 0 8)
           (segment 0.5 saw)
-          (slow 2 "0.5" :: Pattern Double)
+          (slow 2 "0" :: Pattern Double)
       {-
       -- not sure what this is supposed to do!
       it "holding values over multiple cycles works in combination" $ do
@@ -81,49 +81,49 @@
     describe "rand" $ do
       it "generates a (pseudo-)random number between zero & one" $ do
         it "at the start of a cycle" $
-          (queryArc rand (Arc 0 0)) `shouldBe` fmap toEvent [(((0, 0), (0, 0)), 0.5000844 :: Float)]
+          (queryArc rand (Arc 0 0)) `shouldBe` [Event Nothing (Arc 0 0) (0.5000844 :: Float)]
         it "at 1/4 of a cycle" $
-          (queryArc rand (Arc 0.25 0.25)) `shouldBe` fmap toEvent
-            [(((0.25, 0.25), (0.25, 0.25)), 0.8587171 :: Float)]
+          (queryArc rand (Arc 0.25 0.25)) `shouldBe` 
+            [Event Nothing (Arc 0.25 0.25) (0.8587171 :: Float)]
         it "at 3/4 of a cycle" $
-          (queryArc rand (Arc 0.75 0.75)) `shouldBe` fmap toEvent
-            [(((0.75, 0.75), (0.75, 0.75)), 0.7277789 :: Float)]
+          (queryArc rand (Arc 0.75 0.75)) `shouldBe` 
+          [Event Nothing (Arc 0.75 0.75) (0.7277789 :: Float)]
 
     describe "range" $ do
       describe "scales a pattern to the supplied range" $ do
         describe "from 3 to 4" $ do
           it "at the start of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 3 4 saw) (Arc 0 0)) `shouldBe` fmap toEvent
-              [(((0, 0), (0, 0)), 3 :: Float)]
+            (queryArc (Sound.Tidal.UI.range 3 4 saw) (Arc 0 0)) `shouldBe` 
+              [Event Nothing (Arc 0 0) (3 :: Float)]
           it "at 1/4 of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 3 4 saw) (Arc 0.25  0.25)) `shouldBe` fmap toEvent
-              [(((0.25, 0.25), (0.25, 0.25)), 3.25 :: Float)]
+            (queryArc (Sound.Tidal.UI.range 3 4 saw) (Arc 0.25  0.25)) `shouldBe`
+              [Event Nothing (Arc 0.25 0.25) (3.25 :: Float)]
           it "at 3/4 of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 3 4 saw) (Arc 0.75 0.75)) `shouldBe` fmap toEvent
-              [(((0.75, 0.75), (0.75, 0.75)), 3.75 :: Float)]
+            (queryArc (Sound.Tidal.UI.range 3 4 saw) (Arc 0.75 0.75)) `shouldBe` 
+              [Event Nothing (Arc 0.75 0.75) (3.75 :: Float)]
 
         describe "from -1 to 1" $ do
           it "at 1/2 of a cycle" $
-            (queryArc (Sound.Tidal.UI.range (-1) 1 saw) (Arc 0.5 0.5)) `shouldBe` fmap toEvent
-              [(((0.5, 0.5), (0.5, 0.5)), 0 :: Float)]
+            (queryArc (Sound.Tidal.UI.range (-1) 1 saw) (Arc 0.5 0.5)) `shouldBe`
+              [Event Nothing (Arc 0.5 0.5) (0 :: Float)]
 
         describe "from 4 to 2" $ do
           it "at the start of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 4 2 saw) (Arc 0 0)) `shouldBe` fmap toEvent
-              [(((0, 0), (0, 0)), 4 :: Float)]
+            (queryArc (Sound.Tidal.UI.range 4 2 saw) (Arc 0 0)) `shouldBe` 
+              [Event Nothing (Arc 0 0) (4 :: Float)]
           it "at 1/4 of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 4 2 saw) (Arc 0.25 0.25)) `shouldBe` fmap toEvent
-              [(((0.25, 0.25), (0.25, 0.25)), 3.5 :: Float)]
+            (queryArc (Sound.Tidal.UI.range 4 2 saw) (Arc 0.25 0.25)) `shouldBe` 
+              [Event Nothing (Arc 0.25 0.25) (3.5 :: Float)]
           it "at 3/4 of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 4 2 saw) (Arc 0.75 0.75)) `shouldBe` fmap toEvent
-              [(((0.75, 0.75), (0.75, 0.75)), 2.5 :: Float)]
+            (queryArc (Sound.Tidal.UI.range 4 2 saw) (Arc 0.75 0.75)) `shouldBe` 
+              [Event Nothing (Arc 0.75 0.75) (2.5 :: Float)]
 
         describe "from 10 to 10" $ do
           it "at 1/2 of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 10 10 saw) (Arc 0.5 0.5)) `shouldBe` fmap toEvent
-              [(((0.5, 0.5), (0.5, 0.5)), 10 :: Float)]
+            (queryArc (Sound.Tidal.UI.range 10 10 saw) (Arc 0.5 0.5)) `shouldBe` 
+              [Event Nothing (Arc 0.5 0.5) (10 :: Float)]
 
-    describe "rot" $ do
+    describe "rot" $ do 
       it "rotates values in a pattern irrespective of structure" $
         property $ comparePD (Arc 0 2)
           (rot 1 "a ~ b c" :: Pattern String)
diff --git a/tidal.cabal b/tidal.cabal
--- a/tidal.cabal
+++ b/tidal.cabal
@@ -1,5 +1,5 @@
 name:                tidal
-version:             1.3.0
+version:             1.4.0
 synopsis:            Pattern language for improvised music
 -- description:
 homepage:            http://tidalcycles.org/
@@ -61,6 +61,7 @@
     , bytestring < 0.11
     , clock < 0.9
     , deepseq >= 1.1.0.0
+    , primitive < 0.8
 
   if !impl(ghc >= 8.4.1)
     build-depends: semigroups >= 0.18 && < 0.20
