2023-11-26 00:45:05 -08:00
|
|
|
module Bergamot.Rules exposing (..)
|
|
|
|
|
2023-12-01 13:10:51 -08:00
|
|
|
import Bergamot.Syntax exposing (Term(..), Metavariable, UnificationVar, unify, emptyUnificationState, instantiate, instantiateList, emptyInstantiationState, resetVars, InstantiationState, UnificationState, reify)
|
2023-11-26 00:45:05 -08:00
|
|
|
import Bergamot.Search as Search exposing (Search)
|
2023-12-01 23:31:43 -08:00
|
|
|
import Bergamot.Utils exposing (encodeStr, encodeLatex)
|
2023-11-26 00:45:05 -08:00
|
|
|
|
|
|
|
import Debug
|
|
|
|
|
|
|
|
type alias Rule =
|
|
|
|
{ name : String
|
|
|
|
, conclusion : Term Metavariable
|
|
|
|
, premises : List (Term Metavariable)
|
|
|
|
}
|
|
|
|
|
2023-12-21 13:31:53 -08:00
|
|
|
type alias Section =
|
|
|
|
{ name : String
|
|
|
|
, rules : List Rule
|
|
|
|
}
|
|
|
|
|
2023-11-26 00:45:05 -08:00
|
|
|
type ProofTree = MkProofTree
|
|
|
|
{ name : String
|
|
|
|
, conclusion : Term UnificationVar
|
|
|
|
, premises : List ProofTree
|
|
|
|
}
|
|
|
|
|
|
|
|
type alias RuleEnv =
|
2023-12-21 13:31:53 -08:00
|
|
|
{ sections : List Section
|
2023-11-26 00:45:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
type alias ProveState =
|
|
|
|
{ unificationState : UnificationState
|
|
|
|
, instantiationState : InstantiationState
|
2023-11-26 21:28:27 -08:00
|
|
|
, gas: Int
|
2023-11-26 00:45:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
type alias Prover a = RuleEnv -> ProveState -> Search (a, ProveState)
|
|
|
|
|
|
|
|
andThen : (a -> Prover b) -> Prover a -> Prover b
|
|
|
|
andThen f p env ps =
|
|
|
|
p env ps
|
2023-12-02 23:46:24 -08:00
|
|
|
|> Search.andThen (\(a, psp) -> (f a) env psp)
|
2023-11-26 00:45:05 -08:00
|
|
|
|
2023-11-26 12:32:28 -08:00
|
|
|
join : Prover (Prover a) -> Prover a
|
|
|
|
join p = andThen (\x -> x) p
|
|
|
|
|
2023-11-26 12:27:44 -08:00
|
|
|
apply : Prover a -> Prover (a -> b) -> Prover b
|
|
|
|
apply pa pf = pf |> andThen (\f -> map f pa)
|
|
|
|
|
2023-11-26 00:45:05 -08:00
|
|
|
map : (a -> b) -> Prover a -> Prover b
|
|
|
|
map f p env ps =
|
|
|
|
p env ps
|
|
|
|
|> Search.map (Tuple.mapFirst f)
|
|
|
|
|
2023-11-26 13:14:44 -08:00
|
|
|
mapM : (a -> Prover b) -> List a -> Prover (List b)
|
|
|
|
mapM f l =
|
|
|
|
case l of
|
|
|
|
x :: xs ->
|
|
|
|
pure (::)
|
|
|
|
|> apply (f x)
|
|
|
|
|> apply (mapM f xs)
|
|
|
|
[] -> pure []
|
|
|
|
|
2023-11-26 00:45:05 -08:00
|
|
|
interleave : Prover a -> Prover a -> Prover a
|
|
|
|
interleave p1 p2 env ps =
|
|
|
|
Search.interleave (p1 env ps) (p2 env ps)
|
|
|
|
|
|
|
|
pure : a -> Prover a
|
|
|
|
pure a env ps = Search.pure (a, ps)
|
|
|
|
|
|
|
|
fail : Prover a
|
|
|
|
fail env ps = Search.fail
|
|
|
|
|
2023-11-26 17:17:10 -08:00
|
|
|
yield : Prover a -> Prover a
|
|
|
|
yield p env ps = Search.yield (p env ps)
|
|
|
|
|
2023-11-26 00:45:05 -08:00
|
|
|
getEnv : Prover RuleEnv
|
|
|
|
getEnv env ps = Search.pure (env, ps)
|
|
|
|
|
2023-12-21 13:31:53 -08:00
|
|
|
getRules : Prover (List Rule)
|
|
|
|
getRules env ps = Search.pure (List.concatMap (.rules) env.sections, ps)
|
|
|
|
|
2023-11-26 13:14:44 -08:00
|
|
|
getUnificationState : Prover UnificationState
|
|
|
|
getUnificationState env ps = Search.pure (ps.unificationState, ps)
|
|
|
|
|
2023-12-21 16:47:56 -08:00
|
|
|
burn : Prover a -> Prover a
|
|
|
|
burn p env ps = if ps.gas > 0 then Search.map (\(a, psp) -> (a, { psp | gas = ps.gas })) (p env { ps | gas = ps.gas - 1 }) else Search.fail
|
2023-11-26 21:28:27 -08:00
|
|
|
|
2023-11-26 12:27:44 -08:00
|
|
|
liftInstantiation : (a -> InstantiationState -> (b, InstantiationState)) -> a -> Prover b
|
|
|
|
liftInstantiation f a env ps =
|
2023-11-26 00:45:05 -08:00
|
|
|
let
|
2023-11-26 12:27:44 -08:00
|
|
|
(b, is) = f a ps.instantiationState
|
2023-11-26 00:45:05 -08:00
|
|
|
in
|
2023-11-26 12:27:44 -08:00
|
|
|
Search.pure (b, { ps | instantiationState = is })
|
|
|
|
|
|
|
|
liftUnification : (a -> a -> UnificationState -> Maybe (a, UnificationState)) -> a -> a -> Prover a
|
|
|
|
liftUnification f a1 a2 env ps =
|
|
|
|
case f a1 a2 ps.unificationState of
|
|
|
|
Just (a, us) -> Search.pure (a, { ps | unificationState = us })
|
|
|
|
Nothing -> Search.fail
|
|
|
|
|
|
|
|
withVars : Prover a -> Prover a
|
|
|
|
withVars p env ps =
|
|
|
|
p env ps
|
|
|
|
|> Search.map (Tuple.mapSecond (\psp -> { psp | instantiationState = resetVars psp.instantiationState }))
|
|
|
|
|
2023-11-26 13:14:44 -08:00
|
|
|
|
|
|
|
reifyProofTree : ProofTree -> Prover ProofTree
|
|
|
|
reifyProofTree (MkProofTree node) =
|
|
|
|
pure (\t trees -> MkProofTree { node | conclusion = t, premises = trees })
|
|
|
|
|> apply (map (reify node.conclusion) getUnificationState)
|
|
|
|
|> apply (mapM reifyProofTree node.premises)
|
|
|
|
|
2023-11-26 12:27:44 -08:00
|
|
|
rule : Term UnificationVar -> Rule -> Prover ProofTree
|
|
|
|
rule t r =
|
|
|
|
withVars (pure Tuple.pair
|
2023-12-01 23:40:29 -08:00
|
|
|
|> apply (liftInstantiation instantiate r.conclusion
|
|
|
|
|> andThen (\conc -> liftUnification unify t conc))
|
2023-11-26 12:27:44 -08:00
|
|
|
|> apply (liftInstantiation instantiateList r.premises))
|
|
|
|
|> andThen (\(conc, prems) ->
|
2023-12-01 23:40:29 -08:00
|
|
|
provePremises prems)
|
|
|
|
|> map (\trees -> MkProofTree { name = r.name, conclusion = t, premises = trees })
|
2023-11-26 00:45:05 -08:00
|
|
|
|
2023-12-01 16:26:34 -08:00
|
|
|
collectStrings : Term UnificationVar -> Prover (List String)
|
|
|
|
collectStrings t =
|
|
|
|
case t of
|
|
|
|
Call "cons" [StringLit s, rest] -> map (\ss -> s :: ss) <| collectStrings rest
|
|
|
|
Call "nil" [] -> pure []
|
|
|
|
_ -> fail
|
|
|
|
|
2023-12-01 13:10:51 -08:00
|
|
|
builtinRules : Term UnificationVar -> Prover ProofTree
|
|
|
|
builtinRules t =
|
|
|
|
case t of
|
|
|
|
Call "concat" [StringLit s1, StringLit s2, Var output] ->
|
|
|
|
liftUnification unify (Var output) (StringLit (s1 ++ s2))
|
2023-12-01 16:26:34 -08:00
|
|
|
|> map (\_ -> MkProofTree { name = "BuiltinConcat", conclusion = t, premises = []})
|
|
|
|
Call "join" [tp, Var output] ->
|
|
|
|
collectStrings tp
|
|
|
|
|> andThen (\ss -> liftUnification unify (Var output) (StringLit (String.concat ss)))
|
|
|
|
|> map (\_ -> MkProofTree { name = "BuiltinJoin", conclusion = t, premises = []})
|
|
|
|
Call "int" [IntLit i] ->
|
|
|
|
MkProofTree { name = "BuiltinInt", conclusion = t, premises = [] }
|
|
|
|
|> pure
|
|
|
|
Call "str" [StringLit s] ->
|
|
|
|
MkProofTree { name = "BuiltinStr", conclusion = t, premises = [] }
|
|
|
|
|> pure
|
2023-12-01 16:56:27 -08:00
|
|
|
Call "sym" [Call s []] ->
|
|
|
|
MkProofTree { name = "BuiltinSym", conclusion = t, premises = [] }
|
|
|
|
|> pure
|
2023-12-01 18:15:32 -08:00
|
|
|
Call "call" [Call s ts, Var name, Var args] ->
|
|
|
|
pure (\_ _ -> MkProofTree { name = "BuiltinCall", conclusion = t, premises = [] })
|
|
|
|
|> apply (liftUnification unify (Var name) (StringLit <| encodeStr s))
|
|
|
|
|> apply (liftUnification unify (Var args) (List.foldr (\x xs -> Call "cons" [x, xs]) (Call "nil" []) ts))
|
2023-12-01 16:26:34 -08:00
|
|
|
Call "tostring" [IntLit i, Var output] ->
|
|
|
|
liftUnification unify (Var output) (StringLit (String.fromInt i))
|
|
|
|
|> map (\_ -> MkProofTree { name = "BuiltinToString", conclusion = t, premises = []})
|
2023-12-01 16:38:46 -08:00
|
|
|
Call "tostring" [Call s [], Var output] ->
|
|
|
|
liftUnification unify (Var output) (StringLit <| encodeStr s)
|
|
|
|
|> map (\_ -> MkProofTree { name = "BuiltinToString", conclusion = t, premises = []})
|
2023-12-01 23:31:43 -08:00
|
|
|
Call "escapestring" [StringLit s, Var output] ->
|
|
|
|
liftUnification unify (Var output) (StringLit (encodeStr s))
|
|
|
|
|> map (\_ -> MkProofTree { name = "BuiltinEscapeString", conclusion = t, premises = []})
|
|
|
|
Call "latexifystring" [StringLit s, Var output] ->
|
|
|
|
liftUnification unify (Var output) (StringLit (encodeLatex s))
|
|
|
|
|> map (\_ -> MkProofTree { name = "BuiltinLatexifyeString", conclusion = t, premises = []})
|
2023-12-01 13:10:51 -08:00
|
|
|
_ -> fail
|
|
|
|
|
2023-11-26 00:45:05 -08:00
|
|
|
provePremises : List (Term UnificationVar) -> Prover (List ProofTree)
|
2023-11-26 13:14:44 -08:00
|
|
|
provePremises = mapM proveTerm
|
2023-11-26 00:45:05 -08:00
|
|
|
|
2023-11-26 12:47:05 -08:00
|
|
|
proveTerm : Term UnificationVar -> Prover ProofTree
|
|
|
|
proveTerm t =
|
2023-12-01 16:26:34 -08:00
|
|
|
map (reify t) getUnificationState
|
|
|
|
|> andThen (\tp ->
|
2023-12-21 16:47:56 -08:00
|
|
|
burn (
|
|
|
|
getRules
|
|
|
|
|> andThen (List.foldr (\r -> interleave ((rule tp r))) (builtinRules tp))))
|
2023-11-26 12:47:05 -08:00
|
|
|
|
2023-11-26 12:32:28 -08:00
|
|
|
prove : Term Metavariable -> Prover ProofTree
|
|
|
|
prove mt =
|
2023-12-01 16:35:22 -08:00
|
|
|
withVars (liftInstantiation instantiate mt)
|
2023-11-26 12:47:05 -08:00
|
|
|
|> andThen proveTerm
|
2023-11-26 00:45:05 -08:00
|
|
|
|
|
|
|
single : RuleEnv -> Prover a -> Maybe a
|
|
|
|
single env p =
|
2023-12-21 16:47:56 -08:00
|
|
|
p env { instantiationState = emptyInstantiationState, unificationState = emptyUnificationState, gas = 30 }
|
2023-11-26 00:45:05 -08:00
|
|
|
|> Search.one
|
|
|
|
|> Maybe.map (Tuple.first << Tuple.first)
|