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
data Backtraced ty where
  
  Epsilon ∷ Backtraced ty
  
  
  Cons ∷ ty → Backtraced ty → Backtraced ty
  
  Snoc ∷ Backtraced ty → ty → Backtraced ty
  
  Append ∷ Backtraced ty → Backtraced ty → Backtraced ty
  deriving (Eq,Ord,Show,Read,Generic,Functor,Foldable,Traversable)
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)