{-# LANGUAGE ParallelListComp #-}
module SMR.Core.Exp.Train where
import SMR.Core.Exp.Base
import Data.Maybe
trainCons :: Car s p -> [Car s p] -> [Car s p]
trainCons c1 cs2
| carIsEmpty c1 = cs2
| otherwise
= case cs2 of
[]
-> c1 : []
c2 : cs2'
| CUps ups1 <- c1
, CUps ups2 <- c2
-> CUps (upsCombine ups1 ups2) : cs2'
| otherwise
-> c1 : cs2
trainAppend :: [Car s p] -> [Car s p] -> [Car s p]
trainAppend ccA ccB
= case ccA of
[] -> ccB
cA : csA -> trainAppend' cA csA ccB
where
trainAppend' c1 cs1 cc2
= case cs1 of
[]
-> trainCons c1 cc2
c1' : cs1'
| CUps ups1 <- c1
, CUps ups1' <- c1'
-> trainAppend' (CUps (upsCombine ups1 ups1')) cs1' cc2
| otherwise
-> c1 : (trainAppend' c1' cs1' cc2)
trainBump :: [Name] -> [Car s p] -> [Car s p]
trainBump ns cs
= case cs of
[] -> []
CSim snv : cs'
-> trainCons (CSim (snvBump ns snv)) $ trainBump ns cs'
CRec snv : cs'
-> trainCons (CRec (snvBump ns snv)) $ trainBump ns cs'
CUps ups : cs'
-> trainCons (CUps (upsBump ns ups)) $ trainBump ns cs'
trainApply :: [Car s p] -> Exp s p -> Exp s p
trainApply cs1 xx
| [] <- cs1
= xx
| otherwise
= case xx of
XRef (RMac _) -> xx
XRef (RSym _) -> xx
XRef (RPrm _) -> xx
XRef (RNom ix) -> trainApplyNom cs1 ix
XVar name depth -> trainApplyVar cs1 name depth
XSub cs2 x2 -> trainApply (trainAppend cs2 cs1) x2
_ -> XSub cs1 xx
trainApplyVar :: [Car s p] -> Name -> Integer -> Exp s p
trainApplyVar cs name depth
= case cs of
[] -> XVar name depth
CSim snv : cs' -> trainApply cs' (snvApplyVar False snv name depth)
CRec snv : cs' -> trainApply cs' (snvApplyVar True snv name depth)
CUps ups : cs' -> trainApply cs' (upsApplyVar ups name depth)
trainApplyNom :: [Car s p] -> Integer -> Exp s p
trainApplyNom cs ix
= case cs of
[] -> XRef (RNom ix)
CSim snv : cs' -> trainApply cs' (snvApplyNom False snv ix)
CRec snv : cs' -> trainApply cs' (snvApplyNom True snv ix)
CUps _ups : cs' -> trainApply cs' (XRef (RNom ix))
carIsEmpty :: Car s p -> Bool
carIsEmpty c
= case c of
CSim snv -> snvIsEmpty snv
CRec snv -> snvIsEmpty snv
CUps ups -> upsIsEmpty ups
snvOfNamesArgs :: [Name] -> [Exp s p] -> Snv s p
snvOfNamesArgs ns xs
= SSnv [BindVar n 0 x | n <- ns | x <- xs]
snvIsEmpty :: Snv s p -> Bool
snvIsEmpty (SSnv bs)
= case bs of
[] -> True
_ -> False
snvBump :: [Name] -> Snv s p -> Snv s p
snvBump ns (SSnv ts)
= SSnv $ mapMaybe (snvBump1 ns) ts
where
snvBump1 names (BindVar name depth x)
= Just $ BindVar name
(depth + (if elem name names then 1 else 0))
(upsApply (UUps (map (\name' -> ((name', 0), 1)) names)) x)
snvBump1 names (BindNom ix x)
= Just $ BindNom ix
(upsApply (UUps (map (\name' -> ((name', 0), 1)) names)) x)
snvApply :: Bool -> Snv s p -> Exp s p -> Exp s p
snvApply isRec snv@(SSnv bs) xx
= case bs of
[] -> xx
_ | isRec -> trainApply (CRec snv : []) xx
_ -> trainApply (CSim snv : []) xx
snvApplyVar :: Bool -> Snv s p -> Name -> Integer -> Exp s p
snvApplyVar isRec snv@(SSnv bs) name depth
= case bs of
[]
-> XVar name depth
BindVar name' depth' x' : bs'
| name == name'
, depth == depth'
-> if isRec then XSub (CRec snv : []) x'
else x'
| name == name'
, depth > depth'
-> XVar name (depth - 1)
| otherwise
-> snvApplyVar isRec (SSnv bs') name depth
BindNom{} : bs'
-> snvApplyVar isRec (SSnv bs') name depth
snvApplyNom :: Bool -> Snv s p -> Integer -> Exp s p
snvApplyNom isRec snv@(SSnv bs) ix
= case bs of
[]
-> XRef (RNom ix)
BindVar{} : bs'
-> snvApplyNom isRec (SSnv bs') ix
BindNom ix' x' : bs'
| ix == ix'
-> if isRec then XSub (CRec snv : []) x'
else x'
| otherwise
-> snvApplyNom isRec (SSnv bs') ix
upsIsEmpty :: Ups -> Bool
upsIsEmpty (UUps bs)
= case bs of
[] -> True
_ -> False
upsApply :: Ups -> Exp s p -> Exp s p
upsApply ups@(UUps us) xx
= case us of
[] -> xx
_ -> trainApply ((CUps ups) : []) xx
upsApplyVar :: Ups -> Name -> Integer -> Exp s n
upsApplyVar (UUps bs) name ix
= case bs of
[]
-> XVar name ix
((name', depth'), inc') : bs'
| name == name'
, depth' <= ix
-> upsApplyVar (UUps bs') name (ix + inc')
| otherwise
-> upsApplyVar (UUps bs') name ix
upsBump :: [Name] -> Ups -> Ups
upsBump ns0 (UUps bs)
= UUps $ mapMaybe (upsBump1 ns0) bs
where
upsBump1 ns l
| ((n, d), inc) <- l
, elem n ns
= Just ((n, d + 1), inc)
| otherwise
= Just l
upsCombine :: Ups -> Ups -> Ups
upsCombine (UUps ts1) (UUps ts2)
= UUps (foldr upsCombineBump ts2 ts1)
upsCombineBump :: UpsBump -> [UpsBump] -> [UpsBump]
upsCombineBump b bs
| ((name, depth), inc) <- b
= case bs of
[]
-> [b]
b'@((name', depth'), inc') : bs'
| name == name'
, depth == depth'
-> ((name, depth'), inc + inc') : bs'
| otherwise
-> b' : (upsCombineBump b bs')