Last active
August 18, 2024 09:59
-
-
Save noughtmare/e02da0ae9dba74acf0f57cfc73ee1d3b to your computer and use it in GitHub Desktop.
Data dependent parsing with explicit variables
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- cabal: | |
build-depends: base, recover-rtti, tasty-bench, tasty-bench-fit | |
-} | |
{-# LANGUAGE GHC2021, GADTs, DataKinds, LambdaCase, TypeFamilies #-} | |
{-# OPTIONS_GHC -Wall #-} | |
-- DATA-DEPENDENT PARSING WITH VARIABLES | |
import Prelude hiding (Monad (..)) | |
import Data.Char (intToDigit) | |
import Data.Kind (Type) | |
-- import Debug.RecoverRTTI | |
-- import Test.Tasty.Bench.Fit | |
-- import Test.Tasty.Bench | |
import Data.Type.Equality | |
import Data.Bifunctor | |
type Var :: [k] -> k -> Type | |
data Var ctx a where | |
Here :: Var (a : ctx) a | |
There :: Var ctx a -> Var (b : ctx) a | |
deriving instance Show (Var ctx a) | |
type Exp :: [Type] -> Type -> Type | |
data Exp ctx a where | |
ENil :: a -> Exp ctx a | |
ECons :: forall ctx a x. Var ctx x -> Exp ctx (x -> a) -> Exp ctx a | |
deriving instance Functor (Exp ctx) | |
instance Applicative (Exp ctx) where | |
pure = ENil | |
ENil f <*> x = fmap f x | |
ECons x xs <*> y = ECons x (flip <$> xs <*> y) | |
ehere :: Exp (x : vs) x | |
ehere = ECons Here (ENil id) | |
ethere :: Exp vs a -> Exp (x : vs) a | |
ethere (ENil x) = ENil x | |
ethere (ECons v x) = ECons (There v) (ethere x) | |
instance Show (Exp ctx a) where | |
-- show (ENil x) = "ENil (" ++ anythingToString x ++ ")" | |
show ENil{} = "ENil{}" | |
show (ECons v xs) = "ECons (" ++ show v ++ ") (" ++ show xs ++ ")" | |
type CFG :: [(Type,Type)] -> [Type] -> Type -> Type | |
data CFG nts vs a where | |
Fail :: CFG nts vs a | |
Or :: CFG nts vs a -> CFG nts vs a -> CFG nts vs a | |
Done :: Exp vs a -> CFG nts vs a | |
Seq :: CFG nts vs a -> (CFG nts (a : vs) b) -> CFG nts vs b | |
Char :: Char -> CFG nts vs () | |
Var :: Var nts '(x, a) -> Exp vs x -> CFG nts vs a | |
Fix :: CFG ('(x,a):nts) (x:vs) a -> Exp vs x -> CFG nts vs a | |
Guard :: Exp vs Bool -> CFG nts vs () | |
Let :: CFG nts (x : vs) y -> CFG ('(x,y):nts) vs a -> CFG nts vs a | |
data Thin xs ys where | |
EndDrop :: Thin xs '[] | |
EndId :: Thin xs xs | |
Keep :: Thin xs ys -> Thin (x : xs) (x : ys) | |
Drop :: Thin xs ys -> Thin (x : xs) ys | |
data CombineThin xs ys zs = forall xs'. CombineThin (Thin xs xs') (Thin xs' ys) (Thin xs' zs) | |
combineThin :: Thin xs ys -> Thin xs zs -> CombineThin xs ys zs | |
combineThin EndDrop t = CombineThin t EndDrop EndId | |
combineThin t EndDrop = CombineThin t EndId EndDrop | |
combineThin EndId t = CombineThin EndId EndId t | |
combineThin t EndId = CombineThin EndId t EndId | |
combineThin (Keep t) (Keep t') = | |
case combineThin t t' of | |
CombineThin x y z -> CombineThin (Keep x) (Keep y) (Keep z) | |
combineThin (Keep t) (Drop t') = | |
case combineThin t t' of | |
CombineThin x y z -> CombineThin (Keep x) (Keep y) (Drop z) | |
combineThin (Drop t) (Keep t') = | |
case combineThin t t' of | |
CombineThin x y z -> CombineThin (Keep x) (Drop y) (Keep z) | |
combineThin (Drop t) (Drop t') = | |
case combineThin t t' of | |
CombineThin x y z -> CombineThin (Drop x) y z | |
data Unused nts vs a = forall nts'. Unused (CFG nts' vs a) (Thin nts nts') | |
combine | |
:: (forall nts'. CFG nts' vsa a -> CFG nts' vsb b -> CFG nts' vsc c) | |
-> Unused nts vsa a -> Unused nts vsb b -> Unused nts vsc c | |
combine f (Unused x t) (Unused y t') = | |
case combineThin t t' of | |
CombineThin tt tx ty -> Unused (f (wkNts (apThin tx) x) (wkNts (apThin ty) y)) tt | |
varToThin :: Var nts a -> Thin nts '[a] | |
varToThin Here = Keep EndDrop | |
varToThin (There v) = Drop (varToThin v) | |
unused :: CFG nts vs a -> Unused nts vs a | |
unused Fail = Unused Fail EndDrop | |
unused (Or x y) = combine Or (unused x) (unused y) | |
unused (Done x) = Unused (Done x) EndDrop | |
unused (Seq x y) = combine Seq (unused x) (unused y) | |
unused (Char c) = Unused (Char c) EndDrop | |
unused (Var v e) = Unused (Var Here e) (varToThin v) | |
unused (Guard e) = Unused (Guard e) EndDrop | |
unused (Fix p e) = | |
case unused p of | |
Unused p' EndDrop -> Unused (Fix (wkNts There p') e) EndDrop | |
Unused p' EndId -> Unused (Fix p' e) EndId | |
Unused p' (Drop t) -> Unused (Fix (wkNts There p') e) t | |
Unused p' (Keep t) -> Unused (Fix p' e) t | |
unused (Let p q) = | |
case (unused p, unused q) of | |
(Unused p' tp, Unused q' EndDrop) -> Unused (Let p' (wkNts (\case) q')) tp | |
(Unused p' tp, Unused q' EndId) -> Unused (Let (wkNts (apThin tp) p') q') EndId | |
(Unused p' tp, Unused q' (Drop tq)) -> | |
case combineThin tp tq of | |
CombineThin tt tp' tq' -> | |
Unused | |
(Let | |
(wkNts (apThin tp') p') | |
(wkNts (There . apThin tq') q')) | |
tt | |
(Unused p' tp, Unused q' (Keep tq)) -> | |
case combineThin tp tq of | |
CombineThin tt tp' tq' -> | |
Unused | |
(Let | |
(wkNts (apThin tp') p') | |
(wkNts (\case Here -> Here; There v -> There $ apThin tq' v) q')) | |
tt | |
eqVar :: Var vs a -> Var vs b -> Maybe (a :~: b) | |
eqVar Here Here = Just Refl | |
eqVar (There v) (There w) = eqVar v w | |
eqVar _ _ = Nothing | |
-- this optimization improves dotsl | |
simplifyE :: Exp vs a -> Exp vs a | |
simplifyE (ECons v (ECons w xs)) | Just Refl <- eqVar v w = ECons v (fmap (\f x -> f x x) xs) | |
simplifyE x = x | |
apThin :: Thin xs ys -> Var ys a -> Var xs a | |
apThin EndDrop x = case x of {} | |
apThin EndId x = x | |
apThin (Drop t) x = There (apThin t x) | |
apThin (Keep t) (There x) = There (apThin t x) | |
apThin (Keep _) Here = Here | |
simplify :: CFG nts vs a -> CFG nts vs a | |
simplify (Seq a b) = | |
case (simplify a, simplify b) of | |
(Fail, _) -> Fail | |
(_, Fail) -> Fail | |
(Done x, y) -> apEG y x | |
(a', b') -> Seq a' b' | |
simplify (Or a b) = | |
case (simplify a, simplify b) of | |
(Fail, x) -> x | |
(x, Fail) -> x | |
(a', b') -> Or a' b' | |
simplify (Fix x e) = | |
-- this optimization improves dotsr | |
case unused x of | |
Unused x' EndDrop -> apEG (wkNts (\case) (simplify x')) (simplifyE e) | |
Unused x' (Drop t) -> apEG (wkNts (apThin t) (simplify x')) (simplifyE e) | |
_ -> Fix (simplify x) (simplifyE e) | |
simplify (Guard e) = case simplifyE e of | |
ENil b -> if b then Done (ENil ()) else Fail | |
e' -> Guard e' | |
simplify (Done e) = Done (simplifyE e) | |
-- simplify (Let (Let p q) r) = Let p (Let (_ q) (_ r)) | |
simplify (Let p q) = | |
case unused (simplify q) of | |
Unused q' EndDrop -> wkNts (\case) q' | |
Unused q' (Drop t) -> wkNts (apThin t) q' | |
_ -> Let (simplify p) (simplify q) | |
simplify (Char c) = Char c | |
simplify Fail = Fail | |
simplify (Var v e) = Var v (simplifyE e) | |
instance Show (CFG nts vs a) where | |
show Fail = "Fail" | |
show (Or x y) = "Or (" ++ show x ++ ") (" ++ show y ++ ")" | |
show (Done e) = "Done (" ++ show e ++ ")" | |
show (Seq x y) = "Seq (" ++ show x ++ ") (" ++ show y ++ ")" | |
show (Char c) = "Char " ++ show c | |
show (Fix p e) = "Fix (" ++ show p ++ ") (" ++ show e ++ ")" | |
show (Var v e) = "Var (" ++ show v ++ ") (" ++ show e ++ ")" | |
show (Guard e) = "Guard (" ++ show e ++ ")" | |
show (Let p q) = "Let (" ++ show p ++ ") (" ++ show q ++ ")" | |
substE :: (forall x. Var vs x -> Exp vs' x) -> Exp vs a -> Exp vs' a | |
substE _ (ENil x) = ENil x | |
substE f (ECons v xs) = substE f xs <*> f v | |
substVs :: (forall x. Var vs x -> Exp vs' x) -> CFG nts vs a -> CFG nts vs' a | |
substVs _ Fail = Fail | |
substVs f (Or p q) = Or (substVs f p) (substVs f q) | |
substVs f (Done x) = Done (substE f x) | |
substVs f (Seq p q) = Seq (substVs f p) (substVs (\case Here -> ECons Here (ENil id); There v -> wkE There $ f v) q) | |
substVs _ (Char c) = Char c | |
substVs f (Var v e) = Var v (substE f e) | |
substVs f (Fix p e) = Fix (substVs (\case Here -> ECons Here (ENil id); There v -> wkE There (f v)) p) (substE f e) | |
substVs f (Guard e) = Guard (substE f e) | |
substVs f (Let p q) = Let (substVs (\case Here -> ehere; There v -> ethere (f v)) p) (substVs f q) | |
wkVs :: (forall x. Var vs x -> Var vs' x) -> CFG nts vs a -> CFG nts vs' a | |
wkVs f = substVs (\v -> ECons (f v) (ENil id)) | |
substNts :: (forall x y. Var nts '(x,y) -> CFG nts' (x:vs) y) -> CFG nts vs a -> CFG nts' vs a | |
substNts _ Fail = Fail | |
substNts f (Or p q) = Or (substNts f p) (substNts f q) | |
substNts _ (Done x) = Done x | |
substNts f (Seq p q) = Seq (substNts f p) (substNts (wkVs (\case Here -> Here; There v -> There (There v)) . f) q) | |
substNts _ (Char c) = Char c | |
substNts f (Var v e) = apEG (f v) e | |
substNts f (Fix p e) = Fix (substNts (\case Here -> Var Here (ECons Here (ENil id)); There v -> wkNts There $ wkVs (\case Here -> Here; There v' -> There (There v')) $ f v) p) e | |
substNts _ (Guard e) = Guard e | |
substNts f (Let p q) = Let (substNts (wkVs (\case Here -> Here; There v -> There (There v)) . f) p) (substNts (\case Here -> Var Here ehere; There v -> wkNts There (f v)) q) | |
wkNts :: (forall x y. Var nts '(x,y) -> Var nts' '(x,y)) -> CFG nts vs a -> CFG nts' vs a | |
wkNts f = substNts ((\v -> Var v (ECons Here (ENil id))) . f) | |
apEE :: Exp (a : vs) b -> Exp vs a -> Exp vs b | |
apEE (ENil x) _ = ENil x | |
apEE (ECons Here xs) e = flip ($) <$> e <*> apEE xs e | |
apEE (ECons (There v) xs) e = ECons v (apEE xs e) | |
apEG :: CFG nts (a : vs) b -> Exp vs a -> CFG nts vs b | |
apEG p e = substVs (\case Here -> e; There v -> ECons v (ENil id)) p | |
both :: (a -> b) -> (a, a) -> (b, b) | |
both f (x, y) = (f x, f y) | |
both1 :: (forall x. f x -> g x) -> (f a, f b) -> (g a, g b) | |
both1 f (x, y) = (f x, f y) | |
wkE :: (forall x. Var vs x -> Var vs' x) -> Exp vs a -> Exp vs' a | |
wkE _ (ENil x) = ENil x | |
wkE f (ECons v xs) = ECons (f v) (wkE f xs) | |
nullable :: (forall x y. Var nts '(x, y) -> [(Exp (x:vs) Bool, Exp (x:vs) y)]) -> CFG nts vs a -> [(Exp vs Bool, Exp vs a)] | |
nullable _ Fail = [] | |
nullable ev (Or p q) = nullable ev p ++ nullable ev q | |
nullable _ (Done x) = [(ENil True, x)] | |
nullable ev (Seq p q) = do | |
(xg,xe) <- nullable ev p | |
(yg,ye) <- nullable ev (apEG q xe) | |
pure (liftA2 (&&) xg yg, ye) | |
nullable _ (Char _) = [] | |
nullable _ (Guard e) = [(e, ENil ())] | |
nullable ev (Var v e) = map (\(x,y) -> (apEE x e, apEE y e)) (ev v) | |
nullable ev (Fix x e) = map (both1 (`apEE` e)) $ nullable (\case Here -> []; There v -> map (both1 (wkE (\case Here -> Here; There v' -> There (There v')))) $ ev v) x | |
nullable ev (Let p q) = | |
let x = nullable (map (both1 (wkE (\case Here -> Here; There v -> There (There v)))) . ev) p | |
in nullable (\case Here -> x; There v -> ev v) q | |
nullable0 :: CFG '[] '[] a -> [a] | |
nullable0 x = do | |
(ENil b, ENil xe) <- nullable (\case) x | |
[xe | b] | |
derivative :: CFG nts vs a | |
-> (forall x y. Var nts '(x,y) -> ([(Exp (x:vs) Bool, Exp (x:vs) y)],Var nts '(x,y))) | |
-> Char -> CFG nts vs a | |
-- derivative cfg _ c | traceShow ("derivative", cfg, c) False = undefined | |
derivative Fail _ _ = Fail | |
derivative (Or p q) nts c = Or (derivative p nts c) (derivative q nts c) | |
derivative (Done _) _ _ = Fail | |
derivative (Seq p q) nts c = Or | |
(foldr Or Fail [Seq (Guard xg) (wkVs There $ derivative (apEG q xe) nts c) | (xg,xe) <- nullable (fst . nts) p]) | |
(Seq (derivative p nts c) q) | |
derivative (Char c') _ c = if c == c' then Done (ENil ()) else Fail | |
derivative (Var v x) nts _ = Var (snd (nts v)) x | |
derivative (Fix @x p x) nts c = | |
Let | |
(Fix (wkVs (\case Here -> Here; There v -> There (There v)) p) (ECons Here (ENil id))) | |
-- substNts (\case Here -> Fix (wkVs (\case Here -> Here; There v -> There (There v)) p) (ECons Here (ENil id)); There v -> Var v ehere) $ | |
(Fix | |
(derivative | |
(wkNts There p) | |
(\case | |
Here -> error "impossible" | |
There Here -> | |
(nullable (map (both1 (wkE (\case Here -> Here; There v -> There (There (There v))))) . fst . nts) (Fix (wkVs (\case Here -> Here; There v -> There (There (There v))) p) (ECons Here (ENil id))) | |
, Here | |
) | |
There (There v) -> let (a,b) = nts v in (map (both1 (wkE (\case Here -> Here; There v' -> There (There v')))) a, There (There b)) | |
) | |
c) | |
x) | |
derivative (Guard _) _ _ = Fail | |
derivative (Let p q) nts c = | |
Let p $ | |
Let | |
(wkNts There $ derivative | |
p | |
(first (map (both1 (wkE (\case | |
Here -> Here | |
There v -> There (There v))))) . nts) | |
c) $ | |
derivative | |
(wkNts There q) | |
(\case | |
Here -> error "impossible" | |
There Here -> | |
(nullable (map (both1 (wkE (\case | |
Here -> Here | |
There v -> There (There v)))) . fst . nts) p | |
,Here) | |
There (There v) -> fmap (There . There) (nts v)) | |
c | |
derivative0 :: CFG '[] '[] a -> Char -> CFG '[] '[] a | |
derivative0 g = derivative g (\case) | |
parse :: CFG '[] '[] a -> String -> [a] | |
parse s [] = nullable0 s | |
parse s (x:xs) = parse (simplify (derivative0 s x)) xs | |
digit :: CFG nts vs Int | |
digit = foldr Or Fail [Seq (Char (intToDigit x)) (Done (ENil x)) | x <- [0..9]] | |
dotsr :: Int -> CFG nts vs () | |
dotsr n = Fix (Or | |
(Seq (Char '.') (Var Here (ECons (There Here) (ENil (subtract 1))))) | |
(Guard (ECons Here (ENil (== 0)))) | |
) (ENil n) | |
dotsl :: Int -> CFG nts vs () | |
dotsl n = Fix (Or | |
(Seq (Guard (ECons Here (ENil (> 0)))) (Seq (Var Here (ECons (There Here) (ENil (subtract 1)))) (Char '.'))) | |
(Guard (ECons Here (ENil (== 0)))) | |
) (ENil n) | |
data X = X | Add X X deriving Show | |
type (<=) :: forall k. [k] -> [k] -> Type | |
type vs <= vs' = forall x. Var vs x -> Var vs' x | |
fix :: (forall nts' vs'. nts <= nts' -> Var nts' '(x,a) -> vs <= vs' -> Var vs' x -> CFG nts' vs' a) -> Exp vs x -> CFG nts vs a | |
fix f = Fix (f There Here There Here) | |
infixr 4 >>= | |
(>>=) :: CFG nts vs a -> (forall vs'. vs <= vs' -> Var vs' a -> CFG nts vs' b) -> CFG nts vs b | |
m >>= k = Seq m (k There Here) | |
return :: Var vs a -> CFG nts vs a | |
return v = Done (ECons v (ENil id)) | |
evar :: Var vs a -> Exp vs a | |
evar v = ECons v (ENil id) | |
infixr 4 >> | |
(>>) :: CFG nts vs a -> CFG nts vs b -> CFG nts vs b | |
m >> k = Seq m (wkVs There k) | |
infixr 3 <|> | |
(<|>) :: CFG nts vs a -> CFG nts vs a -> CFG nts vs a | |
(<|>) = Or | |
ex :: CFG nts vs X | |
ex = fix (\_ p _ b -> Char 'x' >> | |
Done (pure X) | |
<|> Guard (evar b) >> | |
Var p (pure False) >>= \_ x -> | |
Char '+' >> | |
Var p (pure True) >>= \e y -> | |
Done (Add <$> evar (e x) <*> evar y)) | |
(pure True) | |
-- main :: IO () | |
-- main = defaultMain $ | |
-- [ bench (show k) $ nf (\n -> parse (dotsr n) (replicate n '.')) k | |
-- | k <- [10,20..80] | |
-- ] | |
-- main = do | |
-- putStrLn "Start" | |
-- mapM_ print =<< fits (mkFitConfig (\n -> parse (dotsl (fromIntegral n)) (replicate (fromIntegral n) '.')) (10, 100)) |
Perhaps this representation is a bit easier to read:
x =
Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([2, 0]))
)
([])
x =
Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Fix
( Or
(Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (1) ([]); Done ([2, 0]))
)
([])
)
x =
Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (1) ([]); Done ([2, 0]))
)
([])
)
x =
Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([2, 0]))
)
([0])
)
( Fix
( Or
(Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (1) ([]); Done ([0, 2]))
)
([0])
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([2, 0]))
)
([])
)
)
x =
Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([2, 0]))
)
([0])
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (1) ([]); Done ([0, 2]))
)
([0])
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([2, 0]))
)
([])
)
)
x =
Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([2, 0]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Fix
( Or
(Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (1) ([]); Done ([2, 0]))
)
([0])
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([0, 2]))
)
([0])
)
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([2, 0]))
)
([])
)
)
x =
Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([2, 0]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (1) ([]); Done ([2, 0]))
)
([0])
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([0, 2]))
)
([0])
)
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([2, 0]))
)
([])
)
)
x =
Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([2, 0]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([2, 0]))
)
([0])
)
( Fix
( Or
(Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (1) ([]); Done ([0, 2]))
)
([0])
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([2, 0]))
)
([0])
)
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([0, 2]))
)
([0])
)
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([2, 0]))
)
([])
)
)
x =
Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([2, 0]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([2, 0]))
)
([0])
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (1) ([]); Done ([0, 2]))
)
([0])
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([2, 0]))
)
([0])
)
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([0, 2]))
)
([0])
)
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([2, 0]))
)
([])
)
)
x =
Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([2, 0]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([2, 0]))
)
([0])
)
( Let
( Let
( Fix
( Or
(do Char 'x'; Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (0) ([]); Done ([0, 2]))
)
([0])
)
( Fix
( Or
(Done ([]))
(do Guard ([0]); Var (0) ([]); Char '+'; Var (1) ([]); Done ([2, 0]))
)
([0])
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([0, 2]))
)
([0])
)
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([2, 0]))
)
([0])
)
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([0, 2]))
)
([0])
)
)
)
( Fix
( do
Guard ([0])
Or
(do Var (1) ([]); Done ([0]))
(do Var (0) ([]); Char '+'; Var (2) ([]); Done ([2, 0]))
)
([])
)
)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
These are the pretty printed steps of parsing the
ex
grammar on the string "x+x+...":