Separate out Stat from Term

This commit is contained in:
Joscha 2020-12-13 23:23:59 +00:00
parent 90669d01f2
commit d90f2c6a2c
5 changed files with 100 additions and 95 deletions

View file

@ -12,7 +12,7 @@ import Propa.Prolog.Parse
import Propa.Prolog.Unify import Propa.Prolog.Unify
parseAndRun :: T.Text -> T.Text -> IO () parseAndRun :: T.Text -> T.Text -> IO ()
parseAndRun dbText termsText = T.putStrLn $ either id id $ do parseAndRun dbText statsText = T.putStrLn $ either id id $ do
db <- parseDb "<input>" dbText db <- parseDb "<input>" dbText
terms <- parseTerms "<input>" termsText stats <- parseStats "<input>" statsText
pure $ T.intercalate "\n" $ map displayResult $ run db terms pure $ T.intercalate "\n" $ map displayResult $ run db stats

View file

@ -28,33 +28,33 @@ displayName name
, ("\t", "\\t") , ("\t", "\\t")
] ]
displayStat :: T.Text -> [Term T.Text] -> T.Text displayStat :: Stat T.Text -> T.Text
displayStat name [] = displayName name displayStat (Stat "[|]" [a, b]) = "[" <> displayTerm a <> displayList b
displayStat name args displayStat (Stat name []) = displayName name
displayStat (Stat name args)
= displayName name = displayName name
<> "(" <> "("
<> T.intercalate ", " (map displayTerm args) <> T.intercalate ", " (map displayTerm args)
<> ")" <> ")"
displayList :: Term T.Text -> T.Text displayList :: Term T.Text -> T.Text
displayList (Stat "[|]" [a, b]) = "," <> displayTerm a <> displayList b displayList (TStat (Stat "[|]" [a, b])) = "," <> displayTerm a <> displayList b
displayList (Stat "[]" []) = "]" displayList (TStat (Stat "[]" [])) = "]"
displayList t = "|" <> displayTerm t <> "]" displayList t = "|" <> displayTerm t <> "]"
displayTerm :: Term T.Text -> T.Text displayTerm :: Term T.Text -> T.Text
displayTerm (Var v) = v displayTerm (TVar v) = v
displayTerm (Stat "[|]" [a, b]) = "[" <> displayTerm a <> displayList b displayTerm (TStat s) = displayStat s
displayTerm (Stat name args) = displayStat name args
displayTerms :: [Term T.Text] -> T.Text displayTerms :: [Term T.Text] -> T.Text
displayTerms terms = T.intercalate ",\n" (map displayTerm terms) <> "." displayTerms terms = T.intercalate ",\n" (map displayTerm terms) <> "."
displayDef :: Def T.Text -> T.Text displayDef :: Def T.Text -> T.Text
displayDef (Def name args []) = displayStat name args <> "." displayDef (Def stat []) = displayStat stat <> "."
displayDef (Def name args terms) displayDef (Def stat stats)
= displayStat name args = displayStat stat
<> " :-\n" <> " :-\n"
<> T.intercalate ",\n" (map (\t -> " " <> displayTerm t) terms) <> T.intercalate ",\n" (map (\t -> " " <> displayStat t) stats)
<> "." <> "."
displayDefs :: [Def T.Text] -> T.Text displayDefs :: [Def T.Text] -> T.Text
@ -64,5 +64,5 @@ displayResult :: Map.Map T.Text (Term T.Text) -> T.Text
displayResult displayResult
= T.intercalate "\n" = T.intercalate "\n"
. map (\(k, v) -> k <> " = " <> displayTerm v) . map (\(k, v) -> k <> " = " <> displayTerm v)
. filter (\(k, v) -> v /= Var k) . filter (\(k, v) -> v /= TVar k)
. Map.assocs . Map.assocs

View file

