-- | The base constructors for generic backtracing. -- -- NOTE this currently can capture dot-bracket notation, but not deep -- semantics. module DP.Backtraced.Core where import Control.Lens import Data.Foldable import GHC.Generics (Generic) import qualified Data.Sequence as Seq import qualified Test.QuickCheck as QC import qualified Test.SmallCheck.Series as SC -- | This is a bit like a lazy "Data.Sequence" in terms of constructors. We can -- not be spine-strict, otherwise we'd use @Data.Sequence@ and enjoy the better -- performance. data Backtraced ty where -- | This backtrace is done Epsilon ∷ Backtraced ty -- | Expand a backtrace to the left. This is lazy, since backtracing relies -- on laziness. Cons ∷ ty → Backtraced ty → Backtraced ty -- | Expand lazily to the right. Snoc ∷ Backtraced ty → ty → Backtraced ty -- | concatenate two structures Append ∷ Backtraced ty → Backtraced ty → Backtraced ty deriving (Eq,Ord,Show,Read,Generic,Functor,Foldable,Traversable) -- | This is somewhat tricky, since we might have to walk down the structure -- quite a bit and shuffle constructors without changing the actual leaf order. instance Cons (Backtraced ty) (Backtraced ty') ty ty' where {-# Inlinable _Cons #-} _Cons = let go1 Epsilon = Left Epsilon go1 (Cons x xs) = Right (x,xs) go1 (Snoc xs x) = go2 xs (Left x) go1 (Append xs ys) = go2 xs (Right ys) go2 Epsilon (Left y) = Right (y,Epsilon) go2 Epsilon (Right ys) = go1 ys go2 (Cons x xs) (Left y) = Right (x,Snoc xs y) go2 (Cons x xs) (Right ys) = Right (x, Append xs ys) go2 (Snoc xs x) (Left y) = go2 xs (Right $ x `Cons` Epsilon `Snoc` y) go2 (Snoc xs x) (Right ys) = go2 xs (Right $ x `Cons` ys) go2 (Append xs ys) (Left z) = go2 xs (Right $ ys `Snoc` z) go2 (Append xs ys) (Right zs) = go2 xs (Right $ ys `Append` zs) in prism (uncurry Cons) go1 instance Snoc (Backtraced ty) (Backtraced ty') ty ty' where {-# Inlinable _Snoc #-} _Snoc = let go1 Epsilon = Left Epsilon go1 (Cons x xs) = go2 (Left x) xs go1 (Snoc xs x) = Right (xs,x) go1 (Append xs ys) = go2 (Right xs) ys go2 (Left x) Epsilon = Right (Epsilon,x) go2 (Right xs) Epsilon = go1 xs go2 (Left x) (Cons y ys) = go2 (Right $ x `Cons` (y `Cons` Epsilon)) ys go2 (Right xs) (Cons y ys) = go2 (Right $ xs `Snoc` y) ys go2 (Left x) (Snoc ys y) = Right (x `Cons` ys, y) go2 (Right xs) (Snoc ys y) = Right (xs `Append` ys, y) go2 (Left x) (Append ys zs) = go2 (Right $ x `Cons` ys) zs go2 (Right xs) (Append ys zs) = go2 (Right $ xs `Append` ys) zs in prism (uncurry Snoc) go1 (<|) = Cons (|>) = Snoc (><) = Append infixr 5 <| infixr 5 >< infixl 5 |> instance SC.Serial m a ⇒ SC.Serial m (Backtraced a)