packages feed

NanoProlog 0.1.3 → 0.2

raw patch · 7 files changed

+249/−214 lines, 7 filesdep −NanoPrologPVP ok

version bump matches the API change (PVP)

Dependencies removed: NanoProlog

API changes (from Hackage documentation)

- Language.Prolog.NanoProlog.Lib: (:<-:) :: Term -> [Term] -> Rule
- Language.Prolog.NanoProlog.Lib: ApplyRules :: [(Rule, Result)] -> Result
- Language.Prolog.NanoProlog.Lib: Done :: Env -> Result
- Language.Prolog.NanoProlog.Lib: Fun :: LowerCase -> [Term] -> Term
- Language.Prolog.NanoProlog.Lib: Var :: UpperCase -> Term
- Language.Prolog.NanoProlog.Lib: class Subst t
- Language.Prolog.NanoProlog.Lib: class Taggable a
- Language.Prolog.NanoProlog.Lib: data Result
- Language.Prolog.NanoProlog.Lib: data Rule
- Language.Prolog.NanoProlog.Lib: data Term
- Language.Prolog.NanoProlog.Lib: emptyEnv :: Maybe (Map UpperCase t)
- Language.Prolog.NanoProlog.Lib: enumerateDepthFirst :: Proofs -> [String] -> Result -> [(Proofs, Env)]
- Language.Prolog.NanoProlog.Lib: instance Eq Rule
- Language.Prolog.NanoProlog.Lib: instance Eq Term
- Language.Prolog.NanoProlog.Lib: instance Ord Term
- Language.Prolog.NanoProlog.Lib: instance Show Rule
- Language.Prolog.NanoProlog.Lib: instance Show Term
- Language.Prolog.NanoProlog.Lib: instance Subst Rule
- Language.Prolog.NanoProlog.Lib: instance Subst Term
- Language.Prolog.NanoProlog.Lib: instance Subst a => Subst [a]
- Language.Prolog.NanoProlog.Lib: instance Taggable Rule
- Language.Prolog.NanoProlog.Lib: instance Taggable Term
- Language.Prolog.NanoProlog.Lib: instance Taggable a => Taggable [a]
- Language.Prolog.NanoProlog.Lib: pRule :: Parser Rule
- Language.Prolog.NanoProlog.Lib: pTerm, pFun :: Parser Term
- Language.Prolog.NanoProlog.Lib: pTerms :: Parser [Term]
- Language.Prolog.NanoProlog.Lib: show' :: Env -> String
- Language.Prolog.NanoProlog.Lib: solve :: [Rule] -> Maybe Env -> Int -> [Term] -> Result
- Language.Prolog.NanoProlog.Lib: startParse :: (ListLike s b, Show b) => P (Str b s LineColPos) a -> s -> (a, [Error LineColPos])
- Language.Prolog.NanoProlog.Lib: subst :: Subst t => Env -> t -> t
- Language.Prolog.NanoProlog.Lib: tag :: Taggable a => Int -> a -> a
- Language.Prolog.NanoProlog.Lib: type LowerCase = String
- Language.Prolog.NanoProlog.Lib: unify :: (Term, Term) -> Maybe Env -> Maybe Env
+ Language.Prolog.NanoProlog.Interpreter: loop :: [Rule] -> IO ()
+ Language.Prolog.NanoProlog.Interpreter: printSolutions :: Result -> IO ()
+ Language.Prolog.NanoProlog.Interpreter: run :: IO ()
+ Language.Prolog.NanoProlog.NanoProlog: (:<-:) :: Term -> [Term] -> Rule
+ Language.Prolog.NanoProlog.NanoProlog: ApplyRules :: [(Tag, Rule, Result)] -> Result
+ Language.Prolog.NanoProlog.NanoProlog: Done :: Env -> Result
+ Language.Prolog.NanoProlog.NanoProlog: Fun :: LowerCase -> [Term] -> Term
+ Language.Prolog.NanoProlog.NanoProlog: Var :: UpperCase -> Term
+ Language.Prolog.NanoProlog.NanoProlog: class Subst t
+ Language.Prolog.NanoProlog.NanoProlog: class Taggable a
+ Language.Prolog.NanoProlog.NanoProlog: data Result
+ Language.Prolog.NanoProlog.NanoProlog: data Rule
+ Language.Prolog.NanoProlog.NanoProlog: data Term
+ Language.Prolog.NanoProlog.NanoProlog: emptyEnv :: Maybe (Map UpperCase t)
+ Language.Prolog.NanoProlog.NanoProlog: enumerateDepthFirst :: Proofs -> Result -> [(Proofs, Env)]
+ Language.Prolog.NanoProlog.NanoProlog: instance Eq Rule
+ Language.Prolog.NanoProlog.NanoProlog: instance Eq Term
+ Language.Prolog.NanoProlog.NanoProlog: instance Ord Term
+ Language.Prolog.NanoProlog.NanoProlog: instance Show Rule
+ Language.Prolog.NanoProlog.NanoProlog: instance Show Term
+ Language.Prolog.NanoProlog.NanoProlog: instance Subst Rule
+ Language.Prolog.NanoProlog.NanoProlog: instance Subst Term
+ Language.Prolog.NanoProlog.NanoProlog: instance Subst a => Subst [a]
+ Language.Prolog.NanoProlog.NanoProlog: instance Taggable Rule
+ Language.Prolog.NanoProlog.NanoProlog: instance Taggable Term
+ Language.Prolog.NanoProlog.NanoProlog: instance Taggable a => Taggable [a]
+ Language.Prolog.NanoProlog.NanoProlog: pFun :: Parser Term
+ Language.Prolog.NanoProlog.NanoProlog: pRule :: Parser Rule
+ Language.Prolog.NanoProlog.NanoProlog: pTerm :: Parser Term
+ Language.Prolog.NanoProlog.NanoProlog: pTerms :: Parser [Term]
+ Language.Prolog.NanoProlog.NanoProlog: show' :: Env -> String
+ Language.Prolog.NanoProlog.NanoProlog: solve :: [Rule] -> Maybe Env -> [TaggedTerm] -> Result
+ Language.Prolog.NanoProlog.NanoProlog: startParse :: (ListLike s b, Show b) => P (Str b s LineColPos) a -> s -> (a, [Error LineColPos])
+ Language.Prolog.NanoProlog.NanoProlog: subst :: Subst t => Env -> t -> t
+ Language.Prolog.NanoProlog.NanoProlog: tag :: Taggable a => Tag -> a -> a
+ Language.Prolog.NanoProlog.NanoProlog: type LowerCase = String
+ Language.Prolog.NanoProlog.NanoProlog: unify :: (Term, Term) -> Maybe Env -> Maybe Env