@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module Propa.Prolog.Parse module Propa.Prolog.Parse
( parseTerms ( parseStats
, parseDb , parseDb
) where ) where
@ -53,23 +53,26 @@ pCons = brackets $ do
elems <- pTerm `sepBy1` symbol "," elems <- pTerm `sepBy1` symbol ","
void $ symbol "|" void $ symbol "|"
rest <- pTerm rest <- pTerm
pure $ foldr (\a b -> Stat "[|]" [a, b]) rest elems pure $ foldr (\a b -> TStat $ Stat "[|]" [a, b]) rest elems
pList :: Parser (Term T.Text) pList :: Parser (Term T.Text)
pList = do pList = do
elems <- brackets $ pTerm `sepBy` symbol "," elems <- brackets $ pTerm `sepBy` symbol ","
pure $ foldr (\a b -> Stat "[|]" [a, b]) (Stat "[]" []) elems pure $ foldr (\a b -> TStat $ Stat "[|]" [a, b]) (TStat $ Stat "[]" []) elems
pStat :: Parser (T.Text, [Term T.Text]) pStat :: Parser (Stat T.Text)
pStat = do pStat = do
name <- pName name <- pName
terms <- parens (pTerm `sepBy1` symbol ",") <|> pure [] terms <- parens (pTerm `sepBy1` symbol ",") <|> pure []
pure (name, terms) pure $ Stat name terms
pStats :: Parser [Stat T.Text]
pStats = (pStat `sepBy1` symbol ",") <* symbol "."
pTerm :: Parser (Term T.Text) pTerm :: Parser (Term T.Text)
pTerm pTerm
= (Var <$> pVarName) = (TVar <$> pVarName)
<|> (uncurry Stat <$> pStat) <|> (TStat <$> pStat)
<|> try pCons <|> try pCons
<|> pList <|> pList
<|> parens pExpr <|> parens pExpr
@ -79,18 +82,14 @@ pExpr = makeExprParser pTerm
[ [ binary "=" ] [ [ binary "=" ]
] ]
where where
binary name = InfixL $ (\a b -> Stat name [a, b]) <$ symbol name binary name = InfixL $ (\a b -> TStat $ Stat name [a, b]) <$ symbol name
pTerms :: Parser [Term T.Text]
pTerms = (pExpr `sepBy1` symbol ",") <* symbol "."
pDef :: Parser (Def T.Text) pDef :: Parser (Def T.Text)
pDef = do pDef = do
name <- pName stat <- pStat
args <- parens (pExpr `sepBy1` symbol ",") <|> pure [] stats <- (symbol ":-" *> (pStat `sepBy1` symbol ",")) <|> pure []
terms <- (symbol ":-" *> (pExpr `sepBy1` symbol ",")) <|> pure []
void $ symbol "." void $ symbol "."
pure $ Def name args terms pure $ Def stat stats
pDefs :: Parser [Def T.Text] pDefs :: Parser [Def T.Text]
pDefs = many pDef pDefs = many pDef
@ -102,8 +101,8 @@ parseHelper p path input
= first (T.pack . errorBundlePretty) = first (T.pack . errorBundlePretty)
$ parse (space *> p <* eof) path input $ parse (space *> p <* eof) path input
parseTerms :: FilePath -> T.Text -> Either T.Text [Term T.Text] parseStats :: FilePath -> T.Text -> Either T.Text [Stat T.Text]
parseTerms = parseHelper pTerms parseStats = parseHelper pStats
parseDb :: FilePath -> T.Text -> Either T.Text (Db T.Text) parseDb :: FilePath -> T.Text -> Either T.Text (Db T.Text)
parseDb = parseHelper pDefs parseDb = parseHelper pDefs

View file

