le switch

This commit is contained in:
Mirek Kratochvil 2022-10-15 19:21:17 +02:00
parent c45771f947
commit 31c20628ea

View file

@ -1,5 +1,3 @@
{-# LANGUAGE TupleSections #-}
module Interpreter where module Interpreter where
import Data.Function import Data.Function
@ -28,26 +26,30 @@ data Instr
type Code = [Instr] type Code = [Instr]
type Alts = [(Code, Code)] -- clauses to try and the corresponding goals to restore
data GolAlts =
GA Code Alts -- goal + choicepoints
deriving (Show)
type Defs = M.Map (Int, Int) [Code] type Defs = M.Map (Int, Int) [Code]
data Cho =
Cho
{ hed :: Code -- head pointer
, gol :: Code -- goal pointer
, stk :: [Code] -- remaining "and" goals
, cut :: [Cho] -- snapshot of choicepoints
}
deriving (Show)
data Interp = data Interp =
Interp Interp
{ defs :: Defs -- global definitions for lookup { defs :: Defs -- global definitions for lookup
, hed :: Code -- current head , cur :: Cho -- the choice that is being evaluated right now
, gol :: GolAlts -- current goal with local choicepoints , cho :: [Cho] -- remaining choice points
, stk :: [GolAlts] -- stack of caller GolAlts
} }
deriving (Show) deriving (Show)
prove :: Code -> Defs -> Either (Interp, String) Bool prove :: Code -> Defs -> Either (Interp, String) Bool
prove g ds = prove g ds =
let i0 = Interp {defs = ds, hed = g, gol = GA [LastCall] [], stk = []} let i0 =
Interp
{defs = ds, cur = Cho {hed = g, gol = [LastCall], stk = [], cut = []}, cho = []}
run (Left x) = x run (Left x) = x
run (Right x) = run $ proveStep Right Left x run (Right x) = run $ proveStep Right Left x
in run (Right i0) in run (Right i0)
@ -57,54 +59,67 @@ proveStep :: (Interp -> a) -> (Either (Interp, String) Bool -> a) -> Interp -> a
proveStep c f i = go i proveStep c f i = go i
where where
ifail msg = f $ Left (i, msg) ifail msg = f $ Left (i, msg)
withDef f withDef fn
| Just d <- defs i M.!? f = ($ d) | Just d <- defs i M.!? fn = ($ d)
| otherwise = const $ ifail $ "no definition: " ++ show f | otherwise = const $ ifail $ "no definition: " ++ show fn
{- Backtracking: try a fallback clause, restoring goal -} {- Backtracking -}
backtrack i@Interp {gol = GA _ ((s, gs):as)} = c i {hed = s, gol = GA gs as} backtrack i@Interp {cho = chos}
{- B: no next clause, pop stack and continue backtracking at the caller -} {- if available, restore the easiest choicepoint -}
backtrack i@Interp {gol = GA _ [], stk = GA g ss:sss} = | (cho:chos) <- chos = c i {cur = cho, cho = chos}
backtrack i {hed = error "failed hed", gol = GA g ss, stk = sss} {- if there's no other choice, answer no -}
{- B: we ran out of possibilities and there's nothing else to backtrack. No solution found. -} | otherwise = f (Right False)
backtrack i@Interp {gol = GA _ [], stk = []} = f (Right False)
{- Unification -} {- Unification -}
go i@Interp {hed = (U a:hs), gol = GA (U b:gs) ss} -- unify constants go i@Interp {cur = cur@Cho {hed = U a:hs, gol = U b:gs}} -- unify constants
= unify a b = unify a b
where where
uok = c i {hed = hs, gol = GA gs ss} uok = c i {cur = cur {hed = hs, gol = gs}}
unify (Atom a) (Atom b) unify (Atom a) (Atom b)
| a == b = uok | a == b = uok
unify (Struct a) (Struct b) unify (Struct a) (Struct b)
| a == b = uok | a == b = uok
unify _ _ = backtrack i unify _ _ = backtrack i
{- Resolution: Final success -} {- Resulution -}
go i@Interp {hed = [NoGoal], gol = GA [LastCall] _, stk = []} = go i@Interp {cur = cur@Cho {hed = hed, gol = gol, stk = stk}, cho = chos}
f (Right True) {- top-level success -}
{- R: Goal succeeded; continue at parent frame -} | [NoGoal] <- hed
go i@Interp { hed = [NoGoal] , [LastCall] <- gol
, gol = GA [LastCall] _ , [] <- stk = f (Right True)
, stk = GA (Goal:U (Struct f):gs) ss:sss {- succeed and return to caller -}
} = | [NoGoal] <- hed
withDef f $ \(hs:ohs) -> , [LastCall] <- gol
c i {hed = hs, gol = GA gs (map (, gs) ohs ++ ss), stk = sss} , (Goal:U (Struct fn):gs):ss <- stk =
{- R: Start matching next goal -} withDef fn $ \(hs:ohs) ->
go i@Interp { hed = [NoGoal] c
, gol = GA (Call:Goal:U (Struct f):gs) ss i
} = { cur = cur {hed = hs, gol = gs, stk = ss}
withDef f $ \(hs:ohs) -> , cho = [Cho oh gs ss chos | oh <- ohs] ++ chos
c i {hed = hs, gol = GA gs (map (, gs) ohs ++ ss)} }
{- R: Goal head matching succeeded, make a normal call -} {- start matching next goal -}
go i@Interp { hed = (Goal:U (Struct f):ngs) | [NoGoal] <- hed
, gol = GA (Call:gs) ss , (Call:Goal:U (Struct fn):gs) <- gol =
, stk = sss withDef fn $ \(hs:ohs) ->
} = c
withDef f $ \(hs:ohs) -> i
c i {hed = hs, gol = GA ngs (map (, ngs) ohs), stk = GA gs ss : sss} { cur = cur {hed = hs, gol = gs}
, cho = [Cho oh gs stk chos | oh <- ohs] ++ chos
}
{- goal head matching succeeded, make a normal call -}
| (Goal:U (Struct fn):ngs) <- hed
, (Call:gs) <- gol =
withDef fn $ \(hs:ohs) ->
c
i
{ cur = cur {hed = hs, gol = ngs, stk = gs : stk}
, cho = [Cho oh ngs stk chos | oh <- ohs] ++ chos
}
{- R: Successful match continued by tail call -} {- R: Successful match continued by tail call -}
go i@Interp { hed = (Goal:U (Struct f):ngs) | (Goal:U (Struct fn):ngs) <- hed
, gol = GA [LastCall] ss , [LastCall] <- gol =
} = withDef fn $ \(hs:ohs) ->
withDef f $ \(hs:ohs) -> c
c i {hed = hs, gol = GA ngs (map (, ngs) ohs ++ ss)} i
{ cur = cur {hed = hs, gol = ngs}
, cho = [Cho oh ngs stk chos | oh <- ohs] ++ chos
}
{- The End -} {- The End -}
go _ = ifail "impossible instruction combo" go _ = ifail "impossible instruction combo"