Files

NanoProlog.cabal view
@@ -1,5 +1,5 @@ Name:                NanoProlog-Version:             0.1.3+Version:             0.2 Synopsis:            Very small  interpreter for a Prolog-like language Description:         This package was developed to demonstrate the ideas behind                      the Prolog language. It contains a very small interpreter@@ -9,24 +9,24 @@                      a tree showing which rules were applied in which order. License:             BSD3 license-file:        LICENSE-Author:              Doaitse Swierstra, Jurrien Stutterheim-Maintainer:          Jurrien Stutterheim+Author:              Doaitse Swierstra, Jurriën Stutterheim+Maintainer:          j.stutterheim@uu.nl Stability:           Experimental Category:            Language Build-type:          Simple-Cabal-version:       >= 1.8+Cabal-version:       >= 1.6+Extra-Source-Files:  README, royals.pro  Source-repository head   Type:       git   Location:   https://github.com/norm2782/NanoProlog.git  Executable nano-prolog-  Hs-source-dirs: src/Language/Prolog/NanoProlog-  Main-is: NanoProlog.hs+  Hs-source-dirs: src+  Main-is: Main.hs    Build-depends:     base >= 4 && < 5,-    NanoProlog >= 0.1.3,     uu-parsinglib >= 2.7.1  Library@@ -35,4 +35,7 @@                     ListLike == 3.1.*,                     containers == 0.4.*   Hs-Source-Dirs:   src-  Exposed-modules:  Language.Prolog.NanoProlog.Lib+  Exposed-modules:  Language.Prolog.NanoProlog.NanoProlog,+                    Language.Prolog.NanoProlog.Interpreter+  Extensions:       Rank2Types, FlexibleContexts, TypeSynonymInstances,+                    FlexibleInstances
+ README view
@@ -0,0 +1,1 @@+NanoProlog README goes here.
+ royals.pro view
@@ -0,0 +1,24 @@+ma(mien,juul).+ma(juul,bea).+ma(bea,alex).+ma(bea,cons).+oma(X,Z):-ma(X,Y),ouder(Y,Z).++append(nil,X,X).+append(cons(A,X), Y, cons(A,Z)):- append(X,Y,Z) .++pa(alex,ale).+pa(alex,ama).+pa(alex,ari).+ma(max,ale).+ma(max,ama).+ma(max,ari).++ouder(X,Y) :- pa(X,Y).+ouder(X,Y) :- ma(X,Y).++voor(X,Y) :- ouder(X,Y).+voor(X,Y) :- ouder(X,Z), voor(Z,Y).++plus(zero,X,X).+plus(succ(X), Y, succ(Z)) :- plus(X, Y,Z).
+ src/Language/Prolog/NanoProlog/Interpreter.hs view
@@ -0,0 +1,53 @@+module Language.Prolog.NanoProlog.Interpreter where++import            Language.Prolog.NanoProlog.NanoProlog+import            Text.ParserCombinators.UU+import            System.IO++-- * Running the Interpreter+-- ** The main interpreter+-- | The `main` program prompt for a file with Prolog rules and call the main+-- interpreter loop+run :: IO ()+run =  do  hSetBuffering stdin LineBuffering+           putStrLn "File with rules?"+           fn  <- getLine+           s   <- readFile fn+           let (rules, errors) = startParse (pList pRule) s+           if null errors  then  do  mapM_ print rules+                                     loop rules+                           else  do  putStrLn "No rules parsed"+                                     mapM_ print errors+                                     run++-- | `loop` ask for a goal, and enuartes all solutions found, each preceded by+-- a trace conatining the rules applied in a tree-like fashion+loop :: [Rule] -> IO ()+loop rules = do  putStrLn "goal? "+                 s <- getLine+                 unless (s == "quit") $+                   do  let (goal, errors) = startParse pFun s+                       if null errors+                         then  printSolutions (solve rules emptyEnv [("0",goal)])+                         else  do  putStrLn "Some goals were expected:"+                                   mapM_ print errors+                       loop rules++-- | `printSolutions` takes the result of a treewalk, which constructs+-- all the proofs, and pairs them with their final+-- substitutions. Alternative approaches in printing are to print the+-- raw proofs, i.e. without applying the final substitution (remove+-- the @subst env@ ). This nicely shows how the intermediate variables+-- come into life. By including the test on the length the facts+-- directly stemming from the data base are not printed. This makes+-- the proofs much shorter, but a bit less complete.+printSolutions ::  Result -> IO ()+printSolutions result = sequence_+  [  do  sequence_  [  putStrLn (prefix ++ " " ++ show (subst env pr))+                    |  (prefix, pr@(p :<-: pp)) <- reverse proof+--                  ,  length pp >0+                    ]+         putStr "substitution: "+         putStrLn (show' env)+         void getLine+  |  (proof, env) <- enumerateDepthFirst [] result ]
− src/Language/Prolog/NanoProlog/Lib.hs
@@ -1,158 +0,0 @@-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE FlexibleInstances #-}--module Language.Prolog.NanoProlog.Lib (-     LowerCase-  ,  Result(..)-  ,  Rule((:<-:))-  ,  Subst(..)-  ,  Taggable(..)-  ,  Term(..)-  ,  emptyEnv-  ,  enumerateDepthFirst-  ,  pFun-  ,  pRule-  ,  pTerm-  ,  pTerms-  ,  show'-  ,  solve-  ,  startParse-  ,  unify-  ) where--import            Data.ListLike.Base (ListLike)-import            Data.List (intercalate)-import            Data.Map (Map)-import qualified  Data.Map as M-import            Text.ParserCombinators.UU-import            Text.ParserCombinators.UU.BasicInstances-import            Text.ParserCombinators.UU.Utils---- * Types-type UpperCase  = String-type LowerCase  = String--data Term  =  Var UpperCase-           |  Fun LowerCase [Term]-           deriving (Eq, Ord)--data Rule  =  Term :<-: [Term]-           deriving Eq--class Taggable a where-  tag :: Int -> a -> a--instance Taggable Term where-  tag n (Var  x)     = Var  (x ++ show n)-  tag n (Fun  x xs)  = Fun  x (tag n xs)--instance Taggable Rule where-  tag n (c :<-: cs) = tag n c :<-: tag n cs--instance Taggable a => Taggable [a] where-  tag n = map (tag n)--type Env = Map UpperCase Term--emptyEnv :: Maybe (Map UpperCase t)-emptyEnv = Just M.empty---- * The Prolog machinery-data Result  =  Done Env-             |  ApplyRules [(Rule, Result)]--type Proofs = [(String, Rule)]--class Subst t where-  subst :: Env -> t -> t--instance Subst a => Subst [a] where-  subst e = map (subst e)--instance Subst Term where-  subst env (Var x)     = maybe (Var x) (subst env) (M.lookup x env)-  subst env (Fun x cs)  = Fun x (subst env cs)--instance Subst Rule where-  subst env (c :<-: cs) = subst env c :<-: subst env cs--unify :: (Term, Term) -> Maybe Env-> Maybe Env-unify _       Nothing       = Nothing-unify (t, u)  env@(Just m)  = uni (subst m t) (subst m u)-  where  uni  (Var x)  y        = Just (M.insert x  y  m)-         uni  x        (Var y)  = Just (M.insert y  x  m)-         uni  (Fun x xs) (Fun y ys)-           |  x == y && length xs == length ys  = foldr unify env (zip xs ys)-           |  otherwise                         = Nothing--solve :: [Rule] -> Maybe Env -> Int -> [Term] -> Result-solve _      Nothing   _  _       = ApplyRules []-solve _      (Just e)  _  []      = Done e-solve rules  e         n  (t:ts)  = ApplyRules-  [  (rule, solve rules nextenv (n+1) (cs ++ ts))-  |  rule@(c :<-: cs)  <- tag n rules-  ,  nextenv@(Just _)  <- [unify (t, c) e]-  ]---- ** Printing the solutions | `enumerateBreadthFirst` performs a--- depth-first walk over the `Result` tree, while accumulating the--- rules that were applied on the path which was traversed from the--- root to the current node. At a successful leaf this contains the--- full proof.-enumerateDepthFirst :: Proofs -> [String] -> Result -> [(Proofs, Env)]-enumerateDepthFirst proofs _ (Done env) = [(proofs, env)]-enumerateDepthFirst proofs (pr:prefixes) (ApplyRules bs) =-  [ s  |  (rule@(c :<-: cs), subTree) <- bs-       ,  let extraPrefixes = take (length cs) (map (\i -> pr ++ "." ++ show i) [1 ..])-       ,  s <- enumerateDepthFirst ((pr, rule):proofs) (extraPrefixes ++ prefixes) subTree-  ]--{---- | `enumerateBreadthFirst` is still undefined, and is left as an--- exercise to the JCU students-enumerateBreadthFirst :: Proofs -> [String] -> Result -> [(Proofs, Env)]--}---- | `printEnv` prints a single solution, showing only the variables--- that were introduced in the original goal-show' :: Env -> String-show' env = intercalate ", " . filter (not.null) . map showBdg $ M.assocs env-  where  showBdg (x, t)  | isGlobVar x =  x ++ " <- " ++ showTerm t-                         | otherwise = ""-         showTerm t@(Var _)  = showTerm (subst env t)-         showTerm (Fun f []) = f-         showTerm (Fun f ts) = f ++ "(" ++ intercalate ", " (map showTerm ts) ++ ")"-         isGlobVar x = head x `elem` ['A'..'Z'] && last x `notElem` ['0'..'9']--instance Show Term where-  show (Var  i)       = i-  show (Fun  i []  )  = i-  show (Fun  i ts  )  = i ++ "(" ++ showCommas ts ++ ")"--instance Show Rule where-  show (t :<-: []  ) = show t ++ "."-  show (t :<-: ts  ) = show t ++ ":-" ++ showCommas ts ++ "."--showCommas :: Show a => [a] -> String-showCommas l = intercalate ", " (map show l)---- ** Parsing Rules and Terms-startParse :: (ListLike s b, Show b)  => P (Str b s LineColPos) a -> s-                                      -> (a, [Error LineColPos])-startParse p inp  =  parse ((,) <$> p <*> pEnd)-                  $  createStr (LineColPos 0 0 0) inp--pTerm, pVar, pFun :: Parser Term-pTerm  = pVar  <|>  pFun-pVar   = Var   <$>  lexeme (pList1 pUpper)-pFun   = Fun   <$>  pLowerCase <*> (pParens pTerms `opt` [])-  where  pLowerCase :: Parser String-         pLowerCase = (:) <$> pLower <*> lexeme (pList (pLetter <|> pDigit))--pRule :: Parser Rule-pRule = (:<-:) <$> pFun <*> (pSymbol ":-" *> pTerms `opt` []) <* pDot--pTerms :: Parser [Term]-pTerms = pListSep pComma pTerm
src/Language/Prolog/NanoProlog/NanoProlog.hs view
@@ -3,56 +3,158 @@ {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} -module Main where+module Language.Prolog.NanoProlog.NanoProlog (+     LowerCase+  ,  Result(..)+  ,  Rule((:<-:))+  ,  Subst(..)+  ,  Taggable(..)+  ,  Term(..)+  ,  emptyEnv+  ,  enumerateDepthFirst+  ,  pFun+  ,  pRule+  ,  pTerm+  ,  pTerms+  ,  show'+  ,  solve+  ,  startParse+  ,  unify+  ) where -import            Language.Prolog.NanoProlog.Lib+import            Data.ListLike.Base (ListLike)+import            Data.List (intercalate)+import            Data.Map (Map)+import qualified  Data.Map as M import            Text.ParserCombinators.UU-import            System.IO+import            Text.ParserCombinators.UU.BasicInstances+import            Text.ParserCombinators.UU.Utils --- * Running the Interpreter--- ** The main interpreter--- | The `main` program prompt for a file with Prolog rules and call the main--- interpreter loop-main :: IO ()-main = do  hSetBuffering stdin LineBuffering-           putStr "File with rules? "-           fn  <- getLine-           s   <- readFile fn-           let (rules, errors) = startParse (pList pRule)  s-           if null errors  then  do  mapM_ print rules-                                     loop rules-                           else  do  putStrLn "No rules parsed"-                                     mapM_ print errors-                                     main+-- * Types+type UpperCase  = String+type LowerCase  = String+type Tag        = String --- | `loop` ask for a goal, and enuartes all solutions found, each preceded by--- a trace conatining the rules applied in a tree-like fashion-loop :: [Rule] -> IO ()-loop rules = do  putStr "goal? "-                 s <- getLine-                 unless (s == "quit") $-                   do  let (goal, errors) = startParse pFun s-                       if null errors-                         then  printSolutions (solve rules emptyEnv 0 [goal])-                         else  do  putStrLn "Some goals were expected:"-                                   mapM_ print errors-                       loop rules+data Term  =  Var UpperCase+           |  Fun LowerCase [Term]+           deriving (Eq, Ord) --- | `printSolutions` takes the result of a treewalk, which constructs--- all the proofs, and pairs them with their final--- substitutions. Alternative approaches in printing are to print the--- raw proofs, i.e. without applying the final substitution (remove--- the @subst env@ ). This nicely shows how the intermediate variables--- come into life. By including the test on the length the facts--- directly stemming from the data base are not printed. This makes--- the proofs much shorter, but a bit less complete.-printSolutions ::  Result -> IO ()-printSolutions result = sequence_-  [  do  sequence_  [  putStrLn (prefix ++ " " ++ show (subst env pr))-                    |  (prefix, pr@(p :<-: pp)) <- reverse proof---                  ,  length pp >0-                    ]-         putStr "substitution: "-         putStrLn (show' env)-         void getLine-  |  (proof, env) <- enumerateDepthFirst [] ["0"] result ]+type TaggedTerm = (Tag, Term)++data Rule  =  Term :<-: [Term]+           deriving Eq++class Taggable a where+  tag :: Tag -> a -> a++instance Taggable Term where+  tag n (Var  x)     = Var  (x ++ n)+  tag n (Fun  x xs)  = Fun  x (tag n xs)++instance Taggable Rule where+  tag n (c :<-: cs) = tag n c :<-: tag n cs++instance Taggable a => Taggable [a] where+  tag n = map (tag n)++type Env = Map UpperCase Term++emptyEnv :: Maybe (Map UpperCase t)+emptyEnv = Just M.empty++-- * The Prolog machinery+data Result  =  Done Env+             |  ApplyRules [(Tag, Rule, Result)]++type Proofs = [(Tag, Rule)]++class Subst t where+  subst :: Env -> t -> t++instance Subst a => Subst [a] where+  subst e = map (subst e)++instance Subst Term where+  subst env (Var x)     = maybe (Var x) (subst env) (M.lookup x env)+  subst env (Fun x cs)  = Fun x (subst env cs)++instance Subst Rule where+  subst env (c :<-: cs) = subst env c :<-: subst env cs++unify :: (Term, Term) -> Maybe Env-> Maybe Env+unify _       Nothing       = Nothing+unify (t, u)  env@(Just m)  = uni (subst m t) (subst m u)+  where  uni  (Var x)  y        = Just (M.insert x  y  m)+         uni  x        (Var y)  = Just (M.insert y  x  m)+         uni  (Fun x xs) (Fun y ys)+           |  x == y && length xs == length ys  = foldr unify env (zip xs ys)+           |  otherwise                         = Nothing++solve :: [Rule] -> Maybe Env  -> [TaggedTerm] -> Result+solve _      Nothing   _        = ApplyRules []+solve _      (Just e)    []     = Done e+solve rules  e  ((tg,t):ts)  = ApplyRules+  [  (tg, rule, solve rules nextenv (zip (map (\ n -> tg ++ "." ++ show n) [1..]) cs ++ ts))+  |  rule@(c :<-: cs)  <- tag tg rules+  ,  nextenv@(Just _)  <- [unify (t, c) e]+  ]++-- ** Printing the solutions | `enumerateBreadthFirst` performs a+-- depth-first walk over the `Result` tree, while accumulating the+-- rules that were applied on the path which was traversed from the+-- root to the current node. At a successful leaf this contains the+-- full proof.+enumerateDepthFirst :: Proofs -> Result -> [(Proofs, Env)]+enumerateDepthFirst proofs  (Done env) = [(proofs, env)]+enumerateDepthFirst proofs  (ApplyRules bs) =+  [ s  |  (tag, rule@(c :<-: cs), subTree) <- bs+       ,  s <- enumerateDepthFirst ((tag, rule):proofs) subTree+  ]++{-+-- | `enumerateBreadthFirst` is still undefined, and is left as an+-- exercise to the JCU students+enumerateBreadthFirst :: Proofs -> [String] -> Result -> [(Proofs, Env)]+-}++-- | `printEnv` prints a single solution, showing only the variables+-- that were introduced in the original goal+show' :: Env -> String+show' env = intercalate ", " . filter (not.null) . map showBdg $ M.assocs env+  where  showBdg (x, t)  | isGlobVar x =  x ++ " <- " ++ showTerm t+                         | otherwise = ""+         showTerm t@(Var _)  = showTerm (subst env t)+         showTerm (Fun f []) = f+         showTerm (Fun f ts) = f ++ "(" ++ intercalate ", " (map showTerm ts) ++ ")"+         isGlobVar x = head x `elem` ['A'..'Z'] && last x `notElem` ['0'..'9']++instance Show Term where+  show (Var  i)       = i+  show (Fun  i []  )  = i+  show (Fun  i ts  )  = i ++ "(" ++ showCommas ts ++ ")"++instance Show Rule where+  show (t :<-: []  ) = show t ++ "."+  show (t :<-: ts  ) = show t ++ ":-" ++ showCommas ts ++ "."++showCommas :: Show a => [a] -> String+showCommas l = intercalate ", " (map show l)++-- ** Parsing Rules and Terms+startParse :: (ListLike s b, Show b)  => P (Str b s LineColPos) a -> s+                                      -> (a, [Error LineColPos])+startParse p inp  =  parse ((,) <$> p <*> pEnd)+                  $  createStr (LineColPos 0 0 0) inp++pTerm, pVar, pFun :: Parser Term+pTerm  = pVar  <|>  pFun+pVar   = Var   <$>  lexeme (pList1 pUpper)+pFun   = Fun   <$>  pLowerCase <*> (pParens pTerms `opt` [])+  where  pLowerCase :: Parser String+         pLowerCase = (:) <$> pLower <*> lexeme (pList (pLetter <|> pDigit))++pRule :: Parser Rule+pRule = (:<-:) <$> pFun <*> (pSymbol ":-" *> pTerms `opt` []) <* pDot++pTerms :: Parser [Term]+pTerms = pListSep pComma pTerm
+ src/Main.hs view
@@ -0,0 +1,10 @@+module Main where++import            Language.Prolog.NanoProlog.Interpreter (run)++-- * Running the Interpreter+-- ** The main interpreter+-- | The `main` program prompt for a file with Prolog rules and call the main+-- interpreter loop+main :: IO ()+main = run