@ -1,41 +1,51 @@
module Propa.Prolog.Types module Propa.Prolog.Types
( Term(..) ( Stat(..)
, Term(..)
, Def(..) , Def(..)
, Db , Db
) where ) where
import qualified Data.Text as T import qualified Data.Text as T
data Stat a = Stat T.Text [Term a]
deriving (Show, Eq)
instance Functor Stat where
fmap f (Stat name terms) = Stat name $ fmap (fmap f) terms
instance Foldable Stat where
foldMap f (Stat _ terms) = foldMap (foldMap f) terms
instance Traversable Stat where
traverse f (Stat name terms) = Stat name <$> traverse (traverse f) terms
data Term a data Term a
= Var a = TVar a
| Stat T.Text [Term a] | TStat (Stat a)
deriving (Show, Eq) deriving (Show, Eq)
instance Functor Term where instance Functor Term where
fmap f (Var a) = Var $ f a fmap f (TVar a) = TVar $ f a
fmap f (Stat name args) = Stat name $ fmap (fmap f) args fmap f (TStat s) = TStat $ fmap f s
instance Foldable Term where instance Foldable Term where
foldMap f (Var a) = f a foldMap f (TVar a) = f a
foldMap f (Stat _ args) = foldMap (foldMap f) args foldMap f (TStat s) = foldMap f s
instance Traversable Term where instance Traversable Term where
traverse f (Var a) = Var <$> f a traverse f (TVar a) = TVar <$> f a
traverse f (Stat name args) = Stat name <$> traverse (traverse f) args traverse f (TStat s) = TStat <$> traverse f s
data Def a = Def T.Text [Term a] [Term a] data Def a = Def (Stat a) [Stat a]
deriving (Show) deriving (Show)
instance Functor Def where instance Functor Def where
fmap f (Def dName dArgs dTerms) = Def dName (fmap f <$> dArgs) (fmap f <$> dTerms) fmap f (Def stat stats) = Def (fmap f stat) (fmap f <$> stats)
instance Foldable Def where instance Foldable Def where
foldMap f (Def _ dArgs dTerms) = foldMap (foldMap f) dArgs <> foldMap (foldMap f) dTerms foldMap f (Def stat stats) = foldMap f stat <> foldMap (foldMap f) stats
instance Traversable Def where instance Traversable Def where
traverse f (Def dName dArgs dTerms) traverse f (Def stat stats) = Def <$> traverse f stat <*> traverse (traverse f) stats
= Def dName
<$> traverse (traverse f) dArgs
<*> traverse (traverse f) dTerms
type Db a = [Def a] type Db a = [Def a]

View file

