Prolog ã¤ã³ã¿ããªã¿ã Haskell ã§æ¸ãã¾ããããã°ããæ¸ããã ãã§æºè¶³ãã¦ãã¾ã£ã¦ããã®ã§ããããã®ã¾ã¾äººç¥ããæ¶ãã¦è¡ãã®ãå¯ããã®ã§åå¼·ããäºãæ¸ãã¾ããã¾ããåèã«ããã½ã¼ã¹ã¯ååæ¸ãã hugs98/demos/prolog/ ã§ãããã®ã½ã¼ã¹ã大å¤çãã¦è¯ãã®ã§ãããç´ äººç®ã«ã¯ç°¡æ½ããã¦é£ããã®ã¨ãæ¸ãããã®ãå¤ãã®ã do è¨æ³ãå ¨ã使ã£ã¦ããªãã®ã§ããããã¸ããç§é¢¨ã«ã¢ã¬ã³ã¸ãã¾ãããã½ã¼ã¹ã http://github.com/propella/prolog/tree ã«ç½®ãã¦ããã¾ãããªããè¨èã®ä½¿ãæ¹ã¨ãééã£ã¦ããããããªãã®ã§æ°ã¥ãã人ã¯æãã¦ãã ããã
å®è¡
å®è¡ã®ä»æ¹ã¯ Prolog.hs ããã¦ã³ãã¼ããã¦ã
runghc Prolog.hs
ã§ããfood(apple). ã®ããã«ããã¨ã«ã¼ã«ã«è¿½å ã§ã?- apple(X). ã§åãåããã?? ã§å ¨é¨ã®ã«ã¼ã«ã表示ãã¾ãã
runghc Prolog.hs < demo.prolog
ã®ããã«ããã¨ããã¹ããã¡ã¤ã«ã«æ¸ãããç©ãå®è¡ããäºãåºæ¥ã¾ãã
ãã¼ã¿æ§é
ã§ã¯æ©éä¸èº«ããç´¹ä»ãã¾ãã
module Prolog (Term(..), Clause(..), w, s, cons, parse, parse', atom, variable, struct, list, nil, terms, arguments, term, clause, clauses, query, display, unify, unifyList, applyTerm, prove, rename, solveString) where import Text.ParserCombinators.Parsec import Data.Maybe (maybeToList) import Char (isUpper)
é¢æ°ã沢山ã¨ãã¹ãã¼ããã¦ãã®ã¯ã¦ããããã¹ãã§ä½¿ãããã£ãããã§ããã©ã¤ãã©ãªã¯ããã¼ãµã¨ã㦠Parsec ã使ã£ã¦ã¾ãããã¨ãmaybeToLst 㨠isUpper ãã¤ã³ãã¼ããã¦ã¾ãã
infix 6 :- data Term = Var String Int | Struct String [Term] deriving (Show, Eq) data Clause = Term :- [Term] deriving (Show, Eq) data Command = Fact Clause | Query [Term] | ShowAll | Noop type Rules = [Clause]
ãã㧠Prolog ã®ãã¼ã¿ãå®ç¾©ãã¦ãã¾ããProlog ã®é ã¯å¤æ° Var ã¾ãã¯è¿°èª Struct ã§ããå¤æ°ã¯å¤æ°åã ãã§è¯ããããªç©ã§ãããProlog ã®å¤æ°ã®ã¹ã³ã¼ãã¯ä¸ã¤ã®ã«ã¼ã«å ã ããªã®ã§ãåºå¥ããããã«å¾ã§çªå·ãä»ãã¾ãããã㧠Var String Int ã¨ãªã£ã¦ãã¾ããè¿°èªã«ã¯ apple ã®ãããªåç´ãªãã¤ã¨ãsucc(zero) ã®ãããªæ§é ãæã£ã奴ã®äºéãããã¾ãããåç´ãªãã¤ãå¼ãæ°ãã¼ãã®æ§é ã¨ãã¦æ±ãã¾ããã¤ã¾ããapple 㨠apple() ã¯åãæå³ã§ããç¯ã¯ Clause ã¨ãã¦å®ç¾©ãã¦ãã¾ããHaskell ã¯ã³ã³ã¹ãã©ã¯ã¿ã«ãæ¼ç®åã使ããã®ã§ããªãã¨ãªã Prolog ã£ã½ã表ç¾åºæ¥ã¾ããã㨠Command ã¯ã¤ã³ã¿ã©ã¯ãã£ãã«ã¼ãã§ä½¿ãã¾ãã
ãã㧠Prolog ã®ãã¼ã¿ã Haskell ã®ãã¼ã¿ã¨ãã¦è¡¨ç¾åºæ¥ã¾ãããããªãç ©éã§ããä¾ãã°"mortal(X) :- man(X)" 㯠Struct "mortal" [Var "X" 0] :- [(Struct "man" [Var "X" 0])] ã®ããã«ãªã£ã¦ãã¾ãã¾ããããã§ã¯ãã¹ãã±ã¼ã¹ãæ¸ãã®ã大å¤ãªã®ã§ã便å©é¢æ°ãä½ã£ã¦ããã¾ãã便å©é¢æ°ã使ã㨠s"mortal" [w"X"] :- [s"man" [w"X"] ] ã«ãªã£ã¦ã¡ãã£ã¨ã¾ãã§ãã
-- Utility constructors for debugging w :: String -> Term w s@(x:xs) | isUpper x = Var s 0 | otherwise = Struct s [] s :: String -> [Term] -> Term s n xs = Struct n xs cons s cdr = (Struct "cons" [w s, cdr])
ã¦ããã£ã±ã¼ã·ã§ã³
ã¦ããã£ã±ã¼ã·ã§ã³ã¨ããã®ã¯è¦ããã«è¶ ç°¡åãªæ¹ç¨å¼ã解ãäºã§ããä¾ãã°ã(X, orange) = (apple, Y) ã¨ããæ¹ç¨å¼ããã£ãããããããåãããªãé¨åãåãåãã㦠X = apple 㧠Y = orange ã¨ããçããæ±ããã®ãã¦ããã£ã±ã¼ã·ã§ã³ã§ããããã§ã¯ãã®çãã表ç¾ããã®ã«ã[(å¤æ°, å 容)] ã¨ãããã¢ã®ãªã¹ã Substitutionãããããé£æ³ãªã¹ãã使ãã¾ãã
---- Unification ---- type Substitution = [(Term, Term)]
å ã»ã©ã®ä¾ã§çããå¾ãã«ã¯ã
- åã©ãããå¾ã©ããããã¢ã«ããã[(X, apple), (orange, Y)]
- å¤æ°ãå·¦ã«æ¥ãããã«ããã[(X, apple), (Y, orange)]
ã¨ããã ããªã®ã§ç°¡åã§ããã§ã¯ (X, Y) = (Y, banana). ã¨ããæ¹ç¨å¼ã¯ã©ãã§ããããï¼ç¶ã足ãã¨ã[(X, Y), (Y, banana)] ã¨ãããªã¹ããåºæ¥ã¾ãããããã X ãæ±ããã«ã¯ã
- å³è¾ºãå¤æ°ã®ã¨ãã¯ãã®å¤æ°ã§ããã«å帰çã«æ®ããæ¢ãã
- ãªã¹ããç¶ã足ãæã«ããã«å¤å½¢ã㦠[(X, banana), (Y, banana)] ã«ããã
ã®äºéãã®ãããããããã¨æãã¾ããå¤æ°ã®åç §ã追å ããå¤ãã¨ãã«ã¯åè ã®æ¹ãé ãã§ããç°¡åã§ãããã°ããããã®ã§åè ã使ãã¾ãã
ã§ã¯ããã«é£ããåé¡ (X, Y) = (banana, X) ã¯ã©ãã§ããããï¼ãããç¶ã足ã㨠[(X, banana), (Y, X)] ã«ãªããX ã¯æ±ã¾ãã¾ãããY ãæ±ããã«ã¯åããããä¸åº¦æ¤ç´¢ããªãã¦ã¯ãªãã¾ãããä¸åã®ã¦ããã£ã±ã¼ã·ã§ã³ã§å ¨ã¦ã®å¤æ°ã®å¤ãæ±ã¾ããªãå ´åãåã³åããæ¤ç´¢ããã¨ç¡éã«ã¼ãã«ãªã£ã¦ãã¾ãã®ã§ãããã¯ç¡çã§ãã
ãã®å ´åãX ã banana ã§ããäºã¯åãã£ã¦ããã®ã§ãç¶ã足ãåã« (Y, X) ã® X ã banana ã§ç½®ãæãã¦ã[(X, banana), (Y, banana)] ã¨ããã¨ä¸æãããã¾ãããã®ç½®ãæãã apply ã¨å¼ã³ã¾ããã¾ã¨ããã¨ã
- 両辺ã®è¦ç´ ã®æ°ãåãäºã確èªããã
- å·¦å´ãå¤æ°ã«ãªããããªé£æ³ãªã¹ããä½ã(ã¡ãªã¿ã«ãã©ã£ã¡ãå¤æ°ã®æã¯ã©ã£ã¡ã§ãè¯ãã§ã)ã
- é£æ³ãªã¹ãã«æ¬¡ã®è¦ç´ ãç¶ã足ãæã¯ãå¤æ°ãä»ã¾ã§åãã£ã¦ããå¤ã¨ç½®ãæãã¦ããç¶ã足ãã
ããã°ã©ã ã§æ¸ãã¨ãããªæãã§ããã¦ããã£ã±ã¼ã·ã§ã³ã§ããªãå ´å㯠Nothing ãè¿ãã¾ãã
true = [] -- apply [(w"X", w"Y"), (w"Y", w"Z")] [(w"X"), (w"Y")] == [(w"Z"), (w"Z")] apply :: Substitution -> [Term] -> [Term] apply s ts = [applyTerm s t | t <- ts] applyTerm [] (Var y n) = Var y n applyTerm ((Var x i, t):s) (Var y j) | x == y && i == j = applyTerm s t | otherwise = applyTerm s (Var y j) applyTerm s (Struct n ts) = Struct n (apply s ts) -- unify (w"X") (w"apple") == Just [(w"X", w"apple")] unify :: Term -> Term -> Maybe Substitution unify (Var x n) (Var y m) = Just [(Var x n, Var y m)] unify (Var x n) y = Just [(Var x n, y)] unify x (Var y m) = Just [(Var y m, x)] unify (Struct a xs) (Struct b ys) | a == b = unifyList xs ys | otherwise = Nothing unifyList :: [Term] -> [Term] -> Maybe Substitution unifyList [] [] = Just true unifyList [] _ = Nothing unifyList _ [] = Nothing unifyList (x:xs) (y:ys) = do s <- unify x y s' <- unifyList (apply s xs) (apply s ys) return (s ++ s')
æ¤ç´¢
ãããã«ã¼ã«ãä¸ã¤ã§è³ªåãä¸ã¤ããç¡ãå ´åã¯ãã¦ããã£ã±ã¼ã·ã§ã³ã ãã§ååã§ããä¾ãã° (X, orange) = (apple, Y) ã¯
r(X, orange). ?- r(apple, Y).
ã¨åãã§ããã ãã©å®éã«ã¯ã«ã¼ã«ã沢山çµåãããã®ãæ®éã§ã沢山ã®ã«ã¼ã«ãé çªã«ã¦ããã£ã±ã¼ã·ã§ã³ãã¦è¡ã£ã¦æçµçãªçããæ±ãã¾ãããã®æ¤ç´¢é åºã¯ã¦ããã£ã±ã¼ã·ã§ã³èªä½ã¨ã¯ç¬ç«ããæ©è½ãªã®ã§ãæ··ãã¦èããªããã注æãã¦ãã ãããProlog ã§ã¯ãæ·±ãåªå æ¢ç´¢ã¨è¨ã£ã¦ãå¯è½æ§ã®æ¨ã端ããé ã«ããã¦ããã£ã±ã¼ã·ã§ã³ãã¦è¡ãã¾ããæ¨ã®åå²ç¹ã¯äºç¨®é¡ãã£ã¦æå³ãå ¨ç¶éãã®ã§æ··ããªãã§ãã ããã
- ã´ã¼ã« (AND é¢ä¿) : ã´ã¼ã«ã¯ã³ã³ãã§åºåãããé ã®å½¢ã§ä¸ãããã¾ããã½ã¼ã¹ä¸ã§ã¯æ¨ªã«ä¸¦ã³ã¾ãã
- é¸æè¢ (OR é¢ä¿) : é¸æè¢ã¯ããã´ã¼ã«ã«ã¦ããã£ã±ã¼ã·ã§ã³åºæ¥ãé é¨ãæã¤ã«ã¼ã«ã§ããã½ã¼ã¹ä¸ã§ã¯ç¸¦ã«ä¸¦ã³ã¾ãã
æ¤ç´¢æ¨ã®æã®ç«¯ã«ã¯äºã¤ã®å ´åãããã¾ããä¸ã¤ã¯ã´ã¼ã«ãçã§ããã¨åãã£ãå ´åã§ãapple. ã®ããã«é é¨ã¯ãããã©ä½é¨ã®ãªãã«ã¼ã«ã«å½ãã£ãæã§ããããä¸ã¤ã¯é¸æè¢ãç¡ããªã£ãå ´åã§ããã½ã¼ã¹ã³ã¼ãä¸ã§ã¯ãã¦ããã£ã±ã¼ã·ã§ã³ã失æãã㨠unify é¢æ°ã¯ Nothing ãè¿ãã®ã§ maybeToList ã§é¸æè¢ã®ãªã¹ãããé¤å¤ãã¦ãã¾ãã
---- Solver ---- prove :: Rules -> [Term] -> [Substitution] prove rules goals = find rules 1 goals -- Depth first search -- find (parse' clauses "p(X):-q(X). q(a).") 1 [parse' term "p(X)"] find :: Rules -> Int -> [Term] -> [Substitution] find rules i [] = [true] find rules i goals = do let rules' = rename rules i (s, goals') <- branch rules' goals solution <- find rules (i + 1) goals' return (s ++ solution) -- Find next branches. A branch is a pair of substitution and next goals. -- branch (parse' clauses "n(z). n(s(X)):-n(X).") (parse' query "?-n(X).") branch :: Rules -> [Term] -> [(Substitution, [Term])] branch rules (goal:goals) = do head :- body <- rules s <- maybeToList (unify goal head) return (s, apply s (body ++ goals))
æå¾ã«éè¦ãªã®ããfind é¢æ°ã§æ¤ç´¢ãå§ããåã«ãã¼ã¿ãã¼ã¹ã«å«ã¾ããå¤æ°ã®ã¤ã³ããã¯ã¹ãä¸æ¬ãã¦æ¸ãæããäºã§ããããã§ãå¥ã®ã«ã¼ã«ã«å«ã¾ããå¤æ°ãéãäºãä¿è¨¼ãã¾ããapply ã¯å¤æ°ãå¤ã§ç½®ãæãã¾ãããrename ã¯å¤æ°ã®ã¤ã³ããã¯ã¹ã ããæ¸ãæãã¾ãããã¼ã¿ãã¼ã¹ãå ¨é¨æ¸ãæãããªãã¦å¯è±ªçã§ãããå®éã«ã¯ Hakell ã®ç´ æ´ãããé 延è©ä¾¡ã«ãã£ã¦å¿ è¦ãªåã ãæ¸ãæããäºã«ãªãã¾ã(å¤å)ã
-- Rename all variables in the rules to split namespaces. rename :: Rules -> Int -> Rules rename rules i = [ renameVar head :- renameVars body | head :- body <- rules] where renameVar (Var s _) = Var s i renameVar (Struct s ts) = Struct s (renameVars ts) renameVars ts = [renameVar t | t <- ts]
é¢ç½ãé¨åã¯ãããããã§ãããã¨ãParsec ã«ããææ³ããåã¯ã©ã¹ã使ã£ãæåå表示ããç¶ç¶æ¸¡ãã«ããã¤ã³ã¿ã©ã¯ãã£ãã·ã§ã«ã®å®è£ ãªã©ãé¢ç½ã話é¡ã¯è²ã ããã¾ãããã®è¾ºã«ãã¨ãã¾ãã