@ -2,7 +2,6 @@
module Propa.Prolog.Unify module Propa.Prolog.Unify
( run ( run
, runOne
) where ) where
import Control.Monad import Control.Monad
@ -36,30 +35,30 @@ data Context = Context
{ cDb :: Db T.Text { cDb :: Db T.Text
, cVarIdx :: Int , cVarIdx :: Int
, cVars :: Map.Map Int Int , cVars :: Map.Map Int Int
, cTerms :: Map.Map Int (T.Text, [Term Int]) , cStats :: Map.Map Int (Stat Int)
} deriving (Show) } deriving (Show)
newContext :: [Def T.Text] -> Context newContext :: [Def T.Text] -> Context
newContext db = Context db 0 Map.empty Map.empty newContext db = Context db 0 Map.empty Map.empty
learnVar :: Int -> Int -> UniM () bindVar :: Int -> Int -> UniM ()
learnVar k v = modify $ \c -> c{cVars = Map.insert k v $ cVars c} bindVar k v = modify $ \c -> c{cVars = Map.insert k v $ cVars c}
learnTerm :: Int -> T.Text -> [Term Int] -> UniM () bindStat :: Int -> Stat Int -> UniM ()
learnTerm k name args = modify $ \c -> c{cTerms = Map.insert k (name, args) $ cTerms c} bindStat k s = modify $ \c -> c{cStats = Map.insert k s $ cStats c}
-- | Look up a variable, first repeatedly in the var map and then the term map. -- | Look up a variable, first repeatedly in the var map and then the term map.
-- Returns statements unchanged. -- Returns statements unchanged.
-- --
-- If this returns a variable, then that variable is not bound. -- If this returns a variable, then that variable is not bound.
lookupVar :: Term Int -> UniM (Term Int) lookupVar :: Term Int -> UniM (Term Int)
lookupVar (Var v) = do lookupVar (TVar v) = do
c <- get c <- get
let lastV = follow (cVars c) v let lastV = follow (cVars c) v
pure $ case cTerms c Map.!? lastV of pure $ case cStats c Map.!? lastV of
Nothing -> Var lastV Nothing -> TVar lastV
Just (name, args) -> Stat name args Just s -> TStat s
lookupVar t@(Stat _ _) = pure t lookupVar t@(TStat _) = pure t
-- | A simple state monad transformer over the list monad for easy backtracking. -- | A simple state monad transformer over the list monad for easy backtracking.
-- Needs to be changed when implementing cuts. -- Needs to be changed when implementing cuts.
@ -81,33 +80,34 @@ understand a = do
vmap <- varMap a vmap <- varMap a
pure (fmap (vmap Map.!) a, vmap) pure (fmap (vmap Map.!) a, vmap)
satisfy :: Term Int -> UniM () satisfy :: Stat Int -> UniM ()
satisfy (Var _) = pure () satisfy s = do
satisfy (Stat name args) = do
c <- get c <- get
(Def dName dArgs dTerms, _) <- understand =<< lift (cDb c) (Def dStat dStats, _) <- understand =<< lift (cDb c)
lift $ guard $ name == dName -- Not sure if 'lift' is really necessary unifyStat s dStat
unifyTerms args dArgs satisfyStats dStats
satisfyTerms dTerms
satisfyTerms :: [Term Int] -> UniM () satisfyStats :: [Stat Int] -> UniM ()
satisfyTerms = traverse_ satisfy satisfyStats = traverse_ satisfy
unifyStat :: Stat Int -> Stat Int -> UniM ()
unifyStat (Stat name1 args1) (Stat name2 args2) = do
guard $ name1 == name2
unifyTerms args1 args2
unify :: Term Int -> Term Int -> UniM () unify :: Term Int -> Term Int -> UniM ()
unify t1 t2 = do unify t1 t2 = do
t1' <- lookupVar t1 t1' <- lookupVar t1
t2' <- lookupVar t2 t2' <- lookupVar t2
case (t1', t2') of case (t1', t2') of
(Stat name1 args1, Stat name2 args2) -> do (TStat s1, TStat s2) -> unifyStat s1 s2
lift $ guard $ name1 == name2 (TVar v, TStat s) -> bindStat v s
unifyTerms args1 args2 (TStat s, TVar v) -> bindStat v s
(Var v1, Stat name2 args2) -> learnTerm v1 name2 args2 (TVar v1, TVar v2) -> bindVar v1 v2 -- The order shouldn't really matter
(Stat name1 args1, Var v2) -> learnTerm v2 name1 args1
(Var v1, Var v2) -> learnVar v1 v2 -- The order shouldn't really matter
unifyTerms :: [Term Int] -> [Term Int] -> UniM () unifyTerms :: [Term Int] -> [Term Int] -> UniM ()
unifyTerms t1 t2 = do unifyTerms t1 t2 = do
lift $ guard $ length t1 == length t2 guard $ length t1 == length t2
sequenceA_ $ zipWith unify t1 t2 sequenceA_ $ zipWith unify t1 t2
-- Figuring out how to display the result of the unification -- Figuring out how to display the result of the unification
@ -136,30 +136,26 @@ resolveVars :: Term Int -> UniM (Term Int)
resolveVars t = do resolveVars t = do
t2 <- lookupVar t t2 <- lookupVar t
case t2 of case t2 of
(Var v) -> pure $ Var v (TVar v) -> pure $ TVar v
(Stat name args) -> do (TStat (Stat name args)) -> TStat . Stat name <$> traverse resolveVars args
args2 <- traverse resolveVars args
pure $ Stat name args2
-- | Helper type so I can resolve variables in multiple terms simultaneously. -- | Helper type so I can resolve variables in multiple statements
newtype Terms a = Terms { unTerms :: [Term a] } -- simultaneously.
newtype Stats a = Stats { unStats :: [Stat a] }
instance Functor Terms where instance Functor Stats where
fmap f (Terms ts) = Terms $ fmap (fmap f) ts fmap f (Stats ts) = Stats $ fmap (fmap f) ts
instance Foldable Terms where instance Foldable Stats where
foldMap f (Terms ts) = foldMap (foldMap f) ts foldMap f (Stats ts) = foldMap (foldMap f) ts
run :: Db T.Text -> [Term T.Text] -> [Map.Map T.Text (Term T.Text)] run :: Db T.Text -> [Stat T.Text] -> [Map.Map T.Text (Term T.Text)]
run db terms = map fst $ runStateT helper $ newContext db run db stats = map fst $ runStateT helper $ newContext db
where where
helper = do helper = do
(terms2, vmap) <- understand $ Terms terms (stats2, vmap) <- understand $ Stats stats
satisfyTerms $ unTerms terms2 satisfyStats $ unStats stats2
tmap <- traverse (resolveVars . Var) vmap tmap <- traverse (resolveVars . TVar) vmap
c <- get c <- get
let naming = findVarNaming vmap (cVars c) $ Map.elems tmap let naming = findVarNaming vmap (cVars c) $ Map.elems tmap
pure $ fmap (naming Map.!) <$> tmap pure $ fmap (naming Map.!) <$> tmap
runOne :: Db T.Text -> Term T.Text -> [Map.Map T.Text (Term T.Text)]
runOne db term = run db [term]