From b25f85e231f75ae436356b698723dfefd039f38d Mon Sep 17 00:00:00 2001 From: Johann Rosain Date: Sun, 20 Jul 2025 21:41:14 +0200 Subject: [PATCH 1/8] Removal of invasive type system --- src/AST/formsDef.go | 242 +------ src/AST/formula.go | 14 - src/AST/maker.go | 45 +- src/AST/quantifiers.go | 37 +- src/AST/term.go | 115 +--- src/AST/termsDef.go | 84 +-- src/Core/Sko/inner-skolemization.go | 4 +- src/Core/Sko/interface.go | 33 +- src/Core/Sko/outer-skolemization.go | 4 +- src/Core/Sko/preinner-skolemization.go | 14 +- src/Core/instanciation.go | 2 +- src/Core/rules_type.go | 5 +- src/Core/substitutions_search.go | 12 - src/Engine/pretyper.go | 6 +- src/Engine/syntax-translation.go | 25 +- .../equality/bse/equality_problem_list.go | 2 - src/Mods/equality/bse/equality_types.go | 12 +- src/Mods/equality/sateq/subsgatherer.go | 2 +- src/Mods/equality/sateq/termrep.go | 4 - src/Mods/gs3/dependency.go | 4 - src/Mods/lambdapi/context.go | 30 +- src/Mods/lambdapi/formDecorator.go | 2 +- src/Mods/lambdapi/proof.go | 18 +- src/Mods/rocq/context.go | 11 +- src/Search/rules.go | 5 - src/Typing/apply_rules.go | 310 ++++----- src/Typing/contexts.go | 614 +++++++++--------- src/Typing/form_rules.go | 400 ++++++------ src/Typing/launch_rules.go | 286 ++++---- src/Typing/prooftree_dump.go | 234 +++---- src/Typing/rules.go | 404 ++++++------ src/Typing/term_rules.go | 363 +++++------ src/Typing/type.go | 318 +++++---- src/Typing/type_rules.go | 372 +++++------ src/Typing/wf_rules.go | 60 +- src/Unif/matching.go | 11 +- src/Unif/parsing.go | 30 +- src/Unif/substitutions_type.go | 6 +- src/main.go | 16 +- 39 files changed, 1789 insertions(+), 2367 deletions(-) diff --git a/src/AST/formsDef.go b/src/AST/formsDef.go index e8b55413..55ff9ba5 100644 --- a/src/AST/formsDef.go +++ b/src/AST/formsDef.go @@ -119,10 +119,6 @@ func (a All) RenameVariables() Form { return All{a.quantifier.renameVariables()} } -func (a All) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return All{a.quantifier.replaceTypeByMeta(varList, index)} -} - func (a All) ReplaceTermByTerm(old Term, new Term) (Form, bool) { quant, isReplaced := a.quantifier.replaceTermByTerm(old, new) return All{quant}, isReplaced @@ -175,10 +171,6 @@ func (e Ex) RenameVariables() Form { return Ex{e.quantifier.renameVariables()} } -func (e Ex) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return Ex{e.quantifier.replaceTypeByMeta(varList, index)} -} - func (e Ex) ReplaceTermByTerm(old Term, new Term) (Form, bool) { quant, isReplaced := e.quantifier.replaceTermByTerm(old, new) return Ex{quant}, isReplaced @@ -192,138 +184,6 @@ func (e Ex) ReplaceMetaByTerm(meta Meta, term Term) Form { return Ex{e.quantifier.replaceMetaByTerm(meta, term)} } -// ----------------------------------------------------------------------------- -// Π-types - -type AllType struct { - *MappedString - index int - tvList []TypeVar - form Form - metas Lib.Cache[Lib.Set[Meta], AllType] -} - -func MakeAllTypeSimple( - i int, - typeVars []TypeVar, - form Form, - metas Lib.Set[Meta], -) AllType { - fms := &MappedString{} - at := AllType{ - fms, - i, - typeVars, - form, - Lib.MkCache(metas, AllType.forceGetMetas), - } - fms.MappableString = &at - return at -} - -func MakeAllType(i int, typeVars []TypeVar, form Form) AllType { - return MakeAllTypeSimple(i, typeVars, form, Lib.EmptySet[Meta]()) -} - -func MakerAllType(typeVars []TypeVar, form Form) AllType { - return MakeAllType(MakerIndexFormula(), typeVars, form) -} - -/* Methods */ - -func (a AllType) GetIndex() int { return a.index } -func (a AllType) GetVarList() []TypeVar { return copyTypeVarList(a.tvList) } -func (a AllType) GetForm() Form { return a.form.Copy() } -func (a AllType) GetType() TypeScheme { return DefaultPropType(0) } - -/* Form interface */ - -func (a AllType) ToMappedString(mapping MapString, displayTypes bool) string { - return mapping[QuantVarOpen] + Glob.ListToString(a.GetVarList(), ", ", "") + " : " + mapping[TypeVarType] + mapping[QuantVarClose] + mapping[QuantVarSep] + " (" + a.GetForm().ToString() + ")" -} - -func (a AllType) ToString() string { - return a.MappedString.ToString() -} - -func (a AllType) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return "(" + mapping[AllTypeQuant] + " " + mapping[QuantVarOpen] + Glob.ListToString(a.GetVarList(), ", ", "") + " : " + mapping[TypeVarType] + mapping[QuantVarClose] + mapping[QuantVarSep] + " (%s))" -} - -func (a AllType) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - return "", "" -} - -func (a AllType) GetChildrenForMappedString() []MappableString { - return LsToMappableStringSlice(a.GetChildFormulas()) -} - -func (a AllType) forceGetMetas() Lib.Set[Meta] { - return a.GetForm().GetMetas() -} - -func (a AllType) GetMetas() Lib.Set[Meta] { - return a.metas.Get(a) -} - -func (a AllType) Copy() Form { - fms := &MappedString{} - at := AllType{ - fms, - a.index, - copyTypeVarList(a.tvList), - a.form.Copy(), - a.metas.Copy(Lib.Set[Meta].Copy), - } - fms.MappableString = &at - return at -} - -func (a AllType) Equals(f any) bool { - oth, isAll := f.(AllType) - return isAll && - AreEqualsTypeVarList(a.tvList, oth.tvList) && - a.form.Equals(oth.form) -} - -func (a AllType) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakeAllType(a.GetIndex(), a.tvList, a.GetForm().ReplaceTypeByMeta(varList, index)) -} - -func (a AllType) ReplaceTermByTerm(old Term, new Term) (Form, bool) { - f, res := a.GetForm().ReplaceTermByTerm(old, new) - na := MakeAllTypeSimple(a.GetIndex(), a.GetVarList(), f, a.metas.Raw()) - if !res && !a.metas.NeedsUpd() { - na.metas.AvoidUpd() - } - return na, res -} - -func (a AllType) RenameVariables() Form { - return MakeAllType(a.GetIndex(), a.GetVarList(), a.GetForm().RenameVariables()) -} - -func (a AllType) GetSubTerms() Lib.List[Term] { - return a.GetForm().GetSubTerms() -} - -func (a AllType) SubstituteVarByMeta(old Var, new Meta) Form { - f := a.GetForm().SubstituteVarByMeta(old, new) - return MakeAllTypeSimple(a.index, a.tvList, f, a.metas.Raw()) -} - -func (a AllType) GetSubFormulasRecur() Lib.List[Form] { - return getAllSubFormulasAppended(a) -} - -func (a AllType) GetChildFormulas() Lib.List[Form] { - return Lib.MkListV(a.GetForm()) -} - -func (e AllType) ReplaceMetaByTerm(meta Meta, term Term) Form { - return MakeAllType(e.GetIndex(), e.GetVarList(), e.GetForm().ReplaceMetaByTerm(meta, term)) -} - // ----------------------------------------------------------------------------- // Or @@ -367,10 +227,6 @@ func (o Or) GetMetas() Lib.Set[Meta] { return o.metas.Get(o) } -func (o Or) GetType() TypeScheme { - return DefaultPropType(0) -} - func (o Or) GetSubTerms() Lib.List[Term] { res := Lib.NewList[Term]() @@ -414,10 +270,6 @@ func (o Or) GetChildrenForMappedString() []MappableString { return LsToMappableStringSlice(o.GetChildFormulas()) } -func (o Or) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakeOr(o.GetIndex(), replaceList(o.forms, varList, index)) -} - func (o Or) ReplaceTermByTerm(old Term, new Term) (Form, bool) { formList, res := replaceTermInFormList(o.forms, old, new) no := MakeOrSimple(o.GetIndex(), formList, o.metas.Raw()) @@ -508,10 +360,6 @@ func (a And) GetMetas() Lib.Set[Meta] { return a.metas.Get(a) } -func (a And) GetType() TypeScheme { - return DefaultPropType(0) -} - func (a And) GetSubTerms() Lib.List[Term] { res := Lib.NewList[Term]() @@ -558,10 +406,6 @@ func (a And) GetChildrenForMappedString() []MappableString { return LsToMappableStringSlice(a.GetChildFormulas()) } -func (a And) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakeAnd(a.GetIndex(), replaceList(a.forms, varList, index)) -} - func (a And) ReplaceTermByTerm(old Term, new Term) (Form, bool) { varList, res := replaceTermInFormList(a.forms, old, new) na := MakeAndSimple(a.index, varList, a.metas.Raw()) @@ -662,8 +506,7 @@ func (e Equ) GetMetas() Lib.Set[Meta] { return e.metas.Get(e) } -func (e Equ) GetType() TypeScheme { return DefaultPropType(0) } -func (e Equ) ToString() string { return e.ToMappedString(DefaultMapString, true) } +func (e Equ) ToString() string { return e.ToMappedString(DefaultMapString, true) } func (e Equ) Equals(f any) bool { oth, isEqu := f.(Equ) @@ -671,10 +514,6 @@ func (e Equ) Equals(f any) bool { e.f1.Equals(oth.f1) && e.f2.Equals(oth.f2) } -func (e Equ) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakeEqu(e.GetIndex(), e.GetF1().ReplaceTypeByMeta(varList, index), e.GetF2().ReplaceTypeByMeta(varList, index)) -} - func (e Equ) ReplaceTermByTerm(old Term, new Term) (Form, bool) { f1, res1 := e.GetF1().ReplaceTermByTerm(old, new) f2, res2 := e.GetF2().ReplaceTermByTerm(old, new) @@ -785,8 +624,7 @@ func (i Imp) GetMetas() Lib.Set[Meta] { return i.metas.Get(i) } -func (i Imp) GetType() TypeScheme { return DefaultPropType(0) } -func (i Imp) ToString() string { return i.ToMappedString(DefaultMapString, true) } +func (i Imp) ToString() string { return i.ToMappedString(DefaultMapString, true) } func (i Imp) Equals(other any) bool { if typed, ok := other.(Imp); ok { @@ -796,10 +634,6 @@ func (i Imp) Equals(other any) bool { return false } -func (i Imp) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakeImp(i.GetIndex(), i.GetF1().ReplaceTypeByMeta(varList, index), i.GetF2().ReplaceTypeByMeta(varList, index)) -} - func (i Imp) ReplaceTermByTerm(old Term, new Term) (Form, bool) { f1, res1 := i.GetF1().ReplaceTermByTerm(old, new) f2, res2 := i.GetF2().ReplaceTermByTerm(old, new) @@ -884,10 +718,6 @@ func (n Not) GetMetas() Lib.Set[Meta] { return n.metas.Get(n) } -func (n Not) GetType() TypeScheme { - return DefaultPropType(0) -} - func (n Not) GetSubTerms() Lib.List[Term] { return n.GetForm().GetSubTerms() } @@ -924,10 +754,6 @@ func (n Not) GetChildrenForMappedString() []MappableString { return LsToMappableStringSlice(n.GetChildFormulas()) } -func (n Not) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakeNot(n.GetIndex(), n.f.ReplaceTypeByMeta(varList, index)) -} - func (n Not) ReplaceTermByTerm(old Term, new Term) (Form, bool) { f, res := n.f.ReplaceTermByTerm(old, new) @@ -998,37 +824,24 @@ func getDeepFormWithoutNot(form Form, isEven bool) (Form, bool) { type Pred struct { *MappedString - index int - id Id - args Lib.List[Term] - typeVars []TypeApp - typeHint TypeScheme - metas Lib.Cache[Lib.Set[Meta], Pred] + index int + id Id + args Lib.List[Term] + metas Lib.Cache[Lib.Set[Meta], Pred] } func MakePredSimple( index int, id Id, terms Lib.List[Term], - typeApps []TypeApp, metas Lib.Set[Meta], - typeSchemes ...TypeScheme, ) Pred { - var ts TypeScheme - // FIXME: this condition is very suspect - if len(typeSchemes) == 1 { - ts = typeSchemes[0] - } else { - ts = DefaultPropType(terms.Len()) - } fms := &MappedString{} pred := Pred{ fms, index, id, terms, - typeApps, - ts, Lib.MkCache(metas, Pred.forceGetMetas), } fms.MappableString = &pred @@ -1039,26 +852,20 @@ func MakePred( index int, id Id, terms Lib.List[Term], - typeApps []TypeApp, - typeSchemes ...TypeScheme, ) Pred { return MakePredSimple( index, id, terms, - typeApps, Lib.EmptySet[Meta](), - typeSchemes..., ) } func MakerPred( id Id, terms Lib.List[Term], - typeApps []TypeApp, - typeSchemes ...TypeScheme, ) Pred { - return MakePred(MakerIndexFormula(), id, terms, typeApps, typeSchemes...) + return MakePred(MakerIndexFormula(), id, terms) } /* Pred attributes getters */ @@ -1066,11 +873,9 @@ func MakerPred( func (p Pred) GetIndex() int { return p.index } func (p Pred) GetID() Id { return p.id.Copy().(Id) } func (p Pred) GetArgs() Lib.List[Term] { return p.args } -func (p Pred) GetTypeVars() []TypeApp { return CopyTypeAppList(p.typeVars) } /* Formula methods */ -func (p Pred) GetType() TypeScheme { return p.typeHint } func (p Pred) RenameVariables() Form { return p } func (p Pred) ToString() string { @@ -1078,16 +883,11 @@ func (p Pred) ToString() string { } func (p Pred) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - if len(p.typeVars) == 0 && p.GetArgs().Len() == 0 { + if p.GetArgs().Len() == 0 { return p.GetID().ToMappedString(mapping, displayTypes) + "%s" } args := []string{} - if len(p.typeVars) > 0 { - if tv := Glob.ListToString(p.typeVars, ", ", mapping[PredEmpty]); tv != "" { - args = append(args, tv) - } - } args = append(args, "%s") if p.GetID().GetName() == "=" { @@ -1115,9 +915,7 @@ func (p Pred) Copy() Form { p.index, p.id, p.GetArgs(), - CopyTypeAppList(p.GetTypeVars()), p.metas.Raw().Copy(), - p.GetType(), ) if !p.metas.NeedsUpd() { @@ -1129,10 +927,7 @@ func (p Pred) Copy() Form { func (p Pred) Equals(other any) bool { if typed, ok := other.(Pred); ok { - return typed.id.Equals(p.id) && - Lib.ComparableList[TypeApp](p.typeVars).Equals(typed.typeVars) && - Lib.ListEquals(typed.args, p.args) && - p.typeHint.Equals(typed.typeHint) + return typed.id.Equals(p.id) && Lib.ListEquals(typed.args, p.args) } return false @@ -1167,15 +962,6 @@ func (p Pred) GetMetaList() Lib.List[Meta] { return metas } -func (p Pred) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakePred( - p.GetIndex(), - p.GetID(), - replaceTermListTypesByMeta(p.GetArgs(), varList, index), - instanciateTypeAppList(p.typeVars, varList, index), p.GetType(), - ) -} - func (p Pred) ReplaceTermByTerm(old Term, new Term) (Form, bool) { termList, res := replaceTermInTermList(p.GetArgs(), old, new) @@ -1183,9 +969,7 @@ func (p Pred) ReplaceTermByTerm(old Term, new Term) (Form, bool) { p.GetIndex(), p.GetID(), termList, - p.GetTypeVars(), p.metas.Raw(), - p.GetType(), ) if !res && !p.metas.NeedsUpd() { @@ -1216,9 +1000,7 @@ func (p Pred) SubstituteVarByMeta(old Var, new Meta) Form { nf.index, nf.id, nf.args, - nf.typeVars, nf.metas.Raw(), - nf.typeHint, ) } return nf @@ -1249,7 +1031,7 @@ func (p Pred) ReplaceMetaByTerm(meta Meta, term Term) Form { } } - return MakePred(p.GetIndex(), p.id, newTerms, p.typeVars, p.GetType()) + return MakePred(p.GetIndex(), p.id, newTerms) } // ----------------------------------------------------------------------------- @@ -1283,11 +1065,9 @@ func (t Top) GetChildrenForMappedString() []MappableString { return LsToMappableStringSlice(t.GetChildFormulas()) } -func (t Top) GetType() TypeScheme { return DefaultPropType(0) } func (t Top) Copy() Form { return MakeTop(t.GetIndex()) } func (Top) Equals(f any) bool { _, isTop := f.(Top); return isTop } func (Top) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } -func (t Top) ReplaceTypeByMeta([]TypeVar, int) Form { return MakeTop(t.GetIndex()) } func (t Top) ReplaceTermByTerm(Term, Term) (Form, bool) { return MakeTop(t.GetIndex()), false } func (t Top) RenameVariables() Form { return MakeTop(t.GetIndex()) } func (t Top) GetIndex() int { return t.index } @@ -1327,11 +1107,9 @@ func (b Bot) GetChildrenForMappedString() []MappableString { return LsToMappableStringSlice(b.GetChildFormulas()) } -func (b Bot) GetType() TypeScheme { return DefaultPropType(0) } func (b Bot) Copy() Form { return MakeBot(b.GetIndex()) } func (Bot) Equals(f any) bool { _, isBot := f.(Bot); return isBot } func (Bot) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } -func (b Bot) ReplaceTypeByMeta([]TypeVar, int) Form { return MakeBot(b.GetIndex()) } func (b Bot) ReplaceTermByTerm(Term, Term) (Form, bool) { return MakeBot(b.GetIndex()), false } func (b Bot) RenameVariables() Form { return MakeBot(b.GetIndex()) } func (b Bot) GetIndex() int { return b.index } diff --git a/src/AST/formula.go b/src/AST/formula.go index 0b50c2f6..0a1b37d5 100644 --- a/src/AST/formula.go +++ b/src/AST/formula.go @@ -46,7 +46,6 @@ import ( type Form interface { GetIndex() int GetMetas() Lib.Set[Meta] - GetType() TypeScheme GetSubTerms() Lib.List[Term] GetSubFormulasRecur() Lib.List[Form] GetChildFormulas() Lib.List[Form] @@ -54,7 +53,6 @@ type Form interface { Lib.Copyable[Form] MappableString - ReplaceTypeByMeta([]TypeVar, int) Form ReplaceTermByTerm(old Term, new Term) (Form, bool) RenameVariables() Form SubstituteVarByMeta(old Var, new Meta) Form @@ -92,8 +90,6 @@ func replaceTermInTermList( newTermList.Upd(i, MakerFun( nf.GetP(), termList, - nf.GetTypeVars(), - nf.GetTypeHint(), )) res = res || r } @@ -142,16 +138,6 @@ func metasUnion(forms Lib.List[Form]) Lib.Set[Meta] { return res } -func replaceList(oldForms Lib.List[Form], vars []TypeVar, index int) Lib.List[Form] { - newForms := Lib.MkList[Form](oldForms.Len()) - - for i, form := range oldForms.GetSlice() { - newForms.Upd(i, form.ReplaceTypeByMeta(vars, index)) - } - - return newForms -} - // Returns whether the term has been replaced in a subformula or not func replaceTermInFormList(oldForms Lib.List[Form], oldTerm Term, newTerm Term) (Lib.List[Form], bool) { newForms := Lib.MkList[Form](oldForms.Len()) diff --git a/src/AST/maker.go b/src/AST/maker.go index 1289206e..a514c277 100644 --- a/src/AST/maker.go +++ b/src/AST/maker.go @@ -68,12 +68,11 @@ func Init() { Reset() initTypes() Id_eq = MakerId("=") - EmptyPredEq = MakerPred(Id_eq, Lib.NewList[Term](), make([]TypeApp, 0)) + EmptyPredEq = MakerPred(Id_eq, Lib.NewList[Term]()) // Eq/Neq types - tv := MkTypeVar("α") - scheme := MkQuantifiedType([]TypeVar{tv}, MkTypeArrow(MkTypeCross(tv, tv), tv)) - SavePolymorphScheme(Id_eq.GetName(), scheme) + // FIXME: Register the type of equality in the global context + // --- (call an internal function like SaveEqType()) initDefaultMap() } @@ -113,28 +112,28 @@ func MakerNewId(s string) Id { } /* Var maker */ -func MakerVar(s string, t ...TypeApp) Var { +func MakerVar(s string) Var { lock_term.Lock() i, ok := idVar[s] lock_term.Unlock() if ok { - return MakeVar(i, s, getType(t)) + return MakeVar(i, s) } else { - return MakerNewVar(s, getType(t)) + return MakerNewVar(s) } } -func MakerNewVar(s string, t ...TypeApp) Var { +func MakerNewVar(s string) Var { lock_term.Lock() idVar[s] = cpt_term - vr := MakeVar(cpt_term, s, getType(t)) + vr := MakeVar(cpt_term, s) cpt_term += 1 lock_term.Unlock() return vr } /* Meta maker */ -func MakerMeta(s string, formula int, t ...TypeApp) Meta { +func MakerMeta(s string, formula int) Meta { lock_term.Lock() i, ok := occurenceMeta[s] lock_term.Unlock() @@ -144,39 +143,25 @@ func MakerMeta(s string, formula int, t ...TypeApp) Meta { new_index := cpt_term cpt_term += 1 lock_term.Unlock() - return MakeMeta(new_index, i, s, formula, getType(t)) + return MakeMeta(new_index, i, s, formula) } else { lock_term.Lock() occurenceMeta[s] = 1 new_index := cpt_term cpt_term += 1 lock_term.Unlock() - return MakeMeta(new_index, 0, s, formula, getType(t)) + return MakeMeta(new_index, 0, s, formula) } } /* Const maker (given a id, create a fun without args) */ -func MakerConst(id Id, t ...TypeApp) Fun { - return MakeFun(id, Lib.NewList[Term](), []TypeApp{}, getType(t).(TypeScheme), Lib.EmptySet[Meta]()) +func MakerConst(id Id) Fun { + return MakeFun(id, Lib.NewList[Term](), Lib.EmptySet[Meta]()) } /* Fun maker, with given id and args */ -func MakerFun(id Id, terms Lib.List[Term], typeVars []TypeApp, t ...TypeScheme) Fun { - var ts TypeScheme - if len(t) == 1 { - ts = t[0] - } else { - ts = DefaultFunType(terms.Len()) - } - return MakeFun(id, terms, typeVars, ts, Lib.EmptySet[Meta]()) -} - -func getType(t []TypeApp) TypeApp { - if len(t) == 1 { - return t[0] - } else { - return DefaultType() - } +func MakerFun(id Id, terms Lib.List[Term]) Fun { + return MakeFun(id, terms, Lib.EmptySet[Meta]()) } /* Index make for formula */ diff --git a/src/AST/quantifiers.go b/src/AST/quantifiers.go index 6872063e..e6d3e009 100644 --- a/src/AST/quantifiers.go +++ b/src/AST/quantifiers.go @@ -40,7 +40,6 @@ import ( "fmt" "strings" - "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" ) @@ -109,33 +108,11 @@ func ChangeVarSeparator(sep string) string { } func (q quantifier) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - type VarType struct { - vars []Var - type_ TypeApp - } - - varsType := []VarType{} - for _, v := range q.GetVarList() { - found := false - for _, vt := range varsType { - if vt.type_.Equals(v.GetTypeApp()) { - vt.vars = append(vt.vars, v) - found = true - } - } - if !found { - varsType = append(varsType, VarType{[]Var{v}, v.GetTypeApp()}) - } - } - varStrings := []string{} - for _, vt := range varsType { + for _ = range q.GetVarList() { str := mapping[QuantVarOpen] str += ListToMappedString(q.GetVarList(), varSeparator, "", mapping, false) - if displayTypes || Glob.IsRocqOutput() { - str += " : " + vt.type_.ToString() - } varStrings = append(varStrings, str+mapping[QuantVarClose]) } @@ -178,16 +155,6 @@ func (q quantifier) copy() quantifier { return nq } -func (q quantifier) replaceTypeByMeta(varList []TypeVar, index int) quantifier { - return makeQuantifier( - q.GetIndex(), - q.GetVarList(), - q.GetForm().ReplaceTypeByMeta(varList, index), - q.metas.Raw().Copy(), - q.symbol, - ) -} - func (q quantifier) replaceTermByTerm(old Term, new Term) (quantifier, bool) { f, res := q.GetForm().ReplaceTermByTerm(old, new) return makeQuantifier( @@ -205,7 +172,7 @@ func (q quantifier) renameVariables() quantifier { for _, v := range q.GetVarList() { newVar := MakerNewVar(v.GetName()) - newVar = MakerVar(fmt.Sprintf("%s%d", newVar.GetName(), newVar.GetIndex()), v.typeHint) + newVar = MakerVar(fmt.Sprintf("%s%d", newVar.GetName(), newVar.GetIndex())) newVarList = append(newVarList, newVar) newForm, _ = newForm.RenameVariables().ReplaceTermByTerm(v, newVar) } diff --git a/src/AST/term.go b/src/AST/term.go index 87d0a729..6b4160d6 100644 --- a/src/AST/term.go +++ b/src/AST/term.go @@ -37,7 +37,6 @@ package AST import ( - "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" ) @@ -57,11 +56,6 @@ type Term interface { Less(any) bool } -type TypedTerm interface { - GetTypeHint() TypeScheme - GetTypeApp() TypeApp -} - /*** Makers ***/ func MakeId(i int, s string) Id { fms := &MappedString{} @@ -77,123 +71,28 @@ func MakeQuotedId(i int, s string) Id { return id } -func MakeVar(i int, s string, t ...TypeApp) Var { +func MakeVar(i int, s string) Var { fms := &MappedString{} - newVar := Var{fms, i, s, getType(t)} + newVar := Var{fms, i, s} fms.MappableString = &newVar return newVar } -func MakeMeta(index, occurence int, s string, f int, t ...TypeApp) Meta { +func MakeMeta(index, occurence int, s string, f int) Meta { fms := &MappedString{} - meta := Meta{fms, index, occurence, s, f, getType(t)} + meta := Meta{fms, index, occurence, s, f} fms.MappableString = &meta return meta } -func MakeFun(p Id, args Lib.List[Term], typeVars []TypeApp, t TypeScheme, metas Lib.Set[Meta]) Fun { +func MakeFun(p Id, args Lib.List[Term], metas Lib.Set[Meta]) Fun { fms := &MappedString{} - fun := Fun{fms, p, args, typeVars, t, Lib.MkCache(metas, Fun.forceGetMetas)} + fun := Fun{fms, p, args, Lib.MkCache(metas, Fun.forceGetMetas)} fms.MappableString = fun return fun } -/*** Functions ***/ - -func TypeAppArrToTerm(typeApps []TypeApp) Lib.List[Term] { - terms := Lib.MkList[Term](len(typeApps)) - - for i, typeApp := range typeApps { - terms.Upd(i, TypeAppToTerm(typeApp)) - } - - return terms -} - -/* Creates a Term from a TypeApp to unify it properly */ -func TypeAppToTerm(typeApp TypeApp) Term { - var term Term - switch nt := typeApp.(type) { - case TypeVar: - if nt.IsMeta() { - term = typeVarToMeta(nt) - } else { - Glob.Fatal("TERM", "A TypeVar should be only converted to terms if it has been instantiated.") - term = nil - } - case TypeHint: - term = MakerFun( - MakerId(nt.ToString()), - Lib.NewList[Term](), - []TypeApp{}, - MkTypeHint("$tType"), - ) - case TypeCross: - underlyingTypes := nt.GetAllUnderlyingTypes() - args := Lib.MkList[Term](len(underlyingTypes)) - - for i, type_ := range nt.GetAllUnderlyingTypes() { - args.Upd(i, TypeAppToTerm(type_)) - } - - term = MakeFun( - MakerId("$$tCross"), - args, - []TypeApp{}, - MkTypeHint("$tType"), - Lib.EmptySet[Meta](), - ) - case ParameterizedType: - parameters := nt.GetParameters() - args := Lib.MkList[Term](len(parameters)) - - for i, type_ := range nt.GetParameters() { - args.Upd(i, TypeAppToTerm(type_)) - } - - term = MakeFun( - MakerId(nt.ToString()), - args, - []TypeApp{}, - MkTypeHint("$tType"), - Lib.EmptySet[Meta](), - ) - } - return term -} - -func typeVarToMeta(typeVar TypeVar) Meta { - var meta Meta - index, formula, occurence := typeVar.MetaInfos() - if !typeVar.Instantiated() { - meta = MakerMeta(typeVar.ToString(), formula, MkTypeHint("$tType")) - typeVar.Instantiate(meta.index) - } else { - meta = MakeMeta(index, occurence, typeVar.ToString(), formula, MkTypeHint("$tType")) - } - return meta -} - -func replaceTermListTypesByMeta(tl Lib.List[Term], varList []TypeVar, index int) Lib.List[Term] { - res := Lib.MkList[Term](tl.Len()) - - for i, term := range tl.GetSlice() { - if Glob.Is[Fun](term) { - t := Glob.To[Fun](term) - res.Upd(i, MakeFun( - t.GetID(), - replaceTermListTypesByMeta(t.GetArgs(), varList, index), - instanciateTypeAppList(t.GetTypeVars(), varList, index), - t.GetTypeHint(), - t.metas.Raw(), - )) - } else { - res.Upd(i, term) - } - } - - return res -} +/*** Functions **/ func TermEquals(x, y Term) bool { return x.Equals(y) diff --git a/src/AST/termsDef.go b/src/AST/termsDef.go index 8b240000..544c2aff 100644 --- a/src/AST/termsDef.go +++ b/src/AST/termsDef.go @@ -146,11 +146,9 @@ func (i Id) Less(u any) bool { type Fun struct { *MappedString - p Id - args Lib.List[Term] - typeVars []TypeApp - typeHint TypeScheme - metas Lib.Cache[Lib.Set[Meta], Fun] + p Id + args Lib.List[Term] + metas Lib.Cache[Lib.Set[Meta], Fun] } func (f Fun) ToMappedStringSurround(mapping MapString, displayTypes bool) string { @@ -162,44 +160,25 @@ func (f Fun) ToMappedStringChild(mapping MapString, displayTypes bool) (separato } func (f Fun) ToMappedStringSurroundWithId(idString string, mapping MapString, displayTypes bool) string { - if len(f.typeVars) == 0 && f.GetArgs().Len() == 0 { + if f.GetArgs().Len() == 0 { return idString + "%s" } args := []string{} - - if len(f.typeVars) > 0 { - if tv := Glob.ListToString(f.typeVars, ", ", mapping[PredEmpty]); tv != "" { - args = append(args, tv) - } - } args = append(args, "%s") str := idString + "(" + strings.Join(args, mapping[PredTypeVarSep]) + ")" - if displayTypes { - str += " : " + f.typeHint.ToString() - } return str } func ToFlatternStringSurrountWithId(f Fun, idString string, mapping MapString, displayTypes bool) string { - - if len(f.typeVars) == 0 && f.GetArgs().Len() == 0 { + if f.GetArgs().Len() == 0 { return idString + "%s" } args := []string{} - - if len(f.typeVars) > 0 { - if tv := Glob.ListToString(f.typeVars, "_", mapping[PredEmpty]); tv != "" { - args = append(args, tv) - } - } args = append(args, "%s") str := idString + "_" + strings.Join(args, mapping[PredTypeVarSep]) - if displayTypes { - str += " : " + f.typeHint.ToString() - } return str } @@ -213,39 +192,33 @@ func (f Fun) GetID() Id { return f.p.Copy().(Id) } func (f Fun) GetP() Id { return f.p.Copy().(Id) } func (f Fun) GetArgs() Lib.List[Term] { return f.args } -func (f *Fun) SetArgs(tl Lib.List[Term]) { f.args = tl } -func (f *Fun) SetTypeScheme(ts TypeScheme) { f.typeHint = ts } +func (f *Fun) SetArgs(tl Lib.List[Term]) { f.args = tl } -func (f Fun) GetTypeVars() []TypeApp { return f.typeVars } -func (f Fun) GetTypeApp() TypeApp { return nil } -func (f Fun) GetTypeHint() TypeScheme { return f.typeHint } -func (f Fun) GetIndex() int { return f.GetID().GetIndex() } -func (f Fun) GetName() string { return f.GetID().GetName() } -func (f Fun) IsMeta() bool { return false } -func (f Fun) IsFun() bool { return true } -func (Fun) ToMeta() Meta { return MakeEmptyMeta() } +func (f Fun) GetIndex() int { return f.GetID().GetIndex() } +func (f Fun) GetName() string { return f.GetID().GetName() } +func (f Fun) IsMeta() bool { return false } +func (f Fun) IsFun() bool { return true } +func (Fun) ToMeta() Meta { return MakeEmptyMeta() } func (f Fun) Equals(t any) bool { switch typed := t.(type) { case Fun: return typed.GetID().Equals(f.GetID()) && - Lib.ListEquals(typed.GetArgs(), f.GetArgs()) && - f.typeHint.Equals(typed.typeHint) + Lib.ListEquals(typed.GetArgs(), f.GetArgs()) case *Fun: return typed.GetID().Equals(f.GetID()) && - Lib.ListEquals(typed.GetArgs(), f.GetArgs()) && - f.typeHint.Equals(typed.typeHint) + Lib.ListEquals(typed.GetArgs(), f.GetArgs()) default: return false } } func (f Fun) Copy() Term { - return MakeFun(f.GetP(), f.GetArgs(), CopyTypeAppList(f.GetTypeVars()), f.GetTypeHint(), f.metas.Raw()) + return MakeFun(f.GetP(), f.GetArgs(), f.metas.Raw()) } func (f Fun) PointerCopy() *Fun { - nf := MakeFun(f.GetP(), f.GetArgs(), CopyTypeAppList(f.GetTypeVars()), f.GetTypeHint(), f.metas.Raw()) + nf := MakeFun(f.GetP(), f.GetArgs(), f.metas.Raw()) return &nf } @@ -283,7 +256,7 @@ func (f Fun) ReplaceSubTermBy(oldTerm, newTerm Term) Term { return newTerm.Copy() } else { tl, res := replaceFirstOccurrenceTermList(f.GetArgs(), oldTerm, newTerm) - nf := MakeFun(f.GetID(), tl, f.GetTypeVars(), f.GetTypeHint(), f.metas.Raw()) + nf := MakeFun(f.GetID(), tl, f.metas.Raw()) if !res && !f.metas.NeedsUpd() { nf.metas.AvoidUpd() } @@ -296,7 +269,7 @@ func (f Fun) ReplaceAllSubTerm(oldTerm, newTerm Term) Term { return newTerm.Copy() } else { tl, res := ReplaceOccurrence(f.GetArgs(), oldTerm, newTerm) - nf := MakeFun(f.GetID(), tl, f.GetTypeVars(), f.GetTypeHint(), f.metas.Raw()) + nf := MakeFun(f.GetID(), tl, f.metas.Raw()) if !res && !f.metas.NeedsUpd() { nf.metas.AvoidUpd() } @@ -330,18 +303,15 @@ func (f Fun) Less(u any) bool { type Var struct { *MappedString - index int - name string - typeHint TypeApp + index int + name string } -func (v Var) GetTypeApp() TypeApp { return v.typeHint } -func (v Var) GetTypeHint() TypeScheme { return v.typeHint.(TypeScheme) } func (v Var) GetIndex() int { return v.index } func (v Var) GetName() string { return v.name } func (v Var) IsMeta() bool { return false } func (v Var) IsFun() bool { return false } -func (v Var) Copy() Term { return MakeVar(v.GetIndex(), v.GetName(), v.typeHint) } +func (v Var) Copy() Term { return MakeVar(v.GetIndex(), v.GetName()) } func (Var) ToMeta() Meta { return MakeEmptyMeta() } func (Var) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } func (Var) GetMetaList() Lib.List[Meta] { return Lib.NewList[Meta]() } @@ -366,7 +336,7 @@ func (v Var) ReplaceSubTermBy(original_term, new_term Term) Term { func (v Var) ToMappedString(map_ MapString, type_ bool) string { if type_ { - return fmt.Sprintf("%s_%d : %s", v.GetName(), v.GetIndex(), v.typeHint.ToString()) + return fmt.Sprintf("%s_%d : %s", v.GetName(), v.GetIndex()) } return v.GetName() } @@ -377,7 +347,7 @@ func (v Var) ToMappedStringSurround(mapping MapString, displayTypes bool) string func (v Var) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { if displayTypes { - return "", fmt.Sprintf("%s_%d : %s", v.GetName(), v.GetIndex(), v.typeHint.ToString()) + return "", fmt.Sprintf("%s_%d : %s", v.GetName(), v.GetIndex()) } else { return "", v.GetName() } @@ -406,13 +376,11 @@ type Meta struct { occurence int name string formula int - typeHint TypeApp + // FIXME: remember the type of a Meta } func (m Meta) GetFormula() int { return m.formula } -func (m Meta) GetTypeApp() TypeApp { return m.typeHint } -func (m Meta) GetTypeHint() TypeScheme { return m.typeHint.(TypeScheme) } func (m Meta) GetName() string { return m.name } func (m Meta) GetIndex() int { return m.index } func (m Meta) GetOccurence() int { return m.occurence } @@ -428,7 +396,7 @@ func (m Meta) ToMappedStringSurround(mapping MapString, displayTypes bool) strin func (m Meta) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { if displayTypes { - return "", fmt.Sprintf("%s_%d : %s", m.GetName(), m.GetIndex(), m.GetTypeHint().ToString()) + return "", fmt.Sprintf("%s_%d : %s", m.GetName(), m.GetIndex()) } else { return "", fmt.Sprintf("%s_%d", m.GetName(), m.GetIndex()) } @@ -446,7 +414,7 @@ func (m Meta) Equals(t any) bool { } func (m Meta) Copy() Term { - return MakeMeta(m.GetIndex(), m.GetOccurence(), m.GetName(), m.GetFormula(), m.GetTypeApp()) + return MakeMeta(m.GetIndex(), m.GetOccurence(), m.GetName(), m.GetFormula()) } func (m Meta) ReplaceSubTermBy(original_term, new_term Term) Term { @@ -471,7 +439,7 @@ func (m Meta) Less(u any) bool { } func MakeEmptyMeta() Meta { - return MakeMeta(-1, -1, "-1", -1, nil, DefaultType()) + return MakeMeta(-1, -1, "-1", -1) } func MetaEquals(x, y Meta) bool { diff --git a/src/Core/Sko/inner-skolemization.go b/src/Core/Sko/inner-skolemization.go index 4d3d9ac8..93abe49d 100644 --- a/src/Core/Sko/inner-skolemization.go +++ b/src/Core/Sko/inner-skolemization.go @@ -63,7 +63,7 @@ func (sko InnerSkolemization) Skolemize( _ Lib.Set[AST.Meta], ) (Skolemization, AST.Form) { sko.mu.Lock() - symbol := genFreshSymbol(&sko.existingSymbols, sko.mu, x) + symbol := genFreshSymbol(&sko.existingSymbols, &sko.mu, x) sko.mu.Unlock() internalMetas := form.GetMetas().Elements() @@ -71,8 +71,6 @@ func (sko InnerSkolemization) Skolemize( skolemFunc := AST.MakerFun( symbol, Lib.ListMap(internalMetas, Glob.To[AST.Term]), - []AST.TypeApp{}, - mkSkoFuncType(internalMetas, x.GetTypeApp()), ) skolemizedForm, _ := form.ReplaceTermByTerm( diff --git a/src/Core/Sko/interface.go b/src/Core/Sko/interface.go index a79ba10e..984e345f 100644 --- a/src/Core/Sko/interface.go +++ b/src/Core/Sko/interface.go @@ -37,7 +37,6 @@ import ( "sync" "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" ) @@ -59,40 +58,10 @@ type Skolemization interface { ) (Skolemization, AST.Form) } -func mkSkoFuncType( - relevantMetas Lib.List[AST.Meta], - varType AST.TypeApp, -) AST.TypeScheme { - var resultingScheme AST.TypeScheme - - switch relevantMetas.Len() { - case 0: - if typ, ok := varType.(AST.TypeScheme); ok { - resultingScheme = typ - } else { - Glob.Anomaly("Skolemization", "Variable has an illegal type") - } - case 1: - metaType := relevantMetas.At(0).GetTypeApp() - resultingScheme = AST.MkTypeArrow(metaType, varType) - default: - argTypes := Lib.ListMap( - relevantMetas, - func(x AST.Meta) AST.TypeApp { return x.GetTypeApp() }, - ) - resultingScheme = AST.MkTypeArrow( - AST.MkTypeCross(argTypes.GetSlice()...), - varType, - ) - } - - return resultingScheme -} - /* If every Skolem symbol is created using this function, then it will generate * a fresh symbol for sure. Otherwise, nothing is guaranteed. */ -func genFreshSymbol(existingSymbols *Lib.Set[AST.Id], mu sync.Mutex, x AST.Var) AST.Id { +func genFreshSymbol(existingSymbols *Lib.Set[AST.Id], mu *sync.Mutex, x AST.Var) AST.Id { symbol := AST.MakerNewId( fmt.Sprintf("skolem@%v", x.GetName()), ) diff --git a/src/Core/Sko/outer-skolemization.go b/src/Core/Sko/outer-skolemization.go index 14c7bfa9..1e199fe4 100644 --- a/src/Core/Sko/outer-skolemization.go +++ b/src/Core/Sko/outer-skolemization.go @@ -63,7 +63,7 @@ func (sko OuterSkolemization) Skolemize( fvs Lib.Set[AST.Meta], ) (Skolemization, AST.Form) { sko.mu.Lock() - symbol := genFreshSymbol(&sko.existingSymbols, sko.mu, x) + symbol := genFreshSymbol(&sko.existingSymbols, &sko.mu, x) sko.mu.Unlock() metas := fvs.Elements() @@ -71,8 +71,6 @@ func (sko OuterSkolemization) Skolemize( skolemFunc := AST.MakerFun( symbol, Lib.ListMap(metas, Glob.To[AST.Term]), - []AST.TypeApp{}, - mkSkoFuncType(metas, x.GetTypeApp()), ) skolemizedForm, _ := form.ReplaceTermByTerm( diff --git a/src/Core/Sko/preinner-skolemization.go b/src/Core/Sko/preinner-skolemization.go index 8ac9fab2..84e36676 100644 --- a/src/Core/Sko/preinner-skolemization.go +++ b/src/Core/Sko/preinner-skolemization.go @@ -75,7 +75,7 @@ func (sko PreInnerSkolemization) Skolemize( ); ok { symbol = val.Snd } else { - symbol = genFreshSymbol(&sko.existingSymbols, sko.mu, x) + symbol = genFreshSymbol(&sko.existingSymbols, &sko.mu, x) sko.linkedSymbols.Append(Glob.MakePair(realDelta, symbol)) } sko.mu.Unlock() @@ -85,8 +85,6 @@ func (sko PreInnerSkolemization) Skolemize( skolemFunc := AST.MakerFun( symbol, Lib.ListMap(internalMetas, Glob.To[AST.Term]), - []AST.TypeApp{}, - mkSkoFuncType(internalMetas, x.GetTypeApp()), ) skolemizedForm, _ := form.ReplaceTermByTerm( @@ -118,8 +116,6 @@ func alphaConvert( f.GetIndex(), f.GetID(), mappedTerms, - f.GetTypeVars(), - f.GetType(), ) case AST.Not: return AST.MakeNot( @@ -164,6 +160,10 @@ func alphaConvert( k, substitution, vl := makeConvertedVarList(k, substitution, f.GetVarList()) return AST.MakeEx(f.GetIndex(), vl, alphaConvert(f.GetForm(), k, substitution)) } + Glob.Anomaly( + "preinner", + fmt.Sprintf("On alpha-conversion of %s: form does not correspond to any known ones", form.ToString()), + ) return form } @@ -174,7 +174,7 @@ func makeConvertedVarList( ) (int, map[int]AST.Var, []AST.Var) { newVarList := []AST.Var{} for i, v := range vl { - nv := AST.MakeVar(k+i, fresh(k+i), v.GetTypeApp()) + nv := AST.MakeVar(k+i, fresh(k+i)) newVarList = append(newVarList, nv) substitution[v.GetIndex()] = nv } @@ -197,8 +197,6 @@ func alphaConvertTerm(t AST.Term, substitution map[int]AST.Var) AST.Term { return AST.MakerFun( nt.GetID(), mappedTerms, - nt.GetTypeVars(), - nt.GetTypeHint(), ) } return t diff --git a/src/Core/instanciation.go b/src/Core/instanciation.go index 44721858..5df870d8 100644 --- a/src/Core/instanciation.go +++ b/src/Core/instanciation.go @@ -71,7 +71,7 @@ func RealInstantiate( terms Lib.List[AST.Term], ) (FormAndTerms, AST.Meta) { v := varList[0] - meta := AST.MakerMeta(strings.ToUpper(v.GetName()), index, v.GetTypeHint().(AST.TypeApp)) + meta := AST.MakerMeta(strings.ToUpper(v.GetName()), index) subForm = subForm.SubstituteVarByMeta(v, meta) terms = terms.Copy(AST.Term.Copy) diff --git a/src/Core/rules_type.go b/src/Core/rules_type.go index f4e9935f..08a399ea 100644 --- a/src/Core/rules_type.go +++ b/src/Core/rules_type.go @@ -37,7 +37,6 @@ package Core import ( "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" ) /******************/ @@ -86,8 +85,6 @@ func ShowKindOfRule(f AST.Form) KindOfRule { res = Gamma case AST.All: res = Delta - case AST.AllType: - Glob.Anomaly("Kind of rule", "not forall(type) found when it shouldn't happen.") } case AST.And: res = Alpha @@ -95,7 +92,7 @@ func ShowKindOfRule(f AST.Form) KindOfRule { res = Beta case AST.Ex: res = Delta - case AST.All, AST.AllType: + case AST.All: res = Gamma } return res diff --git a/src/Core/substitutions_search.go b/src/Core/substitutions_search.go index bfd5fb24..280bf4b3 100644 --- a/src/Core/substitutions_search.go +++ b/src/Core/substitutions_search.go @@ -210,8 +210,6 @@ func ApplySubstitutionOnTerm(old_symbol AST.Meta, new_symbol, t AST.Term) AST.Te res = AST.MakerFun( nf.GetP(), ApplySubstitutionOnTermList(old_symbol, new_symbol, nf.GetArgs()), - nf.GetTypeVars(), - nf.GetTypeHint(), ) } return res @@ -269,14 +267,6 @@ func ApplySubstitutionOnTermList( return res } -func applySubstitutionOnTypeList(old_symbol AST.Meta, new_symbol AST.Term, tl []AST.TypeApp) []AST.TypeApp { - res := make([]AST.TypeApp, len(tl)) - for i, t := range tl { - res[i] = applySubstitutionOnType(old_symbol.GetTypeApp(), new_symbol.(AST.TypedTerm).GetTypeApp(), t) - } - return res -} - /* Apply a substitution on a formula */ func ApplySubstitutionOnFormula(old_symbol AST.Meta, new_symbol AST.Term, f AST.Form) AST.Form { var res AST.Form @@ -287,8 +277,6 @@ func ApplySubstitutionOnFormula(old_symbol AST.Meta, new_symbol AST.Term, f AST. nf.GetIndex(), nf.GetID(), ApplySubstitutionOnTermList(old_symbol, new_symbol, nf.GetArgs()), - applySubstitutionOnTypeList(old_symbol, new_symbol, nf.GetTypeVars()), - nf.GetType(), ) case AST.Not: res = AST.MakeNot(f.GetIndex(), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetForm())) diff --git a/src/Engine/pretyper.go b/src/Engine/pretyper.go index 1b077b51..86c8d69e 100644 --- a/src/Engine/pretyper.go +++ b/src/Engine/pretyper.go @@ -145,11 +145,7 @@ func splitTypeVars( if isTType(ty.Snd.(Parser.PType)) { tyvars = append(tyvars, AST.MkTypeVar(ty.Fst)) } else { - varTy := ty.Snd.(Parser.PType) - others = append( - others, - AST.MakerVar(ty.Fst, elaborateType(varTy, varTy).(AST.TypeApp)), - ) + others = append(others, AST.MakerVar(ty.Fst)) } } return tyvars, others diff --git a/src/Engine/syntax-translation.go b/src/Engine/syntax-translation.go index 0e27ead9..9ad5a737 100644 --- a/src/Engine/syntax-translation.go +++ b/src/Engine/syntax-translation.go @@ -145,16 +145,10 @@ func elaborateForm(con Context, f, source_form Parser.PForm) AST.Form { case Parser.PPred: typed_arguments := pretype(con, pform.Args()) - type_args, real_args := splitTypes(typed_arguments) + _, real_args := splitTypes(typed_arguments) return AST.MakerPred( AST.MakerId(pform.Symbol()), Lib.ListMap(real_args, aux), - Lib.ListMap( - type_args, - func(pty Parser.PType) AST.TypeApp { - return elaborateType(pty, pty).(AST.TypeApp) - }, - ).GetSlice(), ) case Parser.PUnary: @@ -195,9 +189,6 @@ func elaborateForm(con Context, f, source_form Parser.PForm) AST.Form { if len(vars) != 0 { form = AST.MakerAll(vars, form) } - if len(type_vars) != 0 { - form = AST.MakerAllType(type_vars, form) - } return form case Parser.PQuantEx: if len(type_vars) != 0 { @@ -321,25 +312,15 @@ func elaborateTerm(con Context, t, source_term Parser.PTerm) AST.Term { fail(ty) } // FIXME: get some error function over here - return AST.MakerVar(pterm.Name(), elaborateType(t.Val, t.Val).(AST.TypeApp)) + return AST.MakerVar(pterm.Name()) } case Parser.PFun: typed_arguments := pretype(con, pterm.Args()) - type_args, real_args := splitTypes(typed_arguments) + _, real_args := splitTypes(typed_arguments) fun := AST.MakerFun( AST.MakerId(pterm.Symbol()), Lib.ListMap(real_args, aux), - Lib.ListMap( - type_args, - func(pty Parser.PType) AST.TypeApp { - ty := elaborateType(pty, pty) - if _, ok := ty.(AST.TypeApp); !ok { - fail(ty) - } - return elaborateType(pty, pty).(AST.TypeApp) - }, - ).GetSlice(), ) switch oty := pterm.DefinedType().(type) { case Lib.Some[Parser.PTypeFun]: diff --git a/src/Mods/equality/bse/equality_problem_list.go b/src/Mods/equality/bse/equality_problem_list.go index 52d77e74..689b3ad8 100644 --- a/src/Mods/equality/bse/equality_problem_list.go +++ b/src/Mods/equality/bse/equality_problem_list.go @@ -215,8 +215,6 @@ func buildEqualityProblemMultiListFromPredList(pred AST.Pred, tn Unif.DataStruct newTerm := AST.MakerPred( predId.Copy().(AST.Id), AST.MetaListToTermList(metas), - pred.GetTypeVars(), - pred.GetType(), ) found, complementaryPredList := tn.Unify(newTerm) diff --git a/src/Mods/equality/bse/equality_types.go b/src/Mods/equality/bse/equality_types.go index 87de61e0..5c19e667 100644 --- a/src/Mods/equality/bse/equality_types.go +++ b/src/Mods/equality/bse/equality_types.go @@ -124,15 +124,13 @@ func retrieveEqualities(dt Unif.DataStructure) Equalities { MetaEQ2 := AST.MakerMeta("METAEQ2", -1) // TODO: type this tv := AST.MkTypeVar("EQ") - eq_pred := AST.MakerPred(AST.Id_eq, Lib.NewList[AST.Term](), []AST.TypeApp{}) + eq_pred := AST.MakerPred(AST.Id_eq, Lib.NewList[AST.Term]()) tv.ShouldBeMeta(eq_pred.GetIndex()) tv.Instantiate(1) eq_pred = AST.MakePred( eq_pred.GetIndex(), AST.Id_eq, Lib.MkListV[AST.Term](MetaEQ1, MetaEQ2), - []AST.TypeApp{}, - AST.GetPolymorphicType(AST.Id_eq.GetName(), 1, 2), ) _, eq_list := dt.Unify(eq_pred) @@ -156,18 +154,12 @@ func retrieveInequalities(dt Unif.DataStructure) Inequalities { res := Inequalities{} MetaNEQ1 := AST.MakerMeta("META_NEQ_1", -1) MetaNEQ2 := AST.MakerMeta("META_NEQ_2", -1) - // TODO: type this - tv := AST.MkTypeVar("EQ") - neq_pred := AST.MakerPred(AST.Id_eq, Lib.NewList[AST.Term](), []AST.TypeApp{}) - tv.ShouldBeMeta(neq_pred.GetIndex()) - tv.Instantiate(1) + neq_pred := AST.MakerPred(AST.Id_eq, Lib.NewList[AST.Term]()) neq_pred = AST.MakePred( neq_pred.GetIndex(), AST.Id_eq, Lib.MkListV[AST.Term](MetaNEQ1, MetaNEQ2), - []AST.TypeApp{}, - AST.GetPolymorphicType(AST.Id_eq.GetName(), 1, 2), ) _, neq_list := dt.Unify(neq_pred) diff --git a/src/Mods/equality/sateq/subsgatherer.go b/src/Mods/equality/sateq/subsgatherer.go index 3fd60f13..995193a4 100644 --- a/src/Mods/equality/sateq/subsgatherer.go +++ b/src/Mods/equality/sateq/subsgatherer.go @@ -83,7 +83,7 @@ func translate(toTranslate *eqClass, correspondence map[*eqClass]*termRecord) AS for i, s := range tr.args { args.Upd(i, translate(s, correspondence)) } - return AST.MakerFun(tr.symbolId, args, tr.typeVars, tr.typeHint) + return AST.MakerFun(tr.symbolId, args) } } diff --git a/src/Mods/equality/sateq/termrep.go b/src/Mods/equality/sateq/termrep.go index 8d1a2b84..36c8a42a 100644 --- a/src/Mods/equality/sateq/termrep.go +++ b/src/Mods/equality/sateq/termrep.go @@ -130,8 +130,6 @@ func funTermRecord(t AST.Fun, args []*eqClass) *termRecord { meta: nil, symbolId: t.GetID(), args: args, - typeHint: t.GetTypeHint(), - typeVars: t.GetTypeVars(), } } @@ -141,8 +139,6 @@ type termRecord struct { meta *AST.Meta symbolId AST.Id args []*eqClass - typeHint AST.TypeScheme - typeVars []AST.TypeApp } func (t *termRecord) isMeta() bool { diff --git a/src/Mods/gs3/dependency.go b/src/Mods/gs3/dependency.go index 5ca2c2e9..c452b556 100644 --- a/src/Mods/gs3/dependency.go +++ b/src/Mods/gs3/dependency.go @@ -139,8 +139,6 @@ func getVariableOccurrencesForm(v AST.Var, form AST.Form, currentOcc occurrences currentOcc = getUnaryOcc(v, f.GetForm(), currentOcc, workingPath) case AST.Ex: currentOcc = getUnaryOcc(v, f.GetForm(), currentOcc, workingPath) - case AST.AllType: - currentOcc = getUnaryOcc(v, f.GetForm(), currentOcc, workingPath) } return currentOcc } @@ -209,8 +207,6 @@ func getTermAux(form AST.Form, occ occurrence) AST.Term { term = getUnaryTerm(f.GetForm(), occ) case AST.Ex: term = getUnaryTerm(f.GetForm(), occ) - case AST.AllType: - term = getUnaryTerm(f.GetForm(), occ) } return term } diff --git a/src/Mods/lambdapi/context.go b/src/Mods/lambdapi/context.go index b1359413..ca42bd43 100644 --- a/src/Mods/lambdapi/context.go +++ b/src/Mods/lambdapi/context.go @@ -178,8 +178,6 @@ func getContextFromFormula(root AST.Form) []string { result = getContextFromFormula(nf.GetForm()) case AST.Ex: result = getContextFromFormula(nf.GetForm()) - case AST.AllType: - result = getContextFromFormula(nf.GetForm()) case AST.And: for _, f := range nf.GetChildFormulas().GetSlice() { result = append(result, clean(result, getContextFromFormula(f))...) @@ -198,18 +196,7 @@ func getContextFromFormula(root AST.Form) []string { result = append(result, getContextFromFormula(nf.GetForm())...) case AST.Pred: if !nf.GetID().Equals(AST.Id_eq) { - primitives := nf.GetType().GetPrimitives() - typesStr := "" - - for i, prim := range primitives { - if i != len(primitives)-1 { - typesStr += "τ (" + prim.ToString() + ") → " - } else { - typesStr += prim.ToString() - } - } - - result = append(result, mapDefault(fmt.Sprintf("symbol %s : %s;", nf.GetID().ToMappedString(lambdaPiMapConnectors, false), typesStr))) + result = append(result, mapDefault(fmt.Sprintf("symbol %s;", nf.GetID().ToMappedString(lambdaPiMapConnectors, false)))) } for _, term := range nf.GetArgs().GetSlice() { result = append(result, clean(result, getContextFromTerm(term))...) @@ -226,8 +213,6 @@ func getIdsFromFormula(root AST.Form) []Glob.Pair[string, string] { result = getIdsFromFormula(nf.GetForm()) case AST.Ex: result = getIdsFromFormula(nf.GetForm()) - case AST.AllType: - result = getIdsFromFormula(nf.GetForm()) case AST.And: for _, f := range nf.GetChildFormulas().GetSlice() { result = append(result, getIdsFromFormula(f)...) @@ -257,18 +242,7 @@ func getContextFromTerm(trm AST.Term) []string { result := []string{} if fun, isFun := trm.(AST.Fun); isFun { - - primitives := fun.GetTypeHint().GetPrimitives() - typesStr := "" - for i, prim := range primitives { - if i != len(primitives)-1 { - typesStr += "τ (" + prim.ToString() + ") → " - } else { - typesStr += "τ (" + prim.ToString() + ")" - } - } - - result = append(result, mapDefault(fmt.Sprintf("symbol %s : %s;", fun.GetID().ToMappedString(lambdaPiMapConnectors, false), typesStr))) + result = append(result, mapDefault(fmt.Sprintf("symbol %s;", fun.GetID().ToMappedString(lambdaPiMapConnectors, false)))) for _, term := range fun.GetArgs().GetSlice() { result = append(result, clean(result, getContextFromTerm(term))...) } diff --git a/src/Mods/lambdapi/formDecorator.go b/src/Mods/lambdapi/formDecorator.go index 9838a873..2ea14429 100644 --- a/src/Mods/lambdapi/formDecorator.go +++ b/src/Mods/lambdapi/formDecorator.go @@ -58,7 +58,7 @@ func QuantifierToMappedString(quant string, varList []AST.Var) string { if len(varList) == 0 { return "%s" } else { - result := "(" + quant + " (" + toLambdaIntroString(varList[0], varList[0].GetTypeHint().ToString()) + ", %s))" + result := "(" + quant + " (" + toLambdaIntroString(varList[0], "") + ", %s))" result = fmt.Sprintf(result, QuantifierToMappedString(quant, varList[1:])) return result } diff --git a/src/Mods/lambdapi/proof.go b/src/Mods/lambdapi/proof.go index f5ccba3b..941637c0 100644 --- a/src/Mods/lambdapi/proof.go +++ b/src/Mods/lambdapi/proof.go @@ -147,11 +147,10 @@ func allRules(rule string, target AST.Form, composingForms Lib.List[AST.Form], n func allRulesQuantUniv(rule string, target AST.Form, composingForms Lib.List[AST.Form], nexts []*gs3.GS3Sequent, children []Lib.List[AST.Form], vars []AST.Var, termGen AST.Term) string { quant := "" - typeStr := vars[0].GetTypeApp().ToString() - switch typed := target.(type) { + typeStr := "" + switch target.(type) { case AST.All: quant = lambdaPiMapConnectors[AST.AllQuant] - typeStr = typed.GetVarList()[0].GetTypeHint().ToString() case AST.Not: quant = lambdaPiMapConnectors[AST.ExQuant] } @@ -164,7 +163,7 @@ func allRulesQuantUniv(rule string, target AST.Form, composingForms Lib.List[AST varStrs := []string{} for _, singleVar := range vars { - varStrs = append(varStrs, toLambdaIntroString(singleVar, singleVar.GetTypeHint().ToString())) + varStrs = append(varStrs, toLambdaIntroString(singleVar, "")) } result = fmt.Sprintf(result, strings.Join(varStrs, ", "+quant+" ")) @@ -192,11 +191,10 @@ func getRecursionUnivStr(nexts []*gs3.GS3Sequent, children []Lib.List[AST.Form]) func allRulesQuantExist(rule string, target AST.Form, composingForms Lib.List[AST.Form], nexts []*gs3.GS3Sequent, children []Lib.List[AST.Form], vars []AST.Var, termGen AST.Term) string { quant := "" - typeStr := vars[0].GetTypeApp().ToString() - switch typed := target.(type) { + typeStr := "" + switch target.(type) { case AST.Ex: quant = lambdaPiMapConnectors[AST.ExQuant] - typeStr = typed.GetVarList()[0].GetTypeHint().ToString() case AST.Not: quant = lambdaPiMapConnectors[AST.AllQuant] } @@ -209,7 +207,7 @@ func allRulesQuantExist(rule string, target AST.Form, composingForms Lib.List[AS varStrs := []string{} for _, singleVar := range vars { - varStrs = append(varStrs, toLambdaIntroString(singleVar, singleVar.GetTypeHint().ToString())) + varStrs = append(varStrs, toLambdaIntroString(singleVar, "")) } result = fmt.Sprintf(result, strings.Join(varStrs, ", "+quant+" ")) @@ -224,8 +222,8 @@ func getRecursionExistStr(nexts []*gs3.GS3Sequent, children []Lib.List[AST.Form] for i, next := range nexts { result += "(\n" typesStr := "" - if typed, ok := termGen.(AST.Fun); ok { - typesStr = mapDefault(typed.GetTypeHint().ToString()) + if _, ok := termGen.(AST.Fun); ok { + typesStr = mapDefault("") } result += toLambdaIntroString(termGen, typesStr) + ",\n" for _, childForm := range children[i].GetSlice() { diff --git a/src/Mods/rocq/context.go b/src/Mods/rocq/context.go index bdfa1d79..1fe3360a 100644 --- a/src/Mods/rocq/context.go +++ b/src/Mods/rocq/context.go @@ -99,8 +99,6 @@ func getContextFromFormula(root AST.Form) []string { result = getContextFromFormula(nf.GetForm()) case AST.Ex: result = getContextFromFormula(nf.GetForm()) - case AST.AllType: - result = getContextFromFormula(nf.GetForm()) case AST.And: for _, f := range nf.GetChildFormulas().GetSlice() { result = append(result, clean(result, getContextFromFormula(f))...) @@ -119,8 +117,8 @@ func getContextFromFormula(root AST.Form) []string { result = clean(result, getContextFromFormula(nf.GetForm())) case AST.Pred: if !nf.GetID().Equals(AST.Id_eq) { - result = append(result, mapDefault(fmt.Sprintf("Parameter %s : %s.", - nf.GetID().ToMappedString(rocqMapConnectors(), false), nf.GetType().ToString()))) + result = append(result, mapDefault( + fmt.Sprintf("Parameter %s.", nf.GetID().ToMappedString(rocqMapConnectors(), false)))) } for _, term := range nf.GetArgs().GetSlice() { result = append(result, clean(result, getContextFromTerm(term))...) @@ -132,8 +130,9 @@ func getContextFromFormula(root AST.Form) []string { func getContextFromTerm(trm AST.Term) []string { result := []string{} if fun, isFun := trm.(AST.Fun); isFun { - result = append(result, mapDefault(fmt.Sprintf("Parameter %s : %s.", - fun.GetID().ToMappedString(rocqMapConnectors(), false), fun.GetTypeHint().ToString()))) + result = append(result, + mapDefault(fmt.Sprintf( + "Parameter %s.", fun.GetID().ToMappedString(rocqMapConnectors(), false)))) for _, term := range fun.GetArgs().GetSlice() { result = append(result, clean(result, getContextFromTerm(term))...) } diff --git a/src/Search/rules.go b/src/Search/rules.go index bb7641aa..855aafcb 100644 --- a/src/Search/rules.go +++ b/src/Search/rules.go @@ -43,7 +43,6 @@ import ( "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Unif" - "os" ) var strToPrintMap map[string]string = map[string]string{ @@ -503,10 +502,6 @@ func ApplyGammaRules(fnt Core.FormAndTerms, index int, state *State) (Core.FormA case AST.All: setStateRules(state, "GAMMA", "FORALL") - - case AST.AllType: - Glob.PrintInfo("search", "Typed search not handled yet") - os.Exit(3) } fnt, mm := Core.Instantiate(fnt, index) diff --git a/src/Typing/apply_rules.go b/src/Typing/apply_rules.go index 16a7313f..828b7ae9 100644 --- a/src/Typing/apply_rules.go +++ b/src/Typing/apply_rules.go @@ -32,158 +32,158 @@ package Typing -import ( - "fmt" - - "github.com/GoelandProver/Goeland/AST" -) - -/** - * This file contains all the rules of the typing system. - **/ - -const ( - formIsSet = iota - termIsSet = iota - typeIsSet = iota - schemeIsSet = iota - noConsequence = iota -) - -/* Launch the rules depending on what's on the right side of the sequent. */ -func applyRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Only one of the three should be set - if !onlyOneConsequenceIsSet(state) { - return Reconstruct{ - result: false, - err: fmt.Errorf("multiple elements on the right-side of the sequent. Cannot type this system"), - } - } - - // The applicable rules depend on what is set: the form, the term, or the type ? - switch whatIsSet(state.consequence) { - case formIsSet: - return applyFormRule(state, root, fatherChan) - case termIsSet: - return applyTermRule(state, root, fatherChan) - case typeIsSet: - return applyTypeRule(state, root, fatherChan) - case schemeIsSet: - return applySymRule(state, root, fatherChan) - case noConsequence: - return applyWFRule(state, root, fatherChan) - } - - return Reconstruct{result: true, err: nil} -} - -/* Applies one of the forms rule based on the type of the form. */ -func applyFormRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - var rec Reconstruct - switch (state.consequence.f).(type) { - case AST.All, AST.AllType, AST.Ex: - rec = applyQuantRule(state, root, fatherChan) - case AST.And, AST.Or: - rec = applyNAryRule(state, root, fatherChan) - case AST.Imp, AST.Equ: - rec = applyBinaryRule(state, root, fatherChan) - case AST.Top, AST.Bot: - rec = applyBotTopRule(state, root, fatherChan) - case AST.Not: - rec = applyNotRule(state, root, fatherChan) - case AST.Pred: - rec = applyAppRule(state, root, fatherChan) - } - return rec -} - -/* Applies one of the terms rule based on the type of the form. */ -func applyTermRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - var rec Reconstruct - switch (state.consequence.t).(type) { - case AST.Fun: - rec = applyAppRule(state, root, fatherChan) - case AST.Var: - rec = applyVarRule(state, root, fatherChan) - // Metas shoudln't appear in the formula yet. - // IDs are not a real Term. - } - return rec -} - -/* Applies one of the types rule based on the type of the form. */ -func applyTypeRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - var rec Reconstruct - switch type_ := (state.consequence.a).(type) { - case AST.TypeHint: - if type_.Equals(metaType) { - rec = applyTypeWFRule(state, root, fatherChan) - } else { - rec = applyGlobalTypeVarRule(state, root, fatherChan) - } - case AST.TypeVar: - rec = applyLocalTypeVarRule(state, root, fatherChan) - case AST.TypeCross: - // Apply composed rule: launch a child for each TypeHint of the composed type. - rec = applyCrossRule(state, root, fatherChan) - // There shouldn't be any TypeArrow: can not type a variable with it in first order. - case AST.ParameterizedType: - // Apply app rule, we only need to check if the name of the type exists. - rec = applyAppTypeRule(state, root, fatherChan) - } - return rec -} - -/* Applies one of the WF rule based on the type of the form. */ -func applyWFRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - if state.localContext.isEmpty() && state.globalContext.isEmpty() { - root.appliedRule = "WF_0" - return Reconstruct{result: true, err: nil} - } - if state.localContext.isEmpty() { - root.appliedRule = "WF_1" - return Reconstruct{result: true, err: nil} - } - - return applyWF2(state, root, fatherChan) -} - -/* Checks that at most one consequence of the sequent is set. */ -func onlyOneConsequenceIsSet(state Sequent) bool { - numberSet := 0 - if state.consequence.f != nil { - numberSet++ - } - if state.consequence.t != nil { - numberSet++ - } - if state.consequence.a != nil { - numberSet++ - } - if state.consequence.s != nil { - numberSet++ - } - - return numberSet < 2 -} - -/** - * Returns what is set in the consequence of the sequent. Either it's the form, - * the term, or the type. - * It doesn't check if multiple elements are set, it should be done before. - **/ -func whatIsSet(cons Consequence) int { - var set int - if cons.f != nil { - set = formIsSet - } else if cons.t != nil { - set = termIsSet - } else if cons.a != nil { - set = typeIsSet - } else if cons.s != nil { - set = schemeIsSet - } else { - set = noConsequence - } - return set -} +// import ( +// "fmt" + +// "github.com/GoelandProver/Goeland/AST" +// ) + +// /** +// * This file contains all the rules of the typing system. +// **/ + +// const ( +// formIsSet = iota +// termIsSet = iota +// typeIsSet = iota +// schemeIsSet = iota +// noConsequence = iota +// ) + +// /* Launch the rules depending on what's on the right side of the sequent. */ +// func applyRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// // Only one of the three should be set +// if !onlyOneConsequenceIsSet(state) { +// return Reconstruct{ +// result: false, +// err: fmt.Errorf("multiple elements on the right-side of the sequent. Cannot type this system"), +// } +// } + +// // The applicable rules depend on what is set: the form, the term, or the type ? +// switch whatIsSet(state.consequence) { +// case formIsSet: +// return applyFormRule(state, root, fatherChan) +// case termIsSet: +// return applyTermRule(state, root, fatherChan) +// case typeIsSet: +// return applyTypeRule(state, root, fatherChan) +// case schemeIsSet: +// return applySymRule(state, root, fatherChan) +// case noConsequence: +// return applyWFRule(state, root, fatherChan) +// } + +// return Reconstruct{result: true, err: nil} +// } + +// /* Applies one of the forms rule based on the type of the form. */ +// func applyFormRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// var rec Reconstruct +// switch (state.consequence.f).(type) { +// case AST.All, AST.AllType, AST.Ex: +// rec = applyQuantRule(state, root, fatherChan) +// case AST.And, AST.Or: +// rec = applyNAryRule(state, root, fatherChan) +// case AST.Imp, AST.Equ: +// rec = applyBinaryRule(state, root, fatherChan) +// case AST.Top, AST.Bot: +// rec = applyBotTopRule(state, root, fatherChan) +// case AST.Not: +// rec = applyNotRule(state, root, fatherChan) +// case AST.Pred: +// rec = applyAppRule(state, root, fatherChan) +// } +// return rec +// } + +// /* Applies one of the terms rule based on the type of the form. */ +// func applyTermRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// var rec Reconstruct +// switch (state.consequence.t).(type) { +// case AST.Fun: +// rec = applyAppRule(state, root, fatherChan) +// case AST.Var: +// rec = applyVarRule(state, root, fatherChan) +// // Metas shoudln't appear in the formula yet. +// // IDs are not a real Term. +// } +// return rec +// } + +// /* Applies one of the types rule based on the type of the form. */ +// func applyTypeRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// var rec Reconstruct +// switch type_ := (state.consequence.a).(type) { +// case AST.TypeHint: +// if type_.Equals(metaType) { +// rec = applyTypeWFRule(state, root, fatherChan) +// } else { +// rec = applyGlobalTypeVarRule(state, root, fatherChan) +// } +// case AST.TypeVar: +// rec = applyLocalTypeVarRule(state, root, fatherChan) +// case AST.TypeCross: +// // Apply composed rule: launch a child for each TypeHint of the composed type. +// rec = applyCrossRule(state, root, fatherChan) +// // There shouldn't be any TypeArrow: can not type a variable with it in first order. +// case AST.ParameterizedType: +// // Apply app rule, we only need to check if the name of the type exists. +// rec = applyAppTypeRule(state, root, fatherChan) +// } +// return rec +// } + +// /* Applies one of the WF rule based on the type of the form. */ +// func applyWFRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// if state.localContext.isEmpty() && state.globalContext.isEmpty() { +// root.appliedRule = "WF_0" +// return Reconstruct{result: true, err: nil} +// } +// if state.localContext.isEmpty() { +// root.appliedRule = "WF_1" +// return Reconstruct{result: true, err: nil} +// } + +// return applyWF2(state, root, fatherChan) +// } + +// /* Checks that at most one consequence of the sequent is set. */ +// func onlyOneConsequenceIsSet(state Sequent) bool { +// numberSet := 0 +// if state.consequence.f != nil { +// numberSet++ +// } +// if state.consequence.t != nil { +// numberSet++ +// } +// if state.consequence.a != nil { +// numberSet++ +// } +// if state.consequence.s != nil { +// numberSet++ +// } + +// return numberSet < 2 +// } + +// /** +// * Returns what is set in the consequence of the sequent. Either it's the form, +// * the term, or the type. +// * It doesn't check if multiple elements are set, it should be done before. +// **/ +// func whatIsSet(cons Consequence) int { +// var set int +// if cons.f != nil { +// set = formIsSet +// } else if cons.t != nil { +// set = termIsSet +// } else if cons.a != nil { +// set = typeIsSet +// } else if cons.s != nil { +// set = schemeIsSet +// } else { +// set = noConsequence +// } +// return set +// } diff --git a/src/Typing/contexts.go b/src/Typing/contexts.go index ae9faeac..1a78e62f 100644 --- a/src/Typing/contexts.go +++ b/src/Typing/contexts.go @@ -32,310 +32,310 @@ package Typing -import ( - "fmt" - - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * This file defines the global & local contexts types. - **/ - -/* Stores the local context */ -type LocalContext struct { - vars []AST.Var - typeVars []AST.TypeVar -} - -/* LocalContext methods */ - -/* Adds a var to a copy of the local context and returns it. */ -func (lc LocalContext) addVar(var_ AST.Var) LocalContext { - newLc := lc.copy() - newLc.vars = append(newLc.vars, var_) - return newLc -} - -/* Adds a type var to a copy of the local context and returns it. */ -func (lc LocalContext) addTypeVar(var_ AST.TypeVar) LocalContext { - newLc := lc.copy() - newLc.typeVars = append(newLc.typeVars, var_) - return newLc -} - -/* Copies a LocalContext. */ -func (lc LocalContext) copy() LocalContext { - newVars := make([]AST.Var, len(lc.vars)) - newTypeVars := make([]AST.TypeVar, len(lc.typeVars)) - copy(newVars, lc.vars) - copy(newTypeVars, lc.typeVars) - return LocalContext{vars: newVars, typeVars: newTypeVars} -} - -/* True if all the slices are cleared */ -func (lc LocalContext) isEmpty() bool { - return len(lc.vars)+len(lc.typeVars) == 0 -} - -/** - * Copies the context and pops the first var (and returns it with the new local context). - * It doesn't check if the size of the array is positive, it should be checked before. - **/ -func (lc LocalContext) popVar() (AST.Var, LocalContext) { - newLc := lc.copy() - newLc.vars = newLc.vars[1:] - return lc.vars[0], newLc -} - -/** - * Copies the context and pops the first type var (and returns it with the new local context). - * It doesn't check if the size of the array is positive, it should be checked before. - **/ -func (lc LocalContext) popTypeVar() (AST.TypeVar, LocalContext) { - newLc := lc.copy() - newLc.typeVars = newLc.typeVars[1:] - return lc.typeVars[0], newLc -} - -/* Stores the global context */ -type GlobalContext struct { - primitiveTypes []AST.TypeHint - parameterizedTypes []string - composedType map[string]AST.TypeCross - simpleSchemes map[string][]AST.TypeScheme - polymorphSchemes map[string][]AST.QuantifiedType -} - -/* Copies a GlobalContext into a new variable and returns it. */ -func (gc GlobalContext) copy() GlobalContext { - context := GlobalContext{ - primitiveTypes: make([]AST.TypeHint, len(gc.primitiveTypes)), - parameterizedTypes: make([]string, len(gc.parameterizedTypes)), - simpleSchemes: make(map[string][]AST.TypeScheme), - polymorphSchemes: make(map[string][]AST.QuantifiedType), - } - copy(context.primitiveTypes, gc.primitiveTypes) - copy(context.parameterizedTypes, gc.parameterizedTypes) - - for name, list := range gc.simpleSchemes { - context.simpleSchemes[name] = make([]AST.TypeScheme, len(list)) - copy(context.simpleSchemes[name], list) - } - - for name, list := range gc.polymorphSchemes { - context.polymorphSchemes[name] = make([]AST.QuantifiedType, len(list)) - copy(context.polymorphSchemes[name], list) - } - - return context -} - -/* Gets a simple / polymorphic type scheme from an ID, type variables, and terms */ -func (gc GlobalContext) getTypeScheme( - id AST.Id, - vars []AST.TypeApp, - terms Lib.List[AST.Term], -) (AST.TypeScheme, error) { - args, err := getArgsTypes(gc, terms) - if err != nil { - return nil, err - } - - typeScheme, err := gc.getSimpleTypeScheme(id.GetName(), args) - - if typeScheme == nil { - typeScheme, err = gc.getPolymorphicTypeScheme( - id.GetName(), - len(vars), - terms.Len(), - ) - // Instantiate type scheme with actual types - if typeScheme != nil { - typeScheme = Glob.To[AST.QuantifiedType](typeScheme).Instanciate(vars) - } - } - - if err != nil { - return nil, err - } - - return typeScheme, nil -} - -func flattenCross(ty AST.TypeApp) []AST.TypeApp { - switch nty := ty.(type) { - case AST.TypeCross: - flattened := []AST.TypeApp{} - for _, uty := range nty.GetAllUnderlyingTypes() { - flattened = append(flattened, flattenCross(uty)...) - } - return []AST.TypeApp{AST.MkTypeCross(flattened...)} - } - return []AST.TypeApp{ty} -} - -/* Search for a TypeScheme with the name & the arguments type */ -func (gc GlobalContext) getSimpleTypeScheme(name string, termsType AST.TypeApp) (AST.TypeScheme, error) { - if termsType == nil { - if typeScheme, found := gc.simpleSchemes[name]; found { - return typeScheme[0], nil - } else { - return nil, fmt.Errorf("no constant function with the name %s in the global context", name) - } - } - - termsType = flattenCross(termsType)[0] - if typeSchemeList, found := gc.simpleSchemes[name]; found { - for _, typeScheme := range typeSchemeList { - if AST.GetInputType(typeScheme).Equals(Lib.ComparableList[AST.TypeApp]{termsType}) { - return typeScheme, nil - } - } - } - return nil, fmt.Errorf("no predicate/function with the name %s in the global context and arguments of type %s", name, termsType.ToString()) -} - -/* Gets the polymorphic type scheme corresponding to the input. */ -func (gc GlobalContext) getPolymorphicTypeScheme(name string, varsLen, termsLen int) (AST.TypeScheme, error) { - if typeSchemeList, found := gc.polymorphSchemes[name]; found { - for _, typeScheme := range typeSchemeList { - if termsLen == typeScheme.Size()-1 && varsLen == typeScheme.QuantifiedVarsLen() { - return typeScheme, nil - } - } - } - return nil, fmt.Errorf("no predicate/function with the name %s in the global context", name) -} - -/* Returns true if the TypeHint is found in the context */ -func (gc GlobalContext) isTypeInContext(typeApp AST.TypeScheme) bool { - for _, type_ := range gc.primitiveTypes { - if type_.Equals(typeApp) { - return true - } - } - for _, type_ := range gc.composedType { - if type_.Equals(typeApp) { - return true - } - } - return false -} - -/* Tests if there are no more TypeScheme stored (doesn't check for primitive types) */ -func (gc GlobalContext) isEmpty() bool { - result := true - - for _, app := range gc.simpleSchemes { - result = result && (len(app) == 0) - } - for _, app := range gc.polymorphSchemes { - result = result && (len(app) == 0) - } - - return result -} - -/* Checks if the parameterized types contains the given name */ -func (gc GlobalContext) parameterizedTypesContains(name string) bool { - for _, parameterTypeName := range gc.parameterizedTypes { - if name == parameterTypeName { - return true - } - } - return false -} - -/* Utils */ - -/** - * Creates a global context from all the types / type schemes recorded in the map of types. - * Incrementally verifies if the context is well typed. - * If not, an error is returned. - **/ -func createGlobalContext(context map[string][]AST.App) (GlobalContext, error) { - globalContext := GlobalContext{ - primitiveTypes: []AST.TypeHint{}, - parameterizedTypes: []string{}, - composedType: make(map[string]AST.TypeCross), - simpleSchemes: make(map[string][]AST.TypeScheme), - polymorphSchemes: make(map[string][]AST.QuantifiedType), - } - - // Fill first the primitive types - for name, appList := range context { - if len(appList) == 0 { - globalContext.parameterizedTypes = append(globalContext.parameterizedTypes, name) - } - for _, app := range appList { - if type_, isTypeHint := app.App.(AST.TypeHint); isTypeHint { - if !AST.IsConstant(name) { - globalContext.primitiveTypes = append(globalContext.primitiveTypes, type_) - } - } - } - } - - for name, appList := range context { - // Then, fill everything else - for _, app := range appList { - switch type_ := app.App.(type) { - case AST.TypeHint: - if AST.IsConstant(name) { - globalContext.simpleSchemes[name] = append(globalContext.simpleSchemes[name], type_) - } - case AST.TypeCross: - globalContext.composedType[name] = type_ - case AST.TypeArrow: - globalContext.simpleSchemes[name] = append(globalContext.simpleSchemes[name], type_) - case AST.QuantifiedType: - globalContext.polymorphSchemes[name] = append(globalContext.polymorphSchemes[name], type_) - case AST.ParameterizedType: - globalContext.simpleSchemes[name] = append(globalContext.simpleSchemes[name], type_) - } - if err := incrementalVerificationOfGlobalContext(globalContext.copy(), name, app.App); err != nil { - return GlobalContext{}, err - } - } - } - - if !globalContextIsWellTyped { - globalContextIsWellTyped = true - } - return globalContext, nil -} - -/** - * Triggers rules to verify the global context while it's constructed. - * It will avoid combinatorial explosion on global context well formedness verification. - **/ -func incrementalVerificationOfGlobalContext(globalContext GlobalContext, name string, app AST.TypeScheme) error { - if globalContextIsWellTyped { - return nil - } - - sequent := Sequent{ - globalContext: globalContext, - localContext: LocalContext{}, - } - rec := Reconstruct{err: nil} - proofTree, chan_ := new(ProofTree), make(chan Reconstruct) - - switch type_ := app.(type) { - case AST.TypeCross: - sequent.consequence = Consequence{a: type_} - rec = applyCrossRule(sequent, proofTree, chan_) - case AST.QuantifiedType, AST.TypeArrow: - sequent.consequence = Consequence{s: app} - rec = applySymRule(sequent, proofTree, chan_) - case AST.TypeHint: - if AST.IsConstant(name) { - sequent.consequence = Consequence{a: type_} - rec = applyGlobalTypeVarRule(sequent, proofTree, chan_) - } - } - return rec.err -} +// import ( +// "fmt" + +// "github.com/GoelandProver/Goeland/AST" +// "github.com/GoelandProver/Goeland/Glob" +// "github.com/GoelandProver/Goeland/Lib" +// ) + +// /** +// * This file defines the global & local contexts types. +// **/ + +// /* Stores the local context */ +// type LocalContext struct { +// vars []AST.Var +// typeVars []AST.TypeVar +// } + +// /* LocalContext methods */ + +// /* Adds a var to a copy of the local context and returns it. */ +// func (lc LocalContext) addVar(var_ AST.Var) LocalContext { +// newLc := lc.copy() +// newLc.vars = append(newLc.vars, var_) +// return newLc +// } + +// /* Adds a type var to a copy of the local context and returns it. */ +// func (lc LocalContext) addTypeVar(var_ AST.TypeVar) LocalContext { +// newLc := lc.copy() +// newLc.typeVars = append(newLc.typeVars, var_) +// return newLc +// } + +// /* Copies a LocalContext. */ +// func (lc LocalContext) copy() LocalContext { +// newVars := make([]AST.Var, len(lc.vars)) +// newTypeVars := make([]AST.TypeVar, len(lc.typeVars)) +// copy(newVars, lc.vars) +// copy(newTypeVars, lc.typeVars) +// return LocalContext{vars: newVars, typeVars: newTypeVars} +// } + +// /* True if all the slices are cleared */ +// func (lc LocalContext) isEmpty() bool { +// return len(lc.vars)+len(lc.typeVars) == 0 +// } + +// /** +// * Copies the context and pops the first var (and returns it with the new local context). +// * It doesn't check if the size of the array is positive, it should be checked before. +// **/ +// func (lc LocalContext) popVar() (AST.Var, LocalContext) { +// newLc := lc.copy() +// newLc.vars = newLc.vars[1:] +// return lc.vars[0], newLc +// } + +// /** +// * Copies the context and pops the first type var (and returns it with the new local context). +// * It doesn't check if the size of the array is positive, it should be checked before. +// **/ +// func (lc LocalContext) popTypeVar() (AST.TypeVar, LocalContext) { +// newLc := lc.copy() +// newLc.typeVars = newLc.typeVars[1:] +// return lc.typeVars[0], newLc +// } + +// /* Stores the global context */ +// type GlobalContext struct { +// primitiveTypes []AST.TypeHint +// parameterizedTypes []string +// composedType map[string]AST.TypeCross +// simpleSchemes map[string][]AST.TypeScheme +// polymorphSchemes map[string][]AST.QuantifiedType +// } + +// /* Copies a GlobalContext into a new variable and returns it. */ +// func (gc GlobalContext) copy() GlobalContext { +// context := GlobalContext{ +// primitiveTypes: make([]AST.TypeHint, len(gc.primitiveTypes)), +// parameterizedTypes: make([]string, len(gc.parameterizedTypes)), +// simpleSchemes: make(map[string][]AST.TypeScheme), +// polymorphSchemes: make(map[string][]AST.QuantifiedType), +// } +// copy(context.primitiveTypes, gc.primitiveTypes) +// copy(context.parameterizedTypes, gc.parameterizedTypes) + +// for name, list := range gc.simpleSchemes { +// context.simpleSchemes[name] = make([]AST.TypeScheme, len(list)) +// copy(context.simpleSchemes[name], list) +// } + +// for name, list := range gc.polymorphSchemes { +// context.polymorphSchemes[name] = make([]AST.QuantifiedType, len(list)) +// copy(context.polymorphSchemes[name], list) +// } + +// return context +// } + +// /* Gets a simple / polymorphic type scheme from an ID, type variables, and terms */ +// func (gc GlobalContext) getTypeScheme( +// id AST.Id, +// vars []AST.TypeApp, +// terms Lib.List[AST.Term], +// ) (AST.TypeScheme, error) { +// args, err := getArgsTypes(gc, terms) +// if err != nil { +// return nil, err +// } + +// typeScheme, err := gc.getSimpleTypeScheme(id.GetName(), args) + +// if typeScheme == nil { +// typeScheme, err = gc.getPolymorphicTypeScheme( +// id.GetName(), +// len(vars), +// terms.Len(), +// ) +// // Instantiate type scheme with actual types +// if typeScheme != nil { +// typeScheme = Glob.To[AST.QuantifiedType](typeScheme).Instanciate(vars) +// } +// } + +// if err != nil { +// return nil, err +// } + +// return typeScheme, nil +// } + +// func flattenCross(ty AST.TypeApp) []AST.TypeApp { +// switch nty := ty.(type) { +// case AST.TypeCross: +// flattened := []AST.TypeApp{} +// for _, uty := range nty.GetAllUnderlyingTypes() { +// flattened = append(flattened, flattenCross(uty)...) +// } +// return []AST.TypeApp{AST.MkTypeCross(flattened...)} +// } +// return []AST.TypeApp{ty} +// } + +// /* Search for a TypeScheme with the name & the arguments type */ +// func (gc GlobalContext) getSimpleTypeScheme(name string, termsType AST.TypeApp) (AST.TypeScheme, error) { +// if termsType == nil { +// if typeScheme, found := gc.simpleSchemes[name]; found { +// return typeScheme[0], nil +// } else { +// return nil, fmt.Errorf("no constant function with the name %s in the global context", name) +// } +// } + +// termsType = flattenCross(termsType)[0] +// if typeSchemeList, found := gc.simpleSchemes[name]; found { +// for _, typeScheme := range typeSchemeList { +// if AST.GetInputType(typeScheme).Equals(Lib.ComparableList[AST.TypeApp]{termsType}) { +// return typeScheme, nil +// } +// } +// } +// return nil, fmt.Errorf("no predicate/function with the name %s in the global context and arguments of type %s", name, termsType.ToString()) +// } + +// /* Gets the polymorphic type scheme corresponding to the input. */ +// func (gc GlobalContext) getPolymorphicTypeScheme(name string, varsLen, termsLen int) (AST.TypeScheme, error) { +// if typeSchemeList, found := gc.polymorphSchemes[name]; found { +// for _, typeScheme := range typeSchemeList { +// if termsLen == typeScheme.Size()-1 && varsLen == typeScheme.QuantifiedVarsLen() { +// return typeScheme, nil +// } +// } +// } +// return nil, fmt.Errorf("no predicate/function with the name %s in the global context", name) +// } + +// /* Returns true if the TypeHint is found in the context */ +// func (gc GlobalContext) isTypeInContext(typeApp AST.TypeScheme) bool { +// for _, type_ := range gc.primitiveTypes { +// if type_.Equals(typeApp) { +// return true +// } +// } +// for _, type_ := range gc.composedType { +// if type_.Equals(typeApp) { +// return true +// } +// } +// return false +// } + +// /* Tests if there are no more TypeScheme stored (doesn't check for primitive types) */ +// func (gc GlobalContext) isEmpty() bool { +// result := true + +// for _, app := range gc.simpleSchemes { +// result = result && (len(app) == 0) +// } +// for _, app := range gc.polymorphSchemes { +// result = result && (len(app) == 0) +// } + +// return result +// } + +// /* Checks if the parameterized types contains the given name */ +// func (gc GlobalContext) parameterizedTypesContains(name string) bool { +// for _, parameterTypeName := range gc.parameterizedTypes { +// if name == parameterTypeName { +// return true +// } +// } +// return false +// } + +// /* Utils */ + +// /** +// * Creates a global context from all the types / type schemes recorded in the map of types. +// * Incrementally verifies if the context is well typed. +// * If not, an error is returned. +// **/ +// func createGlobalContext(context map[string][]AST.App) (GlobalContext, error) { +// globalContext := GlobalContext{ +// primitiveTypes: []AST.TypeHint{}, +// parameterizedTypes: []string{}, +// composedType: make(map[string]AST.TypeCross), +// simpleSchemes: make(map[string][]AST.TypeScheme), +// polymorphSchemes: make(map[string][]AST.QuantifiedType), +// } + +// // Fill first the primitive types +// for name, appList := range context { +// if len(appList) == 0 { +// globalContext.parameterizedTypes = append(globalContext.parameterizedTypes, name) +// } +// for _, app := range appList { +// if type_, isTypeHint := app.App.(AST.TypeHint); isTypeHint { +// if !AST.IsConstant(name) { +// globalContext.primitiveTypes = append(globalContext.primitiveTypes, type_) +// } +// } +// } +// } + +// for name, appList := range context { +// // Then, fill everything else +// for _, app := range appList { +// switch type_ := app.App.(type) { +// case AST.TypeHint: +// if AST.IsConstant(name) { +// globalContext.simpleSchemes[name] = append(globalContext.simpleSchemes[name], type_) +// } +// case AST.TypeCross: +// globalContext.composedType[name] = type_ +// case AST.TypeArrow: +// globalContext.simpleSchemes[name] = append(globalContext.simpleSchemes[name], type_) +// case AST.QuantifiedType: +// globalContext.polymorphSchemes[name] = append(globalContext.polymorphSchemes[name], type_) +// case AST.ParameterizedType: +// globalContext.simpleSchemes[name] = append(globalContext.simpleSchemes[name], type_) +// } +// if err := incrementalVerificationOfGlobalContext(globalContext.copy(), name, app.App); err != nil { +// return GlobalContext{}, err +// } +// } +// } + +// if !globalContextIsWellTyped { +// globalContextIsWellTyped = true +// } +// return globalContext, nil +// } + +// /** +// * Triggers rules to verify the global context while it's constructed. +// * It will avoid combinatorial explosion on global context well formedness verification. +// **/ +// func incrementalVerificationOfGlobalContext(globalContext GlobalContext, name string, app AST.TypeScheme) error { +// if globalContextIsWellTyped { +// return nil +// } + +// sequent := Sequent{ +// globalContext: globalContext, +// localContext: LocalContext{}, +// } +// rec := Reconstruct{err: nil} +// proofTree, chan_ := new(ProofTree), make(chan Reconstruct) + +// switch type_ := app.(type) { +// case AST.TypeCross: +// sequent.consequence = Consequence{a: type_} +// rec = applyCrossRule(sequent, proofTree, chan_) +// case AST.QuantifiedType, AST.TypeArrow: +// sequent.consequence = Consequence{s: app} +// rec = applySymRule(sequent, proofTree, chan_) +// case AST.TypeHint: +// if AST.IsConstant(name) { +// sequent.consequence = Consequence{a: type_} +// rec = applyGlobalTypeVarRule(sequent, proofTree, chan_) +// } +// } +// return rec.err +// } diff --git a/src/Typing/form_rules.go b/src/Typing/form_rules.go index e177b4a1..772ec291 100644 --- a/src/Typing/form_rules.go +++ b/src/Typing/form_rules.go @@ -32,203 +32,203 @@ package Typing -import ( - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * This file contains all the rules that the typing system can apply on a formula. - **/ - -/* Applies quantification rule and launches 2 goroutines waiting its children. */ -func applyQuantRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add rule to prooftree - switch (state.consequence.f).(type) { - case AST.All, AST.AllType: - root.appliedRule = "∀" - case AST.Ex: - root.appliedRule = "∃" - } - - var newForm AST.Form - var varTreated AST.Var - var typeTreated AST.TypeVar - - varInstantiated := false - - switch f := (state.consequence.f).(type) { - case AST.All, AST.Ex: - varTreated, newForm = removeOneVar(state.consequence.f) - varInstantiated = true - case AST.AllType: - v := f.GetVarList()[0] - if len(f.GetVarList()) > 1 { - typeTreated, newForm = v, AST.MakeAllType(f.GetIndex(), f.GetVarList()[1:], f.GetForm()) - } else { - typeTreated, newForm = v, f.GetForm() - } - } - - // Create 2 children: - // 1 - First one with the type of the quantified variable. It should be a TypeApp. - // 2 - Second one with the quantified variable added in the local context. - // => copy the local context and use the function to get the global context (copy or not). - // The underlying form should be gotten to be properly typed. - children := mkQuantChildren(state, varInstantiated, varTreated, typeTreated, newForm) - - // Launch the children in a goroutine, and wait for it to close. - // If one branch closes with an error, then the system is not well-typed. - return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -} - -/* Applies OR or AND rule and launches n goroutines waiting its children */ -func applyNAryRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - formList := Lib.NewList[AST.Form]() - // Add rule to prooftree - switch f := (state.consequence.f).(type) { - case AST.And: - root.appliedRule = "∧" - formList = f.GetChildFormulas() - case AST.Or: - root.appliedRule = "∨" - formList = f.GetChildFormulas() - } - - // Construct children with all the formulas - children := []Sequent{} - for _, form := range formList.GetSlice() { - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{f: form}, - }) - } - - // Launch the children in a goroutine, and wait for it to close. - // If one branch closes with an error, then the system is not well-typed. - return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -} - -/* Applies => or <=> rule and launches 2 goroutines waiting its children */ -func applyBinaryRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - var f1, f2 AST.Form - // Add rule to prooftree - switch f := (state.consequence.f).(type) { - case AST.Imp: - root.appliedRule = "⇒" - f1, f2 = f.GetF1(), f.GetF2() - case AST.Equ: - root.appliedRule = "⇔" - f1, f2 = f.GetF1(), f.GetF2() - } - - // Construct children with the 2 formulas - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{f: f1}, - }, - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{f: f2}, - }, - } - - // Launch the children in a goroutine, and wait for it to close. - // If one branch closes with an error, then the system is not well-typed. - return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -} - -/* Applies BOT or TOP rule and does not create a new goroutine */ -func applyBotTopRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add rule to prooftree - switch (state.consequence.f).(type) { - case AST.Top: - root.appliedRule = "⊤" - case AST.Bot: - root.appliedRule = "⊥" - } - - // Construct children with the contexts - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{}, - }, - } - - // If the branch closes with an error, then the system is not well-typed. - return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -} - -func applyNotRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add rule to prooftree - root.appliedRule = "¬" - form := (state.consequence.f).(AST.Not).GetForm() - - // Construct children with the contexts - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{f: form}, - }, - } - - // If the branch closes with an error, then the system is not well-typed. - return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -} - -/** - * Removes the first variable of an exitential or universal form, and returns a - * universal / existential form iff it still possesses other vars. - * Otherwise, it returns the form gotten with GetForm(). - **/ -func removeOneVar(form AST.Form) (AST.Var, AST.Form) { - // It's pretty much the same thing, but I don't have a clue on how to factorize this.. - switch f := form.(type) { - case AST.Ex: - v := f.GetVarList()[0] - if len(f.GetVarList()) > 1 { - return v, AST.MakeEx(f.GetIndex(), f.GetVarList()[1:], f.GetForm()) - } - return v, f.GetForm() - case AST.All: - v := f.GetVarList()[0] - if len(f.GetVarList()) > 1 { - return v, AST.MakeAll(f.GetIndex(), f.GetVarList()[1:], f.GetForm()) - } - return v, f.GetForm() - } - return AST.Var{}, nil -} - -/* Makes the child treating the variable depending on which is set. */ -func mkQuantChildren(state Sequent, varInstantiated bool, varTreated AST.Var, typeTreated AST.TypeVar, newForm AST.Form) []Sequent { - var type_ AST.TypeApp - var newLocalContext LocalContext - if varInstantiated { - type_ = varTreated.GetTypeApp() - newLocalContext = state.localContext.addVar(varTreated) - } else { - type_ = metaType - newLocalContext = state.localContext.addTypeVar(typeTreated) - } - - return []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{a: type_}, - }, - { - globalContext: state.globalContext, - localContext: newLocalContext, - consequence: Consequence{f: newForm}, - }, - } -} +// import ( +// "github.com/GoelandProver/Goeland/AST" +// "github.com/GoelandProver/Goeland/Lib" +// ) + +// /** +// * This file contains all the rules that the typing system can apply on a formula. +// **/ + +// /* Applies quantification rule and launches 2 goroutines waiting its children. */ +// func applyQuantRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// // Add rule to prooftree +// switch (state.consequence.f).(type) { +// case AST.All, AST.AllType: +// root.appliedRule = "∀" +// case AST.Ex: +// root.appliedRule = "∃" +// } + +// var newForm AST.Form +// var varTreated AST.Var +// var typeTreated AST.TypeVar + +// varInstantiated := false + +// switch f := (state.consequence.f).(type) { +// case AST.All, AST.Ex: +// varTreated, newForm = removeOneVar(state.consequence.f) +// varInstantiated = true +// case AST.AllType: +// v := f.GetVarList()[0] +// if len(f.GetVarList()) > 1 { +// typeTreated, newForm = v, AST.MakeAllType(f.GetIndex(), f.GetVarList()[1:], f.GetForm()) +// } else { +// typeTreated, newForm = v, f.GetForm() +// } +// } + +// // Create 2 children: +// // 1 - First one with the type of the quantified variable. It should be a TypeApp. +// // 2 - Second one with the quantified variable added in the local context. +// // => copy the local context and use the function to get the global context (copy or not). +// // The underlying form should be gotten to be properly typed. +// children := mkQuantChildren(state, varInstantiated, varTreated, typeTreated, newForm) + +// // Launch the children in a goroutine, and wait for it to close. +// // If one branch closes with an error, then the system is not well-typed. +// return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) +// } + +// /* Applies OR or AND rule and launches n goroutines waiting its children */ +// func applyNAryRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// formList := Lib.NewList[AST.Form]() +// // Add rule to prooftree +// switch f := (state.consequence.f).(type) { +// case AST.And: +// root.appliedRule = "∧" +// formList = f.GetChildFormulas() +// case AST.Or: +// root.appliedRule = "∨" +// formList = f.GetChildFormulas() +// } + +// // Construct children with all the formulas +// children := []Sequent{} +// for _, form := range formList.GetSlice() { +// children = append(children, Sequent{ +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{f: form}, +// }) +// } + +// // Launch the children in a goroutine, and wait for it to close. +// // If one branch closes with an error, then the system is not well-typed. +// return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) +// } + +// /* Applies => or <=> rule and launches 2 goroutines waiting its children */ +// func applyBinaryRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// var f1, f2 AST.Form +// // Add rule to prooftree +// switch f := (state.consequence.f).(type) { +// case AST.Imp: +// root.appliedRule = "⇒" +// f1, f2 = f.GetF1(), f.GetF2() +// case AST.Equ: +// root.appliedRule = "⇔" +// f1, f2 = f.GetF1(), f.GetF2() +// } + +// // Construct children with the 2 formulas +// children := []Sequent{ +// { +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{f: f1}, +// }, +// { +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{f: f2}, +// }, +// } + +// // Launch the children in a goroutine, and wait for it to close. +// // If one branch closes with an error, then the system is not well-typed. +// return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) +// } + +// /* Applies BOT or TOP rule and does not create a new goroutine */ +// func applyBotTopRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// // Add rule to prooftree +// switch (state.consequence.f).(type) { +// case AST.Top: +// root.appliedRule = "⊤" +// case AST.Bot: +// root.appliedRule = "⊥" +// } + +// // Construct children with the contexts +// children := []Sequent{ +// { +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{}, +// }, +// } + +// // If the branch closes with an error, then the system is not well-typed. +// return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) +// } + +// func applyNotRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// // Add rule to prooftree +// root.appliedRule = "¬" +// form := (state.consequence.f).(AST.Not).GetForm() + +// // Construct children with the contexts +// children := []Sequent{ +// { +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{f: form}, +// }, +// } + +// // If the branch closes with an error, then the system is not well-typed. +// return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) +// } + +// /** +// * Removes the first variable of an exitential or universal form, and returns a +// * universal / existential form iff it still possesses other vars. +// * Otherwise, it returns the form gotten with GetForm(). +// **/ +// func removeOneVar(form AST.Form) (AST.Var, AST.Form) { +// // It's pretty much the same thing, but I don't have a clue on how to factorize this.. +// switch f := form.(type) { +// case AST.Ex: +// v := f.GetVarList()[0] +// if len(f.GetVarList()) > 1 { +// return v, AST.MakeEx(f.GetIndex(), f.GetVarList()[1:], f.GetForm()) +// } +// return v, f.GetForm() +// case AST.All: +// v := f.GetVarList()[0] +// if len(f.GetVarList()) > 1 { +// return v, AST.MakeAll(f.GetIndex(), f.GetVarList()[1:], f.GetForm()) +// } +// return v, f.GetForm() +// } +// return AST.Var{}, nil +// } + +// /* Makes the child treating the variable depending on which is set. */ +// func mkQuantChildren(state Sequent, varInstantiated bool, varTreated AST.Var, typeTreated AST.TypeVar, newForm AST.Form) []Sequent { +// var type_ AST.TypeApp +// var newLocalContext LocalContext +// if varInstantiated { +// type_ = varTreated.GetTypeApp() +// newLocalContext = state.localContext.addVar(varTreated) +// } else { +// type_ = metaType +// newLocalContext = state.localContext.addTypeVar(typeTreated) +// } + +// return []Sequent{ +// { +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{a: type_}, +// }, +// { +// globalContext: state.globalContext, +// localContext: newLocalContext, +// consequence: Consequence{f: newForm}, +// }, +// } +// } diff --git a/src/Typing/launch_rules.go b/src/Typing/launch_rules.go index 369abc5c..7e78036b 100644 --- a/src/Typing/launch_rules.go +++ b/src/Typing/launch_rules.go @@ -32,146 +32,146 @@ package Typing -import ( - "fmt" - "reflect" - - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * This file manages everything related to parallelism / concurrency. - **/ - -type Reconstruct struct { - result bool - forms Lib.List[AST.Form] - terms Lib.List[AST.Term] - err error -} - -/* Launches the first instance of applyRule. Do this to launch the typing system. */ -func launchRuleApplication(state Sequent, root *ProofTree) (AST.Form, error) { - superFatherChan := make(chan Reconstruct) - go tryApplyRule(state, root, superFatherChan) - res := <-superFatherChan - return treatReturns(res) -} - -/* Launches applyRule and manages the error return. */ -func tryApplyRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) { - select { - case <-fatherChan: // Message from the father received: it can only be a kill order. - default: - // No kill order, it's still properly typed, let's apply the next rules. - reconstruct := applyRule(state, root, fatherChan) - select { - case <-fatherChan: // Kill order received, it's finished anyway. - case fatherChan <- reconstruct: // Otherwise, send result to father. - } - } -} - -/* Launch each sequent in a goroutine if sequent length > 1. */ -func launchChildren(sequents []Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - if len(sequents) == 1 { - // Do not launch another goroutine if the applied rule has only 1 child. - return applyRule(sequents[0], root.addChildWith(sequents[0]), fatherChan) - } else { - // Create a channel for each child, and launch it in a goroutine. - chanTab := make([](chan Reconstruct), len(sequents)) - for i := range sequents { - childChan := make(chan Reconstruct) - chanTab[i] = childChan - go tryApplyRule(sequents[i], root.addChildWith(sequents[i]), childChan) - } - // If a child dies with an error, stops the typesearch procedure. - return selectSequents(chanTab, fatherChan) - } -} - -/** - * Waits for all the children to close. - * If an error is received, stops the type-search of every children and sends an error - * to the parent. - **/ -func selectSequents(chansTab [](chan Reconstruct), chanQuit chan Reconstruct) Reconstruct { - // Instantiation - cases := makeCases(chansTab, chanQuit) - hasAnswered := make([]bool, len(chansTab)) // Everything to false - remaining, indexQuit := len(chansTab), len(chansTab) - var errorFound error = nil - - forms := make([]AST.Form, len(chansTab)) - terms := Lib.MkList[AST.Term](len(chansTab)) - - // Wait for all children to finish. - for remaining > 0 && errorFound == nil { - index, value, _ := reflect.Select(cases) - remaining-- - if index == indexQuit { - errorFound = fmt.Errorf("father detected an error") - } else { - res := value.Interface().(Reconstruct) - hasAnswered[index] = true - if !res.result { - errorFound = res.err - } else { - // Once the child sends back to the father, it should only have one item. - if res.forms.Len() == 1 { - forms[index] = res.forms.At(0) - } - if res.terms.Len() == 1 { - terms.Upd(index, res.terms.At(0)) - } - } - } - } - - selectCleanup(errorFound, hasAnswered, chansTab) - return Reconstruct{result: errorFound == nil, forms: Lib.MkListV(forms...), terms: terms, err: errorFound} -} - -/* Utils functions for selectSequents */ - -/* Makes the array of cases from the channels */ -func makeCases(chansTab [](chan Reconstruct), chanQuit chan Reconstruct) []reflect.SelectCase { - cases := make([]reflect.SelectCase, len(chansTab)+1) - // Children - for i, chan_ := range chansTab { - cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(chan_)} - } - // Father - cases[len(chansTab)] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(chanQuit)} - return cases -} - -/* If an error was found, kills all the children. */ -func selectCleanup(errorFound error, hasAnswered []bool, chansTab [](chan Reconstruct)) { - if errorFound != nil { - for i, answered := range hasAnswered { - if !answered { - select { - case <-chansTab[i]: // Filter out, he already responded - case chansTab[i] <- Reconstruct{result: false, err: errorFound}: // Kill child - } - } - } - } -} - -/* Treats the different return types of the system. */ -func treatReturns(res Reconstruct) (AST.Form, error) { - if !res.result { - return nil, res.err - } else { - if res.forms.Len() == 0 { - return nil, res.err - } - if res.forms.Len() > 1 { - return nil, fmt.Errorf("more than one formula is returned by the typing system") - } - return res.forms.At(0), res.err - } -} +// import ( +// "fmt" +// "reflect" + +// "github.com/GoelandProver/Goeland/AST" +// "github.com/GoelandProver/Goeland/Lib" +// ) + +// /** +// * This file manages everything related to parallelism / concurrency. +// **/ + +// type Reconstruct struct { +// result bool +// forms Lib.List[AST.Form] +// terms Lib.List[AST.Term] +// err error +// } + +// /* Launches the first instance of applyRule. Do this to launch the typing system. */ +// func launchRuleApplication(state Sequent, root *ProofTree) (AST.Form, error) { +// superFatherChan := make(chan Reconstruct) +// go tryApplyRule(state, root, superFatherChan) +// res := <-superFatherChan +// return treatReturns(res) +// } + +// /* Launches applyRule and manages the error return. */ +// func tryApplyRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) { +// select { +// case <-fatherChan: // Message from the father received: it can only be a kill order. +// default: +// // No kill order, it's still properly typed, let's apply the next rules. +// reconstruct := applyRule(state, root, fatherChan) +// select { +// case <-fatherChan: // Kill order received, it's finished anyway. +// case fatherChan <- reconstruct: // Otherwise, send result to father. +// } +// } +// } + +// /* Launch each sequent in a goroutine if sequent length > 1. */ +// func launchChildren(sequents []Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// if len(sequents) == 1 { +// // Do not launch another goroutine if the applied rule has only 1 child. +// return applyRule(sequents[0], root.addChildWith(sequents[0]), fatherChan) +// } else { +// // Create a channel for each child, and launch it in a goroutine. +// chanTab := make([](chan Reconstruct), len(sequents)) +// for i := range sequents { +// childChan := make(chan Reconstruct) +// chanTab[i] = childChan +// go tryApplyRule(sequents[i], root.addChildWith(sequents[i]), childChan) +// } +// // If a child dies with an error, stops the typesearch procedure. +// return selectSequents(chanTab, fatherChan) +// } +// } + +// /** +// * Waits for all the children to close. +// * If an error is received, stops the type-search of every children and sends an error +// * to the parent. +// **/ +// func selectSequents(chansTab [](chan Reconstruct), chanQuit chan Reconstruct) Reconstruct { +// // Instantiation +// cases := makeCases(chansTab, chanQuit) +// hasAnswered := make([]bool, len(chansTab)) // Everything to false +// remaining, indexQuit := len(chansTab), len(chansTab) +// var errorFound error = nil + +// forms := make([]AST.Form, len(chansTab)) +// terms := Lib.MkList[AST.Term](len(chansTab)) + +// // Wait for all children to finish. +// for remaining > 0 && errorFound == nil { +// index, value, _ := reflect.Select(cases) +// remaining-- +// if index == indexQuit { +// errorFound = fmt.Errorf("father detected an error") +// } else { +// res := value.Interface().(Reconstruct) +// hasAnswered[index] = true +// if !res.result { +// errorFound = res.err +// } else { +// // Once the child sends back to the father, it should only have one item. +// if res.forms.Len() == 1 { +// forms[index] = res.forms.At(0) +// } +// if res.terms.Len() == 1 { +// terms.Upd(index, res.terms.At(0)) +// } +// } +// } +// } + +// selectCleanup(errorFound, hasAnswered, chansTab) +// return Reconstruct{result: errorFound == nil, forms: Lib.MkListV(forms...), terms: terms, err: errorFound} +// } + +// /* Utils functions for selectSequents */ + +// /* Makes the array of cases from the channels */ +// func makeCases(chansTab [](chan Reconstruct), chanQuit chan Reconstruct) []reflect.SelectCase { +// cases := make([]reflect.SelectCase, len(chansTab)+1) +// // Children +// for i, chan_ := range chansTab { +// cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(chan_)} +// } +// // Father +// cases[len(chansTab)] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(chanQuit)} +// return cases +// } + +// /* If an error was found, kills all the children. */ +// func selectCleanup(errorFound error, hasAnswered []bool, chansTab [](chan Reconstruct)) { +// if errorFound != nil { +// for i, answered := range hasAnswered { +// if !answered { +// select { +// case <-chansTab[i]: // Filter out, he already responded +// case chansTab[i] <- Reconstruct{result: false, err: errorFound}: // Kill child +// } +// } +// } +// } +// } + +// /* Treats the different return types of the system. */ +// func treatReturns(res Reconstruct) (AST.Form, error) { +// if !res.result { +// return nil, res.err +// } else { +// if res.forms.Len() == 0 { +// return nil, res.err +// } +// if res.forms.Len() > 1 { +// return nil, fmt.Errorf("more than one formula is returned by the typing system") +// } +// return res.forms.At(0), res.err +// } +// } diff --git a/src/Typing/prooftree_dump.go b/src/Typing/prooftree_dump.go index b2e82f5d..60a50da4 100644 --- a/src/Typing/prooftree_dump.go +++ b/src/Typing/prooftree_dump.go @@ -32,120 +32,120 @@ package Typing -import ( - "encoding/json" - "errors" - "fmt" - "os" - "strings" - - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" -) - -/** - * This file contains the methods to dump a prooftree in a json. - **/ - -/* Dumps the prooftree in a json. */ -func (root *ProofTree) DumpJson() error { - // Dump folder should be a flag in the future - dump := "../visualization/types/" - // Create a new file - i := 0 - for fileExists(getFileName(dump, i)) { - i++ - } - - f, err := os.OpenFile(getFileName(dump, i), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - return err - } - json, err := root.dump() - - if err != nil { - return err - } - - _, err = f.WriteString(json) - Glob.PrintInfo("DUMP", fmt.Sprintf("Dumped type proof in %s\n", f.Name())) - return err -} - -/* Creates file if not exists, dump informations in it, and calls recursively on each child */ -func (root *ProofTree) dump() (string, error) { - varsString := []string{} - var consequence string = "" - var ts string - if root.typeScheme != nil { - ts = root.typeScheme.ToString() - } - - for _, var_ := range root.sequent.localContext.vars { - varsString = append(varsString, var_.ToString()) - } - for _, var_ := range root.sequent.localContext.typeVars { - varsString = append(varsString, fmt.Sprintf("%s: Type", var_.ToString())) - } - - switch whatIsSet(root.sequent.consequence) { - case formIsSet: - consequence = root.sequent.consequence.f.ToString() - if root.typeScheme == nil { - ts = root.sequent.consequence.f.GetType().ToString() - } - case termIsSet: - consequence = root.sequent.consequence.t.ToString() - if root.typeScheme == nil { - if root.sequent.consequence.t.(AST.TypedTerm).GetTypeHint() == nil { - ts = root.sequent.consequence.t.(AST.TypedTerm).GetTypeApp().ToString() - } else { - ts = root.sequent.consequence.t.(AST.TypedTerm).GetTypeHint().ToString() - } - } - case typeIsSet: - consequence = root.sequent.consequence.a.ToString() - if root.typeScheme == nil { - ts = "Type" - } - } - - childrenProofs := []string{} - - for _, child := range root.children { - bytes, err := child.dump() - if err != nil { - return "", err - } - childrenProofs = append(childrenProofs, bytes) - } - - bytes, err := json.Marshal(&struct { - LocalContext string `json:"localContext"` - Consequence string `json:"consequence"` - TypeScheme string `json:"typeScheme"` - Rule string `json:"rule"` - Children []string `json:"children"` - }{ - LocalContext: strings.Join(varsString, ", "), - Consequence: consequence, - TypeScheme: ts, - Rule: root.appliedRule, - Children: childrenProofs, - }) - - return strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(string(bytes), "\\", ""), "\"{", "{"), "}\"", "}"), err -} - -/* Utils */ - -/* Checks if file exists at given path */ -func fileExists(path string) bool { - _, err := os.Stat(path) - return !errors.Is(err, os.ErrNotExist) -} - -/* Create a formated file name */ -func getFileName(folder string, i int) string { - return fmt.Sprintf("%sproof_%d.json", folder, i) -} +// import ( +// "encoding/json" +// "errors" +// "fmt" +// "os" +// "strings" + +// "github.com/GoelandProver/Goeland/AST" +// "github.com/GoelandProver/Goeland/Glob" +// ) + +// /** +// * This file contains the methods to dump a prooftree in a json. +// **/ + +// /* Dumps the prooftree in a json. */ +// func (root *ProofTree) DumpJson() error { +// // Dump folder should be a flag in the future +// dump := "../visualization/types/" +// // Create a new file +// i := 0 +// for fileExists(getFileName(dump, i)) { +// i++ +// } + +// f, err := os.OpenFile(getFileName(dump, i), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) +// if err != nil { +// return err +// } +// json, err := root.dump() + +// if err != nil { +// return err +// } + +// _, err = f.WriteString(json) +// Glob.PrintInfo("DUMP", fmt.Sprintf("Dumped type proof in %s\n", f.Name())) +// return err +// } + +// /* Creates file if not exists, dump informations in it, and calls recursively on each child */ +// func (root *ProofTree) dump() (string, error) { +// varsString := []string{} +// var consequence string = "" +// var ts string +// if root.typeScheme != nil { +// ts = root.typeScheme.ToString() +// } + +// for _, var_ := range root.sequent.localContext.vars { +// varsString = append(varsString, var_.ToString()) +// } +// for _, var_ := range root.sequent.localContext.typeVars { +// varsString = append(varsString, fmt.Sprintf("%s: Type", var_.ToString())) +// } + +// switch whatIsSet(root.sequent.consequence) { +// case formIsSet: +// consequence = root.sequent.consequence.f.ToString() +// if root.typeScheme == nil { +// ts = root.sequent.consequence.f.GetType().ToString() +// } +// case termIsSet: +// consequence = root.sequent.consequence.t.ToString() +// if root.typeScheme == nil { +// if root.sequent.consequence.t.(AST.TypedTerm).GetTypeHint() == nil { +// ts = root.sequent.consequence.t.(AST.TypedTerm).GetTypeApp().ToString() +// } else { +// ts = root.sequent.consequence.t.(AST.TypedTerm).GetTypeHint().ToString() +// } +// } +// case typeIsSet: +// consequence = root.sequent.consequence.a.ToString() +// if root.typeScheme == nil { +// ts = "Type" +// } +// } + +// childrenProofs := []string{} + +// for _, child := range root.children { +// bytes, err := child.dump() +// if err != nil { +// return "", err +// } +// childrenProofs = append(childrenProofs, bytes) +// } + +// bytes, err := json.Marshal(&struct { +// LocalContext string `json:"localContext"` +// Consequence string `json:"consequence"` +// TypeScheme string `json:"typeScheme"` +// Rule string `json:"rule"` +// Children []string `json:"children"` +// }{ +// LocalContext: strings.Join(varsString, ", "), +// Consequence: consequence, +// TypeScheme: ts, +// Rule: root.appliedRule, +// Children: childrenProofs, +// }) + +// return strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(string(bytes), "\\", ""), "\"{", "{"), "}\"", "}"), err +// } + +// /* Utils */ + +// /* Checks if file exists at given path */ +// func fileExists(path string) bool { +// _, err := os.Stat(path) +// return !errors.Is(err, os.ErrNotExist) +// } + +// /* Create a formated file name */ +// func getFileName(folder string, i int) string { +// return fmt.Sprintf("%sproof_%d.json", folder, i) +// } diff --git a/src/Typing/rules.go b/src/Typing/rules.go index 80713c65..2850fcc2 100644 --- a/src/Typing/rules.go +++ b/src/Typing/rules.go @@ -32,205 +32,205 @@ package Typing -import ( - "reflect" - - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * This file contains the functions to create a typing proof tree. - * It defines the TypingProofTree structure and all the rules to check if a - * system is well-typed. - **/ - -/* Stores the consequence of the sequent */ -type Consequence struct { - f AST.Form - t AST.Term - a AST.TypeApp - s AST.TypeScheme -} - -/* A Sequent is formed of a global context, local context, and a formula or a term to type */ -type Sequent struct { - globalContext GlobalContext - localContext LocalContext - consequence Consequence -} - -/* Makes a typing prooftree to output. */ -type ProofTree struct { - sequent Sequent - appliedRule string - typeScheme AST.TypeScheme - children []*ProofTree -} - -/* ProofTree meta-type */ -var metaType AST.TypeHint - -/* ProofTree methods */ - -/* Creates and adds a child to the prooftree and returns it. */ -func (pt *ProofTree) addChildWith(sequent Sequent) *ProofTree { - child := ProofTree{ - sequent: sequent, - children: []*ProofTree{}, - } - pt.children = append(pt.children, &child) - return &child -} - -var globalContextIsWellTyped bool = false - -/** - * Tries to type form. - * If not well-typed, will return an error. - **/ -func WellFormedVerification(form AST.Form, dump bool) error { - // Instanciate meta type - metaType = AST.MkTypeHint("$tType") - - // Second pass to type variables & to give the typevars to functions and predicates - form = SecondPass(form) - - globalContext, err := createGlobalContext(AST.GetGlobalContext()) - if err != nil { - return err - } - - // Sequent creation - state := Sequent{ - globalContext: globalContext, - localContext: LocalContext{vars: []AST.Var{}, typeVars: []AST.TypeVar{}}, - consequence: Consequence{f: form}, - } - - // Prooftree creation - root := ProofTree{ - sequent: state, - children: []*ProofTree{}, - } - - // Launch the typing system - _, err = launchRuleApplication(state, &root) - - // Dump prooftree in json if it's asked & there is no error - if dump && err == nil { - err = root.DumpJson() - } - - return err -} - -/* Reconstructs a Form depending on what the children has returned */ -func reconstructForm(reconstruction Reconstruct, baseForm AST.Form) Reconstruct { - if !reconstruction.result { - return reconstruction - } - - var f AST.Form - switch form := baseForm.(type) { - case AST.All: - f = AST.MakeAll(form.GetIndex(), form.GetVarList(), unquantify(reconstruction.forms.At(1), form)) - case AST.AllType: - f = AST.MakeAllType(form.GetIndex(), form.GetVarList(), unquantify(reconstruction.forms.At(1), form)) - case AST.Ex: - f = AST.MakeEx(form.GetIndex(), form.GetVarList(), unquantify(reconstruction.forms.At(1), form)) - case AST.And: - f = AST.MakeAnd(form.GetIndex(), reconstruction.forms) - case AST.Or: - f = AST.MakeOr(form.GetIndex(), reconstruction.forms) - case AST.Imp: - f = AST.MakeImp(form.GetIndex(), reconstruction.forms.At(0), reconstruction.forms.At(1)) - case AST.Equ: - f = AST.MakeEqu(form.GetIndex(), reconstruction.forms.At(0), reconstruction.forms.At(1)) - case AST.Not: - f = AST.MakeNot(form.GetIndex(), reconstruction.forms.At(0)) - case AST.Pred: - // The len(form.GetTypeVars()) first children launched are children for typevars. - // So the len(form.GetTypeVars()) first children will return - if reconstruction.terms.Len() > len(form.GetTypeVars()) { - terms := Lib.MkListV(reconstruction.terms.Get( - len(form.GetTypeVars()), - reconstruction.terms.Len(), - )...) - f = AST.MakePred( - form.GetIndex(), - form.GetID(), - terms, - form.GetTypeVars(), - form.GetType(), - ) - } else { - f = AST.MakePred( - form.GetIndex(), - form.GetID(), - Lib.NewList[AST.Term](), - form.GetTypeVars(), - form.GetType(), - ) - } - case AST.Top, AST.Bot: - f = baseForm - } - - return Reconstruct{result: true, forms: Lib.MkListV(f), err: nil} -} - -/* Reconstructs a Term depending on what the children has returned */ -func reconstructTerm(reconstruction Reconstruct, baseTerm AST.Term) Reconstruct { - if !reconstruction.result { - return reconstruction - } - - // fun: reconstruct with children terms - if Glob.Is[AST.Fun](baseTerm) { - termFun := Glob.To[AST.Fun](baseTerm) - var fun AST.Fun - // The len(form.GetTypeVars()) first children launched are children for typevars. - // So the len(form.GetTypeVars()) first children will return - if reconstruction.terms.Len() > len(termFun.GetTypeVars()) { - terms := Lib.MkListV(reconstruction.terms.Get( - len(termFun.GetTypeVars()), - reconstruction.terms.Len(), - )...) - fun = AST.MakerFun( - termFun.GetID(), - terms, - termFun.GetTypeVars(), - termFun.GetTypeHint(), - ) - } else { - fun = AST.MakerFun( - termFun.GetID(), - Lib.NewList[AST.Term](), - termFun.GetTypeVars(), - termFun.GetTypeHint(), - ) - } - return Reconstruct{result: true, terms: Lib.MkListV[AST.Term](fun), err: nil} - } - - return Reconstruct{result: true, terms: Lib.MkListV(baseTerm), err: nil} -} - -/* Utils for reconstructions function */ - -/* Removes all the quantifiers of form of the same type of quant. */ -func unquantify(form AST.Form, quant AST.Form) AST.Form { - for reflect.TypeOf(form) == reflect.TypeOf(quant) { - switch quant.(type) { - case AST.All: - form = Glob.To[AST.All](form).GetForm() - case AST.AllType: - form = Glob.To[AST.AllType](form).GetForm() - case AST.Ex: - form = Glob.To[AST.Ex](form).GetForm() - } - } - return form -} +// import ( +// "reflect" + +// "github.com/GoelandProver/Goeland/AST" +// "github.com/GoelandProver/Goeland/Glob" +// "github.com/GoelandProver/Goeland/Lib" +// ) + +// /** +// * This file contains the functions to create a typing proof tree. +// * It defines the TypingProofTree structure and all the rules to check if a +// * system is well-typed. +// **/ + +// /* Stores the consequence of the sequent */ +// type Consequence struct { +// f AST.Form +// t AST.Term +// a AST.TypeApp +// s AST.TypeScheme +// } + +// /* A Sequent is formed of a global context, local context, and a formula or a term to type */ +// type Sequent struct { +// globalContext GlobalContext +// localContext LocalContext +// consequence Consequence +// } + +// /* Makes a typing prooftree to output. */ +// type ProofTree struct { +// sequent Sequent +// appliedRule string +// typeScheme AST.TypeScheme +// children []*ProofTree +// } + +// /* ProofTree meta-type */ +// var metaType AST.TypeHint + +// /* ProofTree methods */ + +// /* Creates and adds a child to the prooftree and returns it. */ +// func (pt *ProofTree) addChildWith(sequent Sequent) *ProofTree { +// child := ProofTree{ +// sequent: sequent, +// children: []*ProofTree{}, +// } +// pt.children = append(pt.children, &child) +// return &child +// } + +// var globalContextIsWellTyped bool = false + +// /** +// * Tries to type form. +// * If not well-typed, will return an error. +// **/ +// func WellFormedVerification(form AST.Form, dump bool) error { +// // Instanciate meta type +// metaType = AST.MkTypeHint("$tType") + +// // Second pass to type variables & to give the typevars to functions and predicates +// form = SecondPass(form) + +// globalContext, err := createGlobalContext(AST.GetGlobalContext()) +// if err != nil { +// return err +// } + +// // Sequent creation +// state := Sequent{ +// globalContext: globalContext, +// localContext: LocalContext{vars: []AST.Var{}, typeVars: []AST.TypeVar{}}, +// consequence: Consequence{f: form}, +// } + +// // Prooftree creation +// root := ProofTree{ +// sequent: state, +// children: []*ProofTree{}, +// } + +// // Launch the typing system +// _, err = launchRuleApplication(state, &root) + +// // Dump prooftree in json if it's asked & there is no error +// if dump && err == nil { +// err = root.DumpJson() +// } + +// return err +// } + +// /* Reconstructs a Form depending on what the children has returned */ +// func reconstructForm(reconstruction Reconstruct, baseForm AST.Form) Reconstruct { +// if !reconstruction.result { +// return reconstruction +// } + +// var f AST.Form +// switch form := baseForm.(type) { +// case AST.All: +// f = AST.MakeAll(form.GetIndex(), form.GetVarList(), unquantify(reconstruction.forms.At(1), form)) +// case AST.AllType: +// f = AST.MakeAllType(form.GetIndex(), form.GetVarList(), unquantify(reconstruction.forms.At(1), form)) +// case AST.Ex: +// f = AST.MakeEx(form.GetIndex(), form.GetVarList(), unquantify(reconstruction.forms.At(1), form)) +// case AST.And: +// f = AST.MakeAnd(form.GetIndex(), reconstruction.forms) +// case AST.Or: +// f = AST.MakeOr(form.GetIndex(), reconstruction.forms) +// case AST.Imp: +// f = AST.MakeImp(form.GetIndex(), reconstruction.forms.At(0), reconstruction.forms.At(1)) +// case AST.Equ: +// f = AST.MakeEqu(form.GetIndex(), reconstruction.forms.At(0), reconstruction.forms.At(1)) +// case AST.Not: +// f = AST.MakeNot(form.GetIndex(), reconstruction.forms.At(0)) +// case AST.Pred: +// // The len(form.GetTypeVars()) first children launched are children for typevars. +// // So the len(form.GetTypeVars()) first children will return +// if reconstruction.terms.Len() > len(form.GetTypeVars()) { +// terms := Lib.MkListV(reconstruction.terms.Get( +// len(form.GetTypeVars()), +// reconstruction.terms.Len(), +// )...) +// f = AST.MakePred( +// form.GetIndex(), +// form.GetID(), +// terms, +// form.GetTypeVars(), +// form.GetType(), +// ) +// } else { +// f = AST.MakePred( +// form.GetIndex(), +// form.GetID(), +// Lib.NewList[AST.Term](), +// form.GetTypeVars(), +// form.GetType(), +// ) +// } +// case AST.Top, AST.Bot: +// f = baseForm +// } + +// return Reconstruct{result: true, forms: Lib.MkListV(f), err: nil} +// } + +// /* Reconstructs a Term depending on what the children has returned */ +// func reconstructTerm(reconstruction Reconstruct, baseTerm AST.Term) Reconstruct { +// if !reconstruction.result { +// return reconstruction +// } + +// // fun: reconstruct with children terms +// if Glob.Is[AST.Fun](baseTerm) { +// termFun := Glob.To[AST.Fun](baseTerm) +// var fun AST.Fun +// // The len(form.GetTypeVars()) first children launched are children for typevars. +// // So the len(form.GetTypeVars()) first children will return +// if reconstruction.terms.Len() > len(termFun.GetTypeVars()) { +// terms := Lib.MkListV(reconstruction.terms.Get( +// len(termFun.GetTypeVars()), +// reconstruction.terms.Len(), +// )...) +// fun = AST.MakerFun( +// termFun.GetID(), +// terms, +// termFun.GetTypeVars(), +// termFun.GetTypeHint(), +// ) +// } else { +// fun = AST.MakerFun( +// termFun.GetID(), +// Lib.NewList[AST.Term](), +// termFun.GetTypeVars(), +// termFun.GetTypeHint(), +// ) +// } +// return Reconstruct{result: true, terms: Lib.MkListV[AST.Term](fun), err: nil} +// } + +// return Reconstruct{result: true, terms: Lib.MkListV(baseTerm), err: nil} +// } + +// /* Utils for reconstructions function */ + +// /* Removes all the quantifiers of form of the same type of quant. */ +// func unquantify(form AST.Form, quant AST.Form) AST.Form { +// for reflect.TypeOf(form) == reflect.TypeOf(quant) { +// switch quant.(type) { +// case AST.All: +// form = Glob.To[AST.All](form).GetForm() +// case AST.AllType: +// form = Glob.To[AST.AllType](form).GetForm() +// case AST.Ex: +// form = Glob.To[AST.Ex](form).GetForm() +// } +// } +// return form +// } diff --git a/src/Typing/term_rules.go b/src/Typing/term_rules.go index 62ae0d6c..ced4119e 100644 --- a/src/Typing/term_rules.go +++ b/src/Typing/term_rules.go @@ -32,184 +32,185 @@ package Typing -import ( - "fmt" - - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * This file contains the rules for typing terms, and also the App rule. - * The App rule is used for predicates and functions. - **/ - -/* Applies the App rule for predicates or functions */ -func applyAppRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - var index int - var id AST.Id - var terms Lib.List[AST.Term] - var vars []AST.TypeApp - - if whatIsSet(state.consequence) == formIsSet { - index = (state.consequence.f).(AST.Pred).GetIndex() - id = (state.consequence.f).(AST.Pred).GetID() - terms = (state.consequence.f).(AST.Pred).GetArgs() - vars = (state.consequence.f).(AST.Pred).GetTypeVars() - } else { - id = (state.consequence.t).(AST.Fun).GetID() - terms = (state.consequence.t).(AST.Fun).GetArgs() - vars = (state.consequence.t).(AST.Fun).GetTypeVars() - } - - root.appliedRule = "App" - - // Search for the ID in the global context - typeScheme, err := state.globalContext.getTypeScheme(id, vars, terms) - if err != nil { - return Reconstruct{ - result: false, - err: err, - } - } - - // Affect new type scheme to the prooftree - root.typeScheme = typeScheme - primitives := typeScheme.GetPrimitives() - - // Type predicate or function - if whatIsSet(state.consequence) == formIsSet { - fTyped := AST.MakePred(index, id, terms, vars, typeScheme) - return reconstructForm(launchChildren( - createAppChildren(state, vars, terms, primitives), - root, - fatherChan, - ), fTyped) - } else { - fTyped := AST.MakerFun(id, terms, vars, typeScheme) - return reconstructTerm(launchChildren(createAppChildren(state, vars, terms, primitives), root, fatherChan), fTyped) - } -} - -/* Applies the Var rule for a term variable. */ -func applyVarRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add applied rule to the prooftree - root.appliedRule = "Var" - - // Find current variable in the local context - if _, ok := getTermFromLocalContext(state.localContext, state.consequence.t); !ok { - return Reconstruct{ - result: false, - err: fmt.Errorf("term %s not found in the local context", state.consequence.t.ToString()), - } - } - - // No consequence: next rule is the WF rule. - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{}, - }, - } - - return reconstructTerm(launchChildren(children, root, fatherChan), state.consequence.t) -} - -/* Utils functions */ - -/** - * Takes all the types of the terms and makes a cross product of everything - **/ -func getArgsTypes( - context GlobalContext, - terms Lib.List[AST.Term], -) (AST.TypeApp, error) { - if terms.Len() == 0 { - return nil, nil - } - - var types []AST.TypeApp - - for _, term := range terms.GetSlice() { - switch tmpTerm := term.(type) { - case AST.Fun: - typeScheme, err := context.getTypeScheme( - tmpTerm.GetID(), - tmpTerm.GetTypeVars(), - tmpTerm.GetArgs(), - ) - if err != nil { - return nil, err - } - if typeScheme == nil { - return nil, fmt.Errorf("function %s not found in global context", tmpTerm.GetName()) - } - types = append(types, AST.GetOutType(typeScheme)) - case AST.Var: - // Variables can't be of type TypeScheme, so this line shouldn't fail. - types = append(types, tmpTerm.GetTypeApp()) - // There shouldn't be Metas yet. - case AST.Meta: - debug(Lib.MkLazy(func() string { return "Found a Meta while typing everything." })) - // ID is filtered out - } - } - - if len(types) == 1 { - return types[0], nil - } - typeCross := AST.MkTypeCross(types[0], types[1]) - for i := 2; i < len(types); i += 1 { - typeCross = AST.MkTypeCross(typeCross, types[i]) - } - return typeCross, nil -} - -/* Creates children for app rule */ -func createAppChildren( - state Sequent, - vars []AST.TypeApp, - terms Lib.List[AST.Term], - primitives []AST.TypeApp, -) []Sequent { - children := []Sequent{} - - // 1 for each type in the vars - for _, var_ := range vars { - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{a: var_}, - }) - } - - // 1 for each term - for i, term := range terms.GetSlice() { - switch t := term.(type) { - case AST.Fun: - term = AST.MakerFun(t.GetID(), t.GetArgs(), t.GetTypeVars(), primitives[i].(AST.TypeScheme)) - case AST.Meta: - term = AST.MakeMeta(t.GetIndex(), t.GetOccurence(), t.GetName(), t.GetFormula(), primitives[i]) - case AST.Var: - term = AST.MakeVar(t.GetIndex(), t.GetName(), primitives[i]) - } - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{t: term}, - }) - } - - return children -} - -/* Finds the given term in the local context, returns false if it couldn't */ -func getTermFromLocalContext(localContext LocalContext, term AST.Term) (AST.Var, bool) { - for _, var_ := range localContext.vars { - if var_.Equals(term) { - return var_, true - } - } - return AST.Var{}, false -} +// import ( +// "fmt" + +// "github.com/GoelandProver/Goeland/AST" +// "github.com/GoelandProver/Goeland/Glob" +// "github.com/GoelandProver/Goeland/Lib" +// ) + +// /** +// * This file contains the rules for typing terms, and also the App rule. +// * The App rule is used for predicates and functions. +// **/ + +// /* Applies the App rule for predicates or functions */ +// func applyAppRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// var index int +// var id AST.Id +// var terms Lib.List[AST.Term] +// var vars []AST.TypeApp + +// if whatIsSet(state.consequence) == formIsSet { +// index = (state.consequence.f).(AST.Pred).GetIndex() +// id = (state.consequence.f).(AST.Pred).GetID() +// terms = (state.consequence.f).(AST.Pred).GetArgs() +// vars = (state.consequence.f).(AST.Pred).GetTypeVars() +// } else { +// id = (state.consequence.t).(AST.Fun).GetID() +// terms = (state.consequence.t).(AST.Fun).GetArgs() +// vars = (state.consequence.t).(AST.Fun).GetTypeVars() +// } + +// root.appliedRule = "App" + +// // Search for the ID in the global context +// typeScheme, err := state.globalContext.getTypeScheme(id, vars, terms) +// if err != nil { +// return Reconstruct{ +// result: false, +// err: err, +// } +// } + +// // Affect new type scheme to the prooftree +// root.typeScheme = typeScheme +// primitives := typeScheme.GetPrimitives() + +// // Type predicate or function +// if whatIsSet(state.consequence) == formIsSet { +// fTyped := AST.MakePred(index, id, terms, vars, typeScheme) +// return reconstructForm(launchChildren( +// createAppChildren(state, vars, terms, primitives), +// root, +// fatherChan, +// ), fTyped) +// } else { +// fTyped := AST.MakerFun(id, terms, vars, typeScheme) +// return reconstructTerm(launchChildren(createAppChildren(state, vars, terms, primitives), root, fatherChan), fTyped) +// } +// } + +// /* Applies the Var rule for a term variable. */ +// func applyVarRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// // Add applied rule to the prooftree +// root.appliedRule = "Var" + +// // Find current variable in the local context +// if _, ok := getTermFromLocalContext(state.localContext, state.consequence.t); !ok { +// return Reconstruct{ +// result: false, +// err: fmt.Errorf("term %s not found in the local context", state.consequence.t.ToString()), +// } +// } + +// // No consequence: next rule is the WF rule. +// children := []Sequent{ +// { +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{}, +// }, +// } + +// return reconstructTerm(launchChildren(children, root, fatherChan), state.consequence.t) +// } + +// /* Utils functions */ + +// /** +// * Takes all the types of the terms and makes a cross product of everything +// **/ +// func getArgsTypes( +// context GlobalContext, +// terms Lib.List[AST.Term], +// ) (AST.TypeApp, error) { +// if terms.Len() == 0 { +// return nil, nil +// } + +// var types []AST.TypeApp + +// for _, term := range terms.GetSlice() { +// switch tmpTerm := term.(type) { +// case AST.Fun: +// typeScheme, err := context.getTypeScheme( +// tmpTerm.GetID(), +// tmpTerm.GetTypeVars(), +// tmpTerm.GetArgs(), +// ) +// if err != nil { +// return nil, err +// } +// if typeScheme == nil { +// return nil, fmt.Errorf("function %s not found in global context", tmpTerm.GetName()) +// } +// types = append(types, AST.GetOutType(typeScheme)) +// case AST.Var: +// // Variables can't be of type TypeScheme, so this line shouldn't fail. +// types = append(types, tmpTerm.GetTypeApp()) +// // There shouldn't be Metas yet. +// case AST.Meta: +// Glob.PrintDebug("GAT", Lib.MkLazy(func() string { return "Found a Meta while typing everything." })) +// // ID is filtered out +// } +// } + +// if len(types) == 1 { +// return types[0], nil +// } +// typeCross := AST.MkTypeCross(types[0], types[1]) +// for i := 2; i < len(types); i += 1 { +// typeCross = AST.MkTypeCross(typeCross, types[i]) +// } +// return typeCross, nil +// } + +// /* Creates children for app rule */ +// func createAppChildren( +// state Sequent, +// vars []AST.TypeApp, +// terms Lib.List[AST.Term], +// primitives []AST.TypeApp, +// ) []Sequent { +// children := []Sequent{} + +// // 1 for each type in the vars +// for _, var_ := range vars { +// children = append(children, Sequent{ +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{a: var_}, +// }) +// } + +// // 1 for each term +// for i, term := range terms.GetSlice() { +// switch t := term.(type) { +// case AST.Fun: +// term = AST.MakerFun(t.GetID(), t.GetArgs(), t.GetTypeVars(), primitives[i].(AST.TypeScheme)) +// case AST.Meta: +// term = AST.MakeMeta(t.GetIndex(), t.GetOccurence(), t.GetName(), t.GetFormula(), primitives[i]) +// case AST.Var: +// term = AST.MakeVar(t.GetIndex(), t.GetName(), primitives[i]) +// } +// children = append(children, Sequent{ +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{t: term}, +// }) +// } + +// return children +// } + +// /* Finds the given term in the local context, returns false if it couldn't */ +// func getTermFromLocalContext(localContext LocalContext, term AST.Term) (AST.Var, bool) { +// for _, var_ := range localContext.vars { +// if var_.Equals(term) { +// return var_, true +// } +// } +// return AST.Var{}, false +// } diff --git a/src/Typing/type.go b/src/Typing/type.go index 2d530bef..9d64162c 100644 --- a/src/Typing/type.go +++ b/src/Typing/type.go @@ -32,165 +32,159 @@ package Typing -import ( - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -var debug Glob.Debugger - -func InitDebugger() { - debug = Glob.CreateDebugger("typing") -} - -/** - * This file implements a second pass on the given formula to: - * - Type the variables - * - Give a type to the polymorph predicates / functions - **/ - -func SecondPass(form AST.Form) AST.Form { - after := secondPassAux(form, []AST.Var{}, []AST.TypeApp{}) - return after -} - -func secondPassAux(form AST.Form, vars []AST.Var, types []AST.TypeApp) AST.Form { - switch f := form.(type) { - case AST.Pred: - terms := nArySecondPassTerms(f.GetArgs(), vars, types) - - // Special case: defined predicate. We need to infer types. - if f.GetID().Equals(AST.Id_eq) { - return AST.MakePred( - f.GetIndex(), - f.GetID(), - terms, - []AST.TypeApp{ - AST.GetOutType( - Glob.To[AST.TypedTerm, AST.Term](terms.At(0)).GetTypeHint(), - )}) - } - - // Real case: classical predicate, it should be given - return AST.MakePred(f.GetIndex(), f.GetID(), terms, f.GetTypeVars()) - case AST.And: - return AST.MakeAnd(f.GetIndex(), nArySecondPass(f.GetChildFormulas(), vars, types)) - case AST.Or: - return AST.MakeOr(f.GetIndex(), nArySecondPass(f.GetChildFormulas(), vars, types)) - case AST.Imp: - return AST.MakeImp(f.GetIndex(), secondPassAux(f.GetF1(), vars, types), secondPassAux(f.GetF2(), vars, types)) - case AST.Equ: - return AST.MakeEqu(f.GetIndex(), secondPassAux(f.GetF1(), vars, types), secondPassAux(f.GetF2(), vars, types)) - case AST.Not: - return AST.MakeNot(f.GetIndex(), secondPassAux(f.GetForm(), vars, types)) - case AST.All: - return AST.MakeAll(f.GetIndex(), f.GetVarList(), secondPassAux(f.GetForm(), append(vars, f.GetVarList()...), types)) - case AST.Ex: - return AST.MakeEx(f.GetIndex(), f.GetVarList(), secondPassAux(f.GetForm(), append(vars, f.GetVarList()...), types)) - case AST.AllType: - return AST.MakeAllType(f.GetIndex(), f.GetVarList(), secondPassAux(f.GetForm(), vars, append(types, Glob.ConvertList[AST.TypeVar, AST.TypeApp](f.GetVarList())...))) - } - return form -} - -func secondPassTerm(term AST.Term, vars []AST.Var, types []AST.TypeApp) AST.Term { - switch t := term.(type) { - case AST.Fun: - terms := nArySecondPassTerms(t.GetArgs(), vars, types) - - // - It's a function - outType := func(term AST.Term) AST.TypeApp { - return AST.GetOutType(Glob.To[AST.TypedTerm](term).GetTypeHint()) - } - - termsType := []AST.TypeApp{} - for _, tm := range terms.GetSlice() { - termsType = append(termsType, outType(tm)) - } - - return AST.MakerFun(t.GetID(), terms, t.GetTypeVars(), - getTypeOfFunction(t.GetName(), t.GetTypeVars(), termsType)) - - case AST.Var: - return t - } - return term -} - -func nArySecondPass(forms Lib.List[AST.Form], vars []AST.Var, types []AST.TypeApp) Lib.List[AST.Form] { - res := Lib.NewList[AST.Form]() - - for _, form := range forms.GetSlice() { - res.Append(secondPassAux(form, vars, types)) - } - - return res -} - -func nArySecondPassTerms( - terms Lib.List[AST.Term], - vars []AST.Var, - types []AST.TypeApp, -) Lib.List[AST.Term] { - resTerms := Lib.NewList[AST.Term]() - - for _, term := range terms.GetSlice() { - t := secondPassTerm(term, vars, types) - - if t != nil { - resTerms.Append(t) - } - } - - return resTerms -} - -func getTypeOfFunction(name string, vars []AST.TypeApp, termsType []AST.TypeApp) AST.TypeScheme { - // Build TypeCross from termsType - var tt []AST.TypeApp - if len(termsType) >= 2 { - tc := AST.MkTypeCross(termsType[0], termsType[1]) - for i := 2; i < len(termsType); i += 1 { - tc = AST.MkTypeCross(tc, termsType[i]) - } - tt = []AST.TypeApp{tc} - } else { - tt = termsType - } - - simpleTypeScheme := AST.GetType(name, tt...) - if simpleTypeScheme != nil { - if Glob.Is[AST.QuantifiedType](simpleTypeScheme) { - return Glob.To[AST.QuantifiedType](simpleTypeScheme).Instanciate(vars) - } - return simpleTypeScheme - } - - typeScheme := AST.GetPolymorphicType(name, len(vars), len(termsType)) - - if typeScheme != nil { - // Instantiate type scheme with actual types - typeScheme = Glob.To[AST.QuantifiedType](typeScheme).Instanciate(vars) - } else { - // As only distinct objects are here, it should work with only this. - // I leave the other condition if others weirderies are found later. - if len(termsType) == 0 { - AST.SaveConstant(name, Glob.To[AST.TypeApp](AST.DefaultFunType(0))) - } - /* - else { - type_ := DefaultFunType(len(termsType)) - if len(termsType) == 1 { - SaveTypeScheme(name, GetInputType(type_)[0], GetOutType(type_)) - } else { - SaveTypeScheme(name, AST.MkTypeCross(GetInputType(type_)...), GetOutType(type_)) - } - } - */ - typeScheme = AST.DefaultFunType(0) - - } - - return typeScheme -} +// import ( +// "github.com/GoelandProver/Goeland/AST" +// "github.com/GoelandProver/Goeland/Glob" +// "github.com/GoelandProver/Goeland/Lib" +// ) + +// /** +// * This file implements a second pass on the given formula to: +// * - Type the variables +// * - Give a type to the polymorph predicates / functions +// **/ + +// func SecondPass(form AST.Form) AST.Form { +// after := secondPassAux(form, []AST.Var{}, []AST.TypeApp{}) +// return after +// } + +// func secondPassAux(form AST.Form, vars []AST.Var, types []AST.TypeApp) AST.Form { +// switch f := form.(type) { +// case AST.Pred: +// terms := nArySecondPassTerms(f.GetArgs(), vars, types) + +// // Special case: defined predicate. We need to infer types. +// if f.GetID().Equals(AST.Id_eq) { +// return AST.MakePred( +// f.GetIndex(), +// f.GetID(), +// terms, +// []AST.TypeApp{ +// AST.GetOutType( +// Glob.To[AST.TypedTerm, AST.Term](terms.At(0)).GetTypeHint(), +// )}) +// } + +// // Real case: classical predicate, it should be given +// return AST.MakePred(f.GetIndex(), f.GetID(), terms, f.GetTypeVars()) +// case AST.And: +// return AST.MakeAnd(f.GetIndex(), nArySecondPass(f.GetChildFormulas(), vars, types)) +// case AST.Or: +// return AST.MakeOr(f.GetIndex(), nArySecondPass(f.Get, vars, types)) +// case AST.Imp: +// return AST.MakeImp(f.GetIndex(), secondPassAux(f.GetF1(), vars, types), secondPassAux(f.GetF2(), vars, types)) +// case AST.Equ: +// return AST.MakeEqu(f.GetIndex(), secondPassAux(f.GetF1(), vars, types), secondPassAux(f.GetF2(), vars, types)) +// case AST.Not: +// return AST.MakeNot(f.GetIndex(), secondPassAux(f.GetForm(), vars, types)) +// case AST.All: +// return AST.MakeAll(f.GetIndex(), f.GetVarList(), secondPassAux(f.GetForm(), append(vars, f.GetVarList()...), types)) +// case AST.Ex: +// return AST.MakeEx(f.GetIndex(), f.GetVarList(), secondPassAux(f.GetForm(), append(vars, f.GetVarList()...), types)) +// case AST.AllType: +// return AST.MakeAllType(f.GetIndex(), f.GetVarList(), secondPassAux(f.GetForm(), vars, append(types, Glob.ConvertList[AST.TypeVar, AST.TypeApp](f.GetVarList())...))) +// } +// return form +// } + +// func secondPassTerm(term AST.Term, vars []AST.Var, types []AST.TypeApp) AST.Term { +// switch t := term.(type) { +// case AST.Fun: +// terms := nArySecondPassTerms(t.GetArgs(), vars, types) + +// // - It's a function +// outType := func(term AST.Term) AST.TypeApp { +// return AST.GetOutType(Glob.To[AST.TypedTerm](term).GetTypeHint()) +// } + +// termsType := []AST.TypeApp{} +// for _, tm := range terms.GetSlice() { +// termsType = append(termsType, outType(tm)) +// } + +// return AST.MakerFun(t.GetID(), terms, t.GetTypeVars(), +// getTypeOfFunction(t.GetName(), t.GetTypeVars(), termsType)) + +// case AST.Var: +// return t +// } +// return term +// } + +// func nArySecondPass(forms Lib.List[AST.Form], vars []AST.Var, types []AST.TypeApp) Lib.List[AST.Form] { +// res := Lib.NewList[AST.Form]() + +// for _, form := range forms.GetSlice() { +// res.Append(secondPassAux(form, vars, types)) +// } + +// return res +// } + +// func nArySecondPassTerms( +// terms Lib.List[AST.Term], +// vars []AST.Var, +// types []AST.TypeApp, +// ) Lib.List[AST.Term] { +// resTerms := Lib.NewList[AST.Term]() + +// for _, term := range terms.GetSlice() { +// t := secondPassTerm(term, vars, types) + +// if t != nil { +// resTerms.Append(t) +// } +// } + +// return resTerms +// } + +// func getTypeOfFunction(name string, vars []AST.TypeApp, termsType []AST.TypeApp) AST.TypeScheme { +// // Build TypeCross from termsType +// var tt []AST.TypeApp +// if len(termsType) >= 2 { +// tc := AST.MkTypeCross(termsType[0], termsType[1]) +// for i := 2; i < len(termsType); i += 1 { +// tc = AST.MkTypeCross(tc, termsType[i]) +// } +// tt = []AST.TypeApp{tc} +// } else { +// tt = termsType +// } + +// simpleTypeScheme := AST.GetType(name, tt...) +// if simpleTypeScheme != nil { +// if Glob.Is[AST.QuantifiedType](simpleTypeScheme) { +// return Glob.To[AST.QuantifiedType](simpleTypeScheme).Instanciate(vars) +// } +// return simpleTypeScheme +// } + +// typeScheme := AST.GetPolymorphicType(name, len(vars), len(termsType)) + +// if typeScheme != nil { +// // Instantiate type scheme with actual types +// typeScheme = Glob.To[AST.QuantifiedType](typeScheme).Instanciate(vars) +// } else { +// // As only distinct objects are here, it should work with only this. +// // I leave the other condition if others weirderies are found later. +// if len(termsType) == 0 { +// AST.SaveConstant(name, Glob.To[AST.TypeApp](AST.DefaultFunType(0))) +// } +// /* +// else { +// type_ := DefaultFunType(len(termsType)) +// if len(termsType) == 1 { +// SaveTypeScheme(name, GetInputType(type_)[0], GetOutType(type_)) +// } else { +// SaveTypeScheme(name, AST.MkTypeCross(GetInputType(type_)...), GetOutType(type_)) +// } +// } +// */ +// typeScheme = AST.DefaultFunType(0) + +// } + +// return typeScheme +// } diff --git a/src/Typing/type_rules.go b/src/Typing/type_rules.go index 82f03ced..f285ca85 100644 --- a/src/Typing/type_rules.go +++ b/src/Typing/type_rules.go @@ -32,189 +32,189 @@ package Typing -import ( - "fmt" - - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * This file contains the rules for typing terms, and also the App rule. - * The App rule is used for predicates and functions. - **/ - -/* Applies the Var rule for a type variable: erase consequence */ -func applyLocalTypeVarRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add applied rule to the prooftree - root.appliedRule = "Var" - - // Find current variable in the local context - if _, ok := getTypeFromLocalContext(state.localContext, state.consequence.a.(AST.TypeVar)); !ok { - return Reconstruct{ - result: false, - err: fmt.Errorf("TypeVar %s not found in the local context", state.consequence.a.ToString()), - } - } - - // No consequence: next rule is the WF rule. - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{}, - }, - } - - return launchChildren(children, root, fatherChan) -} - -/* Applies the Var rule for a type hint: erase consequence */ -func applyGlobalTypeVarRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add applied rule to the prooftree - root.appliedRule = "Var" - - // Find current variable in the local context - if found := state.globalContext.isTypeInContext(Glob.To[AST.TypeScheme](state.consequence.a)); !found { - return Reconstruct{ - result: false, - err: fmt.Errorf("TypeVar %s not found in the global context", state.consequence.a.ToString()), - } - } - - // No consequence: next rule is the WF rule. - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{}, - }, - } - - return launchChildren(children, root, fatherChan) -} - -/* Applies Type rule: erase consequence */ -func applyTypeWFRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add applied rule to the prooftree - root.appliedRule = "Type" - - // WF child - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{}, - }, - } - - return launchChildren(children, root, fatherChan) -} - -/* Applies Cross rule */ -func applyCrossRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add applied rule to the prooftree - root.appliedRule = "Cross" - - if tc, ok := state.consequence.a.(AST.TypeCross); ok { - // Construct a child for every type recovered - return launchChildren(constructWithTypes(state, tc.GetAllUnderlyingTypes()), root, fatherChan) - } else { - return Reconstruct{ - result: false, - err: fmt.Errorf("CrossRule type on something that is not a TypeCross: %s", state.consequence.a.ToString()), - } - } -} - -/* Sym rule: a child for each type in the input, and one for the output if it's a function */ -func applySymRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - root.appliedRule = "Sym" - - primitives := state.consequence.s.GetPrimitives() - out := AST.GetOutType(state.consequence.s) - - newLocalContext := state.localContext.copy() - if qt, found := state.consequence.s.(AST.QuantifiedType); found { - newLocalContext.typeVars = append(newLocalContext.typeVars, qt.QuantifiedVars()...) - } - - children := []Sequent{} - if Glob.Is[AST.TypeScheme](out) { - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: newLocalContext, - consequence: Consequence{a: out}, - }) - } - - for _, type_ := range primitives[:len(primitives)-1] { - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: newLocalContext, - consequence: Consequence{a: type_}, - }) - } - - return launchChildren(children, root, fatherChan) -} - -/* AppType rule: a child for each type in the input, and checks if the parameterized type exists. */ -func applyAppTypeRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - root.appliedRule = "App" - - type_ := state.consequence.a.(AST.ParameterizedType) - types := type_.GetParameters() - - // Search for the ID in the global context - if !state.globalContext.parameterizedTypesContains(type_.GetName()) { - return Reconstruct{ - result: false, - err: fmt.Errorf("parameterized Type %s not in context", type_.ToString()), - } - } - - children := []Sequent{} - for _, type_ := range types { - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{a: type_}, - }) - } - - result := launchChildren(children, root, fatherChan) - - // Only one term needs to be returned because the ParameterizedType is counted as one. - return Reconstruct{ - result: result.result, - err: result.err, - terms: Lib.NewList[AST.Term](), - } -} - -/* Utils functions */ - -/* Finds the given term in the local context, returns false if it couldn't */ -func getTypeFromLocalContext(localContext LocalContext, typeApp AST.TypeVar) (AST.TypeApp, bool) { - for _, type_ := range localContext.typeVars { - if typeApp.Equals(type_) { - return type_, true - } - } - return AST.TypeVar{}, false -} - -/* Constructs all the children of a composed type */ -func constructWithTypes(state Sequent, types []AST.TypeApp) []Sequent { - children := []Sequent{} - for _, type_ := range types { - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{a: type_}, - }) - } - return children -} +// import ( +// "fmt" + +// "github.com/GoelandProver/Goeland/AST" +// "github.com/GoelandProver/Goeland/Glob" +// "github.com/GoelandProver/Goeland/Lib" +// ) + +// /** +// * This file contains the rules for typing terms, and also the App rule. +// * The App rule is used for predicates and functions. +// **/ + +// /* Applies the Var rule for a type variable: erase consequence */ +// func applyLocalTypeVarRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// // Add applied rule to the prooftree +// root.appliedRule = "Var" + +// // Find current variable in the local context +// if _, ok := getTypeFromLocalContext(state.localContext, state.consequence.a.(AST.TypeVar)); !ok { +// return Reconstruct{ +// result: false, +// err: fmt.Errorf("TypeVar %s not found in the local context", state.consequence.a.ToString()), +// } +// } + +// // No consequence: next rule is the WF rule. +// children := []Sequent{ +// { +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{}, +// }, +// } + +// return launchChildren(children, root, fatherChan) +// } + +// /* Applies the Var rule for a type hint: erase consequence */ +// func applyGlobalTypeVarRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// // Add applied rule to the prooftree +// root.appliedRule = "Var" + +// // Find current variable in the local context +// if found := state.globalContext.isTypeInContext(Glob.To[AST.TypeScheme](state.consequence.a)); !found { +// return Reconstruct{ +// result: false, +// err: fmt.Errorf("TypeVar %s not found in the global context", state.consequence.a.ToString()), +// } +// } + +// // No consequence: next rule is the WF rule. +// children := []Sequent{ +// { +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{}, +// }, +// } + +// return launchChildren(children, root, fatherChan) +// } + +// /* Applies Type rule: erase consequence */ +// func applyTypeWFRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// // Add applied rule to the prooftree +// root.appliedRule = "Type" + +// // WF child +// children := []Sequent{ +// { +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{}, +// }, +// } + +// return launchChildren(children, root, fatherChan) +// } + +// /* Applies Cross rule */ +// func applyCrossRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// // Add applied rule to the prooftree +// root.appliedRule = "Cross" + +// if tc, ok := state.consequence.a.(AST.TypeCross); ok { +// // Construct a child for every type recovered +// return launchChildren(constructWithTypes(state, tc.GetAllUnderlyingTypes()), root, fatherChan) +// } else { +// return Reconstruct{ +// result: false, +// err: fmt.Errorf("CrossRule type on something that is not a TypeCross: %s", state.consequence.a.ToString()), +// } +// } +// } + +// /* Sym rule: a child for each type in the input, and one for the output if it's a function */ +// func applySymRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// root.appliedRule = "Sym" + +// primitives := state.consequence.s.GetPrimitives() +// out := AST.GetOutType(state.consequence.s) + +// newLocalContext := state.localContext.copy() +// if qt, found := state.consequence.s.(AST.QuantifiedType); found { +// newLocalContext.typeVars = append(newLocalContext.typeVars, qt.QuantifiedVars()...) +// } + +// children := []Sequent{} +// if Glob.Is[AST.TypeScheme](out) { +// children = append(children, Sequent{ +// globalContext: state.globalContext, +// localContext: newLocalContext, +// consequence: Consequence{a: out}, +// }) +// } + +// for _, type_ := range primitives[:len(primitives)-1] { +// children = append(children, Sequent{ +// globalContext: state.globalContext, +// localContext: newLocalContext, +// consequence: Consequence{a: type_}, +// }) +// } + +// return launchChildren(children, root, fatherChan) +// } + +// /* AppType rule: a child for each type in the input, and checks if the parameterized type exists. */ +// func applyAppTypeRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// root.appliedRule = "App" + +// type_ := state.consequence.a.(AST.ParameterizedType) +// types := type_.GetParameters() + +// // Search for the ID in the global context +// if !state.globalContext.parameterizedTypesContains(type_.GetName()) { +// return Reconstruct{ +// result: false, +// err: fmt.Errorf("parameterized Type %s not in context", type_.ToString()), +// } +// } + +// children := []Sequent{} +// for _, type_ := range types { +// children = append(children, Sequent{ +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{a: type_}, +// }) +// } + +// result := launchChildren(children, root, fatherChan) + +// // Only one term needs to be returned because the ParameterizedType is counted as one. +// return Reconstruct{ +// result: result.result, +// err: result.err, +// terms: Lib.NewList[AST.Term](), +// } +// } + +// /* Utils functions */ + +// /* Finds the given term in the local context, returns false if it couldn't */ +// func getTypeFromLocalContext(localContext LocalContext, typeApp AST.TypeVar) (AST.TypeApp, bool) { +// for _, type_ := range localContext.typeVars { +// if typeApp.Equals(type_) { +// return type_, true +// } +// } +// return AST.TypeVar{}, false +// } + +// /* Constructs all the children of a composed type */ +// func constructWithTypes(state Sequent, types []AST.TypeApp) []Sequent { +// children := []Sequent{} +// for _, type_ := range types { +// children = append(children, Sequent{ +// globalContext: state.globalContext, +// localContext: state.localContext.copy(), +// consequence: Consequence{a: type_}, +// }) +// } +// return children +// } diff --git a/src/Typing/wf_rules.go b/src/Typing/wf_rules.go index 6ed30f64..186217dc 100644 --- a/src/Typing/wf_rules.go +++ b/src/Typing/wf_rules.go @@ -32,36 +32,36 @@ package Typing -/** - * This file defines the WF rules. - **/ +// /** +// * This file defines the WF rules. +// **/ -/* WF1 rule first empties the variables, and then the types. */ -func applyWF2(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - root.appliedRule = "WF_2" +// /* WF1 rule first empties the variables, and then the types. */ +// func applyWF2(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { +// root.appliedRule = "WF_2" - // Try to empty vars first - if len(state.localContext.vars) > 0 { - // Launch child on the type of the first var - var_, newLocalContext := state.localContext.popVar() - child := []Sequent{ - { - localContext: newLocalContext, - globalContext: state.globalContext, - consequence: Consequence{a: var_.GetTypeApp()}, - }, - } - return launchChildren(child, root, fatherChan) - } +// // Try to empty vars first +// if len(state.localContext.vars) > 0 { +// // Launch child on the type of the first var +// var_, newLocalContext := state.localContext.popVar() +// child := []Sequent{ +// { +// localContext: newLocalContext, +// globalContext: state.globalContext, +// consequence: Consequence{a: var_.GetTypeApp()}, +// }, +// } +// return launchChildren(child, root, fatherChan) +// } - // Then, if vars is not empty, empty the types - _, newLocalContext := state.localContext.popTypeVar() - child := []Sequent{ - { - localContext: newLocalContext, - globalContext: state.globalContext, - consequence: Consequence{a: metaType}, - }, - } - return launchChildren(child, root, fatherChan) -} +// // Then, if vars is not empty, empty the types +// _, newLocalContext := state.localContext.popTypeVar() +// child := []Sequent{ +// { +// localContext: newLocalContext, +// globalContext: state.globalContext, +// consequence: Consequence{a: metaType}, +// }, +// } +// return launchChildren(child, root, fatherChan) +// } diff --git a/src/Unif/matching.go b/src/Unif/matching.go index 4b36e5d4..83c27c08 100644 --- a/src/Unif/matching.go +++ b/src/Unif/matching.go @@ -66,23 +66,18 @@ func (m *Machine) unify(node Node, formula AST.Form) []MatchingSubstitutions { // The formula has to be a predicate. switch formula_type := formula.(type) { case AST.Pred: - terms := TypeAndTermsToTerms(formula_type.GetTypeVars(), formula_type.GetArgs()) - // Transform the predicate to a function to make the tool work properly m.terms = Lib.MkListV[AST.Term](AST.MakerFun( formula_type.GetID(), - terms, - []AST.TypeApp{}, - formula_type.GetType(), + formula_type.GetArgs(), )) result = m.unifyAux(node) if !reflect.DeepEqual(m.failure, result) { filteredResult := []MatchingSubstitutions{} - // For each substitutions, remove the [0...MetaCount(formula_type.GetTypeVars())] ones to put it in another slice (the type slice) for _, matchingSubst := range result { - actualSubsts := matchingSubst.GetSubst()[AST.CountMeta(formula_type.GetTypeVars()):] - filteredResult = append(filteredResult, MakeMatchingSubstitutions(matchingSubst.GetForm(), actualSubsts)) + filteredResult = append(filteredResult, + MakeMatchingSubstitutions(matchingSubst.GetForm(), matchingSubst.GetSubst())) } result = filteredResult } diff --git a/src/Unif/parsing.go b/src/Unif/parsing.go index 4907d8a8..e63b98da 100644 --- a/src/Unif/parsing.go +++ b/src/Unif/parsing.go @@ -34,7 +34,6 @@ package Unif import ( "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" ) @@ -56,11 +55,9 @@ func (t TermForm) GetChildrenForMappedString() []AST.MappableString { return AST.LsToMappableStringSlice(t.GetChildFormulas()) } -func (t TermForm) GetTerm() AST.Term { return t.t.Copy() } -func (t TermForm) Copy() AST.Form { return makeTermForm(t.GetIndex(), t.GetTerm()) } -func (t TermForm) GetType() AST.TypeScheme { return AST.DefaultFunType(0) } -func (t TermForm) RenameVariables() AST.Form { return t } -func (t TermForm) ReplaceTypeByMeta([]AST.TypeVar, int) AST.Form { return t } +func (t TermForm) GetTerm() AST.Term { return t.t.Copy() } +func (t TermForm) Copy() AST.Form { return makeTermForm(t.GetIndex(), t.GetTerm()) } +func (t TermForm) RenameVariables() AST.Form { return t } func (t TermForm) ReplaceTermByTerm(AST.Term, AST.Term) (AST.Form, bool) { return t, false } @@ -125,20 +122,14 @@ func ParseFormula(formula AST.Form) Sequence { // The formula has to be a predicate switch formula_type := formula.(type) { case AST.Pred: - pred := AST.MakePred(formula_type.GetIndex(), formula_type.GetID(), TypeAndTermsToTerms(formula_type.GetTypeVars(), formula_type.GetArgs()), []AST.TypeApp{}, formula_type.GetType()) - instructions := Sequence{formula: pred} + instructions := Sequence{formula: formula_type} instructions.add(Begin{}) - parsePred(pred, &instructions) + parsePred(formula_type, &instructions) instructions.add(End{}) return instructions case TermForm: - if Glob.Is[AST.Fun](formula_type.GetTerm()) { - fun := Glob.To[AST.Fun](formula_type.GetTerm()) - formula = makeTermForm(formula.GetIndex(), AST.MakerFun(fun.GetID(), TypeAndTermsToTerms(fun.GetTypeVars(), fun.GetArgs()), []AST.TypeApp{}, fun.GetTypeHint())) - } - instructions := Sequence{formula: formula} varCount := 0 postCount := 0 @@ -159,17 +150,6 @@ func ParseFormula(formula AST.Form) Sequence { } } -func TypeAndTermsToTerms( - types []AST.TypeApp, - terms Lib.List[AST.Term], -) Lib.List[AST.Term] { - tms := Lib.NewList[AST.Term]() - tms.Append(AST.TypeAppArrToTerm(types).GetSlice()...) - tms.Append(terms.GetSlice()...) - - return tms -} - /* Parses a predicate to machine instructions */ func parsePred(p AST.Pred, instructions *Sequence) { instructions.add(makeCheck(p.GetID())) diff --git a/src/Unif/substitutions_type.go b/src/Unif/substitutions_type.go index 32acc4bc..138bf430 100644 --- a/src/Unif/substitutions_type.go +++ b/src/Unif/substitutions_type.go @@ -213,7 +213,7 @@ func MakeEmptySubstitutionList() []Substitutions { /* Returns a « failed » substitution. */ func Failure() Substitutions { - fail := AST.MakeMeta(-1, -1, "FAILURE", -1, AST.MkTypeHint("i")) + fail := AST.MakeMeta(-1, -1, "FAILURE", -1) return Substitutions{Substitution{fail, fail}} } @@ -314,8 +314,6 @@ func eliminateInside(key AST.Meta, value AST.Term, s Substitutions, has_changed_ new_value := AST.MakerFun( value_2_type.GetP(), eliminateList(key, value, value_2_type.GetArgs(), &has_changed), - value_2_type.GetTypeVars(), - value_2_type.GetTypeHint(), ) if OccurCheckValid(key_2, new_value) { s_tmp.Set(key_2, new_value) @@ -361,8 +359,6 @@ func eliminateList( tempList.Append(AST.MakerFun( lt.GetP(), eliminateList(key, value, lt.GetArgs(), &hasChanged), - lt.GetTypeVars(), - lt.GetTypeHint(), )) default: tempList.Append(elementList) diff --git a/src/main.go b/src/main.go index 41bc8c89..99890e9a 100644 --- a/src/main.go +++ b/src/main.go @@ -58,7 +58,7 @@ import ( "github.com/GoelandProver/Goeland/Parser" "github.com/GoelandProver/Goeland/Search" "github.com/GoelandProver/Goeland/Search/incremental" - "github.com/GoelandProver/Goeland/Typing" + _ "github.com/GoelandProver/Goeland/Typing" "github.com/GoelandProver/Goeland/Unif" ) @@ -201,7 +201,7 @@ func initDebuggers() { equality.InitDebugger() incremental.InitDebugger() Search.InitDebugger() - Typing.InitDebugger() + // Typing.InitDebugger() Unif.InitDebugger() } @@ -392,13 +392,13 @@ func checkForTypedProof(form AST.Form) AST.Form { isTypedProof := !AST.EmptyGlobalContext() && !Glob.NoTypeCheck() if isTypedProof { - err := Typing.WellFormedVerification(form.Copy(), Glob.GetTypeProof()) + // err := Typing.WellFormedVerification(form.Copy(), Glob.GetTypeProof()) - if err != nil { - Glob.Fatal("typechecker", fmt.Sprintf("Typing error: %v", err)) - } else { - Glob.PrintInfo("typechecker", fmt.Sprintf("The problem %s is well typed.", Glob.GetProblemName())) - } + // if err != nil { + // Glob.Fatal(main_label, fmt.Sprintf("Typing error: %v", err)) + // } else { + // Glob.PrintInfo(main_label, "Well typed.") + // } } return form From e21b0174eaf50aa76becf0fc1217f5e5cd5cec89 Mon Sep 17 00:00:00 2001 From: Johann Rosain Date: Tue, 22 Jul 2025 22:42:02 +0200 Subject: [PATCH 2/8] Updated syntax of types and reintroduced them in the internals --- src/AST/formsDef.go | 42 ++- src/AST/formula.go | 19 +- src/AST/maker.go | 20 +- src/AST/manage_apps_types.go | 297 --------------- src/AST/parameterizedtype.go | 166 --------- src/AST/polytypes.go | 177 --------- src/AST/quantifiedtype.go | 159 -------- src/AST/quantifiers.go | 28 +- src/AST/{term_list.go => term-list.go} | 12 - src/AST/term.go | 8 +- src/AST/termsDef.go | 26 +- src/AST/tptp-native-types.go | 167 +++++++++ src/AST/tptp_native.go | 154 -------- src/AST/ty-syntax.go | 334 +++++++++++++++++ src/AST/typearrow.go | 159 -------- src/AST/typecross.go | 129 ------- src/AST/typed-vars.go | 129 +++++++ src/AST/typehint.go | 120 ------ src/AST/typevar.go | 126 ------- src/AST/typing_utils.go | 118 ------ src/Core/Sko/inner-skolemization.go | 11 +- src/Core/Sko/interface.go | 5 +- src/Core/Sko/outer-skolemization.go | 11 +- src/Core/Sko/preinner-skolemization.go | 29 +- src/Core/instanciation.go | 14 +- src/Core/skolemisation.go | 16 +- src/Core/statement.go | 4 +- src/Core/substitutions_search.go | 11 +- src/Engine/pretyper.go | 29 +- src/Engine/syntax-translation.go | 304 ++++++++-------- src/Lib/list.go | 18 +- src/Lib/opt.go | 4 +- src/Lib/sets.go | 18 +- .../equality/bse/equality_problem_list.go | 19 +- src/Mods/equality/bse/equality_types.go | 21 +- src/Mods/equality/sateq/subsgatherer.go | 2 +- src/Mods/equality/sateq/termrep.go | 2 + src/Mods/gs3/dependency.go | 30 +- src/Mods/gs3/proof.go | 8 +- src/Mods/lambdapi/context.go | 113 +++--- src/Mods/lambdapi/formDecorator.go | 9 +- src/Mods/lambdapi/proof.go | 44 ++- src/Mods/rocq/context.go | 42 +-- src/Search/incremental/rules.go | 8 +- src/Typing/apply_rules.go | 189 ---------- src/Typing/contexts.go | 341 ------------------ src/Typing/env-and-context.go | 136 +++++++ src/Typing/form_rules.go | 234 ------------ src/Typing/{wf_rules.go => init.go} | 43 +-- src/Typing/launch_rules.go | 177 --------- src/Typing/prooftree_dump.go | 151 -------- src/Typing/rules.go | 212 +---------- src/Typing/term_rules.go | 216 ----------- src/Typing/type.go | 190 ---------- src/Typing/type_rules.go | 220 ----------- src/Unif/matching.go | 2 + src/Unif/substitutions_type.go | 4 +- src/main.go | 103 +++--- 58 files changed, 1319 insertions(+), 4061 deletions(-) delete mode 100644 src/AST/manage_apps_types.go delete mode 100644 src/AST/parameterizedtype.go delete mode 100644 src/AST/polytypes.go delete mode 100644 src/AST/quantifiedtype.go rename src/AST/{term_list.go => term-list.go} (93%) create mode 100644 src/AST/tptp-native-types.go delete mode 100644 src/AST/tptp_native.go create mode 100644 src/AST/ty-syntax.go delete mode 100644 src/AST/typearrow.go delete mode 100644 src/AST/typecross.go create mode 100644 src/AST/typed-vars.go delete mode 100644 src/AST/typehint.go delete mode 100644 src/AST/typevar.go delete mode 100644 src/AST/typing_utils.go delete mode 100644 src/Typing/apply_rules.go delete mode 100644 src/Typing/contexts.go create mode 100644 src/Typing/env-and-context.go delete mode 100644 src/Typing/form_rules.go rename src/Typing/{wf_rules.go => init.go} (61%) delete mode 100644 src/Typing/launch_rules.go delete mode 100644 src/Typing/prooftree_dump.go delete mode 100644 src/Typing/term_rules.go delete mode 100644 src/Typing/type.go delete mode 100644 src/Typing/type_rules.go diff --git a/src/AST/formsDef.go b/src/AST/formsDef.go index 55ff9ba5..bf1922c3 100644 --- a/src/AST/formsDef.go +++ b/src/AST/formsDef.go @@ -87,24 +87,20 @@ type All struct { quantifier } -func MakeAllSimple(i int, vars []Var, forms Form, metas Lib.Set[Meta]) All { +func MakeAllSimple(i int, vars Lib.List[TypedVar], forms Form, metas Lib.Set[Meta]) All { return All{makeQuantifier(i, vars, forms, metas, AllQuant)} } -func MakeAll(i int, vars []Var, forms Form) All { +func MakeAll(i int, vars Lib.List[TypedVar], forms Form) All { return MakeAllSimple(i, vars, forms, Lib.EmptySet[Meta]()) } -func MakerAll(vars []Var, forms Form) All { +func MakerAll(vars Lib.List[TypedVar], forms Form) All { return MakeAll(MakerIndexFormula(), vars, forms) } func (a All) Equals(other any) bool { - if typed, ok := other.(All); ok { - return AreEqualsVarList(a.GetVarList(), typed.GetVarList()) && a.GetForm().Equals(typed.GetForm()) - } - - return false + return a.quantifier.Equals(other) } func (a All) GetSubFormulasRecur() Lib.List[Form] { @@ -139,24 +135,20 @@ type Ex struct { quantifier } -func MakeExSimple(i int, vars []Var, forms Form, metas Lib.Set[Meta]) Ex { +func MakeExSimple(i int, vars Lib.List[TypedVar], forms Form, metas Lib.Set[Meta]) Ex { return Ex{makeQuantifier(i, vars, forms, metas, ExQuant)} } -func MakeEx(i int, vars []Var, forms Form) Ex { +func MakeEx(i int, vars Lib.List[TypedVar], forms Form) Ex { return MakeExSimple(i, vars, forms, Lib.EmptySet[Meta]()) } -func MakerEx(vars []Var, forms Form) Ex { +func MakerEx(vars Lib.List[TypedVar], forms Form) Ex { return MakeEx(MakerIndexFormula(), vars, forms) } func (e Ex) Equals(other any) bool { - if typed, ok := other.(Ex); ok { - return AreEqualsVarList(e.GetVarList(), typed.GetVarList()) && e.GetForm().Equals(typed.GetForm()) - } - - return false + return e.quantifier.Equals(other) } func (e Ex) GetSubFormulasRecur() Lib.List[Form] { @@ -826,6 +818,7 @@ type Pred struct { *MappedString index int id Id + tys Lib.List[Ty] args Lib.List[Term] metas Lib.Cache[Lib.Set[Meta], Pred] } @@ -833,6 +826,7 @@ type Pred struct { func MakePredSimple( index int, id Id, + tys Lib.List[Ty], terms Lib.List[Term], metas Lib.Set[Meta], ) Pred { @@ -841,6 +835,7 @@ func MakePredSimple( fms, index, id, + tys, terms, Lib.MkCache(metas, Pred.forceGetMetas), } @@ -851,11 +846,13 @@ func MakePredSimple( func MakePred( index int, id Id, + tys Lib.List[Ty], terms Lib.List[Term], ) Pred { return MakePredSimple( index, id, + tys, terms, Lib.EmptySet[Meta](), ) @@ -863,15 +860,17 @@ func MakePred( func MakerPred( id Id, + tys Lib.List[Ty], terms Lib.List[Term], ) Pred { - return MakePred(MakerIndexFormula(), id, terms) + return MakePred(MakerIndexFormula(), id, tys, terms) } /* Pred attributes getters */ func (p Pred) GetIndex() int { return p.index } func (p Pred) GetID() Id { return p.id.Copy().(Id) } +func (p Pred) GetTyArgs() Lib.List[Ty] { return p.tys } func (p Pred) GetArgs() Lib.List[Term] { return p.args } /* Formula methods */ @@ -914,6 +913,7 @@ func (p Pred) Copy() Form { np := MakePredSimple( p.index, p.id, + p.GetTyArgs(), p.GetArgs(), p.metas.Raw().Copy(), ) @@ -927,7 +927,9 @@ func (p Pred) Copy() Form { func (p Pred) Equals(other any) bool { if typed, ok := other.(Pred); ok { - return typed.id.Equals(p.id) && Lib.ListEquals(typed.args, p.args) + return typed.id.Equals(p.id) && + Lib.ListEquals(typed.tys, p.tys) && + Lib.ListEquals(typed.args, p.args) } return false @@ -968,6 +970,7 @@ func (p Pred) ReplaceTermByTerm(old Term, new Term) (Form, bool) { np := MakePredSimple( p.GetIndex(), p.GetID(), + p.GetTyArgs(), termList, p.metas.Raw(), ) @@ -999,6 +1002,7 @@ func (p Pred) SubstituteVarByMeta(old Var, new Meta) Form { return MakePredSimple( nf.index, nf.id, + nf.tys, nf.args, nf.metas.Raw(), ) @@ -1031,7 +1035,7 @@ func (p Pred) ReplaceMetaByTerm(meta Meta, term Term) Form { } } - return MakePred(p.GetIndex(), p.id, newTerms) + return MakePred(p.GetIndex(), p.id, p.tys, newTerms) } // ----------------------------------------------------------------------------- diff --git a/src/AST/formula.go b/src/AST/formula.go index 0a1b37d5..18532b5c 100644 --- a/src/AST/formula.go +++ b/src/AST/formula.go @@ -89,6 +89,7 @@ func replaceTermInTermList( ) newTermList.Upd(i, MakerFun( nf.GetP(), + nf.GetTyArgs(), termList, )) res = res || r @@ -110,24 +111,6 @@ func replaceTermInTermList( /* Utils */ -func instanciateTypeAppList(typeApps []TypeApp, vars []TypeVar, index int) []TypeApp { - // For each typeVar € nf.GetTypeVars(), if typeVar € varList, instanciate typeVar - typeVars := []TypeApp{} - for _, typeVar := range typeApps { - if Glob.Is[TypeVar](typeVar) { - tv := Glob.To[TypeVar](typeVar) - if Lib.ComparableList[TypeVar](vars).Contains(tv) { - tv.ShouldBeMeta(index) - } - typeVars = append(typeVars, tv) - } else { - typeVars = append(typeVars, typeVar) - } - } - - return typeVars -} - func metasUnion(forms Lib.List[Form]) Lib.Set[Meta] { res := Lib.EmptySet[Meta]() diff --git a/src/AST/maker.go b/src/AST/maker.go index a514c277..3b509884 100644 --- a/src/AST/maker.go +++ b/src/AST/maker.go @@ -66,13 +66,9 @@ var EmptyPredEq Pred /* Initialization */ func Init() { Reset() - initTypes() + initTPTPNativeTypes() Id_eq = MakerId("=") - EmptyPredEq = MakerPred(Id_eq, Lib.NewList[Term]()) - - // Eq/Neq types - // FIXME: Register the type of equality in the global context - // --- (call an internal function like SaveEqType()) + EmptyPredEq = MakerPred(Id_eq, Lib.NewList[Ty](), Lib.NewList[Term]()) initDefaultMap() } @@ -133,7 +129,7 @@ func MakerNewVar(s string) Var { } /* Meta maker */ -func MakerMeta(s string, formula int) Meta { +func MakerMeta(s string, formula int, ty Ty) Meta { lock_term.Lock() i, ok := occurenceMeta[s] lock_term.Unlock() @@ -143,25 +139,25 @@ func MakerMeta(s string, formula int) Meta { new_index := cpt_term cpt_term += 1 lock_term.Unlock() - return MakeMeta(new_index, i, s, formula) + return MakeMeta(new_index, i, s, formula, ty) } else { lock_term.Lock() occurenceMeta[s] = 1 new_index := cpt_term cpt_term += 1 lock_term.Unlock() - return MakeMeta(new_index, 0, s, formula) + return MakeMeta(new_index, 0, s, formula, ty) } } /* Const maker (given a id, create a fun without args) */ func MakerConst(id Id) Fun { - return MakeFun(id, Lib.NewList[Term](), Lib.EmptySet[Meta]()) + return MakeFun(id, Lib.NewList[Ty](), Lib.NewList[Term](), Lib.EmptySet[Meta]()) } /* Fun maker, with given id and args */ -func MakerFun(id Id, terms Lib.List[Term]) Fun { - return MakeFun(id, terms, Lib.EmptySet[Meta]()) +func MakerFun(id Id, ty_args Lib.List[Ty], terms Lib.List[Term]) Fun { + return MakeFun(id, ty_args, terms, Lib.EmptySet[Meta]()) } /* Index make for formula */ diff --git a/src/AST/manage_apps_types.go b/src/AST/manage_apps_types.go deleted file mode 100644 index 06b6bbb9..00000000 --- a/src/AST/manage_apps_types.go +++ /dev/null @@ -1,297 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package AST - -import ( - "fmt" - "sync" - - "github.com/GoelandProver/Goeland/Glob" -) - -/** - * This file contains the logic behind the Type Schemes of polymorphic functions - * or predicates. - * A function can have different types of arguments, for example : - * sum: int * int > int - * sum: rat * rat > rat - * but both type schemes should be valid, and kept in memory. - **/ - -/* Maps an application: input type scheme and output type scheme. */ -type App struct { - in TypeApp - out TypeApp - App TypeScheme -} - -/* Map of Type Schemes for a function or a predicate. */ -var typeSchemesMap struct { - tsMap map[string][]App - lock sync.Mutex -} - -var pMap struct { - parametersMap map[string][]TypeApp - lock sync.Mutex -} - -const ( - IsFun = iota - IsProp = iota -) - -/* Saves a TypeScheme in the map of schemes. */ -func SaveTypeScheme(name string, in TypeApp, out TypeApp) error { - tArrow := MkTypeArrow(in, out) - - // If the map contains the name of the function/predicate, a type scheme has already been - // defined for it. It means that the out types shouldn't clash, otherwise, the new type - // scheme is wrong. - tScheme, found := getSchemeFromArgs(name, in) - if tScheme != nil { - if tScheme.Equals(tArrow) { - return nil - } - return fmt.Errorf("trying to save a known type scheme with different return types for the function %s", name) - } - - // It's not in the map, it should be added - typeSchemesMap.lock.Lock() - if found { - typeSchemesMap.tsMap[name] = append(typeSchemesMap.tsMap[name], App{in: in, out: out, App: tArrow}) - } else { - typeSchemesMap.tsMap[name] = []App{{in: in, out: out, App: tArrow}} - } - typeSchemesMap.lock.Unlock() - - return nil -} - -func SavePolymorphScheme(name string, scheme TypeScheme) error { - tScheme, found := getPolymorphSchemeFromArgs(name, scheme) - if tScheme != nil { - if !GetOutType(tScheme).Equals(GetOutType(scheme)) { - return fmt.Errorf("trying to save a known type scheme with different return types for the function %s", name) - } - return nil - } - - // It's not in the map, it should be added - typeSchemesMap.lock.Lock() - if found { - typeSchemesMap.tsMap[name] = append(typeSchemesMap.tsMap[name], App{App: scheme}) - } else { - typeSchemesMap.tsMap[name] = []App{{App: scheme}} - } - typeSchemesMap.lock.Unlock() - - return nil -} - -/* Saves the TypeScheme of a constant function */ -func SaveConstant(name string, out TypeApp) error { - // Check if the constant is already saved in the context - typeSchemesMap.lock.Lock() - if arr, found := typeSchemesMap.tsMap[name]; found { - var err error - if !arr[0].out.Equals(out) { - err = fmt.Errorf("trying to save a known type scheme with different return types for the function %s", name) - } - typeSchemesMap.lock.Unlock() - return err - } - - // Save the constant in the context. - // The line out.(TypeScheme) shouldn't fail : it's never a TypeVar. - typeSchemesMap.tsMap[name] = []App{ - {out: out, App: Glob.To[TypeScheme](out)}, - } - - typeSchemesMap.lock.Unlock() - return nil -} - -/* Checks if the given name is a constant (TypeHint) */ -func IsConstant(name string) bool { - typeSchemesMap.lock.Lock() - _, res := typeSchemesMap.tsMap[name] - typeSchemesMap.lock.Unlock() - return res -} - -/* Gets the TypeScheme from the global context. Returns default type if it doesn't exists. */ -func GetTypeOrDefault(name string, outDefault int, inArgs ...TypeApp) TypeScheme { - typeScheme := GetType(name, inArgs...) - if typeScheme == nil { - var size int - if len(inArgs) == 0 { - size = 0 - } else { - size = inArgs[0].Size() - } - - switch outDefault { - case IsFun: - return DefaultFunType(size) - case IsProp: - return DefaultPropType(size) - } - } - return typeScheme -} - -/* Gets a TypeScheme from the map of schemes with the name. Nil if it doesn't exists in the global context. */ -func GetType(name string, inArgs ...TypeApp) TypeScheme { - if len(inArgs) == 0 { - return getConstantTypeScheme(name) - } - args := inArgs[0] - - if tScheme, _ := getSchemeFromArgs(name, args); tScheme != nil { - return tScheme - } else { - return nil - } -} - -/* Gets a TypeScheme from the map of schemes with the name. Nil if it doesn't exists in the global context. */ -func GetPolymorphicType(name string, lenVars, lenTerms int) TypeScheme { - typeSchemesMap.lock.Lock() - if arr, found := typeSchemesMap.tsMap[name]; found { - for _, fun := range arr { - if fun.App.Size()-1 == lenTerms && (Glob.Is[QuantifiedType](fun.App) && len(fun.App.(QuantifiedType).vars) == lenVars) { - typeSchemesMap.lock.Unlock() - return fun.App - } - } - } - typeSchemesMap.lock.Unlock() - return nil -} - -/* Saves a parameterized type. A TypeApp should be nil if it's unknown */ -func SaveParamereterizedType(name string, types []TypeApp) { - pMap.lock.Lock() - if _, found := pMap.parametersMap[name]; !found { - pMap.parametersMap[name] = types - } - pMap.lock.Unlock() -} - -/* Gets the constants saved in the context */ -func getConstantTypeScheme(name string) TypeScheme { - var tScheme TypeScheme - typeSchemesMap.lock.Lock() - if typeSchemes, found := typeSchemesMap.tsMap[name]; found { - tScheme = typeSchemes[0].App - } else { - // If it's not found, the type is inferred with $i - tScheme = nil - } - typeSchemesMap.lock.Unlock() - return tScheme -} - -/* Returns the TypeScheme from the name & inArgs if it exists in the map. Else, nil. true means fun name is in the map. */ -func getSchemeFromArgs(name string, inArgs TypeApp) (TypeScheme, bool) { - typeSchemesMap.lock.Lock() - if arr, found := typeSchemesMap.tsMap[name]; found { - for _, fun := range arr { - // Polymorphic schemes don't have any of them. - if fun.in == nil || !Glob.Is[TypeScheme](inArgs) { - continue - } - if fun.in.Equals(inArgs) { - typeSchemesMap.lock.Unlock() - return fun.App, true - } - } - typeSchemesMap.lock.Unlock() - return nil, true - } - typeSchemesMap.lock.Unlock() - return nil, false -} - -/* Returns the TypeScheme from the name & inArgs if it exists in the map. Else, nil. true means fun name is in the map. */ -func getPolymorphSchemeFromArgs(name string, scheme TypeScheme) (TypeScheme, bool) { - typeSchemesMap.lock.Lock() - if arr, found := typeSchemesMap.tsMap[name]; found { - for _, fun := range arr { - if GetInputType(fun.App).Equals(GetInputType(scheme)) { - typeSchemesMap.lock.Unlock() - return fun.App, true - } - } - typeSchemesMap.lock.Unlock() - return nil, true - } - typeSchemesMap.lock.Unlock() - return nil, false -} - -/* Returns the global context. Use this only in polyrules. */ -func GetGlobalContext() map[string][]App { - // Get type schemes - typeSchemesMap.lock.Lock() - globalContext := make(map[string][]App) - - for name, app := range typeSchemesMap.tsMap { - globalContext[name] = make([]App, len(app)) - copy(globalContext[name], app) - } - - typeSchemesMap.lock.Unlock() - // Add TypeHints - tMap.lock.Lock() - for name, type_ := range tMap.uidsMap { - globalContext[name] = []App{{App: type_}} - } - tMap.lock.Unlock() - - // Add parameterized types - pMap.lock.Lock() - for name := range pMap.parametersMap { - globalContext[name] = []App{} - } - pMap.lock.Unlock() - return globalContext -} - -func IsPrimitive(name string) bool { - tMap.lock.Lock() - _, found := tMap.uidsMap[name] - tMap.lock.Unlock() - return found -} diff --git a/src/AST/parameterizedtype.go b/src/AST/parameterizedtype.go deleted file mode 100644 index c905c1a1..00000000 --- a/src/AST/parameterizedtype.go +++ /dev/null @@ -1,166 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares one of the basic types used for typing the prover : - * ParameterizedType, a type which is parameterized with other types. - **/ - -package AST - -import ( - "strings" - - "fmt" - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * Parameterized Type (TypeApp + TypeScheme) - * A Type which is parameterized with type apps to compose types. - * Example: map(int, int) - **/ -type ParameterizedType struct { - name string - parameters Lib.ComparableList[TypeApp] -} - -/* TypeScheme interface */ -func (pt ParameterizedType) isScheme() {} -func (pt ParameterizedType) toMappedString(subst map[string]string) string { - mappedString := []string{} - for _, typeScheme := range convert(pt.parameters, typeAppToTypeScheme) { - mappedString = append(mappedString, typeScheme.toMappedString(subst)) - } - return pt.name + "(" + strings.Join(mappedString, ", ") + ")" -} - -/* TypeApp interface */ -func (pt ParameterizedType) isTypeApp() {} -func (pt ParameterizedType) substitute(mapSubst map[TypeVar]string) TypeScheme { - newPt := ParameterizedType{pt.name, Lib.ComparableList[TypeApp]{}} - for _, param := range pt.parameters { - newPt.parameters = append(newPt.parameters, param.substitute(mapSubst).(TypeApp)) - } - return newPt -} -func (pt ParameterizedType) instanciate(substMap map[TypeVar]TypeApp) TypeApp { - newPt := ParameterizedType{pt.name, Lib.ComparableList[TypeApp]{}} - for _, param := range pt.parameters { - newPt.parameters = append(newPt.parameters, param.instanciate(substMap)) - } - return newPt -} - -// Exported methods - -func (pt ParameterizedType) ToString() string { return pt.toMappedString(make(map[string]string)) } -func (pt ParameterizedType) Equals(oth interface{}) bool { - if !Glob.Is[ParameterizedType](oth) { - return false - } - othPT := Glob.To[ParameterizedType](oth) - return pt.name == othPT.name && pt.parameters.Equals(othPT.parameters) -} -func (pt ParameterizedType) Size() int { return 1 } -func (pt ParameterizedType) GetPrimitives() []TypeApp { return []TypeApp{pt} } -func (pt ParameterizedType) GetParameters() []TypeApp { - res := []TypeApp{} - for _, param := range pt.parameters { - if Glob.Is[ParameterizedType](param) { - res = append(res, Glob.To[ParameterizedType](param).GetParameters()...) - } else { - res = append(res, param) - } - } - return res -} - -func (pt ParameterizedType) Copy() TypeApp { - newPT := ParameterizedType{name: pt.name, parameters: make(Lib.ComparableList[TypeApp], len(pt.parameters))} - copy(newPT.parameters, pt.parameters) - return newPT -} - -func (pt ParameterizedType) GetName() string { - return pt.name -} - -/* Makes a Parameterized Type from name and parameters */ -func MkParameterizedType(name string, types []TypeApp) ParameterizedType { - pMap.lock.Lock() - if parameters, found := pMap.parametersMap[name]; found { - k := 0 - nextTypes := make([]TypeApp, len(parameters)) - copy(nextTypes, parameters) - for i, param := range nextTypes { - if param == nil { - nextTypes[i] = types[k] - k++ - } - } - if k != len(types) { - pMap.lock.Unlock() - debug( - Lib.MkLazy(func() string { - return fmt.Sprintf("Name of the type: %s, length of the args: %d", name, len(types)) - })) - Glob.Fatal("PRMTR_TYPE", "Parameterized type can not be instanciated with this number of arguments.") - return ParameterizedType{} - } - types = nextTypes - } else { - pMap.lock.Unlock() - Glob.Fatal("PRMTR_TYPE", "Parameterized type not found.") - return ParameterizedType{} - } - pMap.lock.Unlock() - - parameterizedType := ParameterizedType{name, types} - - vars := []TypeVar{} - for _, type_ := range types { - if var_, ok := type_.(TypeVar); ok { - vars = append(vars, var_) - } - } - - return parameterizedType -} - -func IsParameterizedType(name string) bool { - pMap.lock.Lock() - _, found := pMap.parametersMap[name] - pMap.lock.Unlock() - return found -} diff --git a/src/AST/polytypes.go b/src/AST/polytypes.go deleted file mode 100644 index a15a1267..00000000 --- a/src/AST/polytypes.go +++ /dev/null @@ -1,177 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares the basic interfaces used for typing the prover. - **/ - -package AST - -import ( - "fmt" - "sync" - - "github.com/GoelandProver/Goeland/Glob" -) - -/** - * Polymorphic type, used either as a TypeHint, TypeCross or a TypeArrow to allow the inductive - * composition of either of the 3 to give a TypeScheme. - **/ -type TypeScheme interface { - /* Non-exported methods */ - isScheme() - toMappedString(map[string]string) string - - /* Exported methods */ - ToString() string - Size() int - GetPrimitives() []TypeApp - Equals(oth interface{}) bool -} - -/** - * Used for types which can be put inside a function or a predicate as arguments - * for a polymorphic scheme. - * It includes : TypeVar, TypeHint and TypeCross. - * In TFF, TypeArrow can not be the type of a variable. - * Furthermore, a TypeApp is not a quantified type scheme. - **/ -type TypeApp interface { - /* Non-exported methods */ - isTypeApp() - substitute(map[TypeVar]string) TypeScheme - instanciate(map[TypeVar]TypeApp) TypeApp - - /* Exported methods */ - ToString() string - Copy() TypeApp - Size() int - Equals(oth interface{}) bool -} - -/** - * Makers. - * As each type is unique, and stored in a Glob map (in shared memory), a lock should - * be defined. - **/ - -/* Call the init function before any type is created with MkType. */ -func initTypes() { - // Instantiate tCounter - tCounter.count = 1 - tCounter.lock = sync.Mutex{} - - // Instantiate tMap - tMap.uidsMap = make(map[string]TypeHint) - tMap.lock = sync.Mutex{} - - // Instantiate typeSchemesMap - typeSchemesMap.tsMap = make(map[string][]App) - typeSchemesMap.lock = sync.Mutex{} - - // Instanciate parameters map - pMap.parametersMap = make(map[string][]TypeApp) - pMap.lock = sync.Mutex{} - - // Default types - defaultType = MkTypeHint("$i") - defaultProp = MkTypeHint("$o") - - if Glob.GetArithModule() { - InitTPTPArithmetic() - } -} - -func EmptyTAArray() []TypeApp { - return []TypeApp{} -} - -/* Utils */ - -func utilMapCreation(vars []TypeVar) map[TypeVar]string { - metaTypeMap := make(map[TypeVar]string) - for i, var_ := range vars { - metaTypeMap[var_] = fmt.Sprintf("*_%d", i) - } - return metaTypeMap -} - -func utilMapReverseCreation(vars []TypeVar) map[string]string { - metaTypeMap := make(map[string]string) - for i, var_ := range vars { - metaTypeMap[fmt.Sprintf("*_%d", i)] = var_.ToString() - } - return metaTypeMap -} - -func substTypeAppList(mapSubst map[TypeVar]string, typeApp []TypeApp) []TypeApp { - newTypeApp := []TypeApp{} - for _, type_ := range typeApp { - newTypeApp = append(newTypeApp, type_.substitute(mapSubst).(TypeApp)) - } - return newTypeApp -} - -func instanciateList(mapSubst map[TypeVar]TypeApp, typeApp []TypeApp) []TypeApp { - newTypeApp := []TypeApp{} - for _, type_ := range typeApp { - newTypeApp = append(newTypeApp, type_.instanciate(mapSubst)) - } - return newTypeApp -} - -func EmptyGlobalContext() bool { - typeSchemesMap.lock.Lock() - schemeLen := len(typeSchemesMap.tsMap) - typeSchemesMap.lock.Unlock() - return schemeLen == 1 -} - -func CountMeta(types []TypeApp) int { - metas := 0 - for _, type_ := range types { - if tv, isTv := type_.(TypeVar); isTv && tv.Instantiated() { - metas += 1 - } - } - return metas -} - -/* Copies a list of TypeApp */ -func CopyTypeAppList(ta []TypeApp) []TypeApp { - res := make([]TypeApp, len(ta)) - for i := range ta { - res[i] = ta[i].Copy() - } - return res -} diff --git a/src/AST/quantifiedtype.go b/src/AST/quantifiedtype.go deleted file mode 100644 index 2394c58e..00000000 --- a/src/AST/quantifiedtype.go +++ /dev/null @@ -1,159 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares one of the basic types used for typing the prover : - * QuantifiedType, the Pi operator. - **/ - -package AST - -import ( - "fmt" - "strings" - - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * Quantified TypeScheme. - * It has a list of type vars and an associated scheme. - **/ -type QuantifiedType struct { - vars Lib.ComparableList[TypeVar] - scheme TypeScheme -} - -/* TypeScheme interface */ -func (qt QuantifiedType) isScheme() {} -func (qt QuantifiedType) toMappedString(subst map[string]string) string { - return "Π " + strings.Join(convert(qt.vars, typeTToString[TypeVar]), ", ") + ": Type. " + qt.scheme.toMappedString(subst) -} - -func (qt QuantifiedType) Equals(oth interface{}) bool { - return Glob.Is[QuantifiedType](oth) && qt.scheme.Equals(Glob.To[QuantifiedType](oth).scheme) -} - -func (qt QuantifiedType) QuantifiedVarsLen() int { return len(qt.vars) } -func (qt QuantifiedType) QuantifiedVars() Lib.ComparableList[TypeVar] { return qt.vars } -func (qt QuantifiedType) Size() int { return qt.scheme.Size() } - -func (qt QuantifiedType) ToString() string { - return qt.toMappedString(utilMapReverseCreation(qt.vars)) -} - -func (qt QuantifiedType) GetPrimitives() []TypeApp { - vars := make(map[TypeVar]TypeApp) - for i, var_ := range qt.vars { - vars[MkTypeVar(fmt.Sprintf("*_%d", i))] = var_ - } - primitives := []TypeApp{} - for _, th := range qt.scheme.GetPrimitives() { - if Glob.Is[TypeVar](th) { - if var_, found := vars[th.(TypeVar)]; found { - primitives = append(primitives, var_) - } - } else if Glob.Is[ParameterizedType](th) { - primitives = append(primitives, th.instanciate(vars)) - } else { - primitives = append(primitives, th) - } - } - return primitives -} - -func (qt QuantifiedType) Instanciate(types []TypeApp) TypeScheme { - substMap := make(map[TypeVar]TypeApp) - for i := range qt.vars { - substMap[MkTypeVar(fmt.Sprintf("*_%d", i))] = types[i] - } - - tv := []TypeVar{} - for _, var_ := range types { - if Glob.Is[TypeVar](var_) { - tv = append(tv, Glob.To[TypeVar](var_)) - } else if Glob.Is[ParameterizedType](var_) { - prim := Glob.To[ParameterizedType](var_).GetParameters() - for _, p := range prim { - if Glob.Is[TypeVar](p) { - tv = append(tv, Glob.To[TypeVar](p)) - } - } - } else if Glob.Is[TypeScheme](var_) { - prim := Glob.To[TypeScheme](var_).GetPrimitives() - for _, p := range prim { - if Glob.Is[TypeVar](p) { - tv = append(tv, Glob.To[TypeVar](p)) - } - } - } - } - - if Glob.Is[TypeApp](qt.scheme) { - if len(tv) > 0 { - return MkQuantifiedType(tv, Glob.To[TypeScheme](Glob.To[TypeApp](qt.scheme).instanciate(substMap))) - } - return Glob.To[TypeScheme](Glob.To[TypeApp](qt.scheme).instanciate(substMap)) - } else if Glob.Is[TypeArrow](qt.scheme) { - if len(tv) > 0 { - return MkQuantifiedType(tv, Glob.To[TypeArrow](qt.scheme).instanciate(substMap)) - } - return Glob.To[TypeArrow](qt.scheme).instanciate(substMap) - } else { - if len(tv) > 0 { - return MkQuantifiedType(tv, Glob.To[TypeScheme](Glob.To[ParameterizedType](qt.scheme).instanciate(substMap))) - } - return Glob.To[TypeScheme](Glob.To[ParameterizedType](qt.scheme).instanciate(substMap)) - } -} - -/* Makes a QuantifiedType from TypeVars and a TypeScheme. */ -func MkQuantifiedType(vars []TypeVar, typeScheme TypeScheme) QuantifiedType { - // Modify the typeScheme to make it modulo alpha-conversion - - // 1 - Corresponding map creation - metaTypeMap := utilMapCreation(vars) - - // 2 - Substitute all TypeVar with the meta type - switch ts := typeScheme.(type) { - case TypeApp: - typeScheme = ts.substitute(metaTypeMap) - case TypeArrow: - typeScheme = ts.substitute(metaTypeMap) - default: - //Paradoxal - Glob.Anomaly("MkQuantifiedType", "Reached an unreachable case.") - } - - return QuantifiedType{vars: vars, scheme: typeScheme} -} diff --git a/src/AST/quantifiers.go b/src/AST/quantifiers.go index e6d3e009..75b770dc 100644 --- a/src/AST/quantifiers.go +++ b/src/AST/quantifiers.go @@ -47,12 +47,12 @@ type quantifier struct { *MappedString metas Lib.Cache[Lib.Set[Meta], quantifier] index int - varList []Var + varList Lib.List[TypedVar] subForm Form symbol FormulaType } -func makeQuantifier(i int, vars []Var, subForm Form, metas Lib.Set[Meta], symbol FormulaType) quantifier { +func makeQuantifier(i int, vars Lib.List[TypedVar], subForm Form, metas Lib.Set[Meta], symbol FormulaType) quantifier { fms := &MappedString{} qua := quantifier{ fms, @@ -71,18 +71,14 @@ func (q quantifier) GetIndex() int { return q.index } -func (q quantifier) GetVarList() []Var { - return copyVarList(q.varList) +func (q quantifier) GetVarList() Lib.List[TypedVar] { + return Lib.ListCpy(q.varList) } func (q quantifier) GetForm() Form { return q.subForm.Copy() } -func (q quantifier) GetType() TypeScheme { - return DefaultPropType(0) -} - func (q quantifier) forceGetMetas() Lib.Set[Meta] { return q.subForm.GetMetas() } @@ -110,9 +106,9 @@ func ChangeVarSeparator(sep string) string { func (q quantifier) ToMappedStringSurround(mapping MapString, displayTypes bool) string { varStrings := []string{} - for _ = range q.GetVarList() { + for _ = range q.GetVarList().GetSlice() { str := mapping[QuantVarOpen] - str += ListToMappedString(q.GetVarList(), varSeparator, "", mapping, false) + str += ListToMappedString(q.GetVarList().GetSlice(), varSeparator, "", mapping, false) varStrings = append(varStrings, str+mapping[QuantVarClose]) } @@ -129,7 +125,7 @@ func (q quantifier) GetChildFormulas() Lib.List[Form] { func (q quantifier) Equals(other any) bool { if typed, ok := other.(quantifier); ok { - return AreEqualsVarList(q.varList, typed.varList) && q.subForm.Equals(typed.subForm) + return Lib.ListEquals(q.varList, typed.varList) && q.subForm.Equals(typed.subForm) } return false @@ -142,7 +138,7 @@ func (q quantifier) GetSubTerms() Lib.List[Term] { func (q quantifier) copy() quantifier { nq := makeQuantifier( q.GetIndex(), - copyVarList(q.GetVarList()), + Lib.ListCpy(q.varList), q.GetForm(), q.metas.Raw().Copy(), q.symbol, @@ -167,14 +163,14 @@ func (q quantifier) replaceTermByTerm(old Term, new Term) (quantifier, bool) { } func (q quantifier) renameVariables() quantifier { - newVarList := []Var{} + newVarList := Lib.NewList[TypedVar]() newForm := q.GetForm() - for _, v := range q.GetVarList() { + for _, v := range q.GetVarList().GetSlice() { newVar := MakerNewVar(v.GetName()) newVar = MakerVar(fmt.Sprintf("%s%d", newVar.GetName(), newVar.GetIndex())) - newVarList = append(newVarList, newVar) - newForm, _ = newForm.RenameVariables().ReplaceTermByTerm(v, newVar) + newVarList.Append(MkTypedVar(newVar.name, newVar.index, v.ty)) + newForm, _ = newForm.RenameVariables().ReplaceTermByTerm(v.ToBoundVar(), newVar) } return makeQuantifier( diff --git a/src/AST/term_list.go b/src/AST/term-list.go similarity index 93% rename from src/AST/term_list.go rename to src/AST/term-list.go index 98d73cf1..ab4d8823 100644 --- a/src/AST/term_list.go +++ b/src/AST/term-list.go @@ -117,10 +117,6 @@ func EqualsWithoutOrder(tl, other Lib.List[Term]) bool { return Lib.ListEquals(tlSorted.List(), otherSorted.List()) } -func AreEqualsTypeVarList(tv1, tv2 []TypeVar) bool { - return Lib.ComparableList[TypeVar](tv1).Equals(tv2) -} - /* check if two lists of var are equals */ func AreEqualsVarList(tl1, tl2 []Var) bool { if len(tl1) != len(tl2) { @@ -142,11 +138,3 @@ func copyVarList(tl []Var) []Var { } return res } - -func copyTypeVarList(tv []TypeVar) []TypeVar { - res := []TypeVar{} - for _, t := range tv { - res = append(res, t.Copy().(TypeVar)) - } - return res -} diff --git a/src/AST/term.go b/src/AST/term.go index 6b4160d6..23adba38 100644 --- a/src/AST/term.go +++ b/src/AST/term.go @@ -78,16 +78,16 @@ func MakeVar(i int, s string) Var { return newVar } -func MakeMeta(index, occurence int, s string, f int) Meta { +func MakeMeta(index, occurence int, s string, f int, ty Ty) Meta { fms := &MappedString{} - meta := Meta{fms, index, occurence, s, f} + meta := Meta{fms, index, occurence, s, f, ty} fms.MappableString = &meta return meta } -func MakeFun(p Id, args Lib.List[Term], metas Lib.Set[Meta]) Fun { +func MakeFun(p Id, ty_args Lib.List[Ty], args Lib.List[Term], metas Lib.Set[Meta]) Fun { fms := &MappedString{} - fun := Fun{fms, p, args, Lib.MkCache(metas, Fun.forceGetMetas)} + fun := Fun{fms, p, ty_args, args, Lib.MkCache(metas, Fun.forceGetMetas)} fms.MappableString = fun return fun } diff --git a/src/AST/termsDef.go b/src/AST/termsDef.go index 544c2aff..49e2bb6f 100644 --- a/src/AST/termsDef.go +++ b/src/AST/termsDef.go @@ -147,6 +147,7 @@ func (i Id) Less(u any) bool { type Fun struct { *MappedString p Id + tys Lib.List[Ty] args Lib.List[Term] metas Lib.Cache[Lib.Set[Meta], Fun] } @@ -190,6 +191,7 @@ func (f Fun) GetChildrenForMappedString() []MappableString { func (f Fun) GetID() Id { return f.p.Copy().(Id) } func (f Fun) GetP() Id { return f.p.Copy().(Id) } +func (f Fun) GetTyArgs() Lib.List[Ty] { return f.tys } func (f Fun) GetArgs() Lib.List[Term] { return f.args } func (f *Fun) SetArgs(tl Lib.List[Term]) { f.args = tl } @@ -204,9 +206,11 @@ func (f Fun) Equals(t any) bool { switch typed := t.(type) { case Fun: return typed.GetID().Equals(f.GetID()) && + Lib.ListEquals(typed.GetTyArgs(), f.GetTyArgs()) && Lib.ListEquals(typed.GetArgs(), f.GetArgs()) case *Fun: return typed.GetID().Equals(f.GetID()) && + Lib.ListEquals(typed.GetTyArgs(), f.GetTyArgs()) && Lib.ListEquals(typed.GetArgs(), f.GetArgs()) default: return false @@ -214,11 +218,11 @@ func (f Fun) Equals(t any) bool { } func (f Fun) Copy() Term { - return MakeFun(f.GetP(), f.GetArgs(), f.metas.Raw()) + return MakeFun(f.GetP(), Lib.ListCpy(f.GetTyArgs()), Lib.ListCpy(f.GetArgs()), f.metas.Raw()) } func (f Fun) PointerCopy() *Fun { - nf := MakeFun(f.GetP(), f.GetArgs(), f.metas.Raw()) + nf := MakeFun(f.GetP(), f.GetTyArgs(), f.GetArgs(), f.metas.Raw()) return &nf } @@ -256,7 +260,7 @@ func (f Fun) ReplaceSubTermBy(oldTerm, newTerm Term) Term { return newTerm.Copy() } else { tl, res := replaceFirstOccurrenceTermList(f.GetArgs(), oldTerm, newTerm) - nf := MakeFun(f.GetID(), tl, f.metas.Raw()) + nf := MakeFun(f.GetID(), f.GetTyArgs(), tl, f.metas.Raw()) if !res && !f.metas.NeedsUpd() { nf.metas.AvoidUpd() } @@ -269,7 +273,7 @@ func (f Fun) ReplaceAllSubTerm(oldTerm, newTerm Term) Term { return newTerm.Copy() } else { tl, res := ReplaceOccurrence(f.GetArgs(), oldTerm, newTerm) - nf := MakeFun(f.GetID(), tl, f.metas.Raw()) + nf := MakeFun(f.GetID(), f.GetTyArgs(), tl, f.metas.Raw()) if !res && !f.metas.NeedsUpd() { nf.metas.AvoidUpd() } @@ -336,7 +340,7 @@ func (v Var) ReplaceSubTermBy(original_term, new_term Term) Term { func (v Var) ToMappedString(map_ MapString, type_ bool) string { if type_ { - return fmt.Sprintf("%s_%d : %s", v.GetName(), v.GetIndex()) + return fmt.Sprintf("%s_%d", v.GetName(), v.GetIndex()) } return v.GetName() } @@ -347,7 +351,7 @@ func (v Var) ToMappedStringSurround(mapping MapString, displayTypes bool) string func (v Var) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { if displayTypes { - return "", fmt.Sprintf("%s_%d : %s", v.GetName(), v.GetIndex()) + return "", fmt.Sprintf("%s_%d", v.GetName(), v.GetIndex()) } else { return "", v.GetName() } @@ -376,7 +380,7 @@ type Meta struct { occurence int name string formula int - // FIXME: remember the type of a Meta + ty Ty } func (m Meta) GetFormula() int { return m.formula } @@ -389,6 +393,7 @@ func (m Meta) IsFun() bool { return false } func (m Meta) ToMeta() Meta { return m } func (m Meta) GetMetas() Lib.Set[Meta] { return Lib.Singleton(m) } func (m Meta) GetMetaList() Lib.List[Meta] { return Lib.MkListV(m) } +func (m Meta) GetTy() Ty { return m.ty } func (m Meta) ToMappedStringSurround(mapping MapString, displayTypes bool) string { return "%s" @@ -396,7 +401,7 @@ func (m Meta) ToMappedStringSurround(mapping MapString, displayTypes bool) strin func (m Meta) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { if displayTypes { - return "", fmt.Sprintf("%s_%d : %s", m.GetName(), m.GetIndex()) + return "", fmt.Sprintf("%s_%d : %s", m.GetName(), m.GetIndex(), m.ty.ToString()) } else { return "", fmt.Sprintf("%s_%d", m.GetName(), m.GetIndex()) } @@ -414,7 +419,7 @@ func (m Meta) Equals(t any) bool { } func (m Meta) Copy() Term { - return MakeMeta(m.GetIndex(), m.GetOccurence(), m.GetName(), m.GetFormula()) + return MakeMeta(m.GetIndex(), m.GetOccurence(), m.GetName(), m.GetFormula(), m.GetTy()) } func (m Meta) ReplaceSubTermBy(original_term, new_term Term) Term { @@ -439,7 +444,8 @@ func (m Meta) Less(u any) bool { } func MakeEmptyMeta() Meta { - return MakeMeta(-1, -1, "-1", -1) + // FIXME: nil are bad + return MakeMeta(-1, -1, "-1", -1, nil) } func MetaEquals(x, y Meta) bool { diff --git a/src/AST/tptp-native-types.go b/src/AST/tptp-native-types.go new file mode 100644 index 00000000..7bc401e1 --- /dev/null +++ b/src/AST/tptp-native-types.go @@ -0,0 +1,167 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** + * This file declares TPTP native types and types scheme : + * - int, rat, real for primitives + * - a bunch of type schemes + **/ + +package AST + +// FIXME: update this file with the new type system + +// var tInt TypeHint +// var tRat TypeHint +// var tReal TypeHint +// var defaultType TypeHint +// var defaultProp TypeHint + +// var intCrossInt TypeApp +// var ratCrossRat TypeApp +// var realCrossReal TypeApp + +var tType Ty + +func initTPTPNativeTypes() { + tType = MkTyConst("$tType") + // FIXME: always register the equality type in the context. +} + +func TType() Ty { + return tType +} + +func IsTType(ty Ty) bool { + return ty.Equals(tType) +} + +// func InitTPTPArithmetic() { +// // Types +// tInt = MkTypeHint("$int") +// tRat = MkTypeHint("$rat") +// tReal = MkTypeHint("$real") + +// intCrossInt = MkTypeCross(tInt, tInt) +// ratCrossRat = MkTypeCross(tRat, tRat) +// realCrossReal = MkTypeCross(tReal, tReal) + +// // Schemes +// // 1 - Binary predicates +// recordBinaryProp("$less") +// recordBinaryProp("$lesseq") +// recordBinaryProp("$greater") +// recordBinaryProp("$greatereq") + +// // 2 - Binary input arguments +// recordBinaryInArgs("$sum") +// recordBinaryInArgs("$difference") +// recordBinaryInArgs("$product") +// recordBinaryInArgs("$quotient_e") +// recordBinaryInArgs("$quotient_t") +// recordBinaryInArgs("$quotient_f") +// recordBinaryInArgs("$remainder_e") +// recordBinaryInArgs("$remainder_t") +// recordBinaryInArgs("$remainder_f") + +// // 3 - $quotient +// SaveTypeScheme("$quotient", ratCrossRat, tRat) +// SaveTypeScheme("$quotient", realCrossReal, tReal) + +// // 4 - Unary input arguments +// recordUnaryInArgs("$uminus") +// recordUnaryInArgs("$floor") +// recordUnaryInArgs("$ceiling") +// recordUnaryInArgs("$truncate") +// recordUnaryInArgs("$round") + +// // 5 - Unary predicates +// recordUnaryProp("$is_int") +// recordUnaryProp("$is_rat") + +// // 6 - Conversion +// recordConversion("$to_int", tInt) +// recordConversion("$to_rat", tRat) +// recordConversion("$to_real", tReal) +// } + +// func recordBinaryProp(name string) { +// SaveTypeScheme(name, intCrossInt, defaultProp) +// SaveTypeScheme(name, ratCrossRat, defaultProp) +// SaveTypeScheme(name, realCrossReal, defaultProp) +// } + +// func recordBinaryInArgs(name string) { +// SaveTypeScheme(name, intCrossInt, tInt) +// SaveTypeScheme(name, ratCrossRat, tRat) +// SaveTypeScheme(name, realCrossReal, tReal) +// } + +// func recordUnaryInArgs(name string) { +// SaveTypeScheme(name, tInt, tInt) +// SaveTypeScheme(name, tRat, tRat) +// SaveTypeScheme(name, tReal, tReal) +// } + +// func recordUnaryProp(name string) { +// SaveTypeScheme(name, tInt, defaultProp) +// SaveTypeScheme(name, tRat, defaultProp) +// SaveTypeScheme(name, tReal, defaultProp) +// } + +// func recordConversion(name string, out TypeApp) { +// SaveTypeScheme(name, tInt, out) +// SaveTypeScheme(name, tRat, out) +// SaveTypeScheme(name, tReal, out) +// } + +// func IsInt(tType TypeScheme) bool { return tType.Equals(tInt) } +// func IsRat(tType TypeScheme) bool { return tType.Equals(tRat) } +// func IsReal(tType TypeScheme) bool { return tType.Equals(tReal) } +// func DefaultType() TypeApp { return defaultType } +// func DefaultProp() TypeApp { return defaultProp } +// func DefaultFunType(len int) TypeScheme { return defaultAppType(len, defaultType) } +// func DefaultPropType(len int) TypeScheme { return defaultAppType(len, defaultProp) } + +// func defaultAppType(len int, out TypeApp) TypeScheme { +// if len == 0 { +// return Glob.To[TypeScheme](out) +// } else if len == 1 { +// return MkTypeArrow(defaultType, out) +// } else { +// ts := []TypeApp{} +// for i := 0; i < len; i++ { +// ts = append(ts, defaultType) +// } +// return MkTypeArrow(MkTypeCross(ts...), out) +// } +// } diff --git a/src/AST/tptp_native.go b/src/AST/tptp_native.go deleted file mode 100644 index bb3b1d04..00000000 --- a/src/AST/tptp_native.go +++ /dev/null @@ -1,154 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares TPTP native types and types scheme : - * - int, rat, real for primitives - * - a bunch of type schemes - **/ - -package AST - -import ( - "github.com/GoelandProver/Goeland/Glob" -) - -var tInt TypeHint -var tRat TypeHint -var tReal TypeHint -var defaultType TypeHint -var defaultProp TypeHint - -var intCrossInt TypeApp -var ratCrossRat TypeApp -var realCrossReal TypeApp - -func InitTPTPArithmetic() { - // Types - tInt = MkTypeHint("$int") - tRat = MkTypeHint("$rat") - tReal = MkTypeHint("$real") - - intCrossInt = MkTypeCross(tInt, tInt) - ratCrossRat = MkTypeCross(tRat, tRat) - realCrossReal = MkTypeCross(tReal, tReal) - - // Schemes - // 1 - Binary predicates - recordBinaryProp("$less") - recordBinaryProp("$lesseq") - recordBinaryProp("$greater") - recordBinaryProp("$greatereq") - - // 2 - Binary input arguments - recordBinaryInArgs("$sum") - recordBinaryInArgs("$difference") - recordBinaryInArgs("$product") - recordBinaryInArgs("$quotient_e") - recordBinaryInArgs("$quotient_t") - recordBinaryInArgs("$quotient_f") - recordBinaryInArgs("$remainder_e") - recordBinaryInArgs("$remainder_t") - recordBinaryInArgs("$remainder_f") - - // 3 - $quotient - SaveTypeScheme("$quotient", ratCrossRat, tRat) - SaveTypeScheme("$quotient", realCrossReal, tReal) - - // 4 - Unary input arguments - recordUnaryInArgs("$uminus") - recordUnaryInArgs("$floor") - recordUnaryInArgs("$ceiling") - recordUnaryInArgs("$truncate") - recordUnaryInArgs("$round") - - // 5 - Unary predicates - recordUnaryProp("$is_int") - recordUnaryProp("$is_rat") - - // 6 - Conversion - recordConversion("$to_int", tInt) - recordConversion("$to_rat", tRat) - recordConversion("$to_real", tReal) -} - -func recordBinaryProp(name string) { - SaveTypeScheme(name, intCrossInt, defaultProp) - SaveTypeScheme(name, ratCrossRat, defaultProp) - SaveTypeScheme(name, realCrossReal, defaultProp) -} - -func recordBinaryInArgs(name string) { - SaveTypeScheme(name, intCrossInt, tInt) - SaveTypeScheme(name, ratCrossRat, tRat) - SaveTypeScheme(name, realCrossReal, tReal) -} - -func recordUnaryInArgs(name string) { - SaveTypeScheme(name, tInt, tInt) - SaveTypeScheme(name, tRat, tRat) - SaveTypeScheme(name, tReal, tReal) -} - -func recordUnaryProp(name string) { - SaveTypeScheme(name, tInt, defaultProp) - SaveTypeScheme(name, tRat, defaultProp) - SaveTypeScheme(name, tReal, defaultProp) -} - -func recordConversion(name string, out TypeApp) { - SaveTypeScheme(name, tInt, out) - SaveTypeScheme(name, tRat, out) - SaveTypeScheme(name, tReal, out) -} - -func IsInt(tType TypeScheme) bool { return tType.Equals(tInt) } -func IsRat(tType TypeScheme) bool { return tType.Equals(tRat) } -func IsReal(tType TypeScheme) bool { return tType.Equals(tReal) } -func DefaultType() TypeApp { return defaultType } -func DefaultProp() TypeApp { return defaultProp } -func DefaultFunType(len int) TypeScheme { return defaultAppType(len, defaultType) } -func DefaultPropType(len int) TypeScheme { return defaultAppType(len, defaultProp) } - -func defaultAppType(len int, out TypeApp) TypeScheme { - if len == 0 { - return Glob.To[TypeScheme](out) - } else if len == 1 { - return MkTypeArrow(defaultType, out) - } else { - ts := []TypeApp{} - for i := 0; i < len; i++ { - ts = append(ts, defaultType) - } - return MkTypeArrow(MkTypeCross(ts...), out) - } -} diff --git a/src/AST/ty-syntax.go b/src/AST/ty-syntax.go new file mode 100644 index 00000000..fb1a32bb --- /dev/null +++ b/src/AST/ty-syntax.go @@ -0,0 +1,334 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** + * This file declares the syntax of the TFF1 type system. + * Variables are internal to polymorphic schemes and are treated with pseudo De Bruijn indices. + **/ + +package AST + +import ( + "fmt" + "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" +) + +type Ty interface { + isTy() + ToString() string + Equals(any) bool + Copy() Ty +} + +// Internal, shouldn't get out so no upper case +type tyVar struct { + repr string +} + +func (tyVar) isTy() {} +func (v tyVar) ToString() string { return v.repr } +func (v tyVar) Equals(oth any) bool { + if ov, ok := oth.(tyVar); ok { + return v.repr == ov.repr + } + return false +} +func (v tyVar) Copy() Ty { return tyVar{v.repr} } + +type TyBound struct { + name string + index int +} + +func (TyBound) isTy() {} +func (b TyBound) ToString() string { return b.name } +func (b TyBound) Equals(oth any) bool { + if bv, ok := oth.(TyBound); ok { + return b.name == bv.name + } + return false +} +func (b TyBound) Copy() Ty { return TyBound{b.name, b.index} } + +type TyMeta struct { + name string +} + +func (TyMeta) isTy() {} +func (m TyMeta) ToString() string { return m.name } +func (m TyMeta) Equals(oth any) bool { + if om, ok := oth.(TyMeta); ok { + return m.name == om.name + } + return false +} +func (m TyMeta) Copy() Ty { return TyMeta{m.name} } + +// Type constructors, e.g., list, option, ... +// Include constants, e.g., $i, $o, ... +type TyConstr struct { + symbol string + args Lib.List[Ty] +} + +func (TyConstr) isTy() {} + +func (c TyConstr) ToString() string { + if c.args.Len() == 0 { + return c.symbol + } + return c.symbol + "(" + Lib.ListToString(c.args, Lib.WithEmpty("")) + ")" +} + +func (c TyConstr) Equals(oth any) bool { + if oc, ok := oth.(TyConstr); ok { + return c.symbol == oc.symbol && + Lib.ListEquals(c.args, oc.args) + } + return false +} + +func (c TyConstr) Copy() Ty { + return TyConstr{c.symbol, Lib.ListCpy(c.args)} +} + +type TyProd struct { + args Lib.List[Ty] +} + +func (TyProd) isTy() {} + +func (p TyProd) ToString() string { + return "(" + Lib.ListToString(p.args, Lib.WithSep(" * "), Lib.WithEmpty("")) + ")" +} + +func (p TyProd) GetTys() Lib.List[Ty] { + return p.args +} + +func (p TyProd) Equals(oth any) bool { + if op, ok := oth.(TyProd); ok { + return Lib.ListEquals(p.args, op.args) + } + return false +} + +func (p TyProd) Copy() Ty { + return TyProd{Lib.ListCpy(p.args)} +} + +type TyFunc struct { + in, out Ty +} + +func (TyFunc) isTy() {} +func (f TyFunc) ToString() string { + return f.in.ToString() + " > " + f.out.ToString() +} +func (f TyFunc) Equals(oth any) bool { + if of, ok := oth.(TyFunc); ok { + return f.in.Equals(of.in) && f.out.Equals(of.out) + } + return false +} + +func (f TyFunc) Copy() Ty { + return TyFunc{f.in.Copy(), f.out.Copy()} +} + +type TyPi struct { + vars Lib.List[string] + ty Ty +} + +func (TyPi) isTy() {} +func (p TyPi) ToString() string { + return "!> [" + p.vars.ToString(func(s string) string { return s }, Lib.WithEmpty("")) + "] : (" + p.ty.ToString() + ")" +} +func (p TyPi) Equals(oth any) bool { + if op, ok := oth.(TyPi); ok { + cmp := func(x, y string) bool { return x == y } + return p.vars.Equals(cmp, p.vars, op.vars) && + p.ty.Equals(op.ty) + } + return false +} + +func (p TyPi) Copy() Ty { + return TyPi{p.vars.Copy(func(x string) string { return x }), p.ty.Copy()} +} + +// Makers + +func MkTyVar(repr string) Ty { + return tyVar{repr} +} + +func MkTyBV(name string, index int) Ty { + return TyBound{name, index} +} + +func MkTyMeta(name string) Ty { + return TyMeta{name} +} + +func MkTyConstr(symbol string, args Lib.List[Ty]) Ty { + return TyConstr{symbol, args} +} + +func MkTyConst(symbol string) Ty { + return TyConstr{symbol, Lib.NewList[Ty]()} +} + +func MkTyProd(args Lib.List[Ty]) Ty { + return TyProd{args} +} + +func MkTyFunc(in, out Ty) Ty { + return TyFunc{in, out} +} + +func MkTyPi(vars Lib.List[string], ty Ty) Ty { + return TyPi{vars, ty} +} + +// FIXME: the Maker logic should be factorized somewhere +func MakerTyBV(name string) Ty { + lock_term.Lock() + i, ok := idVar[name] + lock_term.Unlock() + if ok { + return MkTyBV(name, i) + } else { + lock_term.Lock() + idVar[name] = cpt_term + vr := MkTyBV(name, cpt_term) + cpt_term += 1 + lock_term.Unlock() + return vr + } +} + +func InstantiateTy(ty Ty, instance Lib.List[Ty]) Ty { + switch rty := ty.(type) { + case TyFunc: + if !instance.Empty() { + Glob.Anomaly( + "Ty.Instantiate", + fmt.Sprintf( + "On instantiation of %s: given instance %s has arguments when it shouldn't", + ty.ToString(), + Lib.ListToString(instance, Lib.WithEmpty("(empty instance)")), + ), + ) + } + return ty + case TyPi: + if instance.Len() != rty.vars.Len() { + Glob.Anomaly( + "Ty.Instantiate", + fmt.Sprintf( + "On instantiation of %s: given instance %s does not have the right number of arguments", + ty.ToString(), + Lib.ListToString(instance, Lib.WithEmpty("(empty instance)")), + ), + ) + } + + instanceMap := make(map[string]Ty) + for i, ity := range instance.GetSlice() { + instanceMap[rty.vars.At(i)] = ity + } + return instantiateTyRec(rty.ty, ty, instanceMap) + } + Glob.Anomaly( + "Ty.Instantiate", + fmt.Sprintf("Tried to instantiate %s which is not a Pi-type", ty.ToString()), + ) + return nil +} + +// source type is here for logging +func instantiateTyRec(ty, source Ty, instance map[string]Ty) Ty { + aux := func(ty Ty) Ty { + return instantiateTyRec(ty, source, instance) + } + + switch rty := ty.(type) { + case tyVar: + if val, ok := instance[rty.repr]; ok { + return val + } + Glob.Anomaly( + "Ty.Instantiate", + fmt.Sprintf("Under type %s: type variable %s has no instance", source.ToString(), rty.repr), + ) + + case TyConstr: + return MkTyConstr( + rty.symbol, + Lib.ListMap(rty.args, aux), + ) + + case TyProd: + return MkTyProd(Lib.ListMap(rty.args, aux)) + + case TyFunc: + return MkTyFunc(aux(rty.in), aux(rty.out)) + } + + Glob.Anomaly( + "Ty.Instantiate", + fmt.Sprintf( + "In %s, trying to instantiate %s which is illegal", + source.ToString(), + ty.ToString(), + ), + ) + return nil +} + +func GetArgsTy(ty Ty) Lib.List[Ty] { + switch rty := ty.(type) { + case TyFunc: + switch nty := rty.in.(type) { + case TyProd: + return nty.args + } + } + Glob.Anomaly( + "Ty.GetArgs", + fmt.Sprintf("Tried to extract types of arguments of a non-functional type %s", ty.ToString()), + ) + return Lib.NewList[Ty]() +} diff --git a/src/AST/typearrow.go b/src/AST/typearrow.go deleted file mode 100644 index 6690f424..00000000 --- a/src/AST/typearrow.go +++ /dev/null @@ -1,159 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares one of the basic types used for typing the prover : - * TypeArrow, the -> operator. It's implemented as an input scheme (TypeApp) - * and output arguments (array of TypeScheme). - **/ - -package AST - -import ( - "fmt" - "strings" - - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * Type consisting of two TypeSchemes : the in-arguments parameter(s) and the out parameter. - * For example, if a function f takes to parameters of type int, and returns an int, it - * will be typed as f : (int * int) -> int - * TypeCross has higher precedence than TypeArrow. - **/ -type TypeArrow struct { - left TypeApp - right Lib.ComparableList[TypeApp] -} - -/* TypeScheme interface */ -// Unexported methods. -func (ta TypeArrow) isScheme() {} -func (ta TypeArrow) toMappedString(subst map[string]string) string { - mappedString := []string{Glob.To[TypeScheme](ta.left).toMappedString(subst)} - for _, typeScheme := range convert(ta.right, typeAppToTypeScheme) { - mappedString = append(mappedString, typeScheme.toMappedString(subst)) - } - return "(" + strings.Join(mappedString, " > ") + ")" -} - -/* TypeArrow methods */ -func (ta TypeArrow) substitute(mapSubst map[TypeVar]string) TypeScheme { - return MkTypeArrow(ta.left.substitute(mapSubst).(TypeApp), substTypeAppList(mapSubst, ta.right)...) -} -func (ta TypeArrow) instanciate(mapSubst map[TypeVar]TypeApp) TypeScheme { - return MkTypeArrow(ta.left.instanciate(mapSubst), instanciateList(mapSubst, ta.right)...) -} - -// Exported methods. -/** - * Returns a string of a TypeArrow: (type1 > type2 > ... > typeN). - **/ -func (ta TypeArrow) ToString() string { - list := []string{ta.left.ToString()} - list = append(list, convert(ta.right, typeTToString[TypeApp])...) - return "(" + strings.Join(list, " > ") + ")" -} - -func (ta TypeArrow) Equals(oth interface{}) bool { - if !Glob.Is[TypeArrow](oth) { - return false - } - - othTA := Glob.To[TypeArrow](oth) - return ((ta.left == nil && othTA.left == nil) || ta.left.Equals(othTA.left)) && ta.right.Equals(othTA.right) -} - -func (ta TypeArrow) Size() int { - return ta.left.Size() + sum(convert(ta.right, typeTToSize[TypeApp])) -} - -func (ta TypeArrow) GetPrimitives() []TypeApp { - typeApp := []TypeApp{} - typeApp = typeAppToUnderlyingType(typeApp, ta.left) - return append(typeApp, convert(ta.right, typeAppToUnderlyingType)...) -} - -/* Makes a TypeArrow from two TypeSchemes */ -func MkTypeArrow(left TypeApp, typeApps ...TypeApp) TypeArrow { - if len(typeApps) < 1 { - debug(Lib.MkLazy(func() string { return "There should be at least one out type in a TypeArrow." })) - return TypeArrow{} - } - ta := TypeArrow{left: left, right: make(Lib.ComparableList[TypeApp], len(typeApps))} - copy(ta.right, typeApps) - return ta -} - -/* Gets the out type of an arrow type scheme */ -func GetOutType(typeScheme TypeScheme) TypeApp { - switch t := typeScheme.(type) { - case TypeArrow: - // Returns the out type of the last arrow. - return GetOutType(Glob.To[TypeScheme](t.right[len(t.right)-1])) - case QuantifiedType: - vars := make(map[TypeVar]string) - for i, var_ := range t.vars { - vars[MkTypeVar(fmt.Sprintf("*_%d", i))] = var_.ToString() - } - - if Glob.Is[TypeArrow](t.scheme) { - return GetOutType(Glob.To[TypeArrow](t.scheme).substitute(vars)) - } else { - return GetOutType(Glob.To[TypeApp](t.scheme).substitute(vars)) - } - // typeScheme may be a TypeHint if it comes from a constant. - case TypeHint: - return t - // Everything else is a TypeApp anyways - default: - return t.(TypeApp) - } -} - -/* Gets the input type of an arrow type scheme */ -func GetInputType(typeScheme TypeScheme) Lib.ComparableList[TypeApp] { - switch t := typeScheme.(type) { - case QuantifiedType: - return GetInputType(t.scheme) - case TypeArrow: - typeArrow := Glob.To[TypeArrow](typeScheme) - list := Lib.ComparableList[TypeApp]{typeArrow.left} - list = append(list, typeArrow.right[:len(typeArrow.right)-1]...) - return list - case TypeApp: - return []TypeApp{t} - } - return nil -} diff --git a/src/AST/typecross.go b/src/AST/typecross.go deleted file mode 100644 index 73466cb1..00000000 --- a/src/AST/typecross.go +++ /dev/null @@ -1,129 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares one of the basic types used for typing the prover : - * TypeCross, a conjonction of types. It's a list of TypeApp. - * A TypeArrow can not be a child of a conjonction in first order (no currification occurs). - * Otherwise, the children would be of type TypeScheme. - **/ - -package AST - -import ( - "strings" - - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * A conjonction of types. - * The UID is calculated on creation. - * Please, use MkTypeCross() to make a new TypeCross. - * It's used, for example, for function or predicate arguments. - * For example, take the function + on natural numbers. It takes 2 integers as arguments : - * +: int*int > int - * This notation is the same as +: int > int > int (as > is an imply, - * not(int) v not(int) v int is equivalent to not(int ^ int) v int = int * int > int). - **/ -type TypeCross struct { - types Lib.ComparableList[TypeApp] -} - -/* TypeScheme interface */ -// Non-exported methods. -func (tc TypeCross) isScheme() {} -func (tc TypeCross) toMappedString(subst map[string]string) string { - mappedString := []string{} - for _, typeScheme := range convert(tc.types, typeAppToTypeScheme) { - mappedString = append(mappedString, typeScheme.toMappedString(subst)) - } - if Glob.IsLambdapiOutput() { - return strings.Join(mappedString, " → ") - } - return "(" + strings.Join(mappedString, " * ") + ")" -} - -// Exported methods. -func (tc TypeCross) ToString() string { - if Glob.IsLambdapiOutput() { - return strings.Join(convert(tc.types, typeTToString[TypeApp]), " → ") - } - return "(" + strings.Join(convert(tc.types, typeTToString[TypeApp]), " * ") + ")" -} -func (tc TypeCross) Size() int { return sum(convert(tc.types, typeTToSize[TypeApp])) } - -// GetAllUnderlyingTypes ? Or just tc.types ? I'm thinking the 2nd is better cause the first looses associativity ? Is it fine ? -func (tc TypeCross) GetPrimitives() []TypeApp { return tc.GetAllUnderlyingTypes() } - -func (tc TypeCross) Equals(oth interface{}) bool { - return Glob.Is[TypeCross](oth) && tc.types.Equals(Glob.To[TypeCross](oth).types) -} - -/* TypeApp interface */ -// Non-exported methods. -func (tc TypeCross) isTypeApp() {} -func (tc TypeCross) substitute(mapSubst map[TypeVar]string) TypeScheme { - return MkTypeCross(substTypeAppList(mapSubst, tc.types)...) -} -func (tc TypeCross) instanciate(mapSubst map[TypeVar]TypeApp) TypeApp { - return MkTypeCross(instanciateList(mapSubst, tc.types)...) -} - -// Exported methods. -/** - * Copies the TypeApp slice to avoid wrong modifications. - **/ -func (tc TypeCross) Copy() TypeApp { - return MkTypeCross(convert(tc.types, copyTypeApp)...) -} - -/** - * Returns all primitive types composing this cross type. - **/ -func (tc TypeCross) GetAllUnderlyingTypes() []TypeApp { - return convert(tc.types, typeAppToUnderlyingType) -} - -/** - * Makes a TypeCross from any number of TypeApp. - **/ -func MkTypeCross(typeSchemes ...TypeApp) TypeCross { - if len(typeSchemes) < 2 { - debug(Lib.MkLazy(func() string { return "There should be at least two underlying types in a TypeCross." })) - return TypeCross{} - } - tc := TypeCross{types: make([]TypeApp, len(typeSchemes))} - copy(tc.types, typeSchemes) - return tc -} diff --git a/src/AST/typed-vars.go b/src/AST/typed-vars.go new file mode 100644 index 00000000..f9514fb4 --- /dev/null +++ b/src/AST/typed-vars.go @@ -0,0 +1,129 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** +* This file implements an interface for bound variables. +**/ + +package AST + +import ( + "fmt" +) + +type TypedVar struct { + name string + index int + ty Ty +} + +func (v TypedVar) Copy() TypedVar { + return TypedVar{v.name, v.index, v.ty.Copy()} +} + +func (v TypedVar) Equals(oth any) bool { + if ov, ok := oth.(TypedVar); ok { + return v.name == ov.name && v.index == ov.index && + v.ty.Equals(ov.ty) + } + return false +} + +func (v TypedVar) ToString() string { + return fmt.Sprintf("%s_%d : %s", v.name, v.index, v.ty.ToString()) +} + +func (v TypedVar) GetName() string { + return v.name +} + +func (v TypedVar) GetIndex() int { + return v.index +} + +func (v TypedVar) GetTy() Ty { + return v.ty +} + +func (v TypedVar) ToBoundVar() Var { + return MakeVar(v.index, v.name) +} + +func (v TypedVar) ToTyBoundVar() TyBound { + return MkTyBV(v.name, v.index).(TyBound) +} + +func MkTypedVar(name string, index int, ty Ty) TypedVar { + return TypedVar{name, index, ty} +} + +func MakerTypedVar(name string, ty Ty) TypedVar { + lock_term.Lock() + i, ok := idVar[name] + lock_term.Unlock() + if ok { + return MkTypedVar(name, i, ty) + } else { + lock_term.Lock() + idVar[name] = cpt_term + vr := MkTypedVar(name, cpt_term, ty) + cpt_term += 1 + lock_term.Unlock() + return vr + } +} + +// ----------------------------------------------------------------------------- +// Mappable string interface + +func (v TypedVar) GetChildrenForMappedString() []MappableString { + return []MappableString{} +} + +func (v TypedVar) ToMappedString(map_ MapString, type_ bool) string { + if type_ { + return fmt.Sprintf("%s : %s", v.name, v.ty.ToString()) + } + return v.name +} + +func (v TypedVar) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { + if displayTypes { + return "", fmt.Sprintf("%s : %s", v.name, v.ty.ToString()) + } else { + return "", v.name + } +} + +func (TypedVar) ToMappedStringSurround(_ MapString, _ bool) string { + return "%s" +} diff --git a/src/AST/typehint.go b/src/AST/typehint.go deleted file mode 100644 index 9732181f..00000000 --- a/src/AST/typehint.go +++ /dev/null @@ -1,120 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares the basic types used for typing the prover : - * TypeHint, a primitive type that is used as the basis of the inductive relation - **/ - -package AST - -import ( - "sync" - - "github.com/GoelandProver/Goeland/Glob" -) - -/** - * Primitive type composed of an unique identifier, used to identify it from - * other types, and a name, used for printing options. - **/ -type TypeHint struct { - uid uint64 /* Real ID */ - name string /* Name */ -} - -/* TypeScheme interface */ -// Non-exported methods -func (th TypeHint) isScheme() {} -func (th TypeHint) toMappedString(subst map[string]string) string { return th.ToString() } - -// Exported methods -func (th TypeHint) ToString() string { return th.name } -func (th TypeHint) Size() int { return 1 } -func (th TypeHint) GetPrimitives() []TypeApp { return []TypeApp{th} } - -func (th TypeHint) Equals(oth interface{}) bool { - return Glob.Is[TypeHint](oth) && Glob.To[TypeHint](oth).uid == th.uid -} - -/* TypeApp interface */ -// Non-exported methods -func (th TypeHint) isTypeApp() {} -func (th TypeHint) substitute(mapSubst map[TypeVar]string) TypeScheme { return th } -func (th TypeHint) instanciate(map[TypeVar]TypeApp) TypeApp { return th } - -// Exported methods -func (th TypeHint) Copy() TypeApp { return MkTypeHint(th.name) } - -/* Current unused unique identifier. Comes with a lock. */ -var tCounter struct { - count uint64 - lock sync.Mutex -} - -/* Map of all the unique identifiers of the different types based on their name. */ -var tMap struct { - uidsMap map[string]TypeHint - lock sync.Mutex -} - -/** - * Makes a TypeHint. - * If the name of the type already exists in the map, returns it. - * Else, creates a new TypeHint with a new unique identifier and updates the map recording - * the types. - **/ -func MkTypeHint(typeName string) TypeHint { - // 1 - search if the type is already declared. Returns it if it's found. - tMap.lock.Lock() - if tHint, found := tMap.uidsMap[typeName]; found { - tMap.lock.Unlock() - return tHint - } - tMap.lock.Unlock() - - // 2 - creation of a new type. - tCounter.lock.Lock() - tHint := TypeHint{ - uid: tCounter.count, - name: typeName, - } - tCounter.count += 1 - tCounter.lock.Unlock() - - // 3 - update of the map. - tMap.lock.Lock() - tMap.uidsMap[typeName] = tHint - tMap.lock.Unlock() - - return tHint -} diff --git a/src/AST/typevar.go b/src/AST/typevar.go deleted file mode 100644 index 3051df64..00000000 --- a/src/AST/typevar.go +++ /dev/null @@ -1,126 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares one of the basic types used for typing the prover : - * TypeVar, a variable of type. - **/ - -package AST - -import ( - "github.com/GoelandProver/Goeland/Glob" -) - -const ( - BAD_INDEX = -1 -) - -/** - * A quantified variable of type. - * It can serve in arguments of a function or predicate. - **/ -type TypeVar struct { - name string - metaInfo struct { - formulaIndex int - index int - occurence int - } -} - -/* TypeScheme interface */ -// Non-exported methods. -func (tv TypeVar) isScheme() {} -func (tv TypeVar) toMappedString(subst map[string]string) string { - if substString, inMap := subst[tv.name]; inMap { - return substString - } - return tv.name -} - -// Exported methods. -func (tv TypeVar) ToString() string { return tv.name } -func (tv TypeVar) Size() int { return 1 } -func (tv TypeVar) GetPrimitives() []TypeApp { return []TypeApp{tv} } - -func (tv TypeVar) Equals(oth interface{}) bool { - if tv.metaInfo.formulaIndex != BAD_INDEX && tv.metaInfo.index != BAD_INDEX { - return true - } - if !Glob.Is[TypeVar](oth) { - return false - } - typeVar := Glob.To[TypeVar](oth) - return typeVar.name == tv.name && typeVar.metaInfo == tv.metaInfo -} - -/* TypeApp interface */ -func (tv TypeVar) isTypeApp() {} - -func (tv TypeVar) substitute(mapSubst map[TypeVar]string) TypeScheme { - newTv := tv.Copy().(TypeVar) - newTv.name = mapSubst[tv] - return newTv -} - -func (tv TypeVar) instanciate(mapSubst map[TypeVar]TypeApp) TypeApp { - if typeApp, found := mapSubst[tv]; found { - return typeApp - } else { - return tv - } -} - -func (tv TypeVar) Copy() TypeApp { - newTv := MkTypeVar(tv.name) - newTv.metaInfo = tv.metaInfo - return newTv -} - -/* TypeVar should be converted to Meta when becoming a term */ -func (tv *TypeVar) ShouldBeMeta(formula int) { tv.metaInfo.formulaIndex = formula } -func (tv *TypeVar) Instantiate(index int) { tv.metaInfo.index = index } -func (tv TypeVar) IsMeta() bool { return tv.metaInfo.formulaIndex != BAD_INDEX } -func (tv TypeVar) Instantiated() bool { return tv.metaInfo.index != BAD_INDEX } -func (tv TypeVar) MetaInfos() (int, int, int) { - return tv.metaInfo.formulaIndex, tv.metaInfo.index, tv.metaInfo.occurence -} - -/* Makes a TypeVar from a name */ -func MkTypeVar(name string) TypeVar { - return TypeVar{name, struct { - formulaIndex int - index int - occurence int - }{BAD_INDEX, BAD_INDEX, BAD_INDEX}} -} diff --git a/src/AST/typing_utils.go b/src/AST/typing_utils.go deleted file mode 100644 index 14b00541..00000000 --- a/src/AST/typing_utils.go +++ /dev/null @@ -1,118 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file stores various utils functions for typing. - **/ - -package AST - -import ( - "github.com/GoelandProver/Goeland/Glob" -) - -type Type interface { - Size() int - ToString() string -} - -/** - * Converts a TypeApp to a TypeScheme. - * If the TypeApp is not a TypeScheme, it doesn't do anything. - **/ -func typeAppToTypeScheme(ls []TypeScheme, in TypeApp) []TypeScheme { - if typeScheme := Glob.To[TypeScheme](in); Glob.Is[TypeScheme](in) { - return append(ls, typeScheme) - } - return ls -} - -/** - * Adds input TypeScheme argument String to the list. - * Should be used on call to convert function. - **/ -func typeTToString[T Type](ls []string, in T) []string { - return append(ls, in.ToString()) -} - -/** - * Adds the size of the TypeScheme argument to the list. - * Should be used on call to convert function. - **/ -func typeTToSize[T Type](ls []int, in T) []int { - return append(ls, in.Size()) -} - -/** - * Copies in to the list. - * Use in convert function as a lambda. - **/ -func copyTypeApp(ls []TypeApp, in TypeApp) []TypeApp { - return append(ls, in.Copy()) -} - -/** - * Adds underlying types of the TypeApp argument to the list. - * Should be used on call to convert function. - **/ -func typeAppToUnderlyingType(ls []TypeApp, in TypeApp) []TypeApp { - if tc, isTc := in.(TypeCross); isTc { - return append(ls, tc.GetAllUnderlyingTypes()...) - } else { - return append(ls, in) - } -} - -/** - * Factorizes the loop needed to populate a list of elements with a new type. - * It needs : - * - the original list - * - a transformation function, taking as input the transformed list and the current element. - * If the current element doesn't fit the model of the transformation, you can just return - * the list. Else, append the transformed element to the list and return it. - **/ -func convert[T any, U any](list []T, transform func([]U, T) []U) []U { - transformedList := []U{} - for _, element := range list { - transformedList = transform(transformedList, element) - } - return transformedList -} - -/** Sums a list. **/ -func sum(list []int) int { - s := 0 - for _, element := range list { - s += element - } - return s -} diff --git a/src/Core/Sko/inner-skolemization.go b/src/Core/Sko/inner-skolemization.go index 93abe49d..3db9f882 100644 --- a/src/Core/Sko/inner-skolemization.go +++ b/src/Core/Sko/inner-skolemization.go @@ -47,34 +47,35 @@ import ( type InnerSkolemization struct { existingSymbols Lib.Set[AST.Id] - mu sync.Mutex + mu *sync.Mutex } func MkInnerSkolemization() InnerSkolemization { return InnerSkolemization{ existingSymbols: Lib.EmptySet[AST.Id](), - mu: sync.Mutex{}, + mu: &sync.Mutex{}, } } func (sko InnerSkolemization) Skolemize( _, form AST.Form, - x AST.Var, + x AST.TypedVar, _ Lib.Set[AST.Meta], ) (Skolemization, AST.Form) { sko.mu.Lock() - symbol := genFreshSymbol(&sko.existingSymbols, &sko.mu, x) + symbol := genFreshSymbol(&sko.existingSymbols, x) sko.mu.Unlock() internalMetas := form.GetMetas().Elements() skolemFunc := AST.MakerFun( symbol, + Lib.NewList[AST.Ty](), Lib.ListMap(internalMetas, Glob.To[AST.Term]), ) skolemizedForm, _ := form.ReplaceTermByTerm( - Glob.To[AST.Term](x), + x.ToBoundVar(), Glob.To[AST.Term](skolemFunc), ) diff --git a/src/Core/Sko/interface.go b/src/Core/Sko/interface.go index 984e345f..647a24e8 100644 --- a/src/Core/Sko/interface.go +++ b/src/Core/Sko/interface.go @@ -34,7 +34,6 @@ package Sko import ( "fmt" - "sync" "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Lib" @@ -53,7 +52,7 @@ type Skolemization interface { Skolemize( AST.Form, AST.Form, - AST.Var, + AST.TypedVar, Lib.Set[AST.Meta], ) (Skolemization, AST.Form) } @@ -61,7 +60,7 @@ type Skolemization interface { /* If every Skolem symbol is created using this function, then it will generate * a fresh symbol for sure. Otherwise, nothing is guaranteed. */ -func genFreshSymbol(existingSymbols *Lib.Set[AST.Id], mu *sync.Mutex, x AST.Var) AST.Id { +func genFreshSymbol(existingSymbols *Lib.Set[AST.Id], x AST.TypedVar) AST.Id { symbol := AST.MakerNewId( fmt.Sprintf("skolem@%v", x.GetName()), ) diff --git a/src/Core/Sko/outer-skolemization.go b/src/Core/Sko/outer-skolemization.go index 1e199fe4..1cfa7fa8 100644 --- a/src/Core/Sko/outer-skolemization.go +++ b/src/Core/Sko/outer-skolemization.go @@ -47,34 +47,35 @@ import ( type OuterSkolemization struct { existingSymbols Lib.Set[AST.Id] - mu sync.Mutex + mu *sync.Mutex } func MkOuterSkolemization() OuterSkolemization { return OuterSkolemization{ existingSymbols: Lib.EmptySet[AST.Id](), - mu: sync.Mutex{}, + mu: &sync.Mutex{}, } } func (sko OuterSkolemization) Skolemize( _, form AST.Form, - x AST.Var, + x AST.TypedVar, fvs Lib.Set[AST.Meta], ) (Skolemization, AST.Form) { sko.mu.Lock() - symbol := genFreshSymbol(&sko.existingSymbols, &sko.mu, x) + symbol := genFreshSymbol(&sko.existingSymbols, x) sko.mu.Unlock() metas := fvs.Elements() skolemFunc := AST.MakerFun( symbol, + Lib.NewList[AST.Ty](), Lib.ListMap(metas, Glob.To[AST.Term]), ) skolemizedForm, _ := form.ReplaceTermByTerm( - Glob.To[AST.Term](x), + x.ToBoundVar(), Glob.To[AST.Term](skolemFunc), ) diff --git a/src/Core/Sko/preinner-skolemization.go b/src/Core/Sko/preinner-skolemization.go index 84e36676..b81cd965 100644 --- a/src/Core/Sko/preinner-skolemization.go +++ b/src/Core/Sko/preinner-skolemization.go @@ -49,20 +49,20 @@ import ( type PreInnerSkolemization struct { existingSymbols Lib.Set[AST.Id] linkedSymbols Lib.List[Glob.Pair[AST.Form, AST.Id]] - mu sync.Mutex + mu *sync.Mutex } func MkPreInnerSkolemization() PreInnerSkolemization { return PreInnerSkolemization{ existingSymbols: Lib.EmptySet[AST.Id](), linkedSymbols: Lib.NewList[Glob.Pair[AST.Form, AST.Id]](), - mu: sync.Mutex{}, + mu: &sync.Mutex{}, } } func (sko PreInnerSkolemization) Skolemize( delta, form AST.Form, - x AST.Var, + x AST.TypedVar, _ Lib.Set[AST.Meta], ) (Skolemization, AST.Form) { realDelta := alphaConvert(delta, 0, make(map[int]AST.Var)) @@ -75,7 +75,7 @@ func (sko PreInnerSkolemization) Skolemize( ); ok { symbol = val.Snd } else { - symbol = genFreshSymbol(&sko.existingSymbols, &sko.mu, x) + symbol = genFreshSymbol(&sko.existingSymbols, x) sko.linkedSymbols.Append(Glob.MakePair(realDelta, symbol)) } sko.mu.Unlock() @@ -84,11 +84,12 @@ func (sko PreInnerSkolemization) Skolemize( skolemFunc := AST.MakerFun( symbol, + Lib.NewList[AST.Ty](), Lib.ListMap(internalMetas, Glob.To[AST.Term]), ) skolemizedForm, _ := form.ReplaceTermByTerm( - Glob.To[AST.Term](x), + x.ToBoundVar(), Glob.To[AST.Term](skolemFunc), ) @@ -115,6 +116,7 @@ func alphaConvert( return AST.MakePred( f.GetIndex(), f.GetID(), + f.GetTyArgs(), mappedTerms, ) case AST.Not: @@ -170,15 +172,15 @@ func alphaConvert( func makeConvertedVarList( k int, substitution map[int]AST.Var, - vl []AST.Var, -) (int, map[int]AST.Var, []AST.Var) { - newVarList := []AST.Var{} - for i, v := range vl { - nv := AST.MakeVar(k+i, fresh(k+i)) - newVarList = append(newVarList, nv) - substitution[v.GetIndex()] = nv + vl Lib.List[AST.TypedVar], +) (int, map[int]AST.Var, Lib.List[AST.TypedVar]) { + newVarList := Lib.MkList[AST.TypedVar](vl.Len()) + for i, v := range vl.GetSlice() { + nv := AST.MkTypedVar(fresh(k+i), k+i, v.GetTy()) + newVarList.Upd(i, nv) + substitution[v.GetIndex()] = nv.ToBoundVar() } - return k + len(vl), substitution, newVarList + return k + vl.Len(), substitution, newVarList } func alphaConvertTerm(t AST.Term, substitution map[int]AST.Var) AST.Term { @@ -196,6 +198,7 @@ func alphaConvertTerm(t AST.Term, substitution map[int]AST.Var) AST.Term { }) return AST.MakerFun( nt.GetID(), + nt.GetTyArgs(), mappedTerms, ) } diff --git a/src/Core/instanciation.go b/src/Core/instanciation.go index 5df870d8..58a517b0 100644 --- a/src/Core/instanciation.go +++ b/src/Core/instanciation.go @@ -65,14 +65,14 @@ func Instantiate(fnt FormAndTerms, index int) (FormAndTerms, Lib.Set[AST.Meta]) } func RealInstantiate( - varList []AST.Var, + varList Lib.List[AST.TypedVar], index, status int, subForm AST.Form, terms Lib.List[AST.Term], ) (FormAndTerms, AST.Meta) { - v := varList[0] - meta := AST.MakerMeta(strings.ToUpper(v.GetName()), index) - subForm = subForm.SubstituteVarByMeta(v, meta) + v := varList.At(0) + meta := AST.MakerMeta(strings.ToUpper(v.GetName()), index, v.GetTy()) + subForm = subForm.SubstituteVarByMeta(v.ToBoundVar(), meta) terms = terms.Copy(AST.Term.Copy) terms.Add( @@ -80,12 +80,12 @@ func RealInstantiate( Glob.To[AST.Term](meta), ) - if len(varList) > 1 { + if varList.Len() > 1 { if status == is_exists { - ex := AST.MakerEx(varList[1:], subForm) + ex := AST.MakerEx(varList.Slice(1, varList.Len()), subForm) subForm = AST.MakerNot(ex) } else { - subForm = AST.MakerAll(varList[1:], subForm) + subForm = AST.MakerAll(varList.Slice(1, varList.Len()), subForm) } } else { if status == is_exists { diff --git a/src/Core/skolemisation.go b/src/Core/skolemisation.go index b18593a4..aade0643 100644 --- a/src/Core/skolemisation.go +++ b/src/Core/skolemisation.go @@ -93,7 +93,7 @@ func Skolemize(form AST.Form, branchMetas Lib.Set[AST.Meta]) AST.Form { return realSkolemize( form, f.GetForm(), - f.GetVarList()[0], + f.GetVarList().At(0), f.GetVarList(), branchMetas, isNegAll, @@ -105,7 +105,7 @@ func Skolemize(form AST.Form, branchMetas Lib.Set[AST.Meta]) AST.Form { return realSkolemize( form, nf.GetForm(), - nf.GetVarList()[0], + nf.GetVarList().At(0), nf.GetVarList(), branchMetas, isExists, @@ -119,8 +119,8 @@ func Skolemize(form AST.Form, branchMetas Lib.Set[AST.Meta]) AST.Form { func realSkolemize( initialForm, deltaForm AST.Form, - x AST.Var, - allVars []AST.Var, + x AST.TypedVar, + allVars Lib.List[AST.TypedVar], metas Lib.Set[AST.Meta], typ int, ) AST.Form { @@ -133,13 +133,13 @@ func realSkolemize( selectedSkolemization = sko switch typ { case isNegAll: - if len(allVars) > 1 { - res = AST.MakerAll(allVars[1:], res) + if allVars.Len() > 1 { + res = AST.MakerAll(allVars.Slice(1, allVars.Len()), res) } res = AST.MakerNot(res) case isExists: - if len(allVars) > 1 { - res = AST.MakerEx(allVars[1:], res) + if allVars.Len() > 1 { + res = AST.MakerEx(allVars.Slice(1, allVars.Len()), res) } default: Glob.Anomaly("Skolemization", "impossible reconstruction case") diff --git a/src/Core/statement.go b/src/Core/statement.go index 29fcb21f..5598b747 100644 --- a/src/Core/statement.go +++ b/src/Core/statement.go @@ -50,7 +50,7 @@ func InitDebugger() { type TFFAtomTyping struct { Literal AST.Id - Ts AST.TypeScheme + Ty AST.Ty } // TPTP inputs are a list of statements @@ -137,7 +137,7 @@ func (statement Statement) ToString() string { str := statement.role.ToString() + " " + statement.name + " " switch ty := statement.atomTyping.(type) { case Lib.Some[TFFAtomTyping]: - return str + ty.Val.Literal.GetName() + ": " + ty.Val.Ts.ToString() + return str + ty.Val.Literal.GetName() + ": " + ty.Val.Ty.ToString() case Lib.None[TFFAtomTyping]: return str + "[None]" } diff --git a/src/Core/substitutions_search.go b/src/Core/substitutions_search.go index 280bf4b3..6049da39 100644 --- a/src/Core/substitutions_search.go +++ b/src/Core/substitutions_search.go @@ -209,21 +209,13 @@ func ApplySubstitutionOnTerm(old_symbol AST.Meta, new_symbol, t AST.Term) AST.Te case AST.Fun: res = AST.MakerFun( nf.GetP(), + nf.GetTyArgs(), ApplySubstitutionOnTermList(old_symbol, new_symbol, nf.GetArgs()), ) } return res } -func applySubstitutionOnType(old_type, new_type, t AST.TypeApp) AST.TypeApp { - if tv, isTv := t.(AST.TypeVar); isTv { - if tv.Instantiated() && tv.Equals(old_type) { - return new_type - } - } - return t -} - /* Apply substitutions on a list of terms */ func ApplySubstitutionsOnTermList( s Unif.Substitutions, @@ -276,6 +268,7 @@ func ApplySubstitutionOnFormula(old_symbol AST.Meta, new_symbol AST.Term, f AST. res = AST.MakePred( nf.GetIndex(), nf.GetID(), + nf.GetTyArgs(), ApplySubstitutionOnTermList(old_symbol, new_symbol, nf.GetArgs()), ) case AST.Not: diff --git a/src/Engine/pretyper.go b/src/Engine/pretyper.go index 86c8d69e..1a1b82c6 100644 --- a/src/Engine/pretyper.go +++ b/src/Engine/pretyper.go @@ -82,10 +82,17 @@ func lookupInContext(con Context, name string) Lib.Option[Parser.PType] { return Lib.MkNone[Parser.PType]() } -func isTType(pty Parser.PType) bool { +func isTyConstr(pty Parser.PType) bool { switch ty := pty.(type) { case Parser.PTypeFun: return ty.Symbol() == "$tType" + case Parser.PTypeBin: + switch ty.Operator() { + case Parser.PTypeMap: + return isTyConstr(ty.Right()) + } + case Parser.PTypeQuant: + return isTyConstr(ty.Ty()) } return false } @@ -96,7 +103,7 @@ func splitTypes( actualTys := Lib.NewList[Parser.PType]() others := Lib.NewList[Parser.PTerm]() for _, ty := range tys { - if isTType(ty.Snd) { + if isTyConstr(ty.Snd) { actualTys.Append(parserTermToType(ty.Fst)) } else { others.Append(ty.Fst) @@ -136,17 +143,11 @@ func parserTermToType(pterm Parser.PTerm) Parser.PType { return nil } -func splitTypeVars( - tys []Lib.Pair[string, Parser.PAtomicType], -) ([]AST.TypeVar, []AST.Var) { - tyvars := []AST.TypeVar{} - others := []AST.Var{} - for _, ty := range tys { - if isTType(ty.Snd.(Parser.PType)) { - tyvars = append(tyvars, AST.MkTypeVar(ty.Fst)) - } else { - others = append(others, AST.MakerVar(ty.Fst)) - } +func pretypeVars(vars []Lib.Pair[string, Parser.PAtomicType]) Lib.List[AST.TypedVar] { + res := Lib.MkList[AST.TypedVar](len(vars)) + for i, v := range vars { + ty := elaborateType(v.Snd.(Parser.PType), v.Snd.(Parser.PType), false) + res.Upd(i, AST.MakerTypedVar(v.Fst, ty)) } - return tyvars, others + return res } diff --git a/src/Engine/syntax-translation.go b/src/Engine/syntax-translation.go index 9ad5a737..92b258d8 100644 --- a/src/Engine/syntax-translation.go +++ b/src/Engine/syntax-translation.go @@ -38,11 +38,13 @@ package Engine import ( "fmt" + "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Core" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Parser" + "github.com/GoelandProver/Goeland/Typing" ) type Context []Lib.Pair[string, Parser.PType] @@ -50,31 +52,35 @@ type Context []Lib.Pair[string, Parser.PType] var elab_label string = "Elab" var parsing_label string = "Parsing" -func ToInternalSyntax(parser_statements []Parser.PStatement) []Core.Statement { - statements := []Core.Statement{} +func ToInternalSyntax(parser_statements []Parser.PStatement) (statements []Core.Statement, is_typed bool) { + is_typed = false con := Context{} for _, statement := range parser_statements { - newCon, stmt := elaborateParsingStatement(con, statement) + new_con, stmt, is_typed_stmt := elaborateParsingStatement(con, statement) statements = append(statements, stmt) - con = newCon + con = new_con + is_typed = is_typed || is_typed_stmt } - return statements + return statements, is_typed } func elaborateParsingStatement( con Context, statement Parser.PStatement, -) (Context, Core.Statement) { +) (Context, Core.Statement, bool) { statement_role := elaborateRole(statement.Role(), statement) + is_typed := false var core_statement Core.Statement switch f := statement.Form().(type) { case Lib.Some[Parser.PForm]: + form, is_typed_form := elaborateParsingForm(con, f.Val) core_statement = Core.MakeFormStatement( statement.Name(), statement_role, - elaborateParsingForm(con, f.Val), + form, ) + is_typed = is_typed || is_typed_form case Lib.None[Parser.PForm]: switch ty := statement.TypedConst().(type) { @@ -86,6 +92,7 @@ func elaborateParsingStatement( statement_role, elaborateParsingType(ty.Val), ) + is_typed = true case Lib.None[Lib.Pair[string, Parser.PType]]: if statement.Role() != Parser.Include { @@ -96,7 +103,7 @@ func elaborateParsingStatement( } } } - return con, core_statement + return con, core_statement, is_typed } func elaborateRole(parsing_role Parser.PFormulaRole, stmt Parser.PStatement) Core.FormulaRole { @@ -123,13 +130,13 @@ func elaborateRole(parsing_role Parser.PFormulaRole, stmt Parser.PStatement) Cor return Core.Unknown } -func elaborateParsingForm(con Context, f Parser.PForm) AST.Form { +func elaborateParsingForm(con Context, f Parser.PForm) (AST.Form, bool) { return elaborateForm(con, f, f) } // The [source_form] argument is here for error printing purposes. -func elaborateForm(con Context, f, source_form Parser.PForm) AST.Form { - aux := func(t Parser.PTerm) AST.Term { +func elaborateForm(con Context, f, source_form Parser.PForm) (AST.Form, bool) { + aux := func(t Parser.PTerm) (AST.Term, bool) { return elaborateParsingTerm(con, t) } @@ -138,23 +145,38 @@ func elaborateForm(con Context, f, source_form Parser.PForm) AST.Form { case Parser.PConst: switch pform.PConstant { case Parser.PTop: - return AST.MakerTop() + return AST.MakerTop(), false case Parser.PBot: - return AST.MakerBot() + return AST.MakerBot(), false } case Parser.PPred: typed_arguments := pretype(con, pform.Args()) - _, real_args := splitTypes(typed_arguments) + typed_args, term_args := splitTypes(typed_arguments) + args := Lib.MkList[AST.Term](term_args.Len()) + is_typed := false + + for i, trm := range term_args.GetSlice() { + arg, b := aux(trm) + is_typed = is_typed || b + args.Upd(i, arg) + } + return AST.MakerPred( AST.MakerId(pform.Symbol()), - Lib.ListMap(real_args, aux), - ) + Lib.ListMap( + typed_args, + func(pty Parser.PType) AST.Ty { + return elaborateType(pty, pty, false) + }), + args, + ), is_typed || !typed_args.Empty() case Parser.PUnary: switch pform.PUnaryOp { case Parser.PUnaryNeg: - return AST.MakerNot(elaborateForm(con, pform.PForm, source_form)) + nf, b := elaborateForm(con, pform.PForm, source_form) + return AST.MakerNot(nf), b } case Parser.PBin: @@ -164,19 +186,17 @@ func elaborateForm(con Context, f, source_form Parser.PForm) AST.Form { case Parser.PBinaryAnd: return maybeFlattenAnd(con, pform, source_form) case Parser.PBinaryImp: - return AST.MakerImp( - elaborateForm(con, pform.Left(), source_form), - elaborateForm(con, pform.Right(), source_form), - ) + lft, b1 := elaborateForm(con, pform.Left(), source_form) + rgt, b2 := elaborateForm(con, pform.Right(), source_form) + return AST.MakerImp(lft, rgt), b1 || b2 case Parser.PBinaryEqu: - return AST.MakerEqu( - elaborateForm(con, pform.Left(), source_form), - elaborateForm(con, pform.Right(), source_form), - ) + lft, b1 := elaborateForm(con, pform.Left(), source_form) + rgt, b2 := elaborateForm(con, pform.Right(), source_form) + return AST.MakerEqu(lft, rgt), b1 || b2 } case Parser.PQuant: - type_vars, vars := splitTypeVars(pform.Vars()) + vars := pretypeVars(pform.Vars()) switch pform.PQuantifier { case Parser.PQuantAll: actualVars := Lib.ListMap( @@ -185,13 +205,13 @@ func elaborateForm(con Context, f, source_form Parser.PForm) AST.Form { return Lib.MkPair(p.Fst, p.Snd.(Parser.PType)) }, ) - form := elaborateForm(append(con, actualVars.GetSlice()...), pform.PForm, source_form) - if len(vars) != 0 { + form, b := elaborateForm(append(con, actualVars.GetSlice()...), pform.PForm, source_form) + if !vars.Empty() { form = AST.MakerAll(vars, form) } - return form + return form, b case Parser.PQuantEx: - if len(type_vars) != 0 { + if vars.Any(func(v AST.TypedVar) bool { return AST.IsTType(v.GetTy()) }) { Glob.Anomaly( elab_label, "Found existentially quantified types when parsing "+source_form.ToString(), @@ -203,21 +223,21 @@ func elaborateForm(con Context, f, source_form Parser.PForm) AST.Form { return Lib.MkPair(p.Fst, p.Snd.(Parser.PType)) }, ) - form := elaborateForm(append(con, actualVars.GetSlice()...), pform.PForm, source_form) - if len(vars) != 0 { - return AST.MakerEx(vars, form) + form, b := elaborateForm(append(con, actualVars.GetSlice()...), pform.PForm, source_form) + if !vars.Empty() { + form = AST.MakerEx(vars, form) } - return form + return form, b } } Glob.Anomaly( elab_label, "Parsed formula "+source_form.ToString()+" does not correspond to any internal formula", ) - return nil + return nil, false } -func maybeFlattenOr(con Context, f Parser.PBin, source_form Parser.PForm) AST.Form { +func maybeFlattenOr(con Context, f Parser.PBin, source_form Parser.PForm) (AST.Form, bool) { return maybeFlattenBin( con, f, source_form, func(ls Lib.List[AST.Form]) AST.Form { return AST.MakerOr(ls) }, @@ -225,7 +245,7 @@ func maybeFlattenOr(con Context, f Parser.PBin, source_form Parser.PForm) AST.Fo ) } -func maybeFlattenAnd(con Context, f Parser.PBin, source_form Parser.PForm) AST.Form { +func maybeFlattenAnd(con Context, f Parser.PBin, source_form Parser.PForm) (AST.Form, bool) { return maybeFlattenBin( con, f, source_form, func(ls Lib.List[AST.Form]) AST.Form { return AST.MakerAnd(ls) }, @@ -239,23 +259,22 @@ func maybeFlattenBin( source_form Parser.PForm, maker Lib.Func[Lib.List[AST.Form], AST.Form], op Parser.PBinOp, -) AST.Form { +) (AST.Form, bool) { if !Glob.Flatten() { - return maker( - Lib.MkListV( - elaborateForm(con, f.Left(), source_form), - elaborateForm(con, f.Right(), source_form), - )) + lft, b1 := elaborateForm(con, f.Left(), source_form) + rgt, b2 := elaborateForm(con, f.Right(), source_form) + return maker(Lib.MkListV(lft, rgt)), b1 || b2 } subforms := flatten(f, op) - forms := Lib.MkListV( - Lib.ListMap( - subforms, - func(f Parser.PForm) AST.Form { return elaborateForm(con, f, source_form) }, - ).GetSlice()..., - ) - return maker(forms) + is_typed := false + real_subforms := Lib.MkList[AST.Form](subforms.Len()) + for i, subform := range subforms.GetSlice() { + real_subform, b := elaborateForm(con, subform, source_form) + real_subforms.Upd(i, real_subform) + is_typed = is_typed || b + } + return maker(real_subforms), is_typed } func flatten(f Parser.PForm, op Parser.PBinOp) Lib.List[Parser.PForm] { @@ -270,171 +289,132 @@ func flatten(f Parser.PForm, op Parser.PBinOp) Lib.List[Parser.PForm] { return Lib.MkListV(f) } -func elaborateParsingTerm(con Context, t Parser.PTerm) AST.Term { +func elaborateParsingTerm(con Context, t Parser.PTerm) (AST.Term, bool) { return elaborateTerm(con, t, t) } // The argument [source_term] is here for error printing purposes. -func elaborateTerm(con Context, t, source_term Parser.PTerm) AST.Term { - aux := func(t Parser.PTerm) AST.Term { +func elaborateTerm(con Context, t, source_term Parser.PTerm) (AST.Term, bool) { + aux := func(t Parser.PTerm) (AST.Term, bool) { return elaborateTerm(con, t, source_term) } - fail := func(ty AST.TypeScheme) { - Glob.Fatal( - parsing_label, - fmt.Sprintf( - "Non-atomic type found when pretyping %s: got %s", - t.ToString(), - ty.ToString(), - ), - ) - } - switch pterm := t.(type) { case Parser.PVar: - ty := lookupInContext(con, pterm.Name()) - switch t := ty.(type) { - case Lib.Some[Parser.PType]: - if isTType(t.Val) { - Glob.Anomaly( - elab_label, - fmt.Sprintf( - "Trying to transform the type variable %s into an internal term in %s", - pterm.Name(), - source_term.ToString(), - ), - ) - } - - ty := elaborateType(t.Val, t.Val) - if _, ok := ty.(AST.TypeApp); !ok { - fail(ty) - } - // FIXME: get some error function over here - return AST.MakerVar(pterm.Name()) - } + return AST.MakerVar(pterm.Name()), false case Parser.PFun: typed_arguments := pretype(con, pterm.Args()) - _, real_args := splitTypes(typed_arguments) + ty_args, trm_args := splitTypes(typed_arguments) + args := Lib.MkList[AST.Term](trm_args.Len()) + is_typed := false + + for i, trm := range trm_args.GetSlice() { + arg, b := aux(trm) + is_typed = is_typed || b + args.Upd(i, arg) + } + fun := AST.MakerFun( AST.MakerId(pterm.Symbol()), - Lib.ListMap(real_args, aux), + Lib.ListMap( + ty_args, + func(pty Parser.PType) AST.Ty { + return elaborateType(pty, pty, false) + }), + args, ) switch oty := pterm.DefinedType().(type) { case Lib.Some[Parser.PTypeFun]: - ty := elaborateType(oty.Val, oty.Val).(AST.TypeApp) - AST.SaveConstant(pterm.Symbol(), ty) + ty := elaborateType(oty.Val, oty.Val, false) + Typing.AddToGlobalEnv(pterm.Symbol(), ty) } - return fun + return fun, is_typed || !ty_args.Empty() } Glob.Anomaly( elab_label, "Parsed term "+source_term.ToString()+" does not correspond to any internal term", ) - return nil + return nil, false } func elaborateParsingType(pty Lib.Pair[string, Parser.PType]) Core.TFFAtomTyping { return Core.TFFAtomTyping{ Literal: AST.MakerId(pty.Fst), - Ts: elaborateType(pty.Snd, pty.Snd), + Ty: elaborateType(pty.Snd, pty.Snd, true), } } // The [source_type] argument is here for error printing. -func elaborateType(pty, source_type Parser.PType) AST.TypeScheme { - aux := func(pty Parser.PType) AST.TypeScheme { - return elaborateType(pty, source_type) +func elaborateType(pty, source_type Parser.PType, from_top_level bool) AST.Ty { + aux := func(pty Parser.PType) AST.Ty { + return elaborateType(pty, source_type, from_top_level) } switch ty := pty.(type) { case Parser.PTypeVar: - return AST.MkTypeVar(ty.Name()) - - case Parser.PTypeFun: - if len(ty.Args()) == 0 { - return AST.MkTypeHint(ty.Symbol()) + if from_top_level { + return AST.MkTyVar(ty.Name()) } else { - args := Lib.MkListV(ty.Args()...) - actualArgs := Lib.ListMap( - args, - func(atom Parser.PAtomicType) Parser.PType { return atom.(Parser.PType) }, - ) - elaboratedArgs := Lib.ListMap(actualArgs, aux) - convertedArgs := Lib.ListMap( - elaboratedArgs, - func(ty AST.TypeScheme) AST.TypeApp { return ty.(AST.TypeApp) }, - ) - // FIXME: this is __bad__ - params := []AST.TypeApp{} - for range convertedArgs.GetSlice() { - params = append(params, nil) - } - // FIXME: shouldn't this be internalized when making a new parameterized type - // instead of having to save it before? - AST.SaveParamereterizedType(ty.Symbol(), params) - return AST.MkParameterizedType( - ty.Symbol(), - convertedArgs.GetSlice(), - ) + return AST.MakerTyBV(ty.Name()) } + case Parser.PTypeFun: + args := Lib.MkListV(ty.Args()...) + actualArgs := Lib.ListMap( + args, + func(atom Parser.PAtomicType) Parser.PType { return atom.(Parser.PType) }, + ) + elaboratedArgs := Lib.ListMap(actualArgs, aux) + return AST.MkTyConstr(ty.Symbol(), elaboratedArgs) case Parser.PTypeBin: - new_left := elaborateType(ty.Left(), source_type) - new_right := elaborateType(ty.Right(), source_type) - - fail := func(cse string) { + fail_if_forbidden := func(ty Parser.PType) { Glob.Fatal( parsing_label, fmt.Sprintf( - "Non-atomic type found under the %s type %s in %s", - cse, + "Non-atomic type (%s) found under the type %s", ty.ToString(), source_type.ToString(), ), ) } + fail_if_forbidden(ty.Left()) + fail_if_forbidden(ty.Right()) + + new_left := elaborateType(ty.Left(), source_type, from_top_level) + new_right := elaborateType(ty.Right(), source_type, from_top_level) + switch ty.Operator() { case Parser.PTypeProd: - if !Glob.Is[AST.TypeApp](new_left) { - fail("map") - } - if !Glob.Is[AST.TypeApp](new_right) { - fail("map") - } - left_list := flattenProd(new_left.(AST.TypeApp)) - right_list := flattenProd(new_right.(AST.TypeApp)) - return AST.MkTypeCross(append(left_list, right_list...)...) + left_list := flattenProd(new_left) + right_list := flattenProd(new_right) + return AST.MkTyProd(Lib.MkListV(append(left_list, right_list...)...)) case Parser.PTypeMap: - if !Glob.Is[AST.TypeApp](new_left) { - fail("map") - } - if !Glob.Is[AST.TypeApp](new_right) { - fail("map") - } - return AST.MkTypeArrow( - elaborateType(ty.Left(), source_type).(AST.TypeApp), - elaborateType(ty.Right(), source_type).(AST.TypeApp), + return AST.MkTyFunc( + elaborateType(ty.Left(), source_type, from_top_level), + elaborateType(ty.Right(), source_type, from_top_level), ) } case Parser.PTypeQuant: switch ty.Quant() { case Parser.PTypeAll: - vars := Lib.MkListV(ty.Vars()...) - actualVars := Lib.ListMap( - vars, - func(p Lib.Pair[string, Parser.PAtomicType]) AST.TypeVar { - return AST.MkTypeVar(p.Fst) - }, - ) - return AST.MkQuantifiedType( - actualVars.GetSlice(), - elaborateType(ty.Ty(), source_type), - ) + var_names := Lib.MkList[string](len(ty.Vars())) + for i, v := range ty.Vars() { + var_names.Upd(i, v.Fst) + } + + underlying_type := elaborateType(ty.Ty(), source_type, from_top_level) + + if Glob.Is[AST.TyPi](underlying_type) { + Glob.Anomaly( + elab_label, + fmt.Sprintf("Found nested Pi-type in %s", source_type.ToString()), + ) + } + + return AST.MkTyPi(var_names, underlying_type) } } @@ -445,14 +425,14 @@ func elaborateType(pty, source_type Parser.PType) AST.TypeScheme { return nil } -func flattenProd(ty AST.TypeApp) []AST.TypeApp { +func flattenProd(ty AST.Ty) []AST.Ty { switch nty := ty.(type) { - case AST.TypeCross: - res := []AST.TypeApp{} - for _, uty := range nty.GetAllUnderlyingTypes() { + case AST.TyProd: + res := []AST.Ty{} + for _, uty := range nty.GetTys().GetSlice() { res = append(res, flattenProd(uty)...) } return res } - return []AST.TypeApp{ty} + return []AST.Ty{ty} } diff --git a/src/Lib/list.go b/src/Lib/list.go index 584143e7..b0da6659 100644 --- a/src/Lib/list.go +++ b/src/Lib/list.go @@ -92,13 +92,13 @@ func (l List[T]) Slice(st, ed int) List[T] { return List[T]{values: l.values[st:ed]} } -func ListEquals[T Comparable](ls0, ls1 List[T]) bool { +func (l List[T]) Equals(cmp Func2[T, T, bool], ls0, ls1 List[T]) bool { if ls0.Len() != ls1.Len() { return false } for i := range ls0.values { - if !ls0.At(i).Equals(ls1.At(i)) { + if !cmp(ls0.At(i), ls1.At(i)) { return false } } @@ -106,6 +106,11 @@ func ListEquals[T Comparable](ls0, ls1 List[T]) bool { return true } +func ListEquals[T Comparable](ls0, ls1 List[T]) bool { + cmp := func(x, y T) bool { return x.Equals(y) } + return ls0.Equals(cmp, ls0, ls1) +} + type IterToStringOpts struct { sep string empty string @@ -244,6 +249,15 @@ func (l List[T]) RemoveAt(index int) List[T] { return new_list } +func (l List[T]) Any(pred Func[T, bool]) bool { + for _, el := range l.values { + if pred(el) { + return true + } + } + return false +} + func ToStrictlyOrderedList[T StrictlyOrdered](l List[T]) StrictlyOrderedList[T] { return StrictlyOrderedList[T]{values: l} } diff --git a/src/Lib/opt.go b/src/Lib/opt.go index e85b2a80..f78c6124 100644 --- a/src/Lib/opt.go +++ b/src/Lib/opt.go @@ -47,10 +47,10 @@ type None[A any] struct{} func (Some[A]) isOpt() {} func (None[A]) isOpt() {} -func OptBind[A, B any](u Option[A], f Func[A, B]) Option[B] { +func OptBind[A, B any](u Option[A], f Func[A, Option[B]]) Option[B] { switch x := u.(type) { case Some[A]: - return Some[B]{f(x.Val)} + return f(x.Val) case None[A]: return None[B]{} } diff --git a/src/Lib/sets.go b/src/Lib/sets.go index 3be6ea17..be86e7d4 100644 --- a/src/Lib/sets.go +++ b/src/Lib/sets.go @@ -47,6 +47,7 @@ package Lib import ( _ "fmt" + "slices" ) // ----------------------------------------------------------------------------- @@ -302,12 +303,7 @@ func (s0 Set[T]) Diff(s1 Set[T]) Set[T] { } func (s0 Set[T]) Disjoint(s1 Set[T]) bool { - for _, x := range s1.Elements().GetSlice() { - if s0.Contains(x) { - return false - } - } - return true + return !slices.ContainsFunc(s1.Elements().GetSlice(), s0.Contains) } func (s Set[T]) Cardinal() int { @@ -322,6 +318,16 @@ func (s Set[T]) Copy() Set[T] { return mkSet(nodeCpy(s.root)) } +func (s Set[T]) Filter(pred Func[T, bool]) Set[T] { + res := EmptySet[T]() + for _, x := range s.Elements().GetSlice() { + if pred(x) { + res.Add(x) + } + } + return res +} + // ----------------------------------------------------------------------------- // Internal; do not call. diff --git a/src/Mods/equality/bse/equality_problem_list.go b/src/Mods/equality/bse/equality_problem_list.go index 689b3ad8..a6b6479d 100644 --- a/src/Mods/equality/bse/equality_problem_list.go +++ b/src/Mods/equality/bse/equality_problem_list.go @@ -45,7 +45,9 @@ import ( "strings" "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" + "github.com/GoelandProver/Goeland/Typing" "github.com/GoelandProver/Goeland/Unif" ) @@ -208,12 +210,25 @@ func buildEqualityProblemMultiListFromPredList(pred AST.Pred, tn Unif.DataStruct predId := pred.GetID() metas := Lib.NewList[AST.Meta]() - for _, arg := range pred.GetArgs().GetSlice() { - metas = Lib.ListAdd(metas, AST.MakerMeta("METAEQ_"+arg.ToString(), -1)) + var ty AST.Ty + switch rty := Typing.QueryEnvInstance(predId.GetName(), pred.GetTyArgs()).(type) { + case Lib.Some[AST.Ty]: + ty = rty.Val + case Lib.None[AST.Ty]: + Glob.Anomaly( + "Equality.Build", + fmt.Sprintf("Type of predicate %s not found", pred.ToString()), + ) + } + tys := AST.GetArgsTy(ty) + + for i, arg := range pred.GetArgs().GetSlice() { + metas = Lib.ListAdd(metas, AST.MakerMeta("METAEQ_"+arg.ToString(), -1, tys.At(i))) } newTerm := AST.MakerPred( predId.Copy().(AST.Id), + pred.GetTyArgs(), AST.MetaListToTermList(metas), ) found, complementaryPredList := tn.Unify(newTerm) diff --git a/src/Mods/equality/bse/equality_types.go b/src/Mods/equality/bse/equality_types.go index 5c19e667..7d117918 100644 --- a/src/Mods/equality/bse/equality_types.go +++ b/src/Mods/equality/bse/equality_types.go @@ -120,16 +120,15 @@ func (equs Equalities) removeHalf() Equalities { /* Retrieve equalities from a datastructure */ func retrieveEqualities(dt Unif.DataStructure) Equalities { res := Equalities{} - MetaEQ1 := AST.MakerMeta("METAEQ1", -1) - MetaEQ2 := AST.MakerMeta("METAEQ2", -1) - // TODO: type this - tv := AST.MkTypeVar("EQ") - eq_pred := AST.MakerPred(AST.Id_eq, Lib.NewList[AST.Term]()) - tv.ShouldBeMeta(eq_pred.GetIndex()) - tv.Instantiate(1) + meta_ty := AST.MkTyMeta("META_TY_EQ") + MetaEQ1 := AST.MakerMeta("METAEQ1", -1, meta_ty) + MetaEQ2 := AST.MakerMeta("METAEQ2", -1, meta_ty) + + eq_pred := AST.MakerPred(AST.Id_eq, Lib.NewList[AST.Ty](), Lib.NewList[AST.Term]()) eq_pred = AST.MakePred( eq_pred.GetIndex(), AST.Id_eq, + Lib.MkListV[AST.Ty](meta_ty), Lib.MkListV[AST.Term](MetaEQ1, MetaEQ2), ) _, eq_list := dt.Unify(eq_pred) @@ -152,13 +151,15 @@ func retrieveEqualities(dt Unif.DataStructure) Equalities { /* Retrieve inequalities from a datastructure */ func retrieveInequalities(dt Unif.DataStructure) Inequalities { res := Inequalities{} - MetaNEQ1 := AST.MakerMeta("META_NEQ_1", -1) - MetaNEQ2 := AST.MakerMeta("META_NEQ_2", -1) + meta_ty := AST.MkTyMeta("META_TY_NEQ") + MetaNEQ1 := AST.MakerMeta("META_NEQ_1", -1, meta_ty) + MetaNEQ2 := AST.MakerMeta("META_NEQ_2", -1, meta_ty) - neq_pred := AST.MakerPred(AST.Id_eq, Lib.NewList[AST.Term]()) + neq_pred := AST.MakerPred(AST.Id_eq, Lib.NewList[AST.Ty](), Lib.NewList[AST.Term]()) neq_pred = AST.MakePred( neq_pred.GetIndex(), AST.Id_eq, + Lib.MkListV(meta_ty), Lib.MkListV[AST.Term](MetaNEQ1, MetaNEQ2), ) _, neq_list := dt.Unify(neq_pred) diff --git a/src/Mods/equality/sateq/subsgatherer.go b/src/Mods/equality/sateq/subsgatherer.go index 995193a4..41b30cff 100644 --- a/src/Mods/equality/sateq/subsgatherer.go +++ b/src/Mods/equality/sateq/subsgatherer.go @@ -83,7 +83,7 @@ func translate(toTranslate *eqClass, correspondence map[*eqClass]*termRecord) AS for i, s := range tr.args { args.Upd(i, translate(s, correspondence)) } - return AST.MakerFun(tr.symbolId, args) + return AST.MakerFun(tr.symbolId, tr.tyArgs, args) } } diff --git a/src/Mods/equality/sateq/termrep.go b/src/Mods/equality/sateq/termrep.go index 36c8a42a..244a5777 100644 --- a/src/Mods/equality/sateq/termrep.go +++ b/src/Mods/equality/sateq/termrep.go @@ -36,6 +36,7 @@ import ( "fmt" "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Lib" ) type Ordered[T any] interface { @@ -138,6 +139,7 @@ type termRecord struct { eqClass *eqClass meta *AST.Meta symbolId AST.Id + tyArgs Lib.List[AST.Ty] args []*eqClass } diff --git a/src/Mods/gs3/dependency.go b/src/Mods/gs3/dependency.go index c452b556..6cbef7a9 100644 --- a/src/Mods/gs3/dependency.go +++ b/src/Mods/gs3/dependency.go @@ -55,10 +55,10 @@ func manageGammasInstantiations(initialForm, resultForm AST.Form) AST.Term { //PrintInfo("FORMS", fmt.Sprintf("init: %s, result: %s", initialForm.ToString(), resultForm.ToString())) switch initialGamma := initialForm.(type) { case AST.All: - term = getResultTerm(initialGamma.GetVarList()[0], normalisedInitialForm, resultForm) + term = getResultTerm(initialGamma.GetVarList().At(0), normalisedInitialForm, resultForm) case AST.Not: if ex, ok := initialGamma.GetForm().(AST.Ex); ok { - term = getResultTerm(ex.GetVarList()[0], normalisedInitialForm, resultForm) + term = getResultTerm(ex.GetVarList().At(0), normalisedInitialForm, resultForm) } } //PrintInfo("TERM", fmt.Sprintf("Term: %s ; Result: %s", term.ToString(), resultForm.ToString())) @@ -74,10 +74,10 @@ func manageDeltasSkolemisations(initialForm, resultForm AST.Form) AST.Term { normalisedInitialForm := getNextFormula(initialForm.Copy()) switch initialDelta := initialForm.(type) { case AST.Ex: - term = getResultTerm(initialDelta.GetVarList()[0], normalisedInitialForm, resultForm) + term = getResultTerm(initialDelta.GetVarList().At(0), normalisedInitialForm, resultForm) case AST.Not: if all, ok := initialDelta.GetForm().(AST.All); ok { - term = getResultTerm(all.GetVarList()[0], normalisedInitialForm, resultForm) + term = getResultTerm(all.GetVarList().At(0), normalisedInitialForm, resultForm) } } return term @@ -91,14 +91,14 @@ func getNextFormula(form AST.Form) AST.Form { switch f := form.(type) { case AST.All: varList := f.GetVarList() - if len(varList) > 1 { - return AST.MakerAll(varList[1:], f.GetForm()) + if varList.Len() > 1 { + return AST.MakerAll(varList.Slice(1, varList.Len()), f.GetForm()) } return f.GetForm() case AST.Ex: varList := f.GetVarList() - if len(varList) > 1 { - return AST.MakerEx(varList[1:], f.GetForm()) + if varList.Len() > 1 { + return AST.MakerEx(varList.Slice(1, varList.Len()), f.GetForm()) } return f.GetForm() case AST.Not: @@ -107,17 +107,17 @@ func getNextFormula(form AST.Form) AST.Form { return form } -func getResultTerm(v AST.Var, bareForm, endForm AST.Form) AST.Term { +func getResultTerm(v AST.TypedVar, bareForm, endForm AST.Form) AST.Term { variablesOccurrences := getAllVariableOccurrences(v, bareForm) return getTermAt(endForm, variablesOccurrences) } // Explores the form and if a variable in the varlist is found, returns its occurrence. -func getAllVariableOccurrences(v AST.Var, form AST.Form) occurrences { +func getAllVariableOccurrences(v AST.TypedVar, form AST.Form) occurrences { return getVariableOccurrencesForm(v, form, occurrences{}, occurrence{}) } -func getVariableOccurrencesForm(v AST.Var, form AST.Form, currentOcc occurrences, path occurrence) occurrences { +func getVariableOccurrencesForm(v AST.TypedVar, form AST.Form, currentOcc occurrences, path occurrence) occurrences { workingPath := make(occurrence, len(path)) copy(workingPath, path) switch f := form.(type) { @@ -143,23 +143,23 @@ func getVariableOccurrencesForm(v AST.Var, form AST.Form, currentOcc occurrences return currentOcc } -func getUnaryOcc(v AST.Var, form AST.Form, currentOcc occurrences, path occurrence) occurrences { +func getUnaryOcc(v AST.TypedVar, form AST.Form, currentOcc occurrences, path occurrence) occurrences { return getVariableOccurrencesForm(v, form, currentOcc, append(path, 0)) } -func getNAryOcc(v AST.Var, currentOcc occurrences, path occurrence, fl Lib.List[AST.Form]) occurrences { +func getNAryOcc(v AST.TypedVar, currentOcc occurrences, path occurrence, fl Lib.List[AST.Form]) occurrences { for i, nf := range fl.GetSlice() { currentOcc = getVariableOccurrencesForm(v, nf, currentOcc, appcp(path, i)) } return currentOcc } -func getVariableOccurrencesTerm(v AST.Var, term AST.Term, currentOcc occurrences, path occurrence) occurrences { +func getVariableOccurrencesTerm(v AST.TypedVar, term AST.Term, currentOcc occurrences, path occurrence) occurrences { workingPath := make(occurrence, len(path)) copy(workingPath, path) switch t := term.(type) { case AST.Var: - if t.Equals(v) { + if t.Equals(v.ToBoundVar()) { currentOcc = append(currentOcc, workingPath) } case AST.Fun: diff --git a/src/Mods/gs3/proof.go b/src/Mods/gs3/proof.go index abc5f848..c48b35e2 100644 --- a/src/Mods/gs3/proof.go +++ b/src/Mods/gs3/proof.go @@ -652,20 +652,20 @@ func (gs GS3Proof) findInBetaHist(id int) int { func getAllFormulasDependantOn(term AST.Term, form AST.Form) Lib.List[AST.Form] { switch f := form.(type) { case AST.All: - return getSubformulas(term, f.GetVarList()[0], f.GetForm()) + return getSubformulas(term, f.GetVarList().At(0), f.GetForm()) case AST.Not: if ex, isEx := f.GetForm().(AST.Ex); isEx { - return getSubformulas(term, ex.GetVarList()[0], AST.MakerNot(f.GetForm())) + return getSubformulas(term, ex.GetVarList().At(0), AST.MakerNot(f.GetForm())) } } return Lib.NewList[AST.Form]() } -func getSubformulas(term AST.Term, v AST.Var, form AST.Form) Lib.List[AST.Form] { +func getSubformulas(term AST.Term, v AST.TypedVar, form AST.Form) Lib.List[AST.Form] { subforms := form.GetSubFormulasRecur() dependantSubforms := Lib.NewList[AST.Form]() for _, f := range subforms.GetSlice() { - f, res := f.ReplaceTermByTerm(v, term) + f, res := f.ReplaceTermByTerm(v.ToBoundVar(), term) if res { dependantSubforms.Append(f) } diff --git a/src/Mods/lambdapi/context.go b/src/Mods/lambdapi/context.go index ca42bd43..953fb17f 100644 --- a/src/Mods/lambdapi/context.go +++ b/src/Mods/lambdapi/context.go @@ -50,19 +50,19 @@ func makeContextIfNeeded(root AST.Form, metaList Lib.List[AST.Meta]) string { root = AST.MakerAnd(registeredAxioms) } - if AST.EmptyGlobalContext() { - resultString += strings.Join(getContextFromFormula(root), "\n") + "\n" + // if AST.EmptyGlobalContext() { + resultString += strings.Join(getContextFromFormula(root), "\n") + "\n" - if metaList.Len() > 0 { - resultString += contextualizeMetas(metaList) - } - } else { - resultString += getContextAsString(root) - - if metaList.Len() > 0 { - resultString += contextualizeMetas(metaList) - } + if metaList.Len() > 0 { + resultString += contextualizeMetas(metaList) } + // } else { + // resultString += getContextAsString(root) + + // if metaList.Len() > 0 { + // resultString += contextualizeMetas(metaList) + // } + // } return resultString } @@ -116,54 +116,55 @@ func getContextAsString(root AST.Form) string { } func GlobContextPairs() (types, arrows, others []Glob.Pair[string, string]) { - context := AST.GetGlobalContext() - for k, v := range context { - if k != "=" && k[0] != '$' { - switch typed := v[0].App.(type) { - case AST.TypeArrow: - primitives := typed.GetPrimitives() - typesStr := "" + return []Glob.Pair[string, string]{}, []Glob.Pair[string, string]{}, []Glob.Pair[string, string]{} + // context := AST.GetGlobalContext() + // for k, v := range context { + // if k != "=" && k[0] != '$' { + // switch typed := v[0].App.(type) { + // case AST.TypeArrow: + // primitives := typed.GetPrimitives() + // typesStr := "" - for i, prim := range primitives { - if i != len(primitives)-1 { - typesStr += "τ (" + prim.ToString() + ") → " - } else { - typesStr += prim.ToString() - } - } - arrows = append(arrows, Glob.MakePair(k, typesStr)) - case AST.QuantifiedType: - primitives := typed.GetPrimitives() - typesStr := "" - contextualized := []string{} + // for i, prim := range primitives { + // if i != len(primitives)-1 { + // typesStr += "τ (" + prim.ToString() + ") → " + // } else { + // typesStr += prim.ToString() + // } + // } + // arrows = append(arrows, Glob.MakePair(k, typesStr)) + // case AST.QuantifiedType: + // primitives := typed.GetPrimitives() + // typesStr := "" + // contextualized := []string{} - for i, prim := range primitives { - if i != len(primitives)-1 { - switch typedPrim := prim.(type) { - case AST.TypeVar: - str := AST.SimpleStringMappable(typedPrim.ToString()) - symbol := addToContext(&str) - typesStr += "τ (" + symbol + ") → " - contextualized = append(contextualized, symbol) - case AST.TypeHint: - typesStr += "τ (" + prim.ToString() + ") → " - } - } else { - typesStr += prim.ToString() - } - } - arrows = append(arrows, Glob.MakePair(k, fmt.Sprintf("Π (%s : Type), %s", strings.Join(contextualized, " : Type), ("), typesStr))) - case AST.TypeHint: - if k == typed.ToString() { - types = append(types, Glob.MakePair(k, "Type")) - } else { - others = append(others, Glob.MakePair(k, fmt.Sprintf("τ (%s)", typed.ToString()))) - } - } - } - } + // for i, prim := range primitives { + // if i != len(primitives)-1 { + // switch typedPrim := prim.(type) { + // case AST.TypeVar: + // str := AST.SimpleStringMappable(typedPrim.ToString()) + // symbol := addToContext(&str) + // typesStr += "τ (" + symbol + ") → " + // contextualized = append(contextualized, symbol) + // case AST.TypeHint: + // typesStr += "τ (" + prim.ToString() + ") → " + // } + // } else { + // typesStr += prim.ToString() + // } + // } + // arrows = append(arrows, Glob.MakePair(k, fmt.Sprintf("Π (%s : Type), %s", strings.Join(contextualized, " : Type), ("), typesStr))) + // case AST.TypeHint: + // if k == typed.ToString() { + // types = append(types, Glob.MakePair(k, "Type")) + // } else { + // others = append(others, Glob.MakePair(k, fmt.Sprintf("τ (%s)", typed.ToString()))) + // } + // } + // } + // } - return types, arrows, others + // return types, arrows, others } func contextPreamble() string { diff --git a/src/Mods/lambdapi/formDecorator.go b/src/Mods/lambdapi/formDecorator.go index 2ea14429..267effde 100644 --- a/src/Mods/lambdapi/formDecorator.go +++ b/src/Mods/lambdapi/formDecorator.go @@ -35,6 +35,7 @@ import ( "fmt" "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Lib" ) type DecoratedAll struct { @@ -54,12 +55,12 @@ func (da DecoratedAll) ToMappedStringSurround(mapping AST.MapString, displayType return QuantifierToMappedString(mapping[AST.AllQuant], da.GetVarList()) } -func QuantifierToMappedString(quant string, varList []AST.Var) string { - if len(varList) == 0 { +func QuantifierToMappedString(quant string, varList Lib.List[AST.TypedVar]) string { + if varList.Len() == 0 { return "%s" } else { - result := "(" + quant + " (" + toLambdaIntroString(varList[0], "") + ", %s))" - result = fmt.Sprintf(result, QuantifierToMappedString(quant, varList[1:])) + result := "(" + quant + " (" + toLambdaIntroString(varList.At(0), "") + ", %s))" + result = fmt.Sprintf(result, QuantifierToMappedString(quant, varList.Slice(1, varList.Len()))) return result } } diff --git a/src/Mods/lambdapi/proof.go b/src/Mods/lambdapi/proof.go index 941637c0..8f740adb 100644 --- a/src/Mods/lambdapi/proof.go +++ b/src/Mods/lambdapi/proof.go @@ -144,7 +144,15 @@ func allRules(rule string, target AST.Form, composingForms Lib.List[AST.Form], n return result } -func allRulesQuantUniv(rule string, target AST.Form, composingForms Lib.List[AST.Form], nexts []*gs3.GS3Sequent, children []Lib.List[AST.Form], vars []AST.Var, termGen AST.Term) string { +func allRulesQuantUniv( + rule string, + target AST.Form, + composingForms Lib.List[AST.Form], + nexts []*gs3.GS3Sequent, + children []Lib.List[AST.Form], + vars Lib.List[AST.TypedVar], + termGen AST.Term, +) string { quant := "" typeStr := "" @@ -162,7 +170,7 @@ func allRulesQuantUniv(rule string, target AST.Form, composingForms Lib.List[AST result += "(%s, " + toCorrectString(composingForms.At(0)) + ")\n" varStrs := []string{} - for _, singleVar := range vars { + for _, singleVar := range vars.GetSlice() { varStrs = append(varStrs, toLambdaIntroString(singleVar, "")) } result = fmt.Sprintf(result, strings.Join(varStrs, ", "+quant+" ")) @@ -189,7 +197,15 @@ func getRecursionUnivStr(nexts []*gs3.GS3Sequent, children []Lib.List[AST.Form]) return result } -func allRulesQuantExist(rule string, target AST.Form, composingForms Lib.List[AST.Form], nexts []*gs3.GS3Sequent, children []Lib.List[AST.Form], vars []AST.Var, termGen AST.Term) string { +func allRulesQuantExist( + rule string, + target AST.Form, + composingForms Lib.List[AST.Form], + nexts []*gs3.GS3Sequent, + children []Lib.List[AST.Form], + vars Lib.List[AST.TypedVar], + termGen AST.Term, +) string { quant := "" typeStr := "" switch target.(type) { @@ -206,7 +222,7 @@ func allRulesQuantExist(rule string, target AST.Form, composingForms Lib.List[AS result += "(%s, " + toCorrectString(composingForms.At(0)) + ")\n" varStrs := []string{} - for _, singleVar := range vars { + for _, singleVar := range vars.GetSlice() { varStrs = append(varStrs, toLambdaIntroString(singleVar, "")) } result = fmt.Sprintf(result, strings.Join(varStrs, ", "+quant+" ")) @@ -283,7 +299,15 @@ func deltaEx(proof *gs3.GS3Sequent) string { formulaEx = form } - return allRulesQuantExist("GS3ex", proof.GetTargetForm(), proof.GetTargetForm().GetChildFormulas(), proof.Children(), proof.GetResultFormulasOfChildren(), formulaEx.GetVarList(), proof.TermGenerated()) + return allRulesQuantExist( + "GS3ex", + proof.GetTargetForm(), + proof.GetTargetForm().GetChildFormulas(), + proof.Children(), + proof.GetResultFormulasOfChildren(), + formulaEx.GetVarList(), + proof.TermGenerated(), + ) } func deltaNotAll(proof *gs3.GS3Sequent) string { @@ -304,7 +328,15 @@ func gammaAll(proof *gs3.GS3Sequent) string { formulaAll = form } - return allRulesQuantUniv("GS3all", proof.GetTargetForm(), proof.GetTargetForm().GetChildFormulas(), proof.Children(), proof.GetResultFormulasOfChildren(), formulaAll.GetVarList(), proof.TermGenerated()) + return allRulesQuantUniv( + "GS3all", + proof.GetTargetForm(), + proof.GetTargetForm().GetChildFormulas(), + proof.Children(), + proof.GetResultFormulasOfChildren(), + formulaAll.GetVarList(), + proof.TermGenerated(), + ) } func gammaNotEx(proof *gs3.GS3Sequent) string { diff --git a/src/Mods/rocq/context.go b/src/Mods/rocq/context.go index 1fe3360a..3ec82ed9 100644 --- a/src/Mods/rocq/context.go +++ b/src/Mods/rocq/context.go @@ -59,29 +59,29 @@ func makeContextIfNeeded(root AST.Form, metaList Lib.List[AST.Meta]) string { root = AST.MakerAnd(registeredAxioms) } - if AST.EmptyGlobalContext() { - resultingString += strings.Join(getContextFromFormula(root), "\n") + "\n" + // if AST.EmptyGlobalContext() { + resultingString += strings.Join(getContextFromFormula(root), "\n") + "\n" - if metaList.Len() > 0 { - resultingString += contextualizeMetas(metaList) - } - } else { - context := AST.GetGlobalContext() - for k, v := range context { - if typed, ok := v[0].App.(AST.TypeHint); ok { - if k[0] != '$' && k == typed.ToString() { - resultingString += "Parameter " + k + ": Type.\n" - - } - } - } - - resultingString += strings.Join(getContextFromFormula(root), "\n") + "\n" - - if metaList.Len() > 0 { - resultingString += contextualizeMetas(metaList) - } + if metaList.Len() > 0 { + resultingString += contextualizeMetas(metaList) } + // } else { + // context := AST.GetGlobalContext() + // for k, v := range context { + // if typed, ok := v[0].App.(AST.TypeHint); ok { + // if k[0] != '$' && k == typed.ToString() { + // resultingString += "Parameter " + k + ": Type.\n" + + // } + // } + // } + + // resultingString += strings.Join(getContextFromFormula(root), "\n") + "\n" + + // if metaList.Len() > 0 { + // resultingString += contextualizeMetas(metaList) + // } + // } return resultingString } diff --git a/src/Search/incremental/rules.go b/src/Search/incremental/rules.go index e53c8775..aaabbed0 100644 --- a/src/Search/incremental/rules.go +++ b/src/Search/incremental/rules.go @@ -412,13 +412,13 @@ func (gne *GammaNotExists) getGeneratedMetas() Lib.List[AST.Meta] { return gne.generatedMetas } -func (gne *GammaNotExists) getVarList() []AST.Var { +func (gne *GammaNotExists) getVarList() Lib.List[AST.TypedVar] { if not, isNot := gne.formula.(AST.Not); isNot { if exists, isExists := not.GetForm().(AST.Ex); isExists { return exists.GetVarList() } } - return []AST.Var{} + return Lib.NewList[AST.TypedVar]() } type GammaForall struct { @@ -453,11 +453,11 @@ func (gf *GammaForall) getGeneratedMetas() Lib.List[AST.Meta] { return gf.generatedMetas } -func (gf *GammaForall) getVarList() []AST.Var { +func (gf *GammaForall) getVarList() Lib.List[AST.TypedVar] { if forall, isForall := gf.formula.(AST.All); isForall { return forall.GetVarList() } - return []AST.Var{} + return Lib.NewList[AST.TypedVar]() } type DeltaNotForall struct { diff --git a/src/Typing/apply_rules.go b/src/Typing/apply_rules.go deleted file mode 100644 index 828b7ae9..00000000 --- a/src/Typing/apply_rules.go +++ /dev/null @@ -1,189 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -// import ( -// "fmt" - -// "github.com/GoelandProver/Goeland/AST" -// ) - -// /** -// * This file contains all the rules of the typing system. -// **/ - -// const ( -// formIsSet = iota -// termIsSet = iota -// typeIsSet = iota -// schemeIsSet = iota -// noConsequence = iota -// ) - -// /* Launch the rules depending on what's on the right side of the sequent. */ -// func applyRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// // Only one of the three should be set -// if !onlyOneConsequenceIsSet(state) { -// return Reconstruct{ -// result: false, -// err: fmt.Errorf("multiple elements on the right-side of the sequent. Cannot type this system"), -// } -// } - -// // The applicable rules depend on what is set: the form, the term, or the type ? -// switch whatIsSet(state.consequence) { -// case formIsSet: -// return applyFormRule(state, root, fatherChan) -// case termIsSet: -// return applyTermRule(state, root, fatherChan) -// case typeIsSet: -// return applyTypeRule(state, root, fatherChan) -// case schemeIsSet: -// return applySymRule(state, root, fatherChan) -// case noConsequence: -// return applyWFRule(state, root, fatherChan) -// } - -// return Reconstruct{result: true, err: nil} -// } - -// /* Applies one of the forms rule based on the type of the form. */ -// func applyFormRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// var rec Reconstruct -// switch (state.consequence.f).(type) { -// case AST.All, AST.AllType, AST.Ex: -// rec = applyQuantRule(state, root, fatherChan) -// case AST.And, AST.Or: -// rec = applyNAryRule(state, root, fatherChan) -// case AST.Imp, AST.Equ: -// rec = applyBinaryRule(state, root, fatherChan) -// case AST.Top, AST.Bot: -// rec = applyBotTopRule(state, root, fatherChan) -// case AST.Not: -// rec = applyNotRule(state, root, fatherChan) -// case AST.Pred: -// rec = applyAppRule(state, root, fatherChan) -// } -// return rec -// } - -// /* Applies one of the terms rule based on the type of the form. */ -// func applyTermRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// var rec Reconstruct -// switch (state.consequence.t).(type) { -// case AST.Fun: -// rec = applyAppRule(state, root, fatherChan) -// case AST.Var: -// rec = applyVarRule(state, root, fatherChan) -// // Metas shoudln't appear in the formula yet. -// // IDs are not a real Term. -// } -// return rec -// } - -// /* Applies one of the types rule based on the type of the form. */ -// func applyTypeRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// var rec Reconstruct -// switch type_ := (state.consequence.a).(type) { -// case AST.TypeHint: -// if type_.Equals(metaType) { -// rec = applyTypeWFRule(state, root, fatherChan) -// } else { -// rec = applyGlobalTypeVarRule(state, root, fatherChan) -// } -// case AST.TypeVar: -// rec = applyLocalTypeVarRule(state, root, fatherChan) -// case AST.TypeCross: -// // Apply composed rule: launch a child for each TypeHint of the composed type. -// rec = applyCrossRule(state, root, fatherChan) -// // There shouldn't be any TypeArrow: can not type a variable with it in first order. -// case AST.ParameterizedType: -// // Apply app rule, we only need to check if the name of the type exists. -// rec = applyAppTypeRule(state, root, fatherChan) -// } -// return rec -// } - -// /* Applies one of the WF rule based on the type of the form. */ -// func applyWFRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// if state.localContext.isEmpty() && state.globalContext.isEmpty() { -// root.appliedRule = "WF_0" -// return Reconstruct{result: true, err: nil} -// } -// if state.localContext.isEmpty() { -// root.appliedRule = "WF_1" -// return Reconstruct{result: true, err: nil} -// } - -// return applyWF2(state, root, fatherChan) -// } - -// /* Checks that at most one consequence of the sequent is set. */ -// func onlyOneConsequenceIsSet(state Sequent) bool { -// numberSet := 0 -// if state.consequence.f != nil { -// numberSet++ -// } -// if state.consequence.t != nil { -// numberSet++ -// } -// if state.consequence.a != nil { -// numberSet++ -// } -// if state.consequence.s != nil { -// numberSet++ -// } - -// return numberSet < 2 -// } - -// /** -// * Returns what is set in the consequence of the sequent. Either it's the form, -// * the term, or the type. -// * It doesn't check if multiple elements are set, it should be done before. -// **/ -// func whatIsSet(cons Consequence) int { -// var set int -// if cons.f != nil { -// set = formIsSet -// } else if cons.t != nil { -// set = termIsSet -// } else if cons.a != nil { -// set = typeIsSet -// } else if cons.s != nil { -// set = schemeIsSet -// } else { -// set = noConsequence -// } -// return set -// } diff --git a/src/Typing/contexts.go b/src/Typing/contexts.go deleted file mode 100644 index 1a78e62f..00000000 --- a/src/Typing/contexts.go +++ /dev/null @@ -1,341 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -// import ( -// "fmt" - -// "github.com/GoelandProver/Goeland/AST" -// "github.com/GoelandProver/Goeland/Glob" -// "github.com/GoelandProver/Goeland/Lib" -// ) - -// /** -// * This file defines the global & local contexts types. -// **/ - -// /* Stores the local context */ -// type LocalContext struct { -// vars []AST.Var -// typeVars []AST.TypeVar -// } - -// /* LocalContext methods */ - -// /* Adds a var to a copy of the local context and returns it. */ -// func (lc LocalContext) addVar(var_ AST.Var) LocalContext { -// newLc := lc.copy() -// newLc.vars = append(newLc.vars, var_) -// return newLc -// } - -// /* Adds a type var to a copy of the local context and returns it. */ -// func (lc LocalContext) addTypeVar(var_ AST.TypeVar) LocalContext { -// newLc := lc.copy() -// newLc.typeVars = append(newLc.typeVars, var_) -// return newLc -// } - -// /* Copies a LocalContext. */ -// func (lc LocalContext) copy() LocalContext { -// newVars := make([]AST.Var, len(lc.vars)) -// newTypeVars := make([]AST.TypeVar, len(lc.typeVars)) -// copy(newVars, lc.vars) -// copy(newTypeVars, lc.typeVars) -// return LocalContext{vars: newVars, typeVars: newTypeVars} -// } - -// /* True if all the slices are cleared */ -// func (lc LocalContext) isEmpty() bool { -// return len(lc.vars)+len(lc.typeVars) == 0 -// } - -// /** -// * Copies the context and pops the first var (and returns it with the new local context). -// * It doesn't check if the size of the array is positive, it should be checked before. -// **/ -// func (lc LocalContext) popVar() (AST.Var, LocalContext) { -// newLc := lc.copy() -// newLc.vars = newLc.vars[1:] -// return lc.vars[0], newLc -// } - -// /** -// * Copies the context and pops the first type var (and returns it with the new local context). -// * It doesn't check if the size of the array is positive, it should be checked before. -// **/ -// func (lc LocalContext) popTypeVar() (AST.TypeVar, LocalContext) { -// newLc := lc.copy() -// newLc.typeVars = newLc.typeVars[1:] -// return lc.typeVars[0], newLc -// } - -// /* Stores the global context */ -// type GlobalContext struct { -// primitiveTypes []AST.TypeHint -// parameterizedTypes []string -// composedType map[string]AST.TypeCross -// simpleSchemes map[string][]AST.TypeScheme -// polymorphSchemes map[string][]AST.QuantifiedType -// } - -// /* Copies a GlobalContext into a new variable and returns it. */ -// func (gc GlobalContext) copy() GlobalContext { -// context := GlobalContext{ -// primitiveTypes: make([]AST.TypeHint, len(gc.primitiveTypes)), -// parameterizedTypes: make([]string, len(gc.parameterizedTypes)), -// simpleSchemes: make(map[string][]AST.TypeScheme), -// polymorphSchemes: make(map[string][]AST.QuantifiedType), -// } -// copy(context.primitiveTypes, gc.primitiveTypes) -// copy(context.parameterizedTypes, gc.parameterizedTypes) - -// for name, list := range gc.simpleSchemes { -// context.simpleSchemes[name] = make([]AST.TypeScheme, len(list)) -// copy(context.simpleSchemes[name], list) -// } - -// for name, list := range gc.polymorphSchemes { -// context.polymorphSchemes[name] = make([]AST.QuantifiedType, len(list)) -// copy(context.polymorphSchemes[name], list) -// } - -// return context -// } - -// /* Gets a simple / polymorphic type scheme from an ID, type variables, and terms */ -// func (gc GlobalContext) getTypeScheme( -// id AST.Id, -// vars []AST.TypeApp, -// terms Lib.List[AST.Term], -// ) (AST.TypeScheme, error) { -// args, err := getArgsTypes(gc, terms) -// if err != nil { -// return nil, err -// } - -// typeScheme, err := gc.getSimpleTypeScheme(id.GetName(), args) - -// if typeScheme == nil { -// typeScheme, err = gc.getPolymorphicTypeScheme( -// id.GetName(), -// len(vars), -// terms.Len(), -// ) -// // Instantiate type scheme with actual types -// if typeScheme != nil { -// typeScheme = Glob.To[AST.QuantifiedType](typeScheme).Instanciate(vars) -// } -// } - -// if err != nil { -// return nil, err -// } - -// return typeScheme, nil -// } - -// func flattenCross(ty AST.TypeApp) []AST.TypeApp { -// switch nty := ty.(type) { -// case AST.TypeCross: -// flattened := []AST.TypeApp{} -// for _, uty := range nty.GetAllUnderlyingTypes() { -// flattened = append(flattened, flattenCross(uty)...) -// } -// return []AST.TypeApp{AST.MkTypeCross(flattened...)} -// } -// return []AST.TypeApp{ty} -// } - -// /* Search for a TypeScheme with the name & the arguments type */ -// func (gc GlobalContext) getSimpleTypeScheme(name string, termsType AST.TypeApp) (AST.TypeScheme, error) { -// if termsType == nil { -// if typeScheme, found := gc.simpleSchemes[name]; found { -// return typeScheme[0], nil -// } else { -// return nil, fmt.Errorf("no constant function with the name %s in the global context", name) -// } -// } - -// termsType = flattenCross(termsType)[0] -// if typeSchemeList, found := gc.simpleSchemes[name]; found { -// for _, typeScheme := range typeSchemeList { -// if AST.GetInputType(typeScheme).Equals(Lib.ComparableList[AST.TypeApp]{termsType}) { -// return typeScheme, nil -// } -// } -// } -// return nil, fmt.Errorf("no predicate/function with the name %s in the global context and arguments of type %s", name, termsType.ToString()) -// } - -// /* Gets the polymorphic type scheme corresponding to the input. */ -// func (gc GlobalContext) getPolymorphicTypeScheme(name string, varsLen, termsLen int) (AST.TypeScheme, error) { -// if typeSchemeList, found := gc.polymorphSchemes[name]; found { -// for _, typeScheme := range typeSchemeList { -// if termsLen == typeScheme.Size()-1 && varsLen == typeScheme.QuantifiedVarsLen() { -// return typeScheme, nil -// } -// } -// } -// return nil, fmt.Errorf("no predicate/function with the name %s in the global context", name) -// } - -// /* Returns true if the TypeHint is found in the context */ -// func (gc GlobalContext) isTypeInContext(typeApp AST.TypeScheme) bool { -// for _, type_ := range gc.primitiveTypes { -// if type_.Equals(typeApp) { -// return true -// } -// } -// for _, type_ := range gc.composedType { -// if type_.Equals(typeApp) { -// return true -// } -// } -// return false -// } - -// /* Tests if there are no more TypeScheme stored (doesn't check for primitive types) */ -// func (gc GlobalContext) isEmpty() bool { -// result := true - -// for _, app := range gc.simpleSchemes { -// result = result && (len(app) == 0) -// } -// for _, app := range gc.polymorphSchemes { -// result = result && (len(app) == 0) -// } - -// return result -// } - -// /* Checks if the parameterized types contains the given name */ -// func (gc GlobalContext) parameterizedTypesContains(name string) bool { -// for _, parameterTypeName := range gc.parameterizedTypes { -// if name == parameterTypeName { -// return true -// } -// } -// return false -// } - -// /* Utils */ - -// /** -// * Creates a global context from all the types / type schemes recorded in the map of types. -// * Incrementally verifies if the context is well typed. -// * If not, an error is returned. -// **/ -// func createGlobalContext(context map[string][]AST.App) (GlobalContext, error) { -// globalContext := GlobalContext{ -// primitiveTypes: []AST.TypeHint{}, -// parameterizedTypes: []string{}, -// composedType: make(map[string]AST.TypeCross), -// simpleSchemes: make(map[string][]AST.TypeScheme), -// polymorphSchemes: make(map[string][]AST.QuantifiedType), -// } - -// // Fill first the primitive types -// for name, appList := range context { -// if len(appList) == 0 { -// globalContext.parameterizedTypes = append(globalContext.parameterizedTypes, name) -// } -// for _, app := range appList { -// if type_, isTypeHint := app.App.(AST.TypeHint); isTypeHint { -// if !AST.IsConstant(name) { -// globalContext.primitiveTypes = append(globalContext.primitiveTypes, type_) -// } -// } -// } -// } - -// for name, appList := range context { -// // Then, fill everything else -// for _, app := range appList { -// switch type_ := app.App.(type) { -// case AST.TypeHint: -// if AST.IsConstant(name) { -// globalContext.simpleSchemes[name] = append(globalContext.simpleSchemes[name], type_) -// } -// case AST.TypeCross: -// globalContext.composedType[name] = type_ -// case AST.TypeArrow: -// globalContext.simpleSchemes[name] = append(globalContext.simpleSchemes[name], type_) -// case AST.QuantifiedType: -// globalContext.polymorphSchemes[name] = append(globalContext.polymorphSchemes[name], type_) -// case AST.ParameterizedType: -// globalContext.simpleSchemes[name] = append(globalContext.simpleSchemes[name], type_) -// } -// if err := incrementalVerificationOfGlobalContext(globalContext.copy(), name, app.App); err != nil { -// return GlobalContext{}, err -// } -// } -// } - -// if !globalContextIsWellTyped { -// globalContextIsWellTyped = true -// } -// return globalContext, nil -// } - -// /** -// * Triggers rules to verify the global context while it's constructed. -// * It will avoid combinatorial explosion on global context well formedness verification. -// **/ -// func incrementalVerificationOfGlobalContext(globalContext GlobalContext, name string, app AST.TypeScheme) error { -// if globalContextIsWellTyped { -// return nil -// } - -// sequent := Sequent{ -// globalContext: globalContext, -// localContext: LocalContext{}, -// } -// rec := Reconstruct{err: nil} -// proofTree, chan_ := new(ProofTree), make(chan Reconstruct) - -// switch type_ := app.(type) { -// case AST.TypeCross: -// sequent.consequence = Consequence{a: type_} -// rec = applyCrossRule(sequent, proofTree, chan_) -// case AST.QuantifiedType, AST.TypeArrow: -// sequent.consequence = Consequence{s: app} -// rec = applySymRule(sequent, proofTree, chan_) -// case AST.TypeHint: -// if AST.IsConstant(name) { -// sequent.consequence = Consequence{a: type_} -// rec = applyGlobalTypeVarRule(sequent, proofTree, chan_) -// } -// } -// return rec.err -// } diff --git a/src/Typing/env-and-context.go b/src/Typing/env-and-context.go new file mode 100644 index 00000000..e544f6c4 --- /dev/null +++ b/src/Typing/env-and-context.go @@ -0,0 +1,136 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** + * This file declares the environments of the typing process. + * In particular, it handles the global context and its accesses. +**/ + +package Typing + +import ( + "sync" + + "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Lib" +) + +// We define an ordered type of pairs of (string, Ty) in order to use sets. +type definedType struct { + name string + ty AST.Ty +} + +func (dty definedType) Less(oth any) bool { + if other, ok := oth.(definedType); ok { + return dty.name < other.name + } + return false +} + +func (dty definedType) Equals(oth any) bool { + if other, ok := oth.(definedType); ok { + return dty.name == other.name && dty.ty.Equals(other.ty) + } + return false +} + +// A context is a set of defined types +type Con struct { + defs Lib.Set[definedType] +} + +func emptyCon() Con { + return Con{Lib.EmptySet[definedType]()} +} + +func (con Con) Copy() Con { + return Con{con.defs.Copy()} +} + +func (con Con) add(name string, ty AST.Ty) Con { + return Con{con.defs.Add(definedType{name, ty})} +} + +func (con Con) contains(name string, ty AST.Ty) bool { + return con.defs.Contains(definedType{name, ty}) +} + +// We could use [Con] to do environments, but as we need to query by name it's faster to use a map. +type Env struct { + con map[string]AST.Ty + mut sync.Mutex +} + +func safeGlobalOperation[T any](f func() T) T { + global_env.mut.Lock() + res := f() + global_env.mut.Unlock() + return res +} + +func AddToGlobalEnv(name string, ty AST.Ty) { + safeGlobalOperation( + func() any { + global_env.con[name] = ty + return nil + }, + ) +} + +func unsafeQuery(name string) Lib.Option[AST.Ty] { + if ty, ok := global_env.con[name]; ok { + return Lib.MkSome(ty) + } + return Lib.MkNone[AST.Ty]() +} + +func QueryGlobalEnv(name string) Lib.Option[AST.Ty] { + return safeGlobalOperation(func() Lib.Option[AST.Ty] { return unsafeQuery(name) }) +} + +// Queries the environment and, if found, instantiate the definition with the given types. +// Guaranteed to not return a Pi-type. +func QueryEnvInstance(name string, instance Lib.List[AST.Ty]) Lib.Option[AST.Ty] { + return safeGlobalOperation( + func() Lib.Option[AST.Ty] { + // If [name] is safely found in the environment, instantiates it with the given vars + // Otherwise, return None + return Lib.OptBind( + unsafeQuery(name), + func(ty AST.Ty) Lib.Option[AST.Ty] { + return Lib.MkSome(AST.InstantiateTy(ty, instance)) + }, + ) + }, + ) +} diff --git a/src/Typing/form_rules.go b/src/Typing/form_rules.go deleted file mode 100644 index 772ec291..00000000 --- a/src/Typing/form_rules.go +++ /dev/null @@ -1,234 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -// import ( -// "github.com/GoelandProver/Goeland/AST" -// "github.com/GoelandProver/Goeland/Lib" -// ) - -// /** -// * This file contains all the rules that the typing system can apply on a formula. -// **/ - -// /* Applies quantification rule and launches 2 goroutines waiting its children. */ -// func applyQuantRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// // Add rule to prooftree -// switch (state.consequence.f).(type) { -// case AST.All, AST.AllType: -// root.appliedRule = "∀" -// case AST.Ex: -// root.appliedRule = "∃" -// } - -// var newForm AST.Form -// var varTreated AST.Var -// var typeTreated AST.TypeVar - -// varInstantiated := false - -// switch f := (state.consequence.f).(type) { -// case AST.All, AST.Ex: -// varTreated, newForm = removeOneVar(state.consequence.f) -// varInstantiated = true -// case AST.AllType: -// v := f.GetVarList()[0] -// if len(f.GetVarList()) > 1 { -// typeTreated, newForm = v, AST.MakeAllType(f.GetIndex(), f.GetVarList()[1:], f.GetForm()) -// } else { -// typeTreated, newForm = v, f.GetForm() -// } -// } - -// // Create 2 children: -// // 1 - First one with the type of the quantified variable. It should be a TypeApp. -// // 2 - Second one with the quantified variable added in the local context. -// // => copy the local context and use the function to get the global context (copy or not). -// // The underlying form should be gotten to be properly typed. -// children := mkQuantChildren(state, varInstantiated, varTreated, typeTreated, newForm) - -// // Launch the children in a goroutine, and wait for it to close. -// // If one branch closes with an error, then the system is not well-typed. -// return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -// } - -// /* Applies OR or AND rule and launches n goroutines waiting its children */ -// func applyNAryRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// formList := Lib.NewList[AST.Form]() -// // Add rule to prooftree -// switch f := (state.consequence.f).(type) { -// case AST.And: -// root.appliedRule = "∧" -// formList = f.GetChildFormulas() -// case AST.Or: -// root.appliedRule = "∨" -// formList = f.GetChildFormulas() -// } - -// // Construct children with all the formulas -// children := []Sequent{} -// for _, form := range formList.GetSlice() { -// children = append(children, Sequent{ -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{f: form}, -// }) -// } - -// // Launch the children in a goroutine, and wait for it to close. -// // If one branch closes with an error, then the system is not well-typed. -// return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -// } - -// /* Applies => or <=> rule and launches 2 goroutines waiting its children */ -// func applyBinaryRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// var f1, f2 AST.Form -// // Add rule to prooftree -// switch f := (state.consequence.f).(type) { -// case AST.Imp: -// root.appliedRule = "⇒" -// f1, f2 = f.GetF1(), f.GetF2() -// case AST.Equ: -// root.appliedRule = "⇔" -// f1, f2 = f.GetF1(), f.GetF2() -// } - -// // Construct children with the 2 formulas -// children := []Sequent{ -// { -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{f: f1}, -// }, -// { -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{f: f2}, -// }, -// } - -// // Launch the children in a goroutine, and wait for it to close. -// // If one branch closes with an error, then the system is not well-typed. -// return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -// } - -// /* Applies BOT or TOP rule and does not create a new goroutine */ -// func applyBotTopRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// // Add rule to prooftree -// switch (state.consequence.f).(type) { -// case AST.Top: -// root.appliedRule = "⊤" -// case AST.Bot: -// root.appliedRule = "⊥" -// } - -// // Construct children with the contexts -// children := []Sequent{ -// { -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{}, -// }, -// } - -// // If the branch closes with an error, then the system is not well-typed. -// return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -// } - -// func applyNotRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// // Add rule to prooftree -// root.appliedRule = "¬" -// form := (state.consequence.f).(AST.Not).GetForm() - -// // Construct children with the contexts -// children := []Sequent{ -// { -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{f: form}, -// }, -// } - -// // If the branch closes with an error, then the system is not well-typed. -// return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -// } - -// /** -// * Removes the first variable of an exitential or universal form, and returns a -// * universal / existential form iff it still possesses other vars. -// * Otherwise, it returns the form gotten with GetForm(). -// **/ -// func removeOneVar(form AST.Form) (AST.Var, AST.Form) { -// // It's pretty much the same thing, but I don't have a clue on how to factorize this.. -// switch f := form.(type) { -// case AST.Ex: -// v := f.GetVarList()[0] -// if len(f.GetVarList()) > 1 { -// return v, AST.MakeEx(f.GetIndex(), f.GetVarList()[1:], f.GetForm()) -// } -// return v, f.GetForm() -// case AST.All: -// v := f.GetVarList()[0] -// if len(f.GetVarList()) > 1 { -// return v, AST.MakeAll(f.GetIndex(), f.GetVarList()[1:], f.GetForm()) -// } -// return v, f.GetForm() -// } -// return AST.Var{}, nil -// } - -// /* Makes the child treating the variable depending on which is set. */ -// func mkQuantChildren(state Sequent, varInstantiated bool, varTreated AST.Var, typeTreated AST.TypeVar, newForm AST.Form) []Sequent { -// var type_ AST.TypeApp -// var newLocalContext LocalContext -// if varInstantiated { -// type_ = varTreated.GetTypeApp() -// newLocalContext = state.localContext.addVar(varTreated) -// } else { -// type_ = metaType -// newLocalContext = state.localContext.addTypeVar(typeTreated) -// } - -// return []Sequent{ -// { -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{a: type_}, -// }, -// { -// globalContext: state.globalContext, -// localContext: newLocalContext, -// consequence: Consequence{f: newForm}, -// }, -// } -// } diff --git a/src/Typing/wf_rules.go b/src/Typing/init.go similarity index 61% rename from src/Typing/wf_rules.go rename to src/Typing/init.go index 186217dc..f145b260 100644 --- a/src/Typing/wf_rules.go +++ b/src/Typing/init.go @@ -30,38 +30,19 @@ * knowledge of the CeCILL license and that you accept its terms. **/ -package Typing +/** + * This file initializes the global environment (e.g., with TPTP primitives) +**/ -// /** -// * This file defines the WF rules. -// **/ +package Typing -// /* WF1 rule first empties the variables, and then the types. */ -// func applyWF2(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// root.appliedRule = "WF_2" +import ( + "github.com/GoelandProver/Goeland/AST" + "sync" +) -// // Try to empty vars first -// if len(state.localContext.vars) > 0 { -// // Launch child on the type of the first var -// var_, newLocalContext := state.localContext.popVar() -// child := []Sequent{ -// { -// localContext: newLocalContext, -// globalContext: state.globalContext, -// consequence: Consequence{a: var_.GetTypeApp()}, -// }, -// } -// return launchChildren(child, root, fatherChan) -// } +var global_env Env -// // Then, if vars is not empty, empty the types -// _, newLocalContext := state.localContext.popTypeVar() -// child := []Sequent{ -// { -// localContext: newLocalContext, -// globalContext: state.globalContext, -// consequence: Consequence{a: metaType}, -// }, -// } -// return launchChildren(child, root, fatherChan) -// } +func Init() { + global_env = Env{make(map[string]AST.Ty), sync.Mutex{}} +} diff --git a/src/Typing/launch_rules.go b/src/Typing/launch_rules.go deleted file mode 100644 index 7e78036b..00000000 --- a/src/Typing/launch_rules.go +++ /dev/null @@ -1,177 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -// import ( -// "fmt" -// "reflect" - -// "github.com/GoelandProver/Goeland/AST" -// "github.com/GoelandProver/Goeland/Lib" -// ) - -// /** -// * This file manages everything related to parallelism / concurrency. -// **/ - -// type Reconstruct struct { -// result bool -// forms Lib.List[AST.Form] -// terms Lib.List[AST.Term] -// err error -// } - -// /* Launches the first instance of applyRule. Do this to launch the typing system. */ -// func launchRuleApplication(state Sequent, root *ProofTree) (AST.Form, error) { -// superFatherChan := make(chan Reconstruct) -// go tryApplyRule(state, root, superFatherChan) -// res := <-superFatherChan -// return treatReturns(res) -// } - -// /* Launches applyRule and manages the error return. */ -// func tryApplyRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) { -// select { -// case <-fatherChan: // Message from the father received: it can only be a kill order. -// default: -// // No kill order, it's still properly typed, let's apply the next rules. -// reconstruct := applyRule(state, root, fatherChan) -// select { -// case <-fatherChan: // Kill order received, it's finished anyway. -// case fatherChan <- reconstruct: // Otherwise, send result to father. -// } -// } -// } - -// /* Launch each sequent in a goroutine if sequent length > 1. */ -// func launchChildren(sequents []Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// if len(sequents) == 1 { -// // Do not launch another goroutine if the applied rule has only 1 child. -// return applyRule(sequents[0], root.addChildWith(sequents[0]), fatherChan) -// } else { -// // Create a channel for each child, and launch it in a goroutine. -// chanTab := make([](chan Reconstruct), len(sequents)) -// for i := range sequents { -// childChan := make(chan Reconstruct) -// chanTab[i] = childChan -// go tryApplyRule(sequents[i], root.addChildWith(sequents[i]), childChan) -// } -// // If a child dies with an error, stops the typesearch procedure. -// return selectSequents(chanTab, fatherChan) -// } -// } - -// /** -// * Waits for all the children to close. -// * If an error is received, stops the type-search of every children and sends an error -// * to the parent. -// **/ -// func selectSequents(chansTab [](chan Reconstruct), chanQuit chan Reconstruct) Reconstruct { -// // Instantiation -// cases := makeCases(chansTab, chanQuit) -// hasAnswered := make([]bool, len(chansTab)) // Everything to false -// remaining, indexQuit := len(chansTab), len(chansTab) -// var errorFound error = nil - -// forms := make([]AST.Form, len(chansTab)) -// terms := Lib.MkList[AST.Term](len(chansTab)) - -// // Wait for all children to finish. -// for remaining > 0 && errorFound == nil { -// index, value, _ := reflect.Select(cases) -// remaining-- -// if index == indexQuit { -// errorFound = fmt.Errorf("father detected an error") -// } else { -// res := value.Interface().(Reconstruct) -// hasAnswered[index] = true -// if !res.result { -// errorFound = res.err -// } else { -// // Once the child sends back to the father, it should only have one item. -// if res.forms.Len() == 1 { -// forms[index] = res.forms.At(0) -// } -// if res.terms.Len() == 1 { -// terms.Upd(index, res.terms.At(0)) -// } -// } -// } -// } - -// selectCleanup(errorFound, hasAnswered, chansTab) -// return Reconstruct{result: errorFound == nil, forms: Lib.MkListV(forms...), terms: terms, err: errorFound} -// } - -// /* Utils functions for selectSequents */ - -// /* Makes the array of cases from the channels */ -// func makeCases(chansTab [](chan Reconstruct), chanQuit chan Reconstruct) []reflect.SelectCase { -// cases := make([]reflect.SelectCase, len(chansTab)+1) -// // Children -// for i, chan_ := range chansTab { -// cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(chan_)} -// } -// // Father -// cases[len(chansTab)] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(chanQuit)} -// return cases -// } - -// /* If an error was found, kills all the children. */ -// func selectCleanup(errorFound error, hasAnswered []bool, chansTab [](chan Reconstruct)) { -// if errorFound != nil { -// for i, answered := range hasAnswered { -// if !answered { -// select { -// case <-chansTab[i]: // Filter out, he already responded -// case chansTab[i] <- Reconstruct{result: false, err: errorFound}: // Kill child -// } -// } -// } -// } -// } - -// /* Treats the different return types of the system. */ -// func treatReturns(res Reconstruct) (AST.Form, error) { -// if !res.result { -// return nil, res.err -// } else { -// if res.forms.Len() == 0 { -// return nil, res.err -// } -// if res.forms.Len() > 1 { -// return nil, fmt.Errorf("more than one formula is returned by the typing system") -// } -// return res.forms.At(0), res.err -// } -// } diff --git a/src/Typing/prooftree_dump.go b/src/Typing/prooftree_dump.go deleted file mode 100644 index 60a50da4..00000000 --- a/src/Typing/prooftree_dump.go +++ /dev/null @@ -1,151 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -// import ( -// "encoding/json" -// "errors" -// "fmt" -// "os" -// "strings" - -// "github.com/GoelandProver/Goeland/AST" -// "github.com/GoelandProver/Goeland/Glob" -// ) - -// /** -// * This file contains the methods to dump a prooftree in a json. -// **/ - -// /* Dumps the prooftree in a json. */ -// func (root *ProofTree) DumpJson() error { -// // Dump folder should be a flag in the future -// dump := "../visualization/types/" -// // Create a new file -// i := 0 -// for fileExists(getFileName(dump, i)) { -// i++ -// } - -// f, err := os.OpenFile(getFileName(dump, i), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) -// if err != nil { -// return err -// } -// json, err := root.dump() - -// if err != nil { -// return err -// } - -// _, err = f.WriteString(json) -// Glob.PrintInfo("DUMP", fmt.Sprintf("Dumped type proof in %s\n", f.Name())) -// return err -// } - -// /* Creates file if not exists, dump informations in it, and calls recursively on each child */ -// func (root *ProofTree) dump() (string, error) { -// varsString := []string{} -// var consequence string = "" -// var ts string -// if root.typeScheme != nil { -// ts = root.typeScheme.ToString() -// } - -// for _, var_ := range root.sequent.localContext.vars { -// varsString = append(varsString, var_.ToString()) -// } -// for _, var_ := range root.sequent.localContext.typeVars { -// varsString = append(varsString, fmt.Sprintf("%s: Type", var_.ToString())) -// } - -// switch whatIsSet(root.sequent.consequence) { -// case formIsSet: -// consequence = root.sequent.consequence.f.ToString() -// if root.typeScheme == nil { -// ts = root.sequent.consequence.f.GetType().ToString() -// } -// case termIsSet: -// consequence = root.sequent.consequence.t.ToString() -// if root.typeScheme == nil { -// if root.sequent.consequence.t.(AST.TypedTerm).GetTypeHint() == nil { -// ts = root.sequent.consequence.t.(AST.TypedTerm).GetTypeApp().ToString() -// } else { -// ts = root.sequent.consequence.t.(AST.TypedTerm).GetTypeHint().ToString() -// } -// } -// case typeIsSet: -// consequence = root.sequent.consequence.a.ToString() -// if root.typeScheme == nil { -// ts = "Type" -// } -// } - -// childrenProofs := []string{} - -// for _, child := range root.children { -// bytes, err := child.dump() -// if err != nil { -// return "", err -// } -// childrenProofs = append(childrenProofs, bytes) -// } - -// bytes, err := json.Marshal(&struct { -// LocalContext string `json:"localContext"` -// Consequence string `json:"consequence"` -// TypeScheme string `json:"typeScheme"` -// Rule string `json:"rule"` -// Children []string `json:"children"` -// }{ -// LocalContext: strings.Join(varsString, ", "), -// Consequence: consequence, -// TypeScheme: ts, -// Rule: root.appliedRule, -// Children: childrenProofs, -// }) - -// return strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(string(bytes), "\\", ""), "\"{", "{"), "}\"", "}"), err -// } - -// /* Utils */ - -// /* Checks if file exists at given path */ -// func fileExists(path string) bool { -// _, err := os.Stat(path) -// return !errors.Is(err, os.ErrNotExist) -// } - -// /* Create a formated file name */ -// func getFileName(folder string, i int) string { -// return fmt.Sprintf("%sproof_%d.json", folder, i) -// } diff --git a/src/Typing/rules.go b/src/Typing/rules.go index 2850fcc2..7b2f9768 100644 --- a/src/Typing/rules.go +++ b/src/Typing/rules.go @@ -30,207 +30,17 @@ * knowledge of the CeCILL license and that you accept its terms. **/ -package Typing - -// import ( -// "reflect" - -// "github.com/GoelandProver/Goeland/AST" -// "github.com/GoelandProver/Goeland/Glob" -// "github.com/GoelandProver/Goeland/Lib" -// ) - -// /** -// * This file contains the functions to create a typing proof tree. -// * It defines the TypingProofTree structure and all the rules to check if a -// * system is well-typed. -// **/ - -// /* Stores the consequence of the sequent */ -// type Consequence struct { -// f AST.Form -// t AST.Term -// a AST.TypeApp -// s AST.TypeScheme -// } - -// /* A Sequent is formed of a global context, local context, and a formula or a term to type */ -// type Sequent struct { -// globalContext GlobalContext -// localContext LocalContext -// consequence Consequence -// } - -// /* Makes a typing prooftree to output. */ -// type ProofTree struct { -// sequent Sequent -// appliedRule string -// typeScheme AST.TypeScheme -// children []*ProofTree -// } - -// /* ProofTree meta-type */ -// var metaType AST.TypeHint - -// /* ProofTree methods */ - -// /* Creates and adds a child to the prooftree and returns it. */ -// func (pt *ProofTree) addChildWith(sequent Sequent) *ProofTree { -// child := ProofTree{ -// sequent: sequent, -// children: []*ProofTree{}, -// } -// pt.children = append(pt.children, &child) -// return &child -// } - -// var globalContextIsWellTyped bool = false - -// /** -// * Tries to type form. -// * If not well-typed, will return an error. -// **/ -// func WellFormedVerification(form AST.Form, dump bool) error { -// // Instanciate meta type -// metaType = AST.MkTypeHint("$tType") - -// // Second pass to type variables & to give the typevars to functions and predicates -// form = SecondPass(form) - -// globalContext, err := createGlobalContext(AST.GetGlobalContext()) -// if err != nil { -// return err -// } - -// // Sequent creation -// state := Sequent{ -// globalContext: globalContext, -// localContext: LocalContext{vars: []AST.Var{}, typeVars: []AST.TypeVar{}}, -// consequence: Consequence{f: form}, -// } - -// // Prooftree creation -// root := ProofTree{ -// sequent: state, -// children: []*ProofTree{}, -// } - -// // Launch the typing system -// _, err = launchRuleApplication(state, &root) - -// // Dump prooftree in json if it's asked & there is no error -// if dump && err == nil { -// err = root.DumpJson() -// } - -// return err -// } - -// /* Reconstructs a Form depending on what the children has returned */ -// func reconstructForm(reconstruction Reconstruct, baseForm AST.Form) Reconstruct { -// if !reconstruction.result { -// return reconstruction -// } - -// var f AST.Form -// switch form := baseForm.(type) { -// case AST.All: -// f = AST.MakeAll(form.GetIndex(), form.GetVarList(), unquantify(reconstruction.forms.At(1), form)) -// case AST.AllType: -// f = AST.MakeAllType(form.GetIndex(), form.GetVarList(), unquantify(reconstruction.forms.At(1), form)) -// case AST.Ex: -// f = AST.MakeEx(form.GetIndex(), form.GetVarList(), unquantify(reconstruction.forms.At(1), form)) -// case AST.And: -// f = AST.MakeAnd(form.GetIndex(), reconstruction.forms) -// case AST.Or: -// f = AST.MakeOr(form.GetIndex(), reconstruction.forms) -// case AST.Imp: -// f = AST.MakeImp(form.GetIndex(), reconstruction.forms.At(0), reconstruction.forms.At(1)) -// case AST.Equ: -// f = AST.MakeEqu(form.GetIndex(), reconstruction.forms.At(0), reconstruction.forms.At(1)) -// case AST.Not: -// f = AST.MakeNot(form.GetIndex(), reconstruction.forms.At(0)) -// case AST.Pred: -// // The len(form.GetTypeVars()) first children launched are children for typevars. -// // So the len(form.GetTypeVars()) first children will return -// if reconstruction.terms.Len() > len(form.GetTypeVars()) { -// terms := Lib.MkListV(reconstruction.terms.Get( -// len(form.GetTypeVars()), -// reconstruction.terms.Len(), -// )...) -// f = AST.MakePred( -// form.GetIndex(), -// form.GetID(), -// terms, -// form.GetTypeVars(), -// form.GetType(), -// ) -// } else { -// f = AST.MakePred( -// form.GetIndex(), -// form.GetID(), -// Lib.NewList[AST.Term](), -// form.GetTypeVars(), -// form.GetType(), -// ) -// } -// case AST.Top, AST.Bot: -// f = baseForm -// } - -// return Reconstruct{result: true, forms: Lib.MkListV(f), err: nil} -// } - -// /* Reconstructs a Term depending on what the children has returned */ -// func reconstructTerm(reconstruction Reconstruct, baseTerm AST.Term) Reconstruct { -// if !reconstruction.result { -// return reconstruction -// } - -// // fun: reconstruct with children terms -// if Glob.Is[AST.Fun](baseTerm) { -// termFun := Glob.To[AST.Fun](baseTerm) -// var fun AST.Fun -// // The len(form.GetTypeVars()) first children launched are children for typevars. -// // So the len(form.GetTypeVars()) first children will return -// if reconstruction.terms.Len() > len(termFun.GetTypeVars()) { -// terms := Lib.MkListV(reconstruction.terms.Get( -// len(termFun.GetTypeVars()), -// reconstruction.terms.Len(), -// )...) -// fun = AST.MakerFun( -// termFun.GetID(), -// terms, -// termFun.GetTypeVars(), -// termFun.GetTypeHint(), -// ) -// } else { -// fun = AST.MakerFun( -// termFun.GetID(), -// Lib.NewList[AST.Term](), -// termFun.GetTypeVars(), -// termFun.GetTypeHint(), -// ) -// } -// return Reconstruct{result: true, terms: Lib.MkListV[AST.Term](fun), err: nil} -// } +/** + * This file is the entry point to perform typing of a formula. + * It implements all the rules. +**/ -// return Reconstruct{result: true, terms: Lib.MkListV(baseTerm), err: nil} -// } +package Typing -// /* Utils for reconstructions function */ +import ( + "github.com/GoelandProver/Goeland/AST" +) -// /* Removes all the quantifiers of form of the same type of quant. */ -// func unquantify(form AST.Form, quant AST.Form) AST.Form { -// for reflect.TypeOf(form) == reflect.TypeOf(quant) { -// switch quant.(type) { -// case AST.All: -// form = Glob.To[AST.All](form).GetForm() -// case AST.AllType: -// form = Glob.To[AST.AllType](form).GetForm() -// case AST.Ex: -// form = Glob.To[AST.Ex](form).GetForm() -// } -// } -// return form -// } +func TypeCheck(form AST.Form) bool { + return false +} diff --git a/src/Typing/term_rules.go b/src/Typing/term_rules.go deleted file mode 100644 index ced4119e..00000000 --- a/src/Typing/term_rules.go +++ /dev/null @@ -1,216 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -// import ( -// "fmt" - -// "github.com/GoelandProver/Goeland/AST" -// "github.com/GoelandProver/Goeland/Glob" -// "github.com/GoelandProver/Goeland/Lib" -// ) - -// /** -// * This file contains the rules for typing terms, and also the App rule. -// * The App rule is used for predicates and functions. -// **/ - -// /* Applies the App rule for predicates or functions */ -// func applyAppRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// var index int -// var id AST.Id -// var terms Lib.List[AST.Term] -// var vars []AST.TypeApp - -// if whatIsSet(state.consequence) == formIsSet { -// index = (state.consequence.f).(AST.Pred).GetIndex() -// id = (state.consequence.f).(AST.Pred).GetID() -// terms = (state.consequence.f).(AST.Pred).GetArgs() -// vars = (state.consequence.f).(AST.Pred).GetTypeVars() -// } else { -// id = (state.consequence.t).(AST.Fun).GetID() -// terms = (state.consequence.t).(AST.Fun).GetArgs() -// vars = (state.consequence.t).(AST.Fun).GetTypeVars() -// } - -// root.appliedRule = "App" - -// // Search for the ID in the global context -// typeScheme, err := state.globalContext.getTypeScheme(id, vars, terms) -// if err != nil { -// return Reconstruct{ -// result: false, -// err: err, -// } -// } - -// // Affect new type scheme to the prooftree -// root.typeScheme = typeScheme -// primitives := typeScheme.GetPrimitives() - -// // Type predicate or function -// if whatIsSet(state.consequence) == formIsSet { -// fTyped := AST.MakePred(index, id, terms, vars, typeScheme) -// return reconstructForm(launchChildren( -// createAppChildren(state, vars, terms, primitives), -// root, -// fatherChan, -// ), fTyped) -// } else { -// fTyped := AST.MakerFun(id, terms, vars, typeScheme) -// return reconstructTerm(launchChildren(createAppChildren(state, vars, terms, primitives), root, fatherChan), fTyped) -// } -// } - -// /* Applies the Var rule for a term variable. */ -// func applyVarRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// // Add applied rule to the prooftree -// root.appliedRule = "Var" - -// // Find current variable in the local context -// if _, ok := getTermFromLocalContext(state.localContext, state.consequence.t); !ok { -// return Reconstruct{ -// result: false, -// err: fmt.Errorf("term %s not found in the local context", state.consequence.t.ToString()), -// } -// } - -// // No consequence: next rule is the WF rule. -// children := []Sequent{ -// { -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{}, -// }, -// } - -// return reconstructTerm(launchChildren(children, root, fatherChan), state.consequence.t) -// } - -// /* Utils functions */ - -// /** -// * Takes all the types of the terms and makes a cross product of everything -// **/ -// func getArgsTypes( -// context GlobalContext, -// terms Lib.List[AST.Term], -// ) (AST.TypeApp, error) { -// if terms.Len() == 0 { -// return nil, nil -// } - -// var types []AST.TypeApp - -// for _, term := range terms.GetSlice() { -// switch tmpTerm := term.(type) { -// case AST.Fun: -// typeScheme, err := context.getTypeScheme( -// tmpTerm.GetID(), -// tmpTerm.GetTypeVars(), -// tmpTerm.GetArgs(), -// ) -// if err != nil { -// return nil, err -// } -// if typeScheme == nil { -// return nil, fmt.Errorf("function %s not found in global context", tmpTerm.GetName()) -// } -// types = append(types, AST.GetOutType(typeScheme)) -// case AST.Var: -// // Variables can't be of type TypeScheme, so this line shouldn't fail. -// types = append(types, tmpTerm.GetTypeApp()) -// // There shouldn't be Metas yet. -// case AST.Meta: -// Glob.PrintDebug("GAT", Lib.MkLazy(func() string { return "Found a Meta while typing everything." })) -// // ID is filtered out -// } -// } - -// if len(types) == 1 { -// return types[0], nil -// } -// typeCross := AST.MkTypeCross(types[0], types[1]) -// for i := 2; i < len(types); i += 1 { -// typeCross = AST.MkTypeCross(typeCross, types[i]) -// } -// return typeCross, nil -// } - -// /* Creates children for app rule */ -// func createAppChildren( -// state Sequent, -// vars []AST.TypeApp, -// terms Lib.List[AST.Term], -// primitives []AST.TypeApp, -// ) []Sequent { -// children := []Sequent{} - -// // 1 for each type in the vars -// for _, var_ := range vars { -// children = append(children, Sequent{ -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{a: var_}, -// }) -// } - -// // 1 for each term -// for i, term := range terms.GetSlice() { -// switch t := term.(type) { -// case AST.Fun: -// term = AST.MakerFun(t.GetID(), t.GetArgs(), t.GetTypeVars(), primitives[i].(AST.TypeScheme)) -// case AST.Meta: -// term = AST.MakeMeta(t.GetIndex(), t.GetOccurence(), t.GetName(), t.GetFormula(), primitives[i]) -// case AST.Var: -// term = AST.MakeVar(t.GetIndex(), t.GetName(), primitives[i]) -// } -// children = append(children, Sequent{ -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{t: term}, -// }) -// } - -// return children -// } - -// /* Finds the given term in the local context, returns false if it couldn't */ -// func getTermFromLocalContext(localContext LocalContext, term AST.Term) (AST.Var, bool) { -// for _, var_ := range localContext.vars { -// if var_.Equals(term) { -// return var_, true -// } -// } -// return AST.Var{}, false -// } diff --git a/src/Typing/type.go b/src/Typing/type.go deleted file mode 100644 index 9d64162c..00000000 --- a/src/Typing/type.go +++ /dev/null @@ -1,190 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -// import ( -// "github.com/GoelandProver/Goeland/AST" -// "github.com/GoelandProver/Goeland/Glob" -// "github.com/GoelandProver/Goeland/Lib" -// ) - -// /** -// * This file implements a second pass on the given formula to: -// * - Type the variables -// * - Give a type to the polymorph predicates / functions -// **/ - -// func SecondPass(form AST.Form) AST.Form { -// after := secondPassAux(form, []AST.Var{}, []AST.TypeApp{}) -// return after -// } - -// func secondPassAux(form AST.Form, vars []AST.Var, types []AST.TypeApp) AST.Form { -// switch f := form.(type) { -// case AST.Pred: -// terms := nArySecondPassTerms(f.GetArgs(), vars, types) - -// // Special case: defined predicate. We need to infer types. -// if f.GetID().Equals(AST.Id_eq) { -// return AST.MakePred( -// f.GetIndex(), -// f.GetID(), -// terms, -// []AST.TypeApp{ -// AST.GetOutType( -// Glob.To[AST.TypedTerm, AST.Term](terms.At(0)).GetTypeHint(), -// )}) -// } - -// // Real case: classical predicate, it should be given -// return AST.MakePred(f.GetIndex(), f.GetID(), terms, f.GetTypeVars()) -// case AST.And: -// return AST.MakeAnd(f.GetIndex(), nArySecondPass(f.GetChildFormulas(), vars, types)) -// case AST.Or: -// return AST.MakeOr(f.GetIndex(), nArySecondPass(f.Get, vars, types)) -// case AST.Imp: -// return AST.MakeImp(f.GetIndex(), secondPassAux(f.GetF1(), vars, types), secondPassAux(f.GetF2(), vars, types)) -// case AST.Equ: -// return AST.MakeEqu(f.GetIndex(), secondPassAux(f.GetF1(), vars, types), secondPassAux(f.GetF2(), vars, types)) -// case AST.Not: -// return AST.MakeNot(f.GetIndex(), secondPassAux(f.GetForm(), vars, types)) -// case AST.All: -// return AST.MakeAll(f.GetIndex(), f.GetVarList(), secondPassAux(f.GetForm(), append(vars, f.GetVarList()...), types)) -// case AST.Ex: -// return AST.MakeEx(f.GetIndex(), f.GetVarList(), secondPassAux(f.GetForm(), append(vars, f.GetVarList()...), types)) -// case AST.AllType: -// return AST.MakeAllType(f.GetIndex(), f.GetVarList(), secondPassAux(f.GetForm(), vars, append(types, Glob.ConvertList[AST.TypeVar, AST.TypeApp](f.GetVarList())...))) -// } -// return form -// } - -// func secondPassTerm(term AST.Term, vars []AST.Var, types []AST.TypeApp) AST.Term { -// switch t := term.(type) { -// case AST.Fun: -// terms := nArySecondPassTerms(t.GetArgs(), vars, types) - -// // - It's a function -// outType := func(term AST.Term) AST.TypeApp { -// return AST.GetOutType(Glob.To[AST.TypedTerm](term).GetTypeHint()) -// } - -// termsType := []AST.TypeApp{} -// for _, tm := range terms.GetSlice() { -// termsType = append(termsType, outType(tm)) -// } - -// return AST.MakerFun(t.GetID(), terms, t.GetTypeVars(), -// getTypeOfFunction(t.GetName(), t.GetTypeVars(), termsType)) - -// case AST.Var: -// return t -// } -// return term -// } - -// func nArySecondPass(forms Lib.List[AST.Form], vars []AST.Var, types []AST.TypeApp) Lib.List[AST.Form] { -// res := Lib.NewList[AST.Form]() - -// for _, form := range forms.GetSlice() { -// res.Append(secondPassAux(form, vars, types)) -// } - -// return res -// } - -// func nArySecondPassTerms( -// terms Lib.List[AST.Term], -// vars []AST.Var, -// types []AST.TypeApp, -// ) Lib.List[AST.Term] { -// resTerms := Lib.NewList[AST.Term]() - -// for _, term := range terms.GetSlice() { -// t := secondPassTerm(term, vars, types) - -// if t != nil { -// resTerms.Append(t) -// } -// } - -// return resTerms -// } - -// func getTypeOfFunction(name string, vars []AST.TypeApp, termsType []AST.TypeApp) AST.TypeScheme { -// // Build TypeCross from termsType -// var tt []AST.TypeApp -// if len(termsType) >= 2 { -// tc := AST.MkTypeCross(termsType[0], termsType[1]) -// for i := 2; i < len(termsType); i += 1 { -// tc = AST.MkTypeCross(tc, termsType[i]) -// } -// tt = []AST.TypeApp{tc} -// } else { -// tt = termsType -// } - -// simpleTypeScheme := AST.GetType(name, tt...) -// if simpleTypeScheme != nil { -// if Glob.Is[AST.QuantifiedType](simpleTypeScheme) { -// return Glob.To[AST.QuantifiedType](simpleTypeScheme).Instanciate(vars) -// } -// return simpleTypeScheme -// } - -// typeScheme := AST.GetPolymorphicType(name, len(vars), len(termsType)) - -// if typeScheme != nil { -// // Instantiate type scheme with actual types -// typeScheme = Glob.To[AST.QuantifiedType](typeScheme).Instanciate(vars) -// } else { -// // As only distinct objects are here, it should work with only this. -// // I leave the other condition if others weirderies are found later. -// if len(termsType) == 0 { -// AST.SaveConstant(name, Glob.To[AST.TypeApp](AST.DefaultFunType(0))) -// } -// /* -// else { -// type_ := DefaultFunType(len(termsType)) -// if len(termsType) == 1 { -// SaveTypeScheme(name, GetInputType(type_)[0], GetOutType(type_)) -// } else { -// SaveTypeScheme(name, AST.MkTypeCross(GetInputType(type_)...), GetOutType(type_)) -// } -// } -// */ -// typeScheme = AST.DefaultFunType(0) - -// } - -// return typeScheme -// } diff --git a/src/Typing/type_rules.go b/src/Typing/type_rules.go deleted file mode 100644 index f285ca85..00000000 --- a/src/Typing/type_rules.go +++ /dev/null @@ -1,220 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -// import ( -// "fmt" - -// "github.com/GoelandProver/Goeland/AST" -// "github.com/GoelandProver/Goeland/Glob" -// "github.com/GoelandProver/Goeland/Lib" -// ) - -// /** -// * This file contains the rules for typing terms, and also the App rule. -// * The App rule is used for predicates and functions. -// **/ - -// /* Applies the Var rule for a type variable: erase consequence */ -// func applyLocalTypeVarRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// // Add applied rule to the prooftree -// root.appliedRule = "Var" - -// // Find current variable in the local context -// if _, ok := getTypeFromLocalContext(state.localContext, state.consequence.a.(AST.TypeVar)); !ok { -// return Reconstruct{ -// result: false, -// err: fmt.Errorf("TypeVar %s not found in the local context", state.consequence.a.ToString()), -// } -// } - -// // No consequence: next rule is the WF rule. -// children := []Sequent{ -// { -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{}, -// }, -// } - -// return launchChildren(children, root, fatherChan) -// } - -// /* Applies the Var rule for a type hint: erase consequence */ -// func applyGlobalTypeVarRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// // Add applied rule to the prooftree -// root.appliedRule = "Var" - -// // Find current variable in the local context -// if found := state.globalContext.isTypeInContext(Glob.To[AST.TypeScheme](state.consequence.a)); !found { -// return Reconstruct{ -// result: false, -// err: fmt.Errorf("TypeVar %s not found in the global context", state.consequence.a.ToString()), -// } -// } - -// // No consequence: next rule is the WF rule. -// children := []Sequent{ -// { -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{}, -// }, -// } - -// return launchChildren(children, root, fatherChan) -// } - -// /* Applies Type rule: erase consequence */ -// func applyTypeWFRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// // Add applied rule to the prooftree -// root.appliedRule = "Type" - -// // WF child -// children := []Sequent{ -// { -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{}, -// }, -// } - -// return launchChildren(children, root, fatherChan) -// } - -// /* Applies Cross rule */ -// func applyCrossRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// // Add applied rule to the prooftree -// root.appliedRule = "Cross" - -// if tc, ok := state.consequence.a.(AST.TypeCross); ok { -// // Construct a child for every type recovered -// return launchChildren(constructWithTypes(state, tc.GetAllUnderlyingTypes()), root, fatherChan) -// } else { -// return Reconstruct{ -// result: false, -// err: fmt.Errorf("CrossRule type on something that is not a TypeCross: %s", state.consequence.a.ToString()), -// } -// } -// } - -// /* Sym rule: a child for each type in the input, and one for the output if it's a function */ -// func applySymRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// root.appliedRule = "Sym" - -// primitives := state.consequence.s.GetPrimitives() -// out := AST.GetOutType(state.consequence.s) - -// newLocalContext := state.localContext.copy() -// if qt, found := state.consequence.s.(AST.QuantifiedType); found { -// newLocalContext.typeVars = append(newLocalContext.typeVars, qt.QuantifiedVars()...) -// } - -// children := []Sequent{} -// if Glob.Is[AST.TypeScheme](out) { -// children = append(children, Sequent{ -// globalContext: state.globalContext, -// localContext: newLocalContext, -// consequence: Consequence{a: out}, -// }) -// } - -// for _, type_ := range primitives[:len(primitives)-1] { -// children = append(children, Sequent{ -// globalContext: state.globalContext, -// localContext: newLocalContext, -// consequence: Consequence{a: type_}, -// }) -// } - -// return launchChildren(children, root, fatherChan) -// } - -// /* AppType rule: a child for each type in the input, and checks if the parameterized type exists. */ -// func applyAppTypeRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { -// root.appliedRule = "App" - -// type_ := state.consequence.a.(AST.ParameterizedType) -// types := type_.GetParameters() - -// // Search for the ID in the global context -// if !state.globalContext.parameterizedTypesContains(type_.GetName()) { -// return Reconstruct{ -// result: false, -// err: fmt.Errorf("parameterized Type %s not in context", type_.ToString()), -// } -// } - -// children := []Sequent{} -// for _, type_ := range types { -// children = append(children, Sequent{ -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{a: type_}, -// }) -// } - -// result := launchChildren(children, root, fatherChan) - -// // Only one term needs to be returned because the ParameterizedType is counted as one. -// return Reconstruct{ -// result: result.result, -// err: result.err, -// terms: Lib.NewList[AST.Term](), -// } -// } - -// /* Utils functions */ - -// /* Finds the given term in the local context, returns false if it couldn't */ -// func getTypeFromLocalContext(localContext LocalContext, typeApp AST.TypeVar) (AST.TypeApp, bool) { -// for _, type_ := range localContext.typeVars { -// if typeApp.Equals(type_) { -// return type_, true -// } -// } -// return AST.TypeVar{}, false -// } - -// /* Constructs all the children of a composed type */ -// func constructWithTypes(state Sequent, types []AST.TypeApp) []Sequent { -// children := []Sequent{} -// for _, type_ := range types { -// children = append(children, Sequent{ -// globalContext: state.globalContext, -// localContext: state.localContext.copy(), -// consequence: Consequence{a: type_}, -// }) -// } -// return children -// } diff --git a/src/Unif/matching.go b/src/Unif/matching.go index 83c27c08..4a24fe15 100644 --- a/src/Unif/matching.go +++ b/src/Unif/matching.go @@ -67,8 +67,10 @@ func (m *Machine) unify(node Node, formula AST.Form) []MatchingSubstitutions { switch formula_type := formula.(type) { case AST.Pred: // Transform the predicate to a function to make the tool work properly + // FIXME: transform type arguments into terms to unify them m.terms = Lib.MkListV[AST.Term](AST.MakerFun( formula_type.GetID(), + formula_type.GetTyArgs(), formula_type.GetArgs(), )) result = m.unifyAux(node) diff --git a/src/Unif/substitutions_type.go b/src/Unif/substitutions_type.go index 138bf430..7c43b118 100644 --- a/src/Unif/substitutions_type.go +++ b/src/Unif/substitutions_type.go @@ -213,7 +213,7 @@ func MakeEmptySubstitutionList() []Substitutions { /* Returns a « failed » substitution. */ func Failure() Substitutions { - fail := AST.MakeMeta(-1, -1, "FAILURE", -1) + fail := AST.MakeEmptyMeta() return Substitutions{Substitution{fail, fail}} } @@ -313,6 +313,7 @@ func eliminateInside(key AST.Meta, value AST.Term, s Substitutions, has_changed_ case AST.Fun: new_value := AST.MakerFun( value_2_type.GetP(), + value_2_type.GetTyArgs(), eliminateList(key, value, value_2_type.GetArgs(), &has_changed), ) if OccurCheckValid(key_2, new_value) { @@ -358,6 +359,7 @@ func eliminateList( case AST.Fun: // If its a function, reccursive call for the arguments tempList.Append(AST.MakerFun( lt.GetP(), + lt.GetTyArgs(), eliminateList(key, value, lt.GetArgs(), &hasChanged), )) default: diff --git a/src/main.go b/src/main.go index 99890e9a..fc4c8b93 100644 --- a/src/main.go +++ b/src/main.go @@ -58,7 +58,7 @@ import ( "github.com/GoelandProver/Goeland/Parser" "github.com/GoelandProver/Goeland/Search" "github.com/GoelandProver/Goeland/Search/incremental" - _ "github.com/GoelandProver/Goeland/Typing" + "github.com/GoelandProver/Goeland/Typing" "github.com/GoelandProver/Goeland/Unif" ) @@ -126,7 +126,11 @@ func presearchLoader() (AST.Form, int) { Glob.PrintInfo( "preloader", - fmt.Sprintf("You are running problem %s on Goeland v.%s", path.Base(problem), Glob.GetVersion()), + fmt.Sprintf( + "You are running problem %s on Goeland v.%s", + path.Base(problem), + Glob.GetVersion(), + ), ) debug( Lib.MkLazy(func() string { @@ -135,12 +139,12 @@ func presearchLoader() (AST.Form, int) { ) statements, bound, containsEquality := Parser.ParseTPTPFile(problem) - actualStatements := Engine.ToInternalSyntax(statements) + actual_statements, is_typed_problem := Engine.ToInternalSyntax(statements) debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Statement : %s", Core.StatementListToString(actualStatements)) + "Statement : %s", Core.StatementListToString(actual_statements)) }), ) @@ -148,7 +152,11 @@ func presearchLoader() (AST.Form, int) { bound = Glob.GetLimit() } - form, bound, contEq := StatementListToFormula(actualStatements, bound, path.Dir(problem)) + form, bound, contEq, is_typed_include := StatementListToFormula( + actual_statements, + bound, + path.Dir(problem), + ) containsEquality = containsEquality || contEq if !containsEquality { @@ -160,7 +168,9 @@ func presearchLoader() (AST.Form, int) { Glob.Fatal(main_label, "Problem not found") } - form = checkForTypedProof(form) + if is_typed_problem || is_typed_include { + checkForTypedProof(form) + } return form, bound } @@ -190,6 +200,7 @@ func initEverything() { initOpts() runtime.GOMAXPROCS(Glob.GetCoreLimit()) AST.Init() + Typing.Init() } func initDebuggers() { @@ -205,8 +216,14 @@ func initDebuggers() { Unif.InitDebugger() } -func StatementListToFormula(statements []Core.Statement, old_bound int, problemDir string) (form AST.Form, bound int, containsEquality bool) { +// FIXME: eventually, we would want to add an "interpretation" layer between elab and internal representation that does this +func StatementListToFormula( + statements []Core.Statement, + old_bound int, + problemDir string, +) (form AST.Form, bound int, containsEquality bool, is_typed_problem bool) { and_list := Lib.NewList[AST.Form]() + is_typed_problem = false negated_conjecture := Lib.MkNone[AST.Form]() bound = old_bound @@ -222,22 +239,25 @@ func StatementListToFormula(statements []Core.Statement, old_bound int, problemD file_name := statement.GetName() realname, err := getFile(file_name, problemDir) - debug(Lib.MkLazy(func() string { return fmt.Sprintf("File to parse : %s\n", realname) })) + debug( + Lib.MkLazy(func() string { return fmt.Sprintf("File to parse : %s\n", realname) }), + ) if err != nil { Glob.Fatal(main_label, err.Error()) - return nil, -1, false + return nil, -1, false, false } new_lstm, bound_tmp, contEq := Parser.ParseTPTPFile(realname) - actual_new_lstm := Engine.ToInternalSyntax(new_lstm) + actual_new_lstm, is_typed := Engine.ToInternalSyntax(new_lstm) containsEquality = containsEquality || contEq - new_form_list, new_bound, contEq := StatementListToFormula( + new_form_list, new_bound, contEq, is_typed := StatementListToFormula( actual_new_lstm, bound_tmp, path.Join(problemDir, path.Dir(file_name)), ) containsEquality = containsEquality || contEq + is_typed_problem = is_typed_problem || is_typed if new_form_list != nil { bound = new_bound @@ -279,29 +299,32 @@ func StatementListToFormula(statements []Core.Statement, old_bound int, problemD } default: - Glob.Fatal("main", fmt.Sprintf("Unmanaged statement role: %s", statement.GetRole().ToString())) + Glob.Fatal( + "main", + fmt.Sprintf("Unmanaged statement role: %s", statement.GetRole().ToString()), + ) } } switch conj := negated_conjecture.(type) { case Lib.None[AST.Form]: if and_list.Empty() { - return nil, bound, containsEquality + return nil, bound, containsEquality, is_typed_problem } else { - return AST.MakerAnd(and_list), bound, containsEquality + return AST.MakerAnd(and_list), bound, containsEquality, is_typed_problem } case Lib.Some[AST.Form]: if and_list.Empty() { - return conj.Val, bound, containsEquality + return conj.Val, bound, containsEquality, is_typed_problem } else { flattened := AST.FlattenAnd(and_list) flattened.Append(conj.Val) - return AST.MakerAnd(flattened), bound, containsEquality + return AST.MakerAnd(flattened), bound, containsEquality, is_typed_problem } } Glob.Anomaly(main_label, "reached an unreachable state") - return nil, -1, false + return nil, -1, false, false } func doAxiomStatement(andList Lib.List[AST.Form], f AST.Form) Lib.List[AST.Form] { @@ -331,33 +354,16 @@ func doConjectureStatement(f AST.Form) AST.Form { } func doTypeStatement(atomTyping Core.TFFAtomTyping) { - typeScheme := atomTyping.Ts + typeScheme := atomTyping.Ty if typeScheme == nil { - Glob.PrintWarn("main", fmt.Sprintf("The constant %s has no type!", atomTyping.Literal.ToString())) - return + Glob.PrintWarn( + "main", + fmt.Sprintf("The constant %s has no type!", atomTyping.Literal.ToString()), + ) } - if typeScheme.Size() == 1 { - isNewType := typeScheme.ToString() == "$tType" - if isNewType { - AST.MkTypeHint(atomTyping.Literal.GetName()) - } else { - isConstant := !Glob.Is[AST.QuantifiedType](typeScheme) - if isConstant { - AST.SaveConstant(atomTyping.Literal.GetName(), typeScheme.GetPrimitives()[0]) - } else { - AST.SavePolymorphScheme(atomTyping.Literal.GetName(), typeScheme) - } - } - } else { - switch typeScheme.(type) { - case AST.TypeArrow: - AST.SaveTypeScheme(atomTyping.Literal.GetName(), AST.GetInputType(typeScheme)[0], AST.GetOutType(typeScheme)) - case AST.QuantifiedType: - AST.SavePolymorphScheme(atomTyping.Literal.GetName(), typeScheme) - } - } + Typing.AddToGlobalEnv(atomTyping.Literal.GetName(), atomTyping.Ty) } func getFile(filename string, dir string) (string, error) { @@ -388,18 +394,9 @@ func getFile(filename string, dir string) (string, error) { return "", fmt.Errorf("file %s not found", filename) } -func checkForTypedProof(form AST.Form) AST.Form { - isTypedProof := !AST.EmptyGlobalContext() && !Glob.NoTypeCheck() - - if isTypedProof { - // err := Typing.WellFormedVerification(form.Copy(), Glob.GetTypeProof()) - - // if err != nil { - // Glob.Fatal(main_label, fmt.Sprintf("Typing error: %v", err)) - // } else { - // Glob.PrintInfo(main_label, "Well typed.") - // } +func checkForTypedProof(form AST.Form) { + if !Glob.NoTypeCheck() && !Typing.TypeCheck(form) { + Glob.Fatal(main_label, fmt.Sprintf("Formula %s is not well typed", form.ToString())) } - - return form + Glob.PrintInfo(main_label, "Problem is well typed") } From 28770d483337163dee2bc1402482590a5620f0b4 Mon Sep 17 00:00:00 2001 From: Johann Rosain Date: Wed, 23 Jul 2025 22:32:14 +0200 Subject: [PATCH 3/8] Implementation of the new typing system --- devtools/test-suite/basic/tf1_syntax_chk.p | 4 +- devtools/test-suite/basic/tfa_syntax_chk.p | 2 +- devtools/test-suite/bugs/bug_53-1.p | 33 +++ src/AST/formsDef.go | 72 ++++- src/AST/formula.go | 8 + src/AST/maker.go | 2 +- src/AST/quantifiers.go | 43 ++- src/AST/term.go | 1 + src/AST/termsDef.go | 35 ++- src/AST/tptp-native-types.go | 153 +++-------- src/AST/ty-syntax.go | 96 +++++-- src/AST/typed-vars.go | 6 +- src/Engine/pretyper.go | 113 +++++++- src/Engine/syntax-translation.go | 257 ++++++++++++++---- src/Engine/tptp-defined-types.go | 155 +++++++++++ src/Lib/par.go | 86 ++++++ src/Lib/string.go | 10 +- .../equality/bse/equality_problem_list.go | 13 +- src/Parser/pprinter.go | 34 +-- src/Parser/psyntax.go | 48 +++- src/Typing/env-and-context.go | 15 + src/Typing/init.go | 111 ++++++++ src/Typing/rules.go | 248 +++++++++++++++++ src/Unif/parsing.go | 3 + src/main.go | 1 + 25 files changed, 1305 insertions(+), 244 deletions(-) create mode 100644 devtools/test-suite/bugs/bug_53-1.p create mode 100644 src/Engine/tptp-defined-types.go create mode 100644 src/Lib/par.go diff --git a/devtools/test-suite/basic/tf1_syntax_chk.p b/devtools/test-suite/basic/tf1_syntax_chk.p index ddbabeb5..fbddcf04 100644 --- a/devtools/test-suite/basic/tf1_syntax_chk.p +++ b/devtools/test-suite/basic/tf1_syntax_chk.p @@ -1,5 +1,5 @@ -% TODO: args -one_step and result NOT_VALID once typing is working again (this is satisfiable) -% exit: 3 +% args: -one_step +% result: NOT VALID tff(beverage_type,type, beverage: $tType ). diff --git a/devtools/test-suite/basic/tfa_syntax_chk.p b/devtools/test-suite/basic/tfa_syntax_chk.p index bcf3c0bb..aa731dfc 100644 --- a/devtools/test-suite/basic/tfa_syntax_chk.p +++ b/devtools/test-suite/basic/tfa_syntax_chk.p @@ -1,5 +1,5 @@ % As arithmetic is not handled by Goeland, we simply check that parsing is OK -% args: -ari -one_step -l 1 +% args: -one_step -l 1 % result: NOT VALID tff(p_int_type,type, diff --git a/devtools/test-suite/bugs/bug_53-1.p b/devtools/test-suite/bugs/bug_53-1.p new file mode 100644 index 00000000..942299af --- /dev/null +++ b/devtools/test-suite/bugs/bug_53-1.p @@ -0,0 +1,33 @@ +% args: -one_step +% exit: 1 + +tff(list_type,type, + list: $tType > $tType ). + +tff(maybe_type,type, + maybe: $tType > $tType ). + +%----Polymorphic symbols +tff(nil_type,type, + nil: + !>[A: $tType] : list(A) ). + +tff(cons_type,type, + cons: + !>[A: $tType] : ( ( A * list(A) ) > list(A) ) ). + +tff(none_type,type, + none: + !>[A: $tType] : maybe(A) ). + +tff(some_type,type, + some: + !>[A: $tType] : ( A > maybe(A) ) ). + +tff(head_type,type, + head: + !>[A: $tType] : ( list(A) > maybe(A) ) ). + +%----This cannot be well typed, the last cons is not well formed +tff(solve_this,conjecture, + head($int,cons($int,1,cons($int,2,cons($int,3)))) = some($int,1) ). diff --git a/src/AST/formsDef.go b/src/AST/formsDef.go index bf1922c3..930773a2 100644 --- a/src/AST/formsDef.go +++ b/src/AST/formsDef.go @@ -120,6 +120,10 @@ func (a All) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return All{quant}, isReplaced } +func (a All) ReplaceTyVar(old TyBound, new Ty) Form { + return All{a.quantifier.replaceTyVar(old, new)} +} + func (a All) SubstituteVarByMeta(old Var, new Meta) Form { return All{a.quantifier.substituteVarByMeta(old, new)} } @@ -168,6 +172,10 @@ func (e Ex) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return Ex{quant}, isReplaced } +func (e Ex) ReplaceTyVar(old TyBound, new Ty) Form { + return Ex{e.quantifier.replaceTyVar(old, new)} +} + func (e Ex) SubstituteVarByMeta(old Var, new Meta) Form { return Ex{e.quantifier.substituteVarByMeta(old, new)} } @@ -271,6 +279,11 @@ func (o Or) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return no, res } +func (o Or) ReplaceTyVar(old TyBound, new Ty) Form { + formList := replaceTyVarInFormList(o.forms, old, new) + return MakeOrSimple(o.GetIndex(), formList, o.metas.Raw()) +} + func (o Or) RenameVariables() Form { return MakeOr(o.GetIndex(), renameFormList(o.forms)) } @@ -407,6 +420,11 @@ func (a And) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return na, res } +func (a And) ReplaceTyVar(old TyBound, new Ty) Form { + formList := replaceTyVarInFormList(a.forms, old, new) + return MakeAndSimple(a.GetIndex(), formList, a.metas.Raw()) +} + func (a And) RenameVariables() Form { return MakeAnd(a.GetIndex(), renameFormList(a.forms)) } @@ -518,6 +536,15 @@ func (e Equ) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return ne, res1 || res2 } +func (e Equ) ReplaceTyVar(old TyBound, new Ty) Form { + return MakeEquSimple( + e.GetIndex(), + e.f1.ReplaceTyVar(old, new), + e.f2.ReplaceTyVar(old, new), + e.metas.Raw(), + ) +} + func (e Equ) RenameVariables() Form { return MakeEqu(e.GetIndex(), e.GetF1().RenameVariables(), e.GetF2().RenameVariables()) } @@ -639,6 +666,15 @@ func (i Imp) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return ni, res1 || res2 } +func (i Imp) ReplaceTyVar(old TyBound, new Ty) Form { + return MakeImpSimple( + i.GetIndex(), + i.f1.ReplaceTyVar(old, new), + i.f2.ReplaceTyVar(old, new), + i.metas.Raw(), + ) +} + func (i Imp) RenameVariables() Form { return MakeImp(i.GetIndex(), i.GetF1().RenameVariables(), i.GetF2().RenameVariables()) } @@ -757,6 +793,14 @@ func (n Not) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return nn, res } +func (n Not) ReplaceTyVar(old TyBound, new Ty) Form { + return MakeNotSimple( + n.GetIndex(), + n.f.ReplaceTyVar(old, new), + n.metas.Raw(), + ) +} + func (n Not) RenameVariables() Form { return MakeNot(n.GetIndex(), n.f.RenameVariables()) } @@ -882,11 +926,17 @@ func (p Pred) ToString() string { } func (p Pred) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - if p.GetArgs().Len() == 0 { + if p.tys.Empty() && p.GetArgs().Empty() { return p.GetID().ToMappedString(mapping, displayTypes) + "%s" } args := []string{} + if !p.tys.Empty() { + if tv := Lib.ListToString(p.tys, Lib.WithEmpty(mapping[PredEmpty])); tv != "" { + args = append(args, tv) + } + } + args = append(args, "%s") if p.GetID().GetName() == "=" { @@ -982,6 +1032,24 @@ func (p Pred) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return np, res } +func (p Pred) ReplaceTyVar(old TyBound, new Ty) Form { + typed_args := Lib.ListMap( + p.tys, + func(t Ty) Ty { return t.ReplaceTyVar(old, new) }, + ) + args := Lib.ListMap( + p.args, + func(t Term) Term { return t.ReplaceTyVar(old, new) }, + ) + return MakePredSimple( + p.GetIndex(), + p.GetID(), + typed_args, + args, + p.metas.Raw(), + ) +} + func (p Pred) GetSubTerms() Lib.List[Term] { res := Lib.NewList[Term]() @@ -1073,6 +1141,7 @@ func (t Top) Copy() Form { return MakeTop(t.Get func (Top) Equals(f any) bool { _, isTop := f.(Top); return isTop } func (Top) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } func (t Top) ReplaceTermByTerm(Term, Term) (Form, bool) { return MakeTop(t.GetIndex()), false } +func (t Top) ReplaceTyVar(TyBound, Ty) Form { return t } func (t Top) RenameVariables() Form { return MakeTop(t.GetIndex()) } func (t Top) GetIndex() int { return t.index } func (t Top) GetSubTerms() Lib.List[Term] { return Lib.NewList[Term]() } @@ -1115,6 +1184,7 @@ func (b Bot) Copy() Form { return MakeBot(b.Get func (Bot) Equals(f any) bool { _, isBot := f.(Bot); return isBot } func (Bot) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } func (b Bot) ReplaceTermByTerm(Term, Term) (Form, bool) { return MakeBot(b.GetIndex()), false } +func (b Bot) ReplaceTyVar(TyBound, Ty) Form { return b } func (b Bot) RenameVariables() Form { return MakeBot(b.GetIndex()) } func (b Bot) GetIndex() int { return b.index } func (b Bot) GetSubTerms() Lib.List[Term] { return Lib.NewList[Term]() } diff --git a/src/AST/formula.go b/src/AST/formula.go index 18532b5c..843675c7 100644 --- a/src/AST/formula.go +++ b/src/AST/formula.go @@ -54,6 +54,7 @@ type Form interface { MappableString ReplaceTermByTerm(old Term, new Term) (Form, bool) + ReplaceTyVar(old TyBound, new Ty) Form RenameVariables() Form SubstituteVarByMeta(old Var, new Meta) Form ReplaceMetaByTerm(meta Meta, term Term) Form @@ -135,6 +136,13 @@ func replaceTermInFormList(oldForms Lib.List[Form], oldTerm Term, newTerm Term) return newForms, res } +func replaceTyVarInFormList(oldForms Lib.List[Form], old TyBound, new Ty) Lib.List[Form] { + return Lib.ListMap( + oldForms, + func(f Form) Form { return f.ReplaceTyVar(old, new) }, + ) +} + func renameFormList(forms Lib.List[Form]) Lib.List[Form] { newForms := Lib.MkList[Form](forms.Len()) diff --git a/src/AST/maker.go b/src/AST/maker.go index 3b509884..c67aa8f4 100644 --- a/src/AST/maker.go +++ b/src/AST/maker.go @@ -66,10 +66,10 @@ var EmptyPredEq Pred /* Initialization */ func Init() { Reset() - initTPTPNativeTypes() Id_eq = MakerId("=") EmptyPredEq = MakerPred(Id_eq, Lib.NewList[Ty](), Lib.NewList[Term]()) initDefaultMap() + initTPTPNativeTypes() } /* Reset all the maps and counters */ diff --git a/src/AST/quantifiers.go b/src/AST/quantifiers.go index 75b770dc..4a0db4a5 100644 --- a/src/AST/quantifiers.go +++ b/src/AST/quantifiers.go @@ -106,11 +106,9 @@ func ChangeVarSeparator(sep string) string { func (q quantifier) ToMappedStringSurround(mapping MapString, displayTypes bool) string { varStrings := []string{} - for _ = range q.GetVarList().GetSlice() { - str := mapping[QuantVarOpen] - str += ListToMappedString(q.GetVarList().GetSlice(), varSeparator, "", mapping, false) - varStrings = append(varStrings, str+mapping[QuantVarClose]) - } + str := mapping[QuantVarOpen] + str += ListToMappedString(q.GetVarList().GetSlice(), varSeparator, "", mapping, false) + varStrings = append(varStrings, str+mapping[QuantVarClose]) return "(" + mapping[q.symbol] + " " + strings.Join(varStrings, " ") + mapping[QuantVarSep] + " (%s))" } @@ -162,20 +160,49 @@ func (q quantifier) replaceTermByTerm(old Term, new Term) (quantifier, bool) { ), res } +func (q quantifier) replaceTyVar(old TyBound, new Ty) quantifier { + f := q.GetForm().ReplaceTyVar(old, new) + return makeQuantifier( + q.GetIndex(), + Lib.ListMap( + q.GetVarList(), + func(p TypedVar) TypedVar { return p.ReplaceTyVar(old, new) }, + ), + f, + q.metas.Raw().Copy(), + q.symbol, + ) +} + func (q quantifier) renameVariables() quantifier { newVarList := Lib.NewList[TypedVar]() - newForm := q.GetForm() + newForm := q.GetForm().RenameVariables() + newTyBv := Lib.NewList[Lib.Pair[TyBound, Ty]]() for _, v := range q.GetVarList().GetSlice() { newVar := MakerNewVar(v.GetName()) newVar = MakerVar(fmt.Sprintf("%s%d", newVar.GetName(), newVar.GetIndex())) newVarList.Append(MkTypedVar(newVar.name, newVar.index, v.ty)) - newForm, _ = newForm.RenameVariables().ReplaceTermByTerm(v.ToBoundVar(), newVar) + f, replaced := newForm.ReplaceTermByTerm(v.ToBoundVar(), newVar) + if !replaced { + newBv := MkTyBV(newVar.name, newVar.index) + f = f.ReplaceTyVar(v.ToTyBoundVar(), newBv) + newTyBv.Append(Lib.MkPair(v.ToTyBoundVar(), newBv)) + } + newForm = f } return makeQuantifier( q.GetIndex(), - newVarList, + Lib.ListMap( + newVarList, + func(p TypedVar) TypedVar { + for _, pair := range newTyBv.GetSlice() { + p = p.ReplaceTyVar(pair.Fst, pair.Snd) + } + return p + }, + ), newForm, q.metas.Raw().Copy(), q.symbol, diff --git a/src/AST/term.go b/src/AST/term.go index 23adba38..b14e25d4 100644 --- a/src/AST/term.go +++ b/src/AST/term.go @@ -53,6 +53,7 @@ type Term interface { GetMetaList() Lib.List[Meta] // Metas appearing in the term ORDERED GetSubTerms() Lib.List[Term] ReplaceSubTermBy(original_term, new_term Term) Term + ReplaceTyVar(old TyBound, new Ty) Term Less(any) bool } diff --git a/src/AST/termsDef.go b/src/AST/termsDef.go index 49e2bb6f..27222ae6 100644 --- a/src/AST/termsDef.go +++ b/src/AST/termsDef.go @@ -111,6 +111,8 @@ func (i Id) ReplaceSubTermBy(original_term, new_term Term) Term { return i } +func (i Id) ReplaceTyVar(TyBound, Ty) Term { return i } + func (i Id) GetSubTerms() Lib.List[Term] { return Lib.MkListV[Term](i) } @@ -161,10 +163,17 @@ func (f Fun) ToMappedStringChild(mapping MapString, displayTypes bool) (separato } func (f Fun) ToMappedStringSurroundWithId(idString string, mapping MapString, displayTypes bool) string { - if f.GetArgs().Len() == 0 { + if f.tys.Empty() && f.GetArgs().Empty() { return idString + "%s" } + args := []string{} + if !f.tys.Empty() { + if tv := Lib.ListToString(f.tys, Lib.WithEmpty(mapping[PredEmpty])); tv != "" { + args = append(args, tv) + } + } + args = append(args, "%s") str := idString + "(" + strings.Join(args, mapping[PredTypeVarSep]) + ")" @@ -268,6 +277,23 @@ func (f Fun) ReplaceSubTermBy(oldTerm, newTerm Term) Term { } } +func (f Fun) ReplaceTyVar(old TyBound, new Ty) Term { + typed_args := Lib.ListMap( + f.tys, + func(t Ty) Ty { return t.ReplaceTyVar(old, new) }, + ) + args := Lib.ListMap( + f.args, + func(t Term) Term { return t.ReplaceTyVar(old, new) }, + ) + return MakeFun( + f.GetID(), + typed_args, + args, + f.metas.Raw(), + ) +} + func (f Fun) ReplaceAllSubTerm(oldTerm, newTerm Term) Term { if f.Equals(oldTerm) { return newTerm.Copy() @@ -338,10 +364,9 @@ func (v Var) ReplaceSubTermBy(original_term, new_term Term) Term { return v } +func (v Var) ReplaceTyVar(TyBound, Ty) Term { return v } + func (v Var) ToMappedString(map_ MapString, type_ bool) string { - if type_ { - return fmt.Sprintf("%s_%d", v.GetName(), v.GetIndex()) - } return v.GetName() } @@ -429,6 +454,8 @@ func (m Meta) ReplaceSubTermBy(original_term, new_term Term) Term { return m } +func (m Meta) ReplaceTyVar(TyBound, Ty) Term { return m } + func (m Meta) GetSubTerms() Lib.List[Term] { return Lib.MkListV[Term](m) } diff --git a/src/AST/tptp-native-types.go b/src/AST/tptp-native-types.go index 7bc401e1..3b4b821d 100644 --- a/src/AST/tptp-native-types.go +++ b/src/AST/tptp-native-types.go @@ -38,130 +38,61 @@ package AST -// FIXME: update this file with the new type system +import ( + "github.com/GoelandProver/Goeland/Lib" +) -// var tInt TypeHint -// var tRat TypeHint -// var tReal TypeHint -// var defaultType TypeHint -// var defaultProp TypeHint +var tType Ty -// var intCrossInt TypeApp -// var ratCrossRat TypeApp -// var realCrossReal TypeApp +var tInt Ty +var tRat Ty +var tReal Ty -var tType Ty +var tIndividual Ty +var tProp Ty func initTPTPNativeTypes() { tType = MkTyConst("$tType") - // FIXME: always register the equality type in the context. + + tInt = MkTyConst("$int") + tRat = MkTyConst("$rat") + tReal = MkTyConst("$real") + + tIndividual = MkTyConst("$i") + tProp = MkTyConst("$o") } func TType() Ty { return tType } +func TInt() Ty { + return tInt +} + +func TRat() Ty { + return tRat +} + +func TReal() Ty { + return tReal +} + +func TIndividual() Ty { + return tIndividual +} + +func TProp() Ty { + return tProp +} + func IsTType(ty Ty) bool { return ty.Equals(tType) } -// func InitTPTPArithmetic() { -// // Types -// tInt = MkTypeHint("$int") -// tRat = MkTypeHint("$rat") -// tReal = MkTypeHint("$real") - -// intCrossInt = MkTypeCross(tInt, tInt) -// ratCrossRat = MkTypeCross(tRat, tRat) -// realCrossReal = MkTypeCross(tReal, tReal) - -// // Schemes -// // 1 - Binary predicates -// recordBinaryProp("$less") -// recordBinaryProp("$lesseq") -// recordBinaryProp("$greater") -// recordBinaryProp("$greatereq") - -// // 2 - Binary input arguments -// recordBinaryInArgs("$sum") -// recordBinaryInArgs("$difference") -// recordBinaryInArgs("$product") -// recordBinaryInArgs("$quotient_e") -// recordBinaryInArgs("$quotient_t") -// recordBinaryInArgs("$quotient_f") -// recordBinaryInArgs("$remainder_e") -// recordBinaryInArgs("$remainder_t") -// recordBinaryInArgs("$remainder_f") - -// // 3 - $quotient -// SaveTypeScheme("$quotient", ratCrossRat, tRat) -// SaveTypeScheme("$quotient", realCrossReal, tReal) - -// // 4 - Unary input arguments -// recordUnaryInArgs("$uminus") -// recordUnaryInArgs("$floor") -// recordUnaryInArgs("$ceiling") -// recordUnaryInArgs("$truncate") -// recordUnaryInArgs("$round") - -// // 5 - Unary predicates -// recordUnaryProp("$is_int") -// recordUnaryProp("$is_rat") - -// // 6 - Conversion -// recordConversion("$to_int", tInt) -// recordConversion("$to_rat", tRat) -// recordConversion("$to_real", tReal) -// } - -// func recordBinaryProp(name string) { -// SaveTypeScheme(name, intCrossInt, defaultProp) -// SaveTypeScheme(name, ratCrossRat, defaultProp) -// SaveTypeScheme(name, realCrossReal, defaultProp) -// } - -// func recordBinaryInArgs(name string) { -// SaveTypeScheme(name, intCrossInt, tInt) -// SaveTypeScheme(name, ratCrossRat, tRat) -// SaveTypeScheme(name, realCrossReal, tReal) -// } - -// func recordUnaryInArgs(name string) { -// SaveTypeScheme(name, tInt, tInt) -// SaveTypeScheme(name, tRat, tRat) -// SaveTypeScheme(name, tReal, tReal) -// } - -// func recordUnaryProp(name string) { -// SaveTypeScheme(name, tInt, defaultProp) -// SaveTypeScheme(name, tRat, defaultProp) -// SaveTypeScheme(name, tReal, defaultProp) -// } - -// func recordConversion(name string, out TypeApp) { -// SaveTypeScheme(name, tInt, out) -// SaveTypeScheme(name, tRat, out) -// SaveTypeScheme(name, tReal, out) -// } - -// func IsInt(tType TypeScheme) bool { return tType.Equals(tInt) } -// func IsRat(tType TypeScheme) bool { return tType.Equals(tRat) } -// func IsReal(tType TypeScheme) bool { return tType.Equals(tReal) } -// func DefaultType() TypeApp { return defaultType } -// func DefaultProp() TypeApp { return defaultProp } -// func DefaultFunType(len int) TypeScheme { return defaultAppType(len, defaultType) } -// func DefaultPropType(len int) TypeScheme { return defaultAppType(len, defaultProp) } - -// func defaultAppType(len int, out TypeApp) TypeScheme { -// if len == 0 { -// return Glob.To[TypeScheme](out) -// } else if len == 1 { -// return MkTypeArrow(defaultType, out) -// } else { -// ts := []TypeApp{} -// for i := 0; i < len; i++ { -// ts = append(ts, defaultType) -// } -// return MkTypeArrow(MkTypeCross(ts...), out) -// } -// } +func DefinedTPTPTypes() Lib.List[TyConstr] { + return Lib.ListMap( + Lib.MkListV(tType, tInt, tRat, tReal, tIndividual, tProp), + func(ty Ty) TyConstr { return ty.(TyConstr) }, + ) +} diff --git a/src/AST/ty-syntax.go b/src/AST/ty-syntax.go index fb1a32bb..bb7639b7 100644 --- a/src/AST/ty-syntax.go +++ b/src/AST/ty-syntax.go @@ -48,6 +48,7 @@ type Ty interface { ToString() string Equals(any) bool Copy() Ty + ReplaceTyVar(TyBound, Ty) Ty } // Internal, shouldn't get out so no upper case @@ -65,6 +66,8 @@ func (v tyVar) Equals(oth any) bool { } func (v tyVar) Copy() Ty { return tyVar{v.repr} } +func (v tyVar) ReplaceTyVar(TyBound, Ty) Ty { return v } + type TyBound struct { name string index int @@ -78,7 +81,15 @@ func (b TyBound) Equals(oth any) bool { } return false } -func (b TyBound) Copy() Ty { return TyBound{b.name, b.index} } +func (b TyBound) Copy() Ty { return TyBound{b.name, b.index} } +func (b TyBound) GetName() string { return b.name } + +func (b TyBound) ReplaceTyVar(old TyBound, new Ty) Ty { + if b.Equals(old) { + return new + } + return b +} type TyMeta struct { name string @@ -94,6 +105,8 @@ func (m TyMeta) Equals(oth any) bool { } func (m TyMeta) Copy() Ty { return TyMeta{m.name} } +func (m TyMeta) ReplaceTyVar(TyBound, Ty) Ty { return m } + // Type constructors, e.g., list, option, ... // Include constants, e.g., $i, $o, ... type TyConstr struct { @@ -122,6 +135,21 @@ func (c TyConstr) Copy() Ty { return TyConstr{c.symbol, Lib.ListCpy(c.args)} } +func (c TyConstr) Symbol() string { + return c.symbol +} + +func (c TyConstr) Args() Lib.List[Ty] { + return c.args +} + +func (c TyConstr) ReplaceTyVar(old TyBound, new Ty) Ty { + return TyConstr{ + c.symbol, + Lib.ListMap(c.args, func(t Ty) Ty { return t.ReplaceTyVar(old, new) }), + } +} + type TyProd struct { args Lib.List[Ty] } @@ -147,6 +175,12 @@ func (p TyProd) Copy() Ty { return TyProd{Lib.ListCpy(p.args)} } +func (p TyProd) ReplaceTyVar(old TyBound, new Ty) Ty { + return TyProd{ + Lib.ListMap(p.args, func(t Ty) Ty { return t.ReplaceTyVar(old, new) }), + } +} + type TyFunc struct { in, out Ty } @@ -166,6 +200,10 @@ func (f TyFunc) Copy() Ty { return TyFunc{f.in.Copy(), f.out.Copy()} } +func (f TyFunc) ReplaceTyVar(old TyBound, new Ty) Ty { + return TyFunc{f.in.ReplaceTyVar(old, new), f.out.ReplaceTyVar(old, new)} +} + type TyPi struct { vars Lib.List[string] ty Ty @@ -188,6 +226,10 @@ func (p TyPi) Copy() Ty { return TyPi{p.vars.Copy(func(x string) string { return x }), p.ty.Copy()} } +func (p TyPi) ReplaceTyVar(old TyBound, new Ty) Ty { + return TyPi{p.vars, p.ty.ReplaceTyVar(old, new)} +} + // Makers func MkTyVar(repr string) Ty { @@ -240,29 +282,28 @@ func MakerTyBV(name string) Ty { } func InstantiateTy(ty Ty, instance Lib.List[Ty]) Ty { + fatal := func(expected int) { + Glob.Fatal( + "Ty.Instantiate", + fmt.Sprintf( + "On instantiation of %s: given instance %s does not have the right number of arguments (expected %d)", + ty.ToString(), + Lib.ListToString(instance, Lib.WithEmpty("(empty instance)")), + expected, + ), + ) + } + switch rty := ty.(type) { - case TyFunc: + case TyConstr, TyFunc: if !instance.Empty() { - Glob.Anomaly( - "Ty.Instantiate", - fmt.Sprintf( - "On instantiation of %s: given instance %s has arguments when it shouldn't", - ty.ToString(), - Lib.ListToString(instance, Lib.WithEmpty("(empty instance)")), - ), - ) + fatal(0) } + return ty case TyPi: if instance.Len() != rty.vars.Len() { - Glob.Anomaly( - "Ty.Instantiate", - fmt.Sprintf( - "On instantiation of %s: given instance %s does not have the right number of arguments", - ty.ToString(), - Lib.ListToString(instance, Lib.WithEmpty("(empty instance)")), - ), - ) + fatal(rty.vars.Len()) } instanceMap := make(map[string]Ty) @@ -320,8 +361,12 @@ func instantiateTyRec(ty, source Ty, instance map[string]Ty) Ty { func GetArgsTy(ty Ty) Lib.List[Ty] { switch rty := ty.(type) { + case TyConstr: + return Lib.NewList[Ty]() case TyFunc: switch nty := rty.in.(type) { + case TyBound, TyConstr: + return Lib.MkListV(rty.in) case TyProd: return nty.args } @@ -332,3 +377,18 @@ func GetArgsTy(ty Ty) Lib.List[Ty] { ) return Lib.NewList[Ty]() } + +func GetOutTy(ty Ty) Ty { + switch rty := ty.(type) { + case TyConstr: + return tType + case TyFunc: + return rty.out + } + + Glob.Anomaly( + "Ty.GetOutTy", + fmt.Sprintf("Tried to extract out type of a non-functional type %s", ty.ToString()), + ) + return nil +} diff --git a/src/AST/typed-vars.go b/src/AST/typed-vars.go index f9514fb4..598488f9 100644 --- a/src/AST/typed-vars.go +++ b/src/AST/typed-vars.go @@ -59,7 +59,7 @@ func (v TypedVar) Equals(oth any) bool { } func (v TypedVar) ToString() string { - return fmt.Sprintf("%s_%d : %s", v.name, v.index, v.ty.ToString()) + return fmt.Sprintf("%s : %s", v.name, v.ty.ToString()) } func (v TypedVar) GetName() string { @@ -82,6 +82,10 @@ func (v TypedVar) ToTyBoundVar() TyBound { return MkTyBV(v.name, v.index).(TyBound) } +func (v TypedVar) ReplaceTyVar(old TyBound, new Ty) TypedVar { + return TypedVar{v.name, v.index, v.ty.ReplaceTyVar(old, new)} +} + func MkTypedVar(name string, index int, ty Ty) TypedVar { return TypedVar{name, index, ty} } diff --git a/src/Engine/pretyper.go b/src/Engine/pretyper.go index 1a1b82c6..16386a83 100644 --- a/src/Engine/pretyper.go +++ b/src/Engine/pretyper.go @@ -38,6 +38,7 @@ package Engine import ( "fmt" + "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" @@ -50,10 +51,15 @@ var defaultType = Parser.MkTypeConst("$i").(Parser.PType) func pretype(con Context, terms []Parser.PTerm) []Lib.Pair[Parser.PTerm, Parser.PType] { tys := []Lib.Pair[Parser.PTerm, Parser.PType]{} for _, term := range terms { + debug(Lib.MkLazy(func() string { return fmt.Sprintf("pretyping %s", term.ToString()) })) lookupName := "" + args := []Parser.PTerm{} + defined_type := Lib.MkNone[Parser.PType]() switch t := term.(type) { case Parser.PFun: lookupName = t.Symbol() + args = t.Args() + defined_type = t.DefinedType() case Parser.PVar: lookupName = t.Name() } @@ -62,21 +68,38 @@ func pretype(con Context, terms []Parser.PTerm) []Lib.Pair[Parser.PTerm, Parser. switch ty := lookupInContext(con, lookupName).(type) { case Lib.Some[Parser.PType]: - tys = append(tys, Lib.MkPair(term, ty.Val)) + real_ty := instantiateType(ty.Val, lookupName, args) + debug_low_level(Lib.MkLazy(func() string { + return fmt.Sprintf("Term in context with type %s", real_ty.ToString()) + })) + + tys = append(tys, Lib.MkPair(term, real_ty)) typed = true + case Lib.None[Parser.PType]: + debug_low_level(Lib.MkLazy(func() string { return "Term not in context, is it defined?" })) + switch oty := defined_type.(type) { + case Lib.Some[Parser.PTypeFun]: + debug_low_level(Lib.MkLazy(func() string { + return fmt.Sprintf("%s has defined type %s", lookupName, oty.Val.ToString()) + })) + tys = append(tys, Lib.MkPair(term, Parser.PType(oty.Val))) + typed = true + } } if !typed { + debug_low_level(Lib.MkLazy(func() string { return "Term is not a defined term, assigning default type" })) tys = append(tys, Lib.MkPair(term, defaultType)) } + } return tys } func lookupInContext(con Context, name string) Lib.Option[Parser.PType] { - for _, p := range con { - if p.Fst == name { - return Lib.MkSome(p.Snd) + for i := len(con) - 1; i >= 0; i-- { + if con[i].Fst == name { + return Lib.MkSome(con[i].Snd) } } return Lib.MkNone[Parser.PType]() @@ -86,13 +109,6 @@ func isTyConstr(pty Parser.PType) bool { switch ty := pty.(type) { case Parser.PTypeFun: return ty.Symbol() == "$tType" - case Parser.PTypeBin: - switch ty.Operator() { - case Parser.PTypeMap: - return isTyConstr(ty.Right()) - } - case Parser.PTypeQuant: - return isTyConstr(ty.Ty()) } return false } @@ -151,3 +167,78 @@ func pretypeVars(vars []Lib.Pair[string, Parser.PAtomicType]) Lib.List[AST.Typed } return res } + +func instantiateType(ty Parser.PType, lookupName string, args []Parser.PTerm) Parser.PType { + switch nty := ty.(type) { + case Parser.PTypeVar, Parser.PTypeFun: + if len(args) > 0 { + Glob.Fatal( + elab_label, + fmt.Sprintf("Expected constant, got %s which is a function", lookupName), + ) + } + + return nty + + case Parser.PTypeBin: + if nty.Operator() != Parser.PTypeMap { + Glob.Fatal( + elab_label, + fmt.Sprintf("Expected map type, got %s", nty.ToString()), + ) + } + + return nty.Right() + + case Parser.PTypeQuant: + type_args := map[string]Parser.PType{} + for i, v := range nty.Vars() { + type_args[v.Fst] = parserTermToType(args[i]) + } + return instantiateRec(nty.Ty(), type_args) + } + Glob.Fatal( + elab_label, + fmt.Sprintf("Expected functional type, got %s", ty.ToString()), + ) + return ty +} + +func instantiateRec(ty Parser.PType, instance map[string]Parser.PType) Parser.PType { + switch nty := ty.(type) { + case Parser.PTypeVar: + if val, ok := instance[nty.Name()]; ok { + return val + } + Glob.Fatal( + elab_label, + fmt.Sprintf("Type variable %s not found in the instance", ty.ToString()), + ) + return ty + + case Parser.PTypeFun: + args := []Parser.PAtomicType{} + for _, arg := range nty.Args() { + args = append(args, instantiateRec(arg.(Parser.PType), instance).(Parser.PAtomicType)) + } + + return Parser.MkPTypeFun(nty.Symbol(), args) + + case Parser.PTypeBin: + new_left := instantiateRec(nty.Left(), instance) + new_right := instantiateRec(nty.Right(), instance) + switch nty.Operator() { + case Parser.PTypeProd: + return Parser.MkTypeProd(new_left, new_right) + + case Parser.PTypeMap: + return new_right + } + } + + Glob.Anomaly( + elab_label, + fmt.Sprintf("Unexpected type on instantiation: %s", ty.ToString()), + ) + return ty +} diff --git a/src/Engine/syntax-translation.go b/src/Engine/syntax-translation.go index 92b258d8..404aab97 100644 --- a/src/Engine/syntax-translation.go +++ b/src/Engine/syntax-translation.go @@ -47,14 +47,20 @@ import ( "github.com/GoelandProver/Goeland/Typing" ) -type Context []Lib.Pair[string, Parser.PType] - var elab_label string = "Elab" var parsing_label string = "Parsing" +var debug Glob.Debugger +var debug_low_level Glob.Debugger + +func InitDebugger() { + debug = Glob.CreateDebugger("elab") + debug_low_level = Glob.CreateDebugger("elab-low") +} + func ToInternalSyntax(parser_statements []Parser.PStatement) (statements []Core.Statement, is_typed bool) { is_typed = false - con := Context{} + con := initialContext() for _, statement := range parser_statements { new_con, stmt, is_typed_stmt := elaborateParsingStatement(con, statement) statements = append(statements, stmt) @@ -74,18 +80,28 @@ func elaborateParsingStatement( switch f := statement.Form().(type) { case Lib.Some[Parser.PForm]: - form, is_typed_form := elaborateParsingForm(con, f.Val) + debug(Lib.MkLazy(func() string { return fmt.Sprintf("Elaborating formula %s", f.Val.ToString()) })) + + new_con, form, is_typed_form := elaborateParsingForm(con, f.Val) core_statement = Core.MakeFormStatement( statement.Name(), statement_role, form, ) is_typed = is_typed || is_typed_form + con = new_con case Lib.None[Parser.PForm]: switch ty := statement.TypedConst().(type) { case Lib.Some[Lib.Pair[string, Parser.PType]]: + debug(Lib.MkLazy(func() string { + return fmt.Sprintf( + "Elaborating type statement %s: %s", + ty.Val.Fst, + ty.Val.Snd.ToString()) + })) + con = append(con, ty.Val) core_statement = Core.MakeTypingStatement( statement.Name(), @@ -130,13 +146,13 @@ func elaborateRole(parsing_role Parser.PFormulaRole, stmt Parser.PStatement) Cor return Core.Unknown } -func elaborateParsingForm(con Context, f Parser.PForm) (AST.Form, bool) { +func elaborateParsingForm(con Context, f Parser.PForm) (Context, AST.Form, bool) { return elaborateForm(con, f, f) } // The [source_form] argument is here for error printing purposes. -func elaborateForm(con Context, f, source_form Parser.PForm) (AST.Form, bool) { - aux := func(t Parser.PTerm) (AST.Term, bool) { +func elaborateForm(con Context, f, source_form Parser.PForm) (Context, AST.Form, bool) { + aux := func(con Context, t Parser.PTerm) (Context, AST.Term, bool) { return elaborateParsingTerm(con, t) } @@ -145,24 +161,34 @@ func elaborateForm(con Context, f, source_form Parser.PForm) (AST.Form, bool) { case Parser.PConst: switch pform.PConstant { case Parser.PTop: - return AST.MakerTop(), false + return con, AST.MakerTop(), false case Parser.PBot: - return AST.MakerBot(), false + return con, AST.MakerBot(), false } case Parser.PPred: typed_arguments := pretype(con, pform.Args()) typed_args, term_args := splitTypes(typed_arguments) - args := Lib.MkList[AST.Term](term_args.Len()) is_typed := false + args := Lib.MkList[AST.Term](term_args.Len()) for i, trm := range term_args.GetSlice() { - arg, b := aux(trm) + new_con, arg, b := aux(con, trm) + con = new_con is_typed = is_typed || b args.Upd(i, arg) } - return AST.MakerPred( + // Special cases: defined types get elaborated to manage ad-hoc polymorphism + if isDefined(pform.Symbol()) { + tys := Lib.ListMap(Lib.MkListV(typed_arguments[typed_args.Len():]...), + func(p Lib.Pair[Parser.PTerm, Parser.PType]) Parser.PType { return p.Snd }) + typed_args = elaborateDefinedFunctionals(con, pform.Symbol(), tys, args) + } else { + is_typed = !typed_args.Empty() + } + + return con, AST.MakerPred( AST.MakerId(pform.Symbol()), Lib.ListMap( typed_args, @@ -170,13 +196,13 @@ func elaborateForm(con Context, f, source_form Parser.PForm) (AST.Form, bool) { return elaborateType(pty, pty, false) }), args, - ), is_typed || !typed_args.Empty() + ), is_typed case Parser.PUnary: switch pform.PUnaryOp { case Parser.PUnaryNeg: - nf, b := elaborateForm(con, pform.PForm, source_form) - return AST.MakerNot(nf), b + new_con, nf, b := elaborateForm(con, pform.PForm, source_form) + return new_con, AST.MakerNot(nf), b } case Parser.PBin: @@ -186,13 +212,13 @@ func elaborateForm(con Context, f, source_form Parser.PForm) (AST.Form, bool) { case Parser.PBinaryAnd: return maybeFlattenAnd(con, pform, source_form) case Parser.PBinaryImp: - lft, b1 := elaborateForm(con, pform.Left(), source_form) - rgt, b2 := elaborateForm(con, pform.Right(), source_form) - return AST.MakerImp(lft, rgt), b1 || b2 + con1, lft, b1 := elaborateForm(con, pform.Left(), source_form) + new_con, rgt, b2 := elaborateForm(con1, pform.Right(), source_form) + return new_con, AST.MakerImp(lft, rgt), b1 || b2 case Parser.PBinaryEqu: - lft, b1 := elaborateForm(con, pform.Left(), source_form) - rgt, b2 := elaborateForm(con, pform.Right(), source_form) - return AST.MakerEqu(lft, rgt), b1 || b2 + con1, lft, b1 := elaborateForm(con, pform.Left(), source_form) + new_con, rgt, b2 := elaborateForm(con1, pform.Right(), source_form) + return new_con, AST.MakerEqu(lft, rgt), b1 || b2 } case Parser.PQuant: @@ -205,11 +231,12 @@ func elaborateForm(con Context, f, source_form Parser.PForm) (AST.Form, bool) { return Lib.MkPair(p.Fst, p.Snd.(Parser.PType)) }, ) - form, b := elaborateForm(append(con, actualVars.GetSlice()...), pform.PForm, source_form) + new_con, form, b := elaborateForm(append(con, actualVars.GetSlice()...), pform.PForm, source_form) if !vars.Empty() { form = AST.MakerAll(vars, form) } - return form, b + return new_con, form, b + case Parser.PQuantEx: if vars.Any(func(v AST.TypedVar) bool { return AST.IsTType(v.GetTy()) }) { Glob.Anomaly( @@ -223,21 +250,21 @@ func elaborateForm(con Context, f, source_form Parser.PForm) (AST.Form, bool) { return Lib.MkPair(p.Fst, p.Snd.(Parser.PType)) }, ) - form, b := elaborateForm(append(con, actualVars.GetSlice()...), pform.PForm, source_form) + new_con, form, b := elaborateForm(append(con, actualVars.GetSlice()...), pform.PForm, source_form) if !vars.Empty() { form = AST.MakerEx(vars, form) } - return form, b + return new_con, form, b } } Glob.Anomaly( elab_label, "Parsed formula "+source_form.ToString()+" does not correspond to any internal formula", ) - return nil, false + return con, nil, false } -func maybeFlattenOr(con Context, f Parser.PBin, source_form Parser.PForm) (AST.Form, bool) { +func maybeFlattenOr(con Context, f Parser.PBin, source_form Parser.PForm) (Context, AST.Form, bool) { return maybeFlattenBin( con, f, source_form, func(ls Lib.List[AST.Form]) AST.Form { return AST.MakerOr(ls) }, @@ -245,7 +272,7 @@ func maybeFlattenOr(con Context, f Parser.PBin, source_form Parser.PForm) (AST.F ) } -func maybeFlattenAnd(con Context, f Parser.PBin, source_form Parser.PForm) (AST.Form, bool) { +func maybeFlattenAnd(con Context, f Parser.PBin, source_form Parser.PForm) (Context, AST.Form, bool) { return maybeFlattenBin( con, f, source_form, func(ls Lib.List[AST.Form]) AST.Form { return AST.MakerAnd(ls) }, @@ -259,22 +286,23 @@ func maybeFlattenBin( source_form Parser.PForm, maker Lib.Func[Lib.List[AST.Form], AST.Form], op Parser.PBinOp, -) (AST.Form, bool) { +) (Context, AST.Form, bool) { if !Glob.Flatten() { - lft, b1 := elaborateForm(con, f.Left(), source_form) - rgt, b2 := elaborateForm(con, f.Right(), source_form) - return maker(Lib.MkListV(lft, rgt)), b1 || b2 + con1, lft, b1 := elaborateForm(con, f.Left(), source_form) + new_con, rgt, b2 := elaborateForm(con1, f.Right(), source_form) + return new_con, maker(Lib.MkListV(lft, rgt)), b1 || b2 } subforms := flatten(f, op) is_typed := false real_subforms := Lib.MkList[AST.Form](subforms.Len()) for i, subform := range subforms.GetSlice() { - real_subform, b := elaborateForm(con, subform, source_form) + new_con, real_subform, b := elaborateForm(con, subform, source_form) + con = new_con real_subforms.Upd(i, real_subform) is_typed = is_typed || b } - return maker(real_subforms), is_typed + return con, maker(real_subforms), is_typed } func flatten(f Parser.PForm, op Parser.PBinOp) Lib.List[Parser.PForm] { @@ -289,36 +317,46 @@ func flatten(f Parser.PForm, op Parser.PBinOp) Lib.List[Parser.PForm] { return Lib.MkListV(f) } -func elaborateParsingTerm(con Context, t Parser.PTerm) (AST.Term, bool) { +func elaborateParsingTerm(con Context, t Parser.PTerm) (Context, AST.Term, bool) { return elaborateTerm(con, t, t) } // The argument [source_term] is here for error printing purposes. -func elaborateTerm(con Context, t, source_term Parser.PTerm) (AST.Term, bool) { - aux := func(t Parser.PTerm) (AST.Term, bool) { +func elaborateTerm(con Context, t, source_term Parser.PTerm) (Context, AST.Term, bool) { + aux := func(con Context, t Parser.PTerm) (Context, AST.Term, bool) { return elaborateTerm(con, t, source_term) } switch pterm := t.(type) { case Parser.PVar: - return AST.MakerVar(pterm.Name()), false + return con, AST.MakerVar(pterm.Name()), false case Parser.PFun: typed_arguments := pretype(con, pterm.Args()) - ty_args, trm_args := splitTypes(typed_arguments) - args := Lib.MkList[AST.Term](trm_args.Len()) + typed_args, term_args := splitTypes(typed_arguments) is_typed := false - for i, trm := range trm_args.GetSlice() { - arg, b := aux(trm) + args := Lib.MkList[AST.Term](term_args.Len()) + for i, trm := range term_args.GetSlice() { + new_con, arg, b := aux(con, trm) + con = new_con is_typed = is_typed || b args.Upd(i, arg) } + // Special cases: defined types get elaborated to manage ad-hoc polymorphism + if isDefined(pterm.Symbol()) { + tys := Lib.ListMap(Lib.MkListV(typed_arguments[typed_args.Len():]...), + func(p Lib.Pair[Parser.PTerm, Parser.PType]) Parser.PType { return p.Snd }) + typed_args = elaborateDefinedFunctionals(con, pterm.Symbol(), tys, args) + } else { + is_typed = !typed_args.Empty() + } + fun := AST.MakerFun( AST.MakerId(pterm.Symbol()), Lib.ListMap( - ty_args, + typed_args, func(pty Parser.PType) AST.Ty { return elaborateType(pty, pty, false) }), @@ -326,17 +364,22 @@ func elaborateTerm(con Context, t, source_term Parser.PTerm) (AST.Term, bool) { ) switch oty := pterm.DefinedType().(type) { case Lib.Some[Parser.PTypeFun]: + debug(Lib.MkLazy(func() string { return fmt.Sprintf("%s is a defined function", pterm.Symbol()) })) + debug_low_level(Lib.MkLazy(func() string { + return fmt.Sprintf("%s has defined type %s", pterm.Symbol(), oty.Val.ToString()) + })) + con = append(con, Lib.MkPair(pterm.Symbol(), Parser.PType(oty.Val))) ty := elaborateType(oty.Val, oty.Val, false) Typing.AddToGlobalEnv(pterm.Symbol(), ty) } - return fun, is_typed || !ty_args.Empty() + return con, fun, is_typed || !typed_args.Empty() } Glob.Anomaly( elab_label, "Parsed term "+source_term.ToString()+" does not correspond to any internal term", ) - return nil, false + return con, nil, false } func elaborateParsingType(pty Lib.Pair[string, Parser.PType]) Core.TFFAtomTyping { @@ -369,14 +412,25 @@ func elaborateType(pty, source_type Parser.PType, from_top_level bool) AST.Ty { case Parser.PTypeBin: fail_if_forbidden := func(ty Parser.PType) { - Glob.Fatal( - parsing_label, - fmt.Sprintf( - "Non-atomic type (%s) found under the type %s", - ty.ToString(), - source_type.ToString(), - ), - ) + fatal := func() { + Glob.Fatal( + parsing_label, + fmt.Sprintf( + "Non-atomic type (%s) found under the type %s", + ty.ToString(), + source_type.ToString(), + ), + ) + } + + switch nty := ty.(type) { + case Parser.PTypeBin: + if nty.Operator() == Parser.PTypeMap { + fatal() + } + case Parser.PTypeQuant: + fatal() + } } fail_if_forbidden(ty.Left()) @@ -436,3 +490,100 @@ func flattenProd(ty AST.Ty) []AST.Ty { } return []AST.Ty{ty} } + +func elaborateDefinedFunctionals( + con Context, + name string, + ty_arguments Lib.List[Parser.PType], + arguments Lib.List[AST.Term], +) Lib.List[Parser.PType] { + debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Elaborating defined functional %s(%s)", name, Lib.ListToString(arguments)) + })) + + // Invariant: call from isDefined, defined_length should be defined as well + if arguments.Len() != defined_length[name] { + Glob.Fatal( + elab_label, + fmt.Sprintf("%s expects %d arguments, got %d", name, defined_length[name], arguments.Len()), + ) + } + + ty_args := Lib.NewList[Parser.PType]() + tys := Lib.NewList[Parser.PType]() + for i, arg := range arguments.GetSlice() { + var ty Lib.Option[Parser.PType] + ty_args := Lib.NewList[Parser.PTerm]() + switch term := arg.(type) { + case AST.Fun: + ty = lookupInContext(con, term.GetName()) + for _, ty := range term.GetTyArgs().GetSlice() { + switch t := ty.(type) { + case AST.TyConstr: + ty_args.Append(Parser.MkFunConst(t.Symbol())) + case AST.TyBound: + ty_args.Append(Parser.MkVar(t.GetName())) + default: + Glob.Anomaly(elab_label, "Found non-constant type parameter in defined type") + } + } + case AST.Var: + ty = lookupInContext(con, term.GetName()) + default: + Glob.Anomaly(elab_label, "Parsed argument is neither a function nor a variable") + } + + switch rty := ty.(type) { + case Lib.Some[Parser.PType]: + tys.Append(instantiateType(rty.Val, arg.GetName(), ty_args.GetSlice())) + case Lib.None[Parser.PType]: + // This is not a defined, let's use the inferred type + tys.Append(ty_arguments.At(i)) + } + } + + // Take the first allowed argument and hope for the best (leave the rest for the typechecker) + elab_ty := Lib.MkNone[Parser.PType]() + for _, ty := range tys.GetSlice() { + if isAllowed(name, ty) { + elab_ty = Lib.MkSome(ty) + break + } + } + + switch ety := elab_ty.(type) { + case Lib.Some[Parser.PType]: + ty_args.Append(ety.Val) + case Lib.None[Parser.PType]: + switch allowed := allowed_elab[name].(type) { + case Lib.Some[Lib.List[Parser.PType]]: + Glob.Fatal( + elab_label, + fmt.Sprintf( + "%s expects arguments in {%s}, but found none with the right type", + name, Lib.ListToString(allowed.Val), + )) + case Lib.None[Lib.List[Parser.PType]]: + Glob.Anomaly( + elab_label, + fmt.Sprintf("allowed_elab[%s] is None but term is not allowed", name), + ) + } + } + + // Special case: quotient of two integers + if name == "$quotient" { + if tys.At(0).Equals(Parser.MkTypeConst("$int")) { + ty_args.Append(Parser.MkTypeConst("$rat").(Parser.PType)) + } else { + ty_args.Append(ty_args.At(0)) + } + } + + debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Defined functional elaborated to %s(%s ; %s)", + name, Lib.ListToString(ty_args), Lib.ListToString(arguments)) + })) + + return ty_args +} diff --git a/src/Engine/tptp-defined-types.go b/src/Engine/tptp-defined-types.go new file mode 100644 index 00000000..8ddc3e90 --- /dev/null +++ b/src/Engine/tptp-defined-types.go @@ -0,0 +1,155 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** + * This file returns an initial context (one augmented with TPTP defined types) +**/ + +package Engine + +import ( + "fmt" + "github.com/GoelandProver/Goeland/Lib" + "github.com/GoelandProver/Goeland/Parser" +) + +type Context []Lib.Pair[string, Parser.PType] + +var defined Lib.Set[Lib.String] +var defined_length map[string]int +var allowed_elab map[string]Lib.Option[Lib.List[Parser.PType]] // None: no restriction + +func initialContext() Context { + defined = Lib.EmptySet[Lib.String]() + defined_length = make(map[string]int) + allowed_elab = make(map[string]Lib.Option[Lib.List[Parser.PType]]) + + tType := Parser.MkTypeConst("$tType").(Parser.PType) + tInt := Parser.MkTypeConst("$int").(Parser.PType) + tRat := Parser.MkTypeConst("$rat").(Parser.PType) + tReal := Parser.MkTypeConst("$real").(Parser.PType) + tProp := Parser.MkTypeConst("$o").(Parser.PType) + + con := []Lib.Pair[string, Parser.PType]{ + Lib.MkPair("$tType", tType), + Lib.MkPair("$int", tType), + Lib.MkPair("$rat", tType), + Lib.MkPair("$real", tType), + Lib.MkPair("$i", tType), + Lib.MkPair("$o", tType), + } + + mkDefined := func(name string, length int, allowed Lib.Option[Lib.List[Parser.PType]], ty Parser.PType) { + defined = defined.Add(Lib.MkString(name)) + defined_length[name] = length + allowed_elab[name] = allowed + con = append(con, Lib.MkPair(name, ty)) + } + + tNumber := Parser.MkPTypeVar("number") + binPoly := func(out Parser.PType) Parser.PType { + return Parser.MkTypeAll( + []Lib.Pair[string, Parser.PAtomicType]{Lib.MkPair("number", tType.(Parser.PAtomicType))}, + Parser.MkTypeMap( + Parser.MkTypeProd(tNumber, tNumber), + out, + ), + ) + } + unPoly := func(out Parser.PType) Parser.PType { + return Parser.MkTypeAll( + []Lib.Pair[string, Parser.PAtomicType]{Lib.MkPair("number", tType.(Parser.PAtomicType))}, + Parser.MkTypeMap(tNumber, out), + ) + } + + mkDefined("$less", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tProp)) + mkDefined("$lesseq", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tProp)) + mkDefined("$greater", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tProp)) + mkDefined("$greatereq", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tProp)) + + mkDefined("$sum", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$difference", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$product", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$quotient_e", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$quotient_t", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$quotient_f", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$remainder_e", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$remainder_t", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$remainder_f", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$quotient", 2, Lib.MkSome(Lib.MkListV(tRat, tReal)), Parser.MkTypeAll( + []Lib.Pair[string, Parser.PAtomicType]{ + Lib.MkPair("number", tType.(Parser.PAtomicType)), + Lib.MkPair("rat_or_real", tType.(Parser.PAtomicType)), + }, + Parser.MkTypeMap( + Parser.MkTypeProd(tNumber, tNumber), + Parser.MkPTypeVar("rat_or_real"), + ))) + + mkDefined("$uminus", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tNumber)) + mkDefined("$floor", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tNumber)) + mkDefined("$ceiling", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tNumber)) + mkDefined("$truncate", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tNumber)) + mkDefined("$round", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tNumber)) + + mkDefined("$is_int", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tProp)) + mkDefined("$is_rat", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tProp)) + + mkDefined("$to_int", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tInt)) + mkDefined("$to_rat", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tRat)) + mkDefined("$to_real", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tReal)) + + mkDefined(Parser.PEqSymbol, 2, Lib.MkNone[Parser.PType](), binPoly(tProp)) + + debug_low_level(Lib.MkLazy(func() string { + str := "Defined symbols:" + for _, s := range defined.Elements().GetSlice() { + str += fmt.Sprintf("\n- %s with %d arguments", s, defined_length[string(s)]) + } + return str + })) + + return con +} + +func isDefined(name string) bool { + return defined.Contains(Lib.MkString(name)) +} + +func isAllowed(name string, ty Parser.PType) bool { + switch allowed := allowed_elab[name].(type) { + case Lib.Some[Lib.List[Parser.PType]]: + return Lib.ListMem(ty, allowed.Val) + } + return true +} diff --git a/src/Lib/par.go b/src/Lib/par.go new file mode 100644 index 00000000..21e1b5df --- /dev/null +++ b/src/Lib/par.go @@ -0,0 +1,86 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** + * This file provides a generic interface to launch goroutines on functions, + * collect their result and compute a final value. + * The computation of the final value is done incrementally at the answer of each child, + * consequently, the function taking care of reconciliating the output of two children + * should be associative, commutative, and have a neutral. + **/ + +package Lib + +import ( + "fmt" + "reflect" +) + +func GenericParallel[T any]( + calls []func(chan T), + reconciliation func(T, T) T, + neutral T, +) (T, error) { + channels := make([](chan T), len(calls)) + for i, call := range calls { + call_chan := make(chan T) + channels[i] = call_chan + go call(call_chan) + } + return genericSelect(channels, reconciliation, neutral) +} + +func genericSelect[T any]( + channels [](chan T), + reconciliation func(T, T) T, + neutral T, +) (T, error) { + remaining := len(channels) + res := neutral + cases := make([]reflect.SelectCase, len(channels)) + for i, channel := range channels { + cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(channel)} + } + + for remaining > 0 { + _, value, _ := reflect.Select(cases) + remaining-- + + if v, ok := value.Interface().(T); ok { + res = reconciliation(res, v) + } else { + return neutral, fmt.Errorf("Error in Lib.Par: channel has not answered a value of the right type.") + } + } + + return res, nil +} diff --git a/src/Lib/string.go b/src/Lib/string.go index c84d5674..05c00449 100644 --- a/src/Lib/string.go +++ b/src/Lib/string.go @@ -37,24 +37,22 @@ package Lib -type String struct { - value string -} +type String string func (s String) Equals(oth any) bool { if str, ok := oth.(String); ok { - return s.value == str.value + return s == str } return false } func (s String) Less(oth any) bool { if str, ok := oth.(String); ok { - return s.value < str.value + return s < str } return false } func MkString(s string) String { - return String{s} + return String(s) } diff --git a/src/Mods/equality/bse/equality_problem_list.go b/src/Mods/equality/bse/equality_problem_list.go index a6b6479d..4491dff3 100644 --- a/src/Mods/equality/bse/equality_problem_list.go +++ b/src/Mods/equality/bse/equality_problem_list.go @@ -45,7 +45,6 @@ import ( "strings" "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Typing" "github.com/GoelandProver/Goeland/Unif" @@ -210,17 +209,15 @@ func buildEqualityProblemMultiListFromPredList(pred AST.Pred, tn Unif.DataStruct predId := pred.GetID() metas := Lib.NewList[AST.Meta]() - var ty AST.Ty + tys := Lib.NewList[AST.Ty]() switch rty := Typing.QueryEnvInstance(predId.GetName(), pred.GetTyArgs()).(type) { case Lib.Some[AST.Ty]: - ty = rty.Val + tys = AST.GetArgsTy(rty.Val) case Lib.None[AST.Ty]: - Glob.Anomaly( - "Equality.Build", - fmt.Sprintf("Type of predicate %s not found", pred.ToString()), - ) + for range pred.GetArgs().GetSlice() { + tys.Append(AST.TIndividual()) + } } - tys := AST.GetArgsTy(ty) for i, arg := range pred.GetArgs().GetSlice() { metas = Lib.ListAdd(metas, AST.MakerMeta("METAEQ_"+arg.ToString(), -1, tys.At(i))) diff --git a/src/Parser/pprinter.go b/src/Parser/pprinter.go index 1128f6dd..24340809 100644 --- a/src/Parser/pprinter.go +++ b/src/Parser/pprinter.go @@ -40,27 +40,27 @@ import ( ) func (t PVar) ToString() string { - return fmt.Sprintf("Var{%s}", t.name) + return fmt.Sprintf("Var(%s)", t.name) } func (f PFun) ToString() string { args := Lib.MkListV(f.arguments...) - return fmt.Sprintf("Fun{%s, %s}", f.symbol, args.ToString(PTerm.ToString)) + return fmt.Sprintf("%s(%s)", f.symbol, args.ToString(PTerm.ToString, Lib.WithEmpty(""))) } func (c PConst) ToString() string { switch c.PConstant { case PTop: - return "Const{$true}" + return "$true" case PBot: - return "Const{$false}" + return "$false" } - return "Const{$unknown}" + return "Const{unknown}" } func (p PPred) ToString() string { args := Lib.MkListV(p.arguments...) - return fmt.Sprintf("Pred{%s, %s}", p.symbol, args.ToString(PTerm.ToString)) + return fmt.Sprintf("%s(%s)", p.symbol, args.ToString(PTerm.ToString, Lib.WithEmpty(""))) } func (u PUnary) ToString() string { @@ -69,37 +69,37 @@ func (u PUnary) ToString() string { case PUnaryNeg: prefix = "Neg" } - return fmt.Sprintf("%s{%s}", prefix, u.PForm.ToString()) + return fmt.Sprintf("%s(%s)", prefix, u.PForm.ToString()) } func (b PBin) ToString() string { - prefix := "" + infix := "" switch b.operator { case PBinaryAnd: - prefix = "And" + infix = "&" case PBinaryOr: - prefix = "Or" + infix = "|" case PBinaryImp: - prefix = "Imp" + infix = "=>" case PBinaryEqu: - prefix = "Equ" + infix = "<=>" } - return fmt.Sprintf("%s{%s, %s}", prefix, b.left.ToString(), b.right.ToString()) + return fmt.Sprintf("(%s) %s (%s)", b.left.ToString(), infix, b.right.ToString()) } func (q PQuant) ToString() string { prefix := "" switch q.PQuantifier { case PQuantAll: - prefix = "All" + prefix = "!" case PQuantEx: - prefix = "Ex" + prefix = "?" } vars := Lib.MkListV(q.vars...) pairStr := func(p Lib.Pair[string, PAtomicType]) string { return "(" + p.Fst + ": " + p.Snd.(PType).ToString() + ")" } - return fmt.Sprintf("%s{%s, %s}", prefix, vars.ToString(pairStr, Lib.WithEmpty("")), q.PForm.ToString()) + return fmt.Sprintf("%s [%s]: (%s)", prefix, vars.ToString(pairStr, Lib.WithEmpty("")), q.PForm.ToString()) } func (v PTypeVar) ToString() string { @@ -140,7 +140,7 @@ func (q PTypeQuant) ToString() string { pairStr := func(p Lib.Pair[string, PAtomicType]) string { return "(" + p.Fst + ": " + p.Snd.(PType).ToString() + ")" } - return fmt.Sprintf("%s[%s]: (%s)", prefix, vars.ToString(pairStr, Lib.WithEmpty("")), q.t.ToString()) + return fmt.Sprintf("%s [%s]: (%s)", prefix, vars.ToString(pairStr, Lib.WithEmpty("")), q.t.ToString()) } func (stmt PStatement) ToString() string { diff --git a/src/Parser/psyntax.go b/src/Parser/psyntax.go index 8fd2dde8..24c4bf1c 100644 --- a/src/Parser/psyntax.go +++ b/src/Parser/psyntax.go @@ -51,6 +51,7 @@ type PAtomicType interface { type PType interface { isPType() ToString() string + Equals(any) bool } type PTypeVar struct { @@ -59,6 +60,12 @@ type PTypeVar struct { func MkPTypeVar(name string) PType { return PTypeVar{name} } func (v PTypeVar) Name() string { return v.name } +func (v PTypeVar) Equals(other any) bool { + if oth, ok := other.(PTypeVar); ok { + return oth.name == v.name + } + return false +} type PTypeFun struct { symbol string @@ -69,7 +76,20 @@ func MkPTypeFun(symbol string, args []PAtomicType) PType { return PTypeFun{symbo func (f PTypeFun) Symbol() string { return f.symbol } func (f PTypeFun) Args() []PAtomicType { return f.arguments } - +func (f PTypeFun) Equals(other any) bool { + if oth, ok := other.(PTypeFun); ok { + if len(f.arguments) != len(oth.arguments) { + return false + } + for i := range f.arguments { + if !f.arguments[i].(PType).Equals(oth.arguments[i]) { + return false + } + } + return oth.symbol == f.symbol + } + return false +} func (PTypeVar) isPAtomicType() {} func (PTypeVar) isPType() {} func (PTypeFun) isPAtomicType() {} @@ -100,6 +120,12 @@ type PTypeBin struct { func (b PTypeBin) Operator() PTypeBinOp { return b.op } func (b PTypeBin) Left() PType { return b.left } func (b PTypeBin) Right() PType { return b.right } +func (b PTypeBin) Equals(other any) bool { + if oth, ok := other.(PTypeBin); ok { + return oth.op == b.op && oth.left.Equals(b.left) && oth.right.Equals(b.right) + } + return false +} type PTypeQuantifier int @@ -116,7 +142,21 @@ type PTypeQuant struct { func (q PTypeQuant) Quant() PTypeQuantifier { return q.quant } func (q PTypeQuant) Vars() []Lib.Pair[string, PAtomicType] { return q.vars } func (q PTypeQuant) Ty() PType { return q.t } - +func (q PTypeQuant) Equals(other any) bool { + if oth, ok := other.(PTypeQuant); ok { + if len(oth.vars) != len(q.vars) { + return false + } + for i := range q.vars { + if q.vars[i].Fst != oth.vars[i].Fst || + !q.vars[i].Snd.(PType).Equals(oth.vars[i].Snd) { + return false + } + } + return oth.quant == q.quant && oth.t.Equals(q.t) + } + return false +} func (PTypeBin) isPType() {} func (PTypeQuant) isPType() {} @@ -156,6 +196,10 @@ type PVar struct { func (v PVar) Name() string { return v.name } +func MkVar(name string) PTerm { + return PVar{name} +} + func (PFun) isPTerm() {} func (PVar) isPTerm() {} diff --git a/src/Typing/env-and-context.go b/src/Typing/env-and-context.go index e544f6c4..48b2e240 100644 --- a/src/Typing/env-and-context.go +++ b/src/Typing/env-and-context.go @@ -40,6 +40,7 @@ package Typing import ( "sync" + "fmt" "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Lib" ) @@ -85,6 +86,20 @@ func (con Con) contains(name string, ty AST.Ty) bool { return con.defs.Contains(definedType{name, ty}) } +func (con Con) addTypedVars(typed_vars Lib.List[AST.TypedVar]) Con { + for _, tv := range typed_vars.GetSlice() { + con = con.add(tv.GetName(), tv.GetTy()) + } + return con +} + +func (con Con) toString() string { + to_string := func(def definedType) string { + return fmt.Sprintf("%s: %s", def.name, def.ty.ToString()) + } + return con.defs.Elements().ToString(to_string, Lib.WithEmpty("{}")) +} + // We could use [Con] to do environments, but as we need to query by name it's faster to use a map. type Env struct { con map[string]AST.Ty diff --git a/src/Typing/init.go b/src/Typing/init.go index f145b260..6411a329 100644 --- a/src/Typing/init.go +++ b/src/Typing/init.go @@ -38,11 +38,122 @@ package Typing import ( "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Lib" "sync" ) var global_env Env +var ari_var string func Init() { global_env = Env{make(map[string]AST.Ty), sync.Mutex{}} + ari_var = "number" + + initTPTPNativeTypes() +} + +func initTPTPNativeTypes() { + for _, ty := range AST.DefinedTPTPTypes().GetSlice() { + AddToGlobalEnv(ty.Symbol(), AST.TType()) + } + + AddToGlobalEnv( + AST.Id_eq.GetName(), + AST.MkTyPi( + Lib.MkListV("α"), + AST.MkTyFunc(AST.MkTyProd(Lib.MkListV(AST.MkTyVar("α"), AST.MkTyVar("α"))), AST.TProp()), + ), + ) + + // 1 - Binary predicates + recordBinaryProp("$less") + recordBinaryProp("$lesseq") + recordBinaryProp("$greater") + recordBinaryProp("$greatereq") + + // 2 - Binary input arguments + recordBinaryInArgs("$sum") + recordBinaryInArgs("$difference") + recordBinaryInArgs("$product") + recordBinaryInArgs("$quotient_e") + recordBinaryInArgs("$quotient_t") + recordBinaryInArgs("$quotient_f") + recordBinaryInArgs("$remainder_e") + recordBinaryInArgs("$remainder_t") + recordBinaryInArgs("$remainder_f") + + // 3 - $quotient + AddToGlobalEnv("$quotient", + AST.MkTyPi( + Lib.MkListV(ari_var, "rat_or_real"), + AST.MkTyFunc( + AST.MkTyProd(Lib.MkListV(AST.MkTyVar(ari_var), AST.MkTyVar(ari_var))), + AST.MkTyVar("rat_or_real")), + )) + + // 4 - Unary input arguments + recordUnaryInArgs("$uminus") + recordUnaryInArgs("$floor") + recordUnaryInArgs("$ceiling") + recordUnaryInArgs("$truncate") + recordUnaryInArgs("$round") + + // 5 - Unary predicates + recordUnaryProp("$is_int") + recordUnaryProp("$is_rat") + + // 6 - Conversion + recordConversion("$to_int", AST.TInt()) + recordConversion("$to_rat", AST.TRat()) + recordConversion("$to_real", AST.TReal()) +} + +func recordBinaryProp(name string) { + AddToGlobalEnv( + name, + AST.MkTyPi( + Lib.MkListV(ari_var), + AST.MkTyFunc(AST.MkTyProd(Lib.MkListV(AST.MkTyVar(ari_var), AST.MkTyVar(ari_var))), AST.TProp()), + ), + ) +} + +func recordBinaryInArgs(name string) { + AddToGlobalEnv( + name, + AST.MkTyPi( + Lib.MkListV(ari_var), + AST.MkTyFunc(AST.MkTyProd(Lib.MkListV(AST.MkTyVar(ari_var), AST.MkTyVar(ari_var))), AST.MkTyVar(ari_var)), + ), + ) +} + +func recordUnaryInArgs(name string) { + AddToGlobalEnv( + name, + AST.MkTyPi( + Lib.MkListV(ari_var), + AST.MkTyFunc(AST.MkTyVar(ari_var), AST.MkTyVar(ari_var)), + ), + ) +} + +func recordUnaryProp(name string) { + AddToGlobalEnv( + name, + AST.MkTyPi( + Lib.MkListV(ari_var), + AST.MkTyFunc(AST.MkTyVar(ari_var), AST.TProp()), + ), + ) +} + +func recordConversion(name string, out AST.Ty) { + AddToGlobalEnv( + name, + AST.MkTyPi( + Lib.MkListV(ari_var), + AST.MkTyFunc(AST.MkTyVar(ari_var), out), + ), + ) } diff --git a/src/Typing/rules.go b/src/Typing/rules.go index 7b2f9768..098aab67 100644 --- a/src/Typing/rules.go +++ b/src/Typing/rules.go @@ -38,9 +38,257 @@ package Typing import ( + "fmt" "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" ) +var label = "typing" + func TypeCheck(form AST.Form) bool { + return typecheckForm(emptyCon(), form) +} + +func typecheckForm(con Con, form AST.Form) bool { + switch f := form.(type) { + case AST.Bot, AST.Top: + return true + case AST.Pred: + return checkFunctional( + con, + f.GetID().GetName(), + f.GetTyArgs(), + f.GetArgs(), + Lib.MkLazy(func() string { return form.ToString() }), + ) + + case AST.Not, AST.And, AST.Or, AST.Imp, AST.Equ: + return typecheckRec( + con, + f.GetChildFormulas(), + Lib.NewList[Lib.Pair[AST.Term, AST.Ty]](), + Lib.NewList[AST.Ty](), + ) + + case AST.All: + return typecheckRec( + con.addTypedVars(f.GetVarList()), + Lib.MkListV(f.GetForm()), + Lib.NewList[Lib.Pair[AST.Term, AST.Ty]](), + Lib.NewList[AST.Ty](), + ) + + case AST.Ex: + return typecheckRec( + con.addTypedVars(f.GetVarList()), + Lib.MkListV(f.GetForm()), + Lib.NewList[Lib.Pair[AST.Term, AST.Ty]](), + Lib.NewList[AST.Ty](), + ) + } + + Glob.Anomaly( + label, + fmt.Sprintf("%s is not a known internal formula", form.ToString()), + ) + return false +} + +func typecheckTerm(con Con, term AST.Term, ty AST.Ty) bool { + switch t := term.(type) { + case AST.Var: + if !con.contains(t.GetName(), ty) { + Glob.Fatal( + label, + fmt.Sprintf( + "Variable %s is either not in the context or should not have type %s\nContext: %s", + t.GetName(), + ty.ToString(), + con.toString(), + )) + return false + } + + return typecheckRec( + con, + Lib.NewList[AST.Form](), + Lib.NewList[Lib.Pair[AST.Term, AST.Ty]](), + Lib.MkListV(ty), + ) + + case AST.Fun: + return checkFunctional( + con, + t.GetID().GetName(), + t.GetTyArgs(), + t.GetArgs(), + Lib.MkLazy(func() string { return t.ToString() }), + ) + } + + Glob.Anomaly( + label, + fmt.Sprintf("Only bound variables and functions should be typechecked, but found %s", term.ToString()), + ) return false } + +func typecheckType(con Con, ty AST.Ty) bool { + switch nty := ty.(type) { + case AST.TyBound: + if !con.contains(nty.GetName(), AST.TType()) { + Glob.PrintInfo("Context", con.toString()) + Glob.Fatal( + label, + fmt.Sprintf( + "Variable %s is either not in the context or is not a type variable\nContext: %s", + nty.ToString(), + con.toString(), + )) + return false + } + + return true + + case AST.TyConstr: + oty := QueryGlobalEnv(nty.Symbol()) + + switch rty := oty.(type) { + case Lib.Some[AST.Ty]: + args := AST.GetArgsTy(rty.Val) + if args.Len() != nty.Args().Len() { + Glob.Fatal( + label, + fmt.Sprintf( + "Type constructor %s expects %d arguments, got %d", + nty.Symbol(), + args.Len(), + nty.Args().Len(), + ), + ) + return false + } + + if nty.Args().Empty() { + return true + } + + return typecheckRec( + con, + Lib.NewList[AST.Form](), + Lib.NewList[Lib.Pair[AST.Term, AST.Ty]](), + nty.Args(), + ) + + case Lib.None[AST.Ty]: + Glob.Anomaly( + label, + fmt.Sprintf("Unknown type %s", nty.ToString()), + ) + } + } + + Glob.Anomaly( + label, + fmt.Sprintf("On typechecking of types: expected atomic type, got %s", ty.ToString()), + ) + return false +} + +func checkFunctional( + con Con, + name string, + tys Lib.List[AST.Ty], + args Lib.List[AST.Term], + debug_str Lib.Lazy[string], +) bool { + oty := QueryEnvInstance(name, tys) + switch ty := oty.(type) { + case Lib.Some[AST.Ty]: + instantiated_ty := AST.GetArgsTy(ty.Val) + terms_checker := buildTermCheckList( + debug_str, + ty.Val, + args, + instantiated_ty, + ) + tys.Append(AST.GetOutTy(ty.Val)) + + return typecheckRec(con, Lib.NewList[AST.Form](), terms_checker, tys) + + case Lib.None[AST.Ty]: + Glob.Fatal( + label, + fmt.Sprintf("Type of %s not found in the global environment", debug_str.Run()), + ) + } + return false +} + +func typecheckRec( + con Con, + forms Lib.List[AST.Form], + typed_terms Lib.List[Lib.Pair[AST.Term, AST.Ty]], + tys Lib.List[AST.Ty], +) bool { + calls := []func(chan bool){} + + for _, form := range forms.GetSlice() { + loop_form := form + calls = append(calls, func(outchan chan bool) { + outchan <- typecheckForm(con, loop_form) + }) + } + + for _, typed_term := range typed_terms.GetSlice() { + loop_term := typed_term + calls = append(calls, func(outchan chan bool) { + outchan <- typecheckTerm(con, loop_term.Fst, loop_term.Snd) + }) + } + + for _, ty := range tys.GetSlice() { + loop_ty := ty + calls = append(calls, func(outchan chan bool) { + outchan <- typecheckType(con, loop_ty) + }) + } + + res, err := Lib.GenericParallel( + calls, + func(x, y bool) bool { return x && y }, + true, // Neutral of the operation + ) + + if err != nil { + Glob.Anomaly( + label, + fmt.Sprintf("Encountered a Lib error: %s", err.Error()), + ) + } + + return res +} + +func buildTermCheckList( + debug_str Lib.Lazy[string], + ty AST.Ty, + terms Lib.List[AST.Term], + tys Lib.List[AST.Ty], +) Lib.List[Lib.Pair[AST.Term, AST.Ty]] { + if terms.Len() != tys.Len() { + Glob.Fatal( + label, + fmt.Sprintf("Expected %d arguments in %s (which has type %s), but got %d", + tys.Len(), debug_str.Run(), ty.ToString(), terms.Len()), + ) + return Lib.NewList[Lib.Pair[AST.Term, AST.Ty]]() + } + + ls := Lib.MkList[Lib.Pair[AST.Term, AST.Ty]](terms.Len()) + for i := range terms.GetSlice() { + ls.Upd(i, Lib.MkPair(terms.At(i), tys.At(i))) + } + return ls +} diff --git a/src/Unif/parsing.go b/src/Unif/parsing.go index e63b98da..8d61a146 100644 --- a/src/Unif/parsing.go +++ b/src/Unif/parsing.go @@ -61,6 +61,9 @@ func (t TermForm) RenameVariables() AST.Form { return t } func (t TermForm) ReplaceTermByTerm(AST.Term, AST.Term) (AST.Form, bool) { return t, false } +func (t TermForm) ReplaceTyVar(AST.TyBound, AST.Ty) AST.Form { + return t +} func (t TermForm) GetIndex() int { return t.index } func (t TermForm) SubstituteVarByMeta(AST.Var, AST.Meta) AST.Form { return t } func (t TermForm) GetInternalMetas() Lib.List[AST.Meta] { return Lib.NewList[AST.Meta]() } diff --git a/src/main.go b/src/main.go index fc4c8b93..5a61e71a 100644 --- a/src/main.go +++ b/src/main.go @@ -214,6 +214,7 @@ func initDebuggers() { Search.InitDebugger() // Typing.InitDebugger() Unif.InitDebugger() + Engine.InitDebugger() } // FIXME: eventually, we would want to add an "interpretation" layer between elab and internal representation that does this From e4263d0c0652cc989d4ed678b388d5671c0dd4ee Mon Sep 17 00:00:00 2001 From: Johann Rosain Date: Sat, 26 Jul 2025 11:53:27 +0200 Subject: [PATCH 4/8] Updated gamma and delta rules to deal with type variables --- src/AST/formsDef.go | 34 ++++++++++++++--------------- src/AST/formula.go | 4 ++-- src/AST/quantifiers.go | 8 +++---- src/AST/term.go | 2 +- src/AST/termsDef.go | 12 +++++------ src/AST/tptp-native-types.go | 2 ++ src/AST/ty-syntax.go | 42 ++++++++++++++++++++++-------------- src/AST/typed-vars.go | 4 ++-- src/Core/Sko/interface.go | 2 +- src/Core/instanciation.go | 38 ++++++++++++++++++++++---------- src/Core/skolemisation.go | 21 ++++++++++++------ src/Unif/parsing.go | 2 +- 12 files changed, 103 insertions(+), 68 deletions(-) diff --git a/src/AST/formsDef.go b/src/AST/formsDef.go index 930773a2..ca395294 100644 --- a/src/AST/formsDef.go +++ b/src/AST/formsDef.go @@ -120,7 +120,7 @@ func (a All) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return All{quant}, isReplaced } -func (a All) ReplaceTyVar(old TyBound, new Ty) Form { +func (a All) SubstTy(old TyBound, new Ty) Form { return All{a.quantifier.replaceTyVar(old, new)} } @@ -172,7 +172,7 @@ func (e Ex) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return Ex{quant}, isReplaced } -func (e Ex) ReplaceTyVar(old TyBound, new Ty) Form { +func (e Ex) SubstTy(old TyBound, new Ty) Form { return Ex{e.quantifier.replaceTyVar(old, new)} } @@ -279,7 +279,7 @@ func (o Or) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return no, res } -func (o Or) ReplaceTyVar(old TyBound, new Ty) Form { +func (o Or) SubstTy(old TyBound, new Ty) Form { formList := replaceTyVarInFormList(o.forms, old, new) return MakeOrSimple(o.GetIndex(), formList, o.metas.Raw()) } @@ -420,7 +420,7 @@ func (a And) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return na, res } -func (a And) ReplaceTyVar(old TyBound, new Ty) Form { +func (a And) SubstTy(old TyBound, new Ty) Form { formList := replaceTyVarInFormList(a.forms, old, new) return MakeAndSimple(a.GetIndex(), formList, a.metas.Raw()) } @@ -536,11 +536,11 @@ func (e Equ) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return ne, res1 || res2 } -func (e Equ) ReplaceTyVar(old TyBound, new Ty) Form { +func (e Equ) SubstTy(old TyBound, new Ty) Form { return MakeEquSimple( e.GetIndex(), - e.f1.ReplaceTyVar(old, new), - e.f2.ReplaceTyVar(old, new), + e.f1.SubstTy(old, new), + e.f2.SubstTy(old, new), e.metas.Raw(), ) } @@ -666,11 +666,11 @@ func (i Imp) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return ni, res1 || res2 } -func (i Imp) ReplaceTyVar(old TyBound, new Ty) Form { +func (i Imp) SubstTy(old TyBound, new Ty) Form { return MakeImpSimple( i.GetIndex(), - i.f1.ReplaceTyVar(old, new), - i.f2.ReplaceTyVar(old, new), + i.f1.SubstTy(old, new), + i.f2.SubstTy(old, new), i.metas.Raw(), ) } @@ -793,10 +793,10 @@ func (n Not) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return nn, res } -func (n Not) ReplaceTyVar(old TyBound, new Ty) Form { +func (n Not) SubstTy(old TyBound, new Ty) Form { return MakeNotSimple( n.GetIndex(), - n.f.ReplaceTyVar(old, new), + n.f.SubstTy(old, new), n.metas.Raw(), ) } @@ -1032,14 +1032,14 @@ func (p Pred) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return np, res } -func (p Pred) ReplaceTyVar(old TyBound, new Ty) Form { +func (p Pred) SubstTy(old TyBound, new Ty) Form { typed_args := Lib.ListMap( p.tys, - func(t Ty) Ty { return t.ReplaceTyVar(old, new) }, + func(t Ty) Ty { return t.SubstTy(old, new) }, ) args := Lib.ListMap( p.args, - func(t Term) Term { return t.ReplaceTyVar(old, new) }, + func(t Term) Term { return t.SubstTy(old, new) }, ) return MakePredSimple( p.GetIndex(), @@ -1141,7 +1141,7 @@ func (t Top) Copy() Form { return MakeTop(t.Get func (Top) Equals(f any) bool { _, isTop := f.(Top); return isTop } func (Top) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } func (t Top) ReplaceTermByTerm(Term, Term) (Form, bool) { return MakeTop(t.GetIndex()), false } -func (t Top) ReplaceTyVar(TyBound, Ty) Form { return t } +func (t Top) SubstTy(TyBound, Ty) Form { return t } func (t Top) RenameVariables() Form { return MakeTop(t.GetIndex()) } func (t Top) GetIndex() int { return t.index } func (t Top) GetSubTerms() Lib.List[Term] { return Lib.NewList[Term]() } @@ -1184,7 +1184,7 @@ func (b Bot) Copy() Form { return MakeBot(b.Get func (Bot) Equals(f any) bool { _, isBot := f.(Bot); return isBot } func (Bot) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } func (b Bot) ReplaceTermByTerm(Term, Term) (Form, bool) { return MakeBot(b.GetIndex()), false } -func (b Bot) ReplaceTyVar(TyBound, Ty) Form { return b } +func (b Bot) SubstTy(TyBound, Ty) Form { return b } func (b Bot) RenameVariables() Form { return MakeBot(b.GetIndex()) } func (b Bot) GetIndex() int { return b.index } func (b Bot) GetSubTerms() Lib.List[Term] { return Lib.NewList[Term]() } diff --git a/src/AST/formula.go b/src/AST/formula.go index 843675c7..16ce1051 100644 --- a/src/AST/formula.go +++ b/src/AST/formula.go @@ -54,7 +54,7 @@ type Form interface { MappableString ReplaceTermByTerm(old Term, new Term) (Form, bool) - ReplaceTyVar(old TyBound, new Ty) Form + SubstTy(old TyBound, new Ty) Form RenameVariables() Form SubstituteVarByMeta(old Var, new Meta) Form ReplaceMetaByTerm(meta Meta, term Term) Form @@ -139,7 +139,7 @@ func replaceTermInFormList(oldForms Lib.List[Form], oldTerm Term, newTerm Term) func replaceTyVarInFormList(oldForms Lib.List[Form], old TyBound, new Ty) Lib.List[Form] { return Lib.ListMap( oldForms, - func(f Form) Form { return f.ReplaceTyVar(old, new) }, + func(f Form) Form { return f.SubstTy(old, new) }, ) } diff --git a/src/AST/quantifiers.go b/src/AST/quantifiers.go index 4a0db4a5..e27c2aca 100644 --- a/src/AST/quantifiers.go +++ b/src/AST/quantifiers.go @@ -161,12 +161,12 @@ func (q quantifier) replaceTermByTerm(old Term, new Term) (quantifier, bool) { } func (q quantifier) replaceTyVar(old TyBound, new Ty) quantifier { - f := q.GetForm().ReplaceTyVar(old, new) + f := q.GetForm().SubstTy(old, new) return makeQuantifier( q.GetIndex(), Lib.ListMap( q.GetVarList(), - func(p TypedVar) TypedVar { return p.ReplaceTyVar(old, new) }, + func(p TypedVar) TypedVar { return p.SubstTy(old, new) }, ), f, q.metas.Raw().Copy(), @@ -186,7 +186,7 @@ func (q quantifier) renameVariables() quantifier { f, replaced := newForm.ReplaceTermByTerm(v.ToBoundVar(), newVar) if !replaced { newBv := MkTyBV(newVar.name, newVar.index) - f = f.ReplaceTyVar(v.ToTyBoundVar(), newBv) + f = f.SubstTy(v.ToTyBoundVar(), newBv) newTyBv.Append(Lib.MkPair(v.ToTyBoundVar(), newBv)) } newForm = f @@ -198,7 +198,7 @@ func (q quantifier) renameVariables() quantifier { newVarList, func(p TypedVar) TypedVar { for _, pair := range newTyBv.GetSlice() { - p = p.ReplaceTyVar(pair.Fst, pair.Snd) + p = p.SubstTy(pair.Fst, pair.Snd) } return p }, diff --git a/src/AST/term.go b/src/AST/term.go index b14e25d4..447728d5 100644 --- a/src/AST/term.go +++ b/src/AST/term.go @@ -53,7 +53,7 @@ type Term interface { GetMetaList() Lib.List[Meta] // Metas appearing in the term ORDERED GetSubTerms() Lib.List[Term] ReplaceSubTermBy(original_term, new_term Term) Term - ReplaceTyVar(old TyBound, new Ty) Term + SubstTy(old TyBound, new Ty) Term Less(any) bool } diff --git a/src/AST/termsDef.go b/src/AST/termsDef.go index 27222ae6..93d6e173 100644 --- a/src/AST/termsDef.go +++ b/src/AST/termsDef.go @@ -111,7 +111,7 @@ func (i Id) ReplaceSubTermBy(original_term, new_term Term) Term { return i } -func (i Id) ReplaceTyVar(TyBound, Ty) Term { return i } +func (i Id) SubstTy(TyBound, Ty) Term { return i } func (i Id) GetSubTerms() Lib.List[Term] { return Lib.MkListV[Term](i) @@ -277,14 +277,14 @@ func (f Fun) ReplaceSubTermBy(oldTerm, newTerm Term) Term { } } -func (f Fun) ReplaceTyVar(old TyBound, new Ty) Term { +func (f Fun) SubstTy(old TyBound, new Ty) Term { typed_args := Lib.ListMap( f.tys, - func(t Ty) Ty { return t.ReplaceTyVar(old, new) }, + func(t Ty) Ty { return t.SubstTy(old, new) }, ) args := Lib.ListMap( f.args, - func(t Term) Term { return t.ReplaceTyVar(old, new) }, + func(t Term) Term { return t.SubstTy(old, new) }, ) return MakeFun( f.GetID(), @@ -364,7 +364,7 @@ func (v Var) ReplaceSubTermBy(original_term, new_term Term) Term { return v } -func (v Var) ReplaceTyVar(TyBound, Ty) Term { return v } +func (v Var) SubstTy(TyBound, Ty) Term { return v } func (v Var) ToMappedString(map_ MapString, type_ bool) string { return v.GetName() @@ -454,7 +454,7 @@ func (m Meta) ReplaceSubTermBy(original_term, new_term Term) Term { return m } -func (m Meta) ReplaceTyVar(TyBound, Ty) Term { return m } +func (m Meta) SubstTy(TyBound, Ty) Term { return m } func (m Meta) GetSubTerms() Lib.List[Term] { return Lib.MkListV[Term](m) diff --git a/src/AST/tptp-native-types.go b/src/AST/tptp-native-types.go index 3b4b821d..320cf3b7 100644 --- a/src/AST/tptp-native-types.go +++ b/src/AST/tptp-native-types.go @@ -60,6 +60,8 @@ func initTPTPNativeTypes() { tIndividual = MkTyConst("$i") tProp = MkTyConst("$o") + + count_meta = 0 } func TType() Ty { diff --git a/src/AST/ty-syntax.go b/src/AST/ty-syntax.go index bb7639b7..1571ea14 100644 --- a/src/AST/ty-syntax.go +++ b/src/AST/ty-syntax.go @@ -39,16 +39,21 @@ package AST import ( "fmt" + "sync" + "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" ) +var meta_mut sync.Mutex +var count_meta int + type Ty interface { isTy() ToString() string Equals(any) bool Copy() Ty - ReplaceTyVar(TyBound, Ty) Ty + SubstTy(TyBound, Ty) Ty } // Internal, shouldn't get out so no upper case @@ -66,7 +71,7 @@ func (v tyVar) Equals(oth any) bool { } func (v tyVar) Copy() Ty { return tyVar{v.repr} } -func (v tyVar) ReplaceTyVar(TyBound, Ty) Ty { return v } +func (v tyVar) SubstTy(TyBound, Ty) Ty { return v } type TyBound struct { name string @@ -84,7 +89,7 @@ func (b TyBound) Equals(oth any) bool { func (b TyBound) Copy() Ty { return TyBound{b.name, b.index} } func (b TyBound) GetName() string { return b.name } -func (b TyBound) ReplaceTyVar(old TyBound, new Ty) Ty { +func (b TyBound) SubstTy(old TyBound, new Ty) Ty { if b.Equals(old) { return new } @@ -92,20 +97,21 @@ func (b TyBound) ReplaceTyVar(old TyBound, new Ty) Ty { } type TyMeta struct { - name string + name string + index int } func (TyMeta) isTy() {} -func (m TyMeta) ToString() string { return m.name } +func (m TyMeta) ToString() string { return fmt.Sprintf("%s_%d", m.name, m.index) } func (m TyMeta) Equals(oth any) bool { if om, ok := oth.(TyMeta); ok { return m.name == om.name } return false } -func (m TyMeta) Copy() Ty { return TyMeta{m.name} } +func (m TyMeta) Copy() Ty { return TyMeta{m.name, m.index} } -func (m TyMeta) ReplaceTyVar(TyBound, Ty) Ty { return m } +func (m TyMeta) SubstTy(TyBound, Ty) Ty { return m } // Type constructors, e.g., list, option, ... // Include constants, e.g., $i, $o, ... @@ -143,10 +149,10 @@ func (c TyConstr) Args() Lib.List[Ty] { return c.args } -func (c TyConstr) ReplaceTyVar(old TyBound, new Ty) Ty { +func (c TyConstr) SubstTy(old TyBound, new Ty) Ty { return TyConstr{ c.symbol, - Lib.ListMap(c.args, func(t Ty) Ty { return t.ReplaceTyVar(old, new) }), + Lib.ListMap(c.args, func(t Ty) Ty { return t.SubstTy(old, new) }), } } @@ -175,9 +181,9 @@ func (p TyProd) Copy() Ty { return TyProd{Lib.ListCpy(p.args)} } -func (p TyProd) ReplaceTyVar(old TyBound, new Ty) Ty { +func (p TyProd) SubstTy(old TyBound, new Ty) Ty { return TyProd{ - Lib.ListMap(p.args, func(t Ty) Ty { return t.ReplaceTyVar(old, new) }), + Lib.ListMap(p.args, func(t Ty) Ty { return t.SubstTy(old, new) }), } } @@ -200,8 +206,8 @@ func (f TyFunc) Copy() Ty { return TyFunc{f.in.Copy(), f.out.Copy()} } -func (f TyFunc) ReplaceTyVar(old TyBound, new Ty) Ty { - return TyFunc{f.in.ReplaceTyVar(old, new), f.out.ReplaceTyVar(old, new)} +func (f TyFunc) SubstTy(old TyBound, new Ty) Ty { + return TyFunc{f.in.SubstTy(old, new), f.out.SubstTy(old, new)} } type TyPi struct { @@ -226,8 +232,8 @@ func (p TyPi) Copy() Ty { return TyPi{p.vars.Copy(func(x string) string { return x }), p.ty.Copy()} } -func (p TyPi) ReplaceTyVar(old TyBound, new Ty) Ty { - return TyPi{p.vars, p.ty.ReplaceTyVar(old, new)} +func (p TyPi) SubstTy(old TyBound, new Ty) Ty { + return TyPi{p.vars, p.ty.SubstTy(old, new)} } // Makers @@ -241,7 +247,11 @@ func MkTyBV(name string, index int) Ty { } func MkTyMeta(name string) Ty { - return TyMeta{name} + meta_mut.Lock() + meta := TyMeta{name, count_meta} + count_meta += 1 + meta_mut.Unlock() + return meta } func MkTyConstr(symbol string, args Lib.List[Ty]) Ty { diff --git a/src/AST/typed-vars.go b/src/AST/typed-vars.go index 598488f9..d1bea6af 100644 --- a/src/AST/typed-vars.go +++ b/src/AST/typed-vars.go @@ -82,8 +82,8 @@ func (v TypedVar) ToTyBoundVar() TyBound { return MkTyBV(v.name, v.index).(TyBound) } -func (v TypedVar) ReplaceTyVar(old TyBound, new Ty) TypedVar { - return TypedVar{v.name, v.index, v.ty.ReplaceTyVar(old, new)} +func (v TypedVar) SubstTy(old TyBound, new Ty) TypedVar { + return TypedVar{v.name, v.index, v.ty.SubstTy(old, new)} } func MkTypedVar(name string, index int, ty Ty) TypedVar { diff --git a/src/Core/Sko/interface.go b/src/Core/Sko/interface.go index 647a24e8..b94c1d5f 100644 --- a/src/Core/Sko/interface.go +++ b/src/Core/Sko/interface.go @@ -64,7 +64,7 @@ func genFreshSymbol(existingSymbols *Lib.Set[AST.Id], x AST.TypedVar) AST.Id { symbol := AST.MakerNewId( fmt.Sprintf("skolem@%v", x.GetName()), ) - existingSymbols.Add(symbol) + *existingSymbols = existingSymbols.Add(symbol) return symbol } diff --git a/src/Core/instanciation.go b/src/Core/instanciation.go index 58a517b0..81cc93aa 100644 --- a/src/Core/instanciation.go +++ b/src/Core/instanciation.go @@ -49,7 +49,7 @@ const ( * Instantiates once the formula fnt. */ func Instantiate(fnt FormAndTerms, index int) (FormAndTerms, Lib.Set[AST.Meta]) { - var meta AST.Meta + var meta Lib.Option[AST.Meta] terms := fnt.GetTerms() switch f := fnt.GetForm().(type) { @@ -61,7 +61,15 @@ func Instantiate(fnt FormAndTerms, index int) (FormAndTerms, Lib.Set[AST.Meta]) fnt, meta = RealInstantiate(f.GetVarList(), index, is_all, f.GetForm(), terms) } - return fnt, Lib.Singleton(meta) + switch m := meta.(type) { + case Lib.Some[AST.Meta]: + return fnt, Lib.Singleton(m.Val) + case Lib.None[AST.Meta]: + return fnt, Lib.EmptySet[AST.Meta]() + } + + Glob.Anomaly("instantiation", "returned bad option type") + return fnt, Lib.EmptySet[AST.Meta]() } func RealInstantiate( @@ -69,16 +77,24 @@ func RealInstantiate( index, status int, subForm AST.Form, terms Lib.List[AST.Term], -) (FormAndTerms, AST.Meta) { +) (FormAndTerms, Lib.Option[AST.Meta]) { v := varList.At(0) - meta := AST.MakerMeta(strings.ToUpper(v.GetName()), index, v.GetTy()) - subForm = subForm.SubstituteVarByMeta(v.ToBoundVar(), meta) + var m Lib.Option[AST.Meta] - terms = terms.Copy(AST.Term.Copy) - terms.Add( - AST.TermEquals, - Glob.To[AST.Term](meta), - ) + if AST.IsTType(v.GetTy()) { + meta := AST.MkTyMeta(strings.ToUpper(v.GetName())) + subForm = subForm.SubstTy(v.ToTyBoundVar(), meta) + m = Lib.MkNone[AST.Meta]() + } else { + meta := AST.MakerMeta(strings.ToUpper(v.GetName()), index, v.GetTy()) + subForm = subForm.SubstituteVarByMeta(v.ToBoundVar(), meta) + terms = terms.Copy(AST.Term.Copy) + terms.Add( + AST.TermEquals, + Glob.To[AST.Term](meta), + ) + m = Lib.MkSome(meta) + } if varList.Len() > 1 { if status == is_exists { @@ -93,5 +109,5 @@ func RealInstantiate( } } - return MakeFormAndTerm(subForm, terms), meta + return MakeFormAndTerm(subForm, terms), m } diff --git a/src/Core/skolemisation.go b/src/Core/skolemisation.go index aade0643..66238d50 100644 --- a/src/Core/skolemisation.go +++ b/src/Core/skolemisation.go @@ -124,13 +124,20 @@ func realSkolemize( metas Lib.Set[AST.Meta], typ int, ) AST.Form { - sko, res := selectedSkolemization.Skolemize( - initialForm, - deltaForm, - x, - metas, - ) - selectedSkolemization = sko + var res AST.Form + + if AST.IsTType(x.GetTy()) { + id := AST.MakerId("skoTy") + res = deltaForm.SubstTy(x.ToTyBoundVar(), AST.MkTyConst(id.ToString())) + } else { + selectedSkolemization, res = selectedSkolemization.Skolemize( + initialForm, + deltaForm, + x, + metas, + ) + } + switch typ { case isNegAll: if allVars.Len() > 1 { diff --git a/src/Unif/parsing.go b/src/Unif/parsing.go index 8d61a146..9674909d 100644 --- a/src/Unif/parsing.go +++ b/src/Unif/parsing.go @@ -61,7 +61,7 @@ func (t TermForm) RenameVariables() AST.Form { return t } func (t TermForm) ReplaceTermByTerm(AST.Term, AST.Term) (AST.Form, bool) { return t, false } -func (t TermForm) ReplaceTyVar(AST.TyBound, AST.Ty) AST.Form { +func (t TermForm) SubstTy(AST.TyBound, AST.Ty) AST.Form { return t } func (t TermForm) GetIndex() int { return t.index } From 7e47707e05b6641a1a6ad908939ec454242d1f09 Mon Sep 17 00:00:00 2001 From: Johann Rosain Date: Sat, 26 Jul 2025 20:00:33 +0200 Subject: [PATCH 5/8] Manage typed proof search and add related tests * non destructive search **does not** manage typed search, only destructive search does * dmt might be incompatible with typed search --- .../test-suite/proofs/tf1_basic_thm-2.out | 28 ++ devtools/test-suite/proofs/tf1_basic_thm-2.p | 40 +++ devtools/test-suite/proofs/tf1_basic_thm.out | 16 + devtools/test-suite/proofs/tf1_basic_thm.p | 40 +++ src/AST/formsDef.go | 38 +-- src/AST/formula.go | 4 +- src/AST/quantifiers.go | 2 +- src/AST/term.go | 2 +- src/AST/termsDef.go | 11 +- src/AST/ty-syntax.go | 91 +++++- src/AST/typed-vars.go | 2 +- src/Core/FormListDS.go | 6 +- src/Core/global_unifier.go | 60 ++-- src/Core/instanciation.go | 2 +- src/Core/int_subst_and_form.go | 8 +- src/Core/subst_and_form.go | 46 ++- src/Core/subst_and_form_and_terms.go | 25 +- src/Core/substitutions_search.go | 279 +++++++++--------- src/Lib/either.go | 103 +++++++ src/Lib/list.go | 10 + src/Mods/assisted/assistant.go | 29 +- src/Mods/assisted/rules.go | 7 +- src/Mods/dmt/rewrite.go | 21 +- src/Mods/dmt/rewritten.go | 3 +- src/Mods/equality/bse/equality.go | 12 +- .../equality/bse/equality_rules_try_apply.go | 3 +- src/Mods/equality/bse/equality_types.go | 8 +- src/Search/child_management.go | 30 +- src/Search/children.go | 30 +- src/Search/destructive.go | 174 +++++++---- src/Search/exchanges.go | 24 +- src/Search/incremental/rulesManager.go | 4 +- src/Search/incremental/search.go | 2 +- src/Search/nonDestructiveSearch.go | 108 ++++--- src/Search/proof.go | 7 +- src/Search/rules.go | 45 +-- src/Search/search.go | 11 +- src/Search/state.go | 23 +- src/Unif/data_structure.go | 2 +- src/Unif/matching.go | 18 +- src/Unif/matching_substitutions.go | 250 ++++++++++++++++ src/Unif/parsing.go | 39 ++- src/Unif/substitutions_tree.go | 5 +- 43 files changed, 1198 insertions(+), 470 deletions(-) create mode 100644 devtools/test-suite/proofs/tf1_basic_thm-2.out create mode 100644 devtools/test-suite/proofs/tf1_basic_thm-2.p create mode 100644 devtools/test-suite/proofs/tf1_basic_thm.out create mode 100644 devtools/test-suite/proofs/tf1_basic_thm.p create mode 100644 src/Lib/either.go diff --git a/devtools/test-suite/proofs/tf1_basic_thm-2.out b/devtools/test-suite/proofs/tf1_basic_thm-2.out new file mode 100644 index 00000000..b87de471 --- /dev/null +++ b/devtools/test-suite/proofs/tf1_basic_thm-2.out @@ -0,0 +1,28 @@ +[0] ALPHA_AND : ((! [A13]: ((maybe(A13) ; head(A13;nil(A13;)) = none(A13;)))) & (! [A15 X17 XS19]: ((maybe(A15) ; head(A15;cons(A15;X17, XS19)) = some(A15;X17)))) & ~((! [A21 X23 Y25 Z27]: ((maybe(A21) ; head(A21;cons(A21;X23, cons(A21;Y25, cons(A21;Z27, nil(A21;))))) = some(A21;X23)))))) + -> [1] (! [A13]: ((maybe(A13) ; head(A13;nil(A13;)) = none(A13;)))), (! [A15 X17 XS19]: ((maybe(A15) ; head(A15;cons(A15;X17, XS19)) = some(A15;X17)))), ~((! [A21 X23 Y25 Z27]: ((maybe(A21) ; head(A21;cons(A21;X23, cons(A21;Y25, cons(A21;Z27, nil(A21;))))) = some(A21;X23))))) + +[1] DELTA_NOT_FORALL : ~((! [A21 X23 Y25 Z27]: ((maybe(A21) ; head(A21;cons(A21;X23, cons(A21;Y25, cons(A21;Z27, nil(A21;))))) = some(A21;X23))))) + -> [2] ~((! [X23 Y25 Z27]: ((maybe(skoTy) ; head(skoTy;cons(skoTy;X23, cons(skoTy;Y25, cons(skoTy;Z27, nil(skoTy;))))) = some(skoTy;X23))))) + +[2] DELTA_NOT_FORALL : ~((! [X23 Y25 Z27]: ((maybe(skoTy) ; head(skoTy;cons(skoTy;X23, cons(skoTy;Y25, cons(skoTy;Z27, nil(skoTy;))))) = some(skoTy;X23))))) + -> [3] ~((! [Y25 Z27]: ((maybe(skoTy) ; head(skoTy;cons(skoTy;skolem@X23, cons(skoTy;Y25, cons(skoTy;Z27, nil(skoTy;))))) = some(skoTy;skolem@X23))))) + +[3] DELTA_NOT_FORALL : ~((! [Y25 Z27]: ((maybe(skoTy) ; head(skoTy;cons(skoTy;skolem@X23, cons(skoTy;Y25, cons(skoTy;Z27, nil(skoTy;))))) = some(skoTy;skolem@X23))))) + -> [4] ~((! [Z27]: ((maybe(skoTy) ; head(skoTy;cons(skoTy;skolem@X23, cons(skoTy;skolem@Y25, cons(skoTy;Z27, nil(skoTy;))))) = some(skoTy;skolem@X23))))) + +[4] DELTA_NOT_FORALL : ~((! [Z27]: ((maybe(skoTy) ; head(skoTy;cons(skoTy;skolem@X23, cons(skoTy;skolem@Y25, cons(skoTy;Z27, nil(skoTy;))))) = some(skoTy;skolem@X23))))) + -> [5] ~((maybe(skoTy) ; head(skoTy;cons(skoTy;skolem@X23, cons(skoTy;skolem@Y25, cons(skoTy;skolem@Z27, nil(skoTy;))))) = some(skoTy;skolem@X23))) + +[5] GAMMA_FORALL : (! [A13]: ((maybe(A13) ; head(A13;nil(A13;)) = none(A13;)))) + -> [6] (maybe(A13_1) ; head(A13_1;nil(A13_1;)) = none(A13_1;)) + +[6] GAMMA_FORALL : (! [A15 X17 XS19]: ((maybe(A15) ; head(A15;cons(A15;X17, XS19)) = some(A15;X17)))) + -> [7] (! [X17 XS19]: ((maybe(skoTy) ; head(skoTy;cons(skoTy;X17, XS19)) = some(skoTy;X17)))) + +[7] GAMMA_FORALL : (! [X17 XS19]: ((maybe(skoTy) ; head(skoTy;cons(skoTy;X17, XS19)) = some(skoTy;X17)))) + -> [8] (! [XS19]: ((maybe(skoTy) ; head(skoTy;cons(skoTy;skolem@X23, XS19)) = some(skoTy;skolem@X23)))) + +[8] GAMMA_FORALL : (! [XS19]: ((maybe(skoTy) ; head(skoTy;cons(skoTy;skolem@X23, XS19)) = some(skoTy;skolem@X23)))) + -> [9] (maybe(skoTy) ; head(skoTy;cons(skoTy;skolem@X23, cons(skoTy;skolem@Y25, cons(skoTy;skolem@Z27, nil(skoTy;))))) = some(skoTy;skolem@X23)) + +[9] CLOSURE : (maybe(skoTy) ; head(skoTy;cons(skoTy;skolem@X23, cons(skoTy;skolem@Y25, cons(skoTy;skolem@Z27, nil(skoTy;))))) = some(skoTy;skolem@X23)) diff --git a/devtools/test-suite/proofs/tf1_basic_thm-2.p b/devtools/test-suite/proofs/tf1_basic_thm-2.p new file mode 100644 index 00000000..f4838a46 --- /dev/null +++ b/devtools/test-suite/proofs/tf1_basic_thm-2.p @@ -0,0 +1,40 @@ +% args: -proof -no_id +% result: VALID + +tff(list_type,type, + list: $tType > $tType ). + +tff(maybe_type,type, + maybe: $tType > $tType ). + +%----Polymorphic symbols +tff(nil_type,type, + nil: + !>[A: $tType] : list(A) ). + +tff(cons_type,type, + cons: + !>[A: $tType] : ( ( A * list(A) ) > list(A) ) ). + +tff(none_type,type, + none: + !>[A: $tType] : maybe(A) ). + +tff(some_type,type, + some: + !>[A: $tType] : ( A > maybe(A) ) ). + +tff(head_type,type, + head: + !>[A: $tType] : ( list(A) > maybe(A) ) ). + +%----Use of polymorphic symbols +tff(head_nil,axiom, + ! [A: $tType] : ( head(A,nil(A)) = none(A) )). + +tff(head_cons,axiom, + ! [A: $tType,X : A,XS : list(A)] : ( head(A,cons(A,X,XS)) = some(A,X) ) ). + +%----With integers +tff(solve_this,conjecture, + ! [A: $tType,X : A,Y : A,Z : A] : ( head(A,cons(A,X,cons(A,Y,cons(A,Z,nil(A))))) = some(A,X) ) ). diff --git a/devtools/test-suite/proofs/tf1_basic_thm.out b/devtools/test-suite/proofs/tf1_basic_thm.out new file mode 100644 index 00000000..39c81f0d --- /dev/null +++ b/devtools/test-suite/proofs/tf1_basic_thm.out @@ -0,0 +1,16 @@ +[0] ALPHA_AND : ((! [A14]: ((maybe(A14) ; head(A14;nil(A14;)) = none(A14;)))) & (! [A16 X18 XS20]: ((maybe(A16) ; head(A16;cons(A16;X18, XS20)) = some(A16;X18)))) & ~((maybe($int) ; head($int;cons($int;1, cons($int;2, cons($int;3, nil($int;))))) = some($int;1)))) + -> [1] (! [A14]: ((maybe(A14) ; head(A14;nil(A14;)) = none(A14;)))), (! [A16 X18 XS20]: ((maybe(A16) ; head(A16;cons(A16;X18, XS20)) = some(A16;X18)))), ~((maybe($int) ; head($int;cons($int;1, cons($int;2, cons($int;3, nil($int;))))) = some($int;1))) + +[1] GAMMA_FORALL : (! [A14]: ((maybe(A14) ; head(A14;nil(A14;)) = none(A14;)))) + -> [2] (maybe(A14_1) ; head(A14_1;nil(A14_1;)) = none(A14_1;)) + +[2] GAMMA_FORALL : (! [A16 X18 XS20]: ((maybe(A16) ; head(A16;cons(A16;X18, XS20)) = some(A16;X18)))) + -> [3] (! [X18 XS20]: ((maybe($int) ; head($int;cons($int;X18, XS20)) = some($int;X18)))) + +[3] GAMMA_FORALL : (! [X18 XS20]: ((maybe($int) ; head($int;cons($int;X18, XS20)) = some($int;X18)))) + -> [4] (! [XS20]: ((maybe($int) ; head($int;cons($int;1, XS20)) = some($int;1)))) + +[4] GAMMA_FORALL : (! [XS20]: ((maybe($int) ; head($int;cons($int;1, XS20)) = some($int;1)))) + -> [5] (maybe($int) ; head($int;cons($int;1, cons($int;2, cons($int;3, nil($int;))))) = some($int;1)) + +[5] CLOSURE : (maybe($int) ; head($int;cons($int;1, cons($int;2, cons($int;3, nil($int;))))) = some($int;1)) diff --git a/devtools/test-suite/proofs/tf1_basic_thm.p b/devtools/test-suite/proofs/tf1_basic_thm.p new file mode 100644 index 00000000..c2ed4f90 --- /dev/null +++ b/devtools/test-suite/proofs/tf1_basic_thm.p @@ -0,0 +1,40 @@ +% args: -proof -no_id +% result: VALID + +tff(list_type,type, + list: $tType > $tType ). + +tff(maybe_type,type, + maybe: $tType > $tType ). + +%----Polymorphic symbols +tff(nil_type,type, + nil: + !>[A: $tType] : list(A) ). + +tff(cons_type,type, + cons: + !>[A: $tType] : ( ( A * list(A) ) > list(A) ) ). + +tff(none_type,type, + none: + !>[A: $tType] : maybe(A) ). + +tff(some_type,type, + some: + !>[A: $tType] : ( A > maybe(A) ) ). + +tff(head_type,type, + head: + !>[A: $tType] : ( list(A) > maybe(A) ) ). + +%----Use of polymorphic symbols +tff(head_nil,axiom, + ! [A: $tType] : ( head(A,nil(A)) = none(A) )). + +tff(head_cons,axiom, + ! [A: $tType,X : A,XS : list(A)] : ( head(A,cons(A,X,XS)) = some(A,X) ) ). + +%----With integers +tff(solve_this,conjecture, + head($int,cons($int,1,cons($int,2,cons($int,3,nil($int))))) = some($int,1) ). diff --git a/src/AST/formsDef.go b/src/AST/formsDef.go index ca395294..717a3d27 100644 --- a/src/AST/formsDef.go +++ b/src/AST/formsDef.go @@ -120,7 +120,7 @@ func (a All) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return All{quant}, isReplaced } -func (a All) SubstTy(old TyBound, new Ty) Form { +func (a All) SubstTy(old TyGenVar, new Ty) Form { return All{a.quantifier.replaceTyVar(old, new)} } @@ -172,7 +172,7 @@ func (e Ex) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return Ex{quant}, isReplaced } -func (e Ex) SubstTy(old TyBound, new Ty) Form { +func (e Ex) SubstTy(old TyGenVar, new Ty) Form { return Ex{e.quantifier.replaceTyVar(old, new)} } @@ -279,7 +279,7 @@ func (o Or) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return no, res } -func (o Or) SubstTy(old TyBound, new Ty) Form { +func (o Or) SubstTy(old TyGenVar, new Ty) Form { formList := replaceTyVarInFormList(o.forms, old, new) return MakeOrSimple(o.GetIndex(), formList, o.metas.Raw()) } @@ -420,7 +420,7 @@ func (a And) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return na, res } -func (a And) SubstTy(old TyBound, new Ty) Form { +func (a And) SubstTy(old TyGenVar, new Ty) Form { formList := replaceTyVarInFormList(a.forms, old, new) return MakeAndSimple(a.GetIndex(), formList, a.metas.Raw()) } @@ -536,7 +536,7 @@ func (e Equ) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return ne, res1 || res2 } -func (e Equ) SubstTy(old TyBound, new Ty) Form { +func (e Equ) SubstTy(old TyGenVar, new Ty) Form { return MakeEquSimple( e.GetIndex(), e.f1.SubstTy(old, new), @@ -666,7 +666,7 @@ func (i Imp) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return ni, res1 || res2 } -func (i Imp) SubstTy(old TyBound, new Ty) Form { +func (i Imp) SubstTy(old TyGenVar, new Ty) Form { return MakeImpSimple( i.GetIndex(), i.f1.SubstTy(old, new), @@ -793,7 +793,7 @@ func (n Not) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return nn, res } -func (n Not) SubstTy(old TyBound, new Ty) Form { +func (n Not) SubstTy(old TyGenVar, new Ty) Form { return MakeNotSimple( n.GetIndex(), n.f.SubstTy(old, new), @@ -1032,7 +1032,7 @@ func (p Pred) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return np, res } -func (p Pred) SubstTy(old TyBound, new Ty) Form { +func (p Pred) SubstTy(old TyGenVar, new Ty) Form { typed_args := Lib.ListMap( p.tys, func(t Ty) Ty { return t.SubstTy(old, new) }, @@ -1092,18 +1092,12 @@ func (p Pred) GetChildFormulas() Lib.List[Form] { } func (p Pred) ReplaceMetaByTerm(meta Meta, term Term) Form { - newTerms := Lib.MkList[Term](p.args.Len()) - - for i, old := range p.args.GetSlice() { - // FIXME: old.GetName() == meta.GetName() ?? - if old.Equals(meta) { - newTerms.Upd(i, term) - } else { - newTerms.Upd(i, old) - } - } - - return MakePred(p.GetIndex(), p.id, p.tys, newTerms) + return MakePred( + p.GetIndex(), + p.id, + p.tys, + Lib.ListMap(p.args, func(t Term) Term { return t.ReplaceSubTermBy(meta, term) }), + ) } // ----------------------------------------------------------------------------- @@ -1141,7 +1135,7 @@ func (t Top) Copy() Form { return MakeTop(t.Get func (Top) Equals(f any) bool { _, isTop := f.(Top); return isTop } func (Top) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } func (t Top) ReplaceTermByTerm(Term, Term) (Form, bool) { return MakeTop(t.GetIndex()), false } -func (t Top) SubstTy(TyBound, Ty) Form { return t } +func (t Top) SubstTy(TyGenVar, Ty) Form { return t } func (t Top) RenameVariables() Form { return MakeTop(t.GetIndex()) } func (t Top) GetIndex() int { return t.index } func (t Top) GetSubTerms() Lib.List[Term] { return Lib.NewList[Term]() } @@ -1184,7 +1178,7 @@ func (b Bot) Copy() Form { return MakeBot(b.Get func (Bot) Equals(f any) bool { _, isBot := f.(Bot); return isBot } func (Bot) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } func (b Bot) ReplaceTermByTerm(Term, Term) (Form, bool) { return MakeBot(b.GetIndex()), false } -func (b Bot) SubstTy(TyBound, Ty) Form { return b } +func (b Bot) SubstTy(TyGenVar, Ty) Form { return b } func (b Bot) RenameVariables() Form { return MakeBot(b.GetIndex()) } func (b Bot) GetIndex() int { return b.index } func (b Bot) GetSubTerms() Lib.List[Term] { return Lib.NewList[Term]() } diff --git a/src/AST/formula.go b/src/AST/formula.go index 16ce1051..dc14eff9 100644 --- a/src/AST/formula.go +++ b/src/AST/formula.go @@ -54,7 +54,7 @@ type Form interface { MappableString ReplaceTermByTerm(old Term, new Term) (Form, bool) - SubstTy(old TyBound, new Ty) Form + SubstTy(old TyGenVar, new Ty) Form RenameVariables() Form SubstituteVarByMeta(old Var, new Meta) Form ReplaceMetaByTerm(meta Meta, term Term) Form @@ -136,7 +136,7 @@ func replaceTermInFormList(oldForms Lib.List[Form], oldTerm Term, newTerm Term) return newForms, res } -func replaceTyVarInFormList(oldForms Lib.List[Form], old TyBound, new Ty) Lib.List[Form] { +func replaceTyVarInFormList(oldForms Lib.List[Form], old TyGenVar, new Ty) Lib.List[Form] { return Lib.ListMap( oldForms, func(f Form) Form { return f.SubstTy(old, new) }, diff --git a/src/AST/quantifiers.go b/src/AST/quantifiers.go index e27c2aca..5ceabff2 100644 --- a/src/AST/quantifiers.go +++ b/src/AST/quantifiers.go @@ -160,7 +160,7 @@ func (q quantifier) replaceTermByTerm(old Term, new Term) (quantifier, bool) { ), res } -func (q quantifier) replaceTyVar(old TyBound, new Ty) quantifier { +func (q quantifier) replaceTyVar(old TyGenVar, new Ty) quantifier { f := q.GetForm().SubstTy(old, new) return makeQuantifier( q.GetIndex(), diff --git a/src/AST/term.go b/src/AST/term.go index 447728d5..116efe92 100644 --- a/src/AST/term.go +++ b/src/AST/term.go @@ -53,7 +53,7 @@ type Term interface { GetMetaList() Lib.List[Meta] // Metas appearing in the term ORDERED GetSubTerms() Lib.List[Term] ReplaceSubTermBy(original_term, new_term Term) Term - SubstTy(old TyBound, new Ty) Term + SubstTy(old TyGenVar, new Ty) Term Less(any) bool } diff --git a/src/AST/termsDef.go b/src/AST/termsDef.go index 93d6e173..beade5e8 100644 --- a/src/AST/termsDef.go +++ b/src/AST/termsDef.go @@ -111,7 +111,7 @@ func (i Id) ReplaceSubTermBy(original_term, new_term Term) Term { return i } -func (i Id) SubstTy(TyBound, Ty) Term { return i } +func (i Id) SubstTy(TyGenVar, Ty) Term { return i } func (i Id) GetSubTerms() Lib.List[Term] { return Lib.MkListV[Term](i) @@ -277,7 +277,7 @@ func (f Fun) ReplaceSubTermBy(oldTerm, newTerm Term) Term { } } -func (f Fun) SubstTy(old TyBound, new Ty) Term { +func (f Fun) SubstTy(old TyGenVar, new Ty) Term { typed_args := Lib.ListMap( f.tys, func(t Ty) Ty { return t.SubstTy(old, new) }, @@ -364,7 +364,7 @@ func (v Var) ReplaceSubTermBy(original_term, new_term Term) Term { return v } -func (v Var) SubstTy(TyBound, Ty) Term { return v } +func (v Var) SubstTy(TyGenVar, Ty) Term { return v } func (v Var) ToMappedString(map_ MapString, type_ bool) string { return v.GetName() @@ -454,7 +454,7 @@ func (m Meta) ReplaceSubTermBy(original_term, new_term Term) Term { return m } -func (m Meta) SubstTy(TyBound, Ty) Term { return m } +func (m Meta) SubstTy(TyGenVar, Ty) Term { return m } func (m Meta) GetSubTerms() Lib.List[Term] { return Lib.MkListV[Term](m) @@ -471,8 +471,7 @@ func (m Meta) Less(u any) bool { } func MakeEmptyMeta() Meta { - // FIXME: nil are bad - return MakeMeta(-1, -1, "-1", -1, nil) + return MakeMeta(-1, -1, "-1", -1, TIndividual()) } func MetaEquals(x, y Meta) bool { diff --git a/src/AST/ty-syntax.go b/src/AST/ty-syntax.go index 1571ea14..8df32395 100644 --- a/src/AST/ty-syntax.go +++ b/src/AST/ty-syntax.go @@ -48,12 +48,16 @@ import ( var meta_mut sync.Mutex var count_meta int +type TyGenVar interface { + isGenVar() +} + type Ty interface { isTy() ToString() string Equals(any) bool Copy() Ty - SubstTy(TyBound, Ty) Ty + SubstTy(TyGenVar, Ty) Ty } // Internal, shouldn't get out so no upper case @@ -71,7 +75,7 @@ func (v tyVar) Equals(oth any) bool { } func (v tyVar) Copy() Ty { return tyVar{v.repr} } -func (v tyVar) SubstTy(TyBound, Ty) Ty { return v } +func (v tyVar) SubstTy(TyGenVar, Ty) Ty { return v } type TyBound struct { name string @@ -79,6 +83,7 @@ type TyBound struct { } func (TyBound) isTy() {} +func (TyBound) isGenVar() {} func (b TyBound) ToString() string { return b.name } func (b TyBound) Equals(oth any) bool { if bv, ok := oth.(TyBound); ok { @@ -89,7 +94,7 @@ func (b TyBound) Equals(oth any) bool { func (b TyBound) Copy() Ty { return TyBound{b.name, b.index} } func (b TyBound) GetName() string { return b.name } -func (b TyBound) SubstTy(old TyBound, new Ty) Ty { +func (b TyBound) SubstTy(old TyGenVar, new Ty) Ty { if b.Equals(old) { return new } @@ -97,21 +102,38 @@ func (b TyBound) SubstTy(old TyBound, new Ty) Ty { } type TyMeta struct { - name string - index int + name string + index int + formula int // for compatibility with term metas } func (TyMeta) isTy() {} +func (TyMeta) isGenVar() {} func (m TyMeta) ToString() string { return fmt.Sprintf("%s_%d", m.name, m.index) } func (m TyMeta) Equals(oth any) bool { if om, ok := oth.(TyMeta); ok { - return m.name == om.name + return m.name == om.name && m.index == om.index } return false } -func (m TyMeta) Copy() Ty { return TyMeta{m.name, m.index} } +func (m TyMeta) Copy() Ty { return TyMeta{m.name, m.index, m.formula} } + +func (m TyMeta) SubstTy(v TyGenVar, new Ty) Ty { + if m.Equals(v) { + return new + } + return m +} -func (m TyMeta) SubstTy(TyBound, Ty) Ty { return m } +func (m TyMeta) ToTermMeta() Meta { return MakeMeta(m.index, -1, m.name, m.formula, tType) } + +func TyMetaFromMeta(m Meta) TyMeta { + return TyMeta{ + m.name, + m.index, + m.formula, + } +} // Type constructors, e.g., list, option, ... // Include constants, e.g., $i, $o, ... @@ -149,7 +171,7 @@ func (c TyConstr) Args() Lib.List[Ty] { return c.args } -func (c TyConstr) SubstTy(old TyBound, new Ty) Ty { +func (c TyConstr) SubstTy(old TyGenVar, new Ty) Ty { return TyConstr{ c.symbol, Lib.ListMap(c.args, func(t Ty) Ty { return t.SubstTy(old, new) }), @@ -181,7 +203,7 @@ func (p TyProd) Copy() Ty { return TyProd{Lib.ListCpy(p.args)} } -func (p TyProd) SubstTy(old TyBound, new Ty) Ty { +func (p TyProd) SubstTy(old TyGenVar, new Ty) Ty { return TyProd{ Lib.ListMap(p.args, func(t Ty) Ty { return t.SubstTy(old, new) }), } @@ -206,7 +228,7 @@ func (f TyFunc) Copy() Ty { return TyFunc{f.in.Copy(), f.out.Copy()} } -func (f TyFunc) SubstTy(old TyBound, new Ty) Ty { +func (f TyFunc) SubstTy(old TyGenVar, new Ty) Ty { return TyFunc{f.in.SubstTy(old, new), f.out.SubstTy(old, new)} } @@ -232,10 +254,14 @@ func (p TyPi) Copy() Ty { return TyPi{p.vars.Copy(func(x string) string { return x }), p.ty.Copy()} } -func (p TyPi) SubstTy(old TyBound, new Ty) Ty { +func (p TyPi) SubstTy(old TyGenVar, new Ty) Ty { return TyPi{p.vars, p.ty.SubstTy(old, new)} } +func (p TyPi) VarsLen() int { + return p.vars.Len() +} + // Makers func MkTyVar(repr string) Ty { @@ -246,9 +272,9 @@ func MkTyBV(name string, index int) Ty { return TyBound{name, index} } -func MkTyMeta(name string) Ty { +func MkTyMeta(name string, formula int) Ty { meta_mut.Lock() - meta := TyMeta{name, count_meta} + meta := TyMeta{name, count_meta, formula} count_meta += 1 meta_mut.Unlock() return meta @@ -402,3 +428,40 @@ func GetOutTy(ty Ty) Ty { ) return nil } + +func TyToTerm(ty Ty) Term { + switch nty := ty.(type) { + case TyMeta: + return nty.ToTermMeta() + case TyConstr: + return MakerFun( + MakerId(nty.symbol), + Lib.NewList[Ty](), + Lib.ListMap(nty.args, TyToTerm), + ) + } + + Glob.Anomaly( + "AST.Ty", + fmt.Sprintf("Trying to convert the non-atomic (or bound var) type %s to a term", ty.ToString()), + ) + return nil +} + +func TermToTy(trm Term) Ty { + switch t := trm.(type) { + case Meta: + return TyMetaFromMeta(t) + case Fun: + return MkTyConstr( + t.GetID().name, + Lib.ListMap(t.args, TermToTy), + ) + } + + Glob.Anomaly( + "AST.Ty", + fmt.Sprintf("Trying to convert the non-atomic (or bound var) term %s to a type", trm.ToString()), + ) + return nil +} diff --git a/src/AST/typed-vars.go b/src/AST/typed-vars.go index d1bea6af..d3e42e6c 100644 --- a/src/AST/typed-vars.go +++ b/src/AST/typed-vars.go @@ -82,7 +82,7 @@ func (v TypedVar) ToTyBoundVar() TyBound { return MkTyBV(v.name, v.index).(TyBound) } -func (v TypedVar) SubstTy(old TyBound, new Ty) TypedVar { +func (v TypedVar) SubstTy(old TyGenVar, new Ty) TypedVar { return TypedVar{v.name, v.index, v.ty.SubstTy(old, new)} } diff --git a/src/Core/FormListDS.go b/src/Core/FormListDS.go index 8022fe82..f9017fa1 100644 --- a/src/Core/FormListDS.go +++ b/src/Core/FormListDS.go @@ -82,11 +82,11 @@ func (fl FormListDS) IsEmpty() bool { return fl.GetFL().Empty() } -func (fl FormListDS) Unify(f AST.Form) (bool, []Unif.MatchingSubstitutions) { +func (fl FormListDS) Unify(f AST.Form) (bool, []Unif.MixedSubstitutions) { for _, element := range fl.GetFL().GetSlice() { if element.Equals(f) { - return true, []Unif.MatchingSubstitutions{} + return true, []Unif.MixedSubstitutions{} } } - return false, []Unif.MatchingSubstitutions{} + return false, []Unif.MixedSubstitutions{} } diff --git a/src/Core/global_unifier.go b/src/Core/global_unifier.go index 3657dca0..aea67a62 100644 --- a/src/Core/global_unifier.go +++ b/src/Core/global_unifier.go @@ -41,7 +41,7 @@ import ( "github.com/GoelandProver/Goeland/Unif" ) -type substitutions = Unif.Substitutions +type substitutions = Lib.List[Unif.MixedSubstitution] /* - The unifier type is a type that keeps the substitutions that close the whole subtree. @@ -86,7 +86,7 @@ func (u *Unifier) AddSubstitutions(cleanedSubst, actualSubst substitutions) { } found := false for i, p := range u.localUnifiers { - if p.Fst.Equals(cleanedSubst) { + if Lib.ListEquals(p.Fst, cleanedSubst) { u.localUnifiers[i].Snd = append(u.localUnifiers[i].Snd, actualSubst) found = true } @@ -102,8 +102,8 @@ func (u *Unifier) PruneUncompatibleSubstitutions(subst substitutions) { } res := make([]Glob.Pair[substitutions, []substitutions], 0) for _, p := range u.localUnifiers { - compat, _ := Unif.MergeSubstitutions(subst, p.Fst) - if !compat.Equals(Unif.Failure()) { + _, succeeded := Unif.MergeMixedSubstitutions(subst, p.Fst) + if succeeded { res = append(res, p) } } @@ -115,29 +115,34 @@ func (u Unifier) IsEmpty() bool { } func (u Unifier) ToString() string { - substsToString := func(index int, element Unif.Substitution) string { - return fmt.Sprintf("(%s -> %s)", element.Key().ToString(), element.Value().ToString()) - } str := "object Unifier{" for _, unifier := range u.localUnifiers { - str += "[ " + strings.Join(Glob.MapTo(unifier.Fst, substsToString), ", ") + " ] --> [ " + strings.Join(Glob.MapTo(unifier.Snd, func(_ int, el substitutions) string { - return strings.Join(Glob.MapTo(el, substsToString), " ; ") - }), " ---- ") + " ], " + str += fmt.Sprintf( + "[ %s ] --> [ %s ]", + Lib.ListToString(unifier.Fst, Lib.WithEmpty("")), + strings.Join(Glob.MapTo( + unifier.Snd, + func(_ int, el substitutions) string { + return Lib.ListToString(el, Lib.WithEmpty("")) + }), + " ; ", + ), + ) } str += "}" return str } /** Returns a global unifier: MGU of all the unifiers found */ -func (u Unifier) GetUnifier() Unif.Substitutions { +func (u Unifier) GetUnifier() substitutions { if !Glob.GetProof() || len(u.localUnifiers) == 0 { - return Unif.MakeEmptySubstitution() + return Lib.NewList[Unif.MixedSubstitution]() } debug(Lib.MkLazy(func() string { return u.ToString() })) if len(u.localUnifiers) > 0 && len(u.localUnifiers[0].Snd) > 0 { return u.localUnifiers[0].Snd[0] } - return Unif.MakeEmptySubstitution() + return Lib.NewList[Unif.MixedSubstitution]() } func (u Unifier) Copy() Unifier { @@ -148,9 +153,9 @@ func (u Unifier) Copy() Unifier { for i, unif := range u.localUnifiers { copy := []substitutions{} for _, subst := range unif.Snd { - copy = append(copy, subst.Copy()) + copy = append(copy, Lib.ListCpy(subst)) } - newLocalUnifier[i] = Glob.MakePair(unif.Fst.Copy(), copy) + newLocalUnifier[i] = Glob.MakePair(Lib.ListCpy(unif.Fst), copy) } return Unifier{ localUnifiers: newLocalUnifier, @@ -178,12 +183,12 @@ func (u *Unifier) Merge(other Unifier) { for _, locUnif := range u.localUnifiers { for _, unifier := range other.localUnifiers { newUnifs := []substitutions{} - res, _ := Unif.MergeSubstitutions(unifier.Fst.Copy(), locUnif.Fst.Copy()) - if !res.Equals(Unif.Failure()) { + res, succeeded := Unif.MergeMixedSubstitutions(unifier.Fst, locUnif.Fst) + if succeeded { for _, subst := range locUnif.Snd { for _, s := range unifier.Snd { - merge, _ := Unif.MergeSubstitutions(subst.Copy(), s.Copy()) - if !merge.Equals(Unif.Failure()) { + merge, success := Unif.MergeMixedSubstitutions(subst, s) + if success { newUnifs = append(newUnifs, merge) } } @@ -199,9 +204,18 @@ func (u *Unifier) Merge(other Unifier) { func (u *Unifier) PruneMetasInSubsts(metas Lib.Set[AST.Meta]) { for i, unif := range u.localUnifiers { for _, meta := range metas.Elements().GetSlice() { - _, index := unif.Fst.Get(meta) - if index != -1 { - u.localUnifiers[i].Fst.Remove(index) + index := Lib.MkNone[int]() + for j, subst := range unif.Fst.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + if s.Val.Key().Equals(meta) { + index = Lib.MkSome(j) + } + } + } + switch id := index.(type) { + case Lib.Some[int]: + u.localUnifiers[i].Fst.RemoveAt(id.Val) } } } @@ -214,7 +228,7 @@ func (u *Unifier) PruneMetasInSubsts(metas Lib.Set[AST.Meta]) { func appendNewUnifiersIfNeeded(unifiers []Glob.Pair[substitutions, []substitutions], res substitutions, newUnifs []substitutions) []Glob.Pair[substitutions, []substitutions] { for i, unif := range unifiers { - if unif.Fst.Equals(res) { + if Lib.ListEquals(unif.Fst, res) { unifiers[i].Snd = append(unifiers[i].Snd, newUnifs...) return unifiers } diff --git a/src/Core/instanciation.go b/src/Core/instanciation.go index 81cc93aa..4b1373b3 100644 --- a/src/Core/instanciation.go +++ b/src/Core/instanciation.go @@ -82,7 +82,7 @@ func RealInstantiate( var m Lib.Option[AST.Meta] if AST.IsTType(v.GetTy()) { - meta := AST.MkTyMeta(strings.ToUpper(v.GetName())) + meta := AST.MkTyMeta(strings.ToUpper(v.GetName()), index) subForm = subForm.SubstTy(v.ToTyBoundVar(), meta) m = Lib.MkNone[AST.Meta]() } else { diff --git a/src/Core/int_subst_and_form.go b/src/Core/int_subst_and_form.go index 5c0b9c72..3dd0d90e 100644 --- a/src/Core/int_subst_and_form.go +++ b/src/Core/int_subst_and_form.go @@ -81,8 +81,8 @@ func (s IntSubstAndForm) Copy() IntSubstAndForm { func (s IntSubstAndForm) ToString() string { res := "{ " + strconv.Itoa(s.GetId_rewrite()) + " - " - if !s.GetSaf().GetSubst().IsEmpty() { - res += s.GetSaf().GetSubst().ToString() + if !s.GetSaf().GetSubst().Empty() { + res += Lib.ListToString(s.GetSaf().GetSubst()) } res += " - " if !s.GetSaf().GetForm().Empty() { @@ -128,8 +128,8 @@ func CopyIntSubstAndFormList(sl []IntSubstAndForm) []IntSubstAndForm { } /* Get a subst list from SubstAndForm lsit */ -func GetSubstListFromIntSubstAndFormList(l []IntSubstAndForm) []Unif.Substitutions { - res := []Unif.Substitutions{} +func GetSubstListFromIntSubstAndFormList(l []IntSubstAndForm) []Lib.List[Unif.MixedSubstitution] { + res := []Lib.List[Unif.MixedSubstitution]{} for _, saf := range l { res = append(res, saf.GetSaf().GetSubst()) } diff --git a/src/Core/subst_and_form.go b/src/Core/subst_and_form.go index 1e869e4b..e43c4ac0 100644 --- a/src/Core/subst_and_form.go +++ b/src/Core/subst_and_form.go @@ -48,27 +48,27 @@ import ( /* Stock the substitution and the corresponding list of formulas */ type SubstAndForm struct { - s Unif.Substitutions + s Lib.List[Unif.MixedSubstitution] f Lib.List[AST.Form] } -func (s SubstAndForm) GetSubst() Unif.Substitutions { - return s.s.Copy() +func (s SubstAndForm) GetSubst() Lib.List[Unif.MixedSubstitution] { + return Lib.ListCpy(s.s) } func (s SubstAndForm) GetForm() Lib.List[AST.Form] { return Lib.ListCpy(s.f) } -func (s *SubstAndForm) SetSubst(subst Unif.Substitutions) { - s.s = subst.Copy() +func (s *SubstAndForm) SetSubst(subst Lib.List[Unif.MixedSubstitution]) { + s.s = Lib.ListCpy(subst) } func (s *SubstAndForm) SetForm(form Lib.List[AST.Form]) { s.f = Lib.ListCpy(form) } func (saf SubstAndForm) IsEmpty() bool { - return saf.s.IsEmpty() && saf.f.Empty() + return saf.s.Empty() && saf.f.Empty() } func (s1 SubstAndForm) Equals(s2 SubstAndForm) bool { - return s1.GetSubst().Equals(s2.GetSubst()) && + return Lib.ListEquals(s1.GetSubst(), s2.GetSubst()) && Lib.ListEquals(s1.GetForm(), s2.GetForm()) } func (s SubstAndForm) Copy() SubstAndForm { @@ -80,8 +80,8 @@ func (s SubstAndForm) Copy() SubstAndForm { } func (s SubstAndForm) ToString() string { res := "{ " - if !s.GetSubst().IsEmpty() { - res += s.GetSubst().ToString() + if !s.GetSubst().Empty() { + res += Lib.ListToString(s.GetSubst()) } res += " - " if !s.GetForm().Empty() { @@ -92,11 +92,11 @@ func (s SubstAndForm) ToString() string { return res } -func MakeSubstAndForm(subst Unif.Substitutions, form Lib.List[AST.Form]) SubstAndForm { - return SubstAndForm{subst.Copy(), Lib.ListCpy(form)} +func MakeSubstAndForm(subst Lib.List[Unif.MixedSubstitution], form Lib.List[AST.Form]) SubstAndForm { + return SubstAndForm{Lib.ListCpy(subst), Lib.ListCpy(form)} } func MakeEmptySubstAndForm() SubstAndForm { - return SubstAndForm{Unif.MakeEmptySubstitution(), Lib.NewList[AST.Form]()} + return SubstAndForm{Lib.NewList[Unif.MixedSubstitution](), Lib.NewList[AST.Form]()} } func (s SubstAndForm) AddFormulas(fl Lib.List[AST.Form]) SubstAndForm { formList := s.GetForm() @@ -105,21 +105,15 @@ func (s SubstAndForm) AddFormulas(fl Lib.List[AST.Form]) SubstAndForm { } /* Remove empty substitution from a substitution list */ -func RemoveEmptySubstFromSubstList(sl []Unif.Substitutions) []Unif.Substitutions { - res := []Unif.Substitutions{} - for _, s := range sl { - if !(s.IsEmpty()) { - res = append(res, s) - } - } - return res +func RemoveEmptySubstFromSubstList(sl Lib.List[Lib.List[Unif.MixedSubstitution]]) Lib.List[Lib.List[Unif.MixedSubstitution]] { + return sl.Filter(func(l Lib.List[Unif.MixedSubstitution]) bool { return !l.Empty() }) } /* Remove empty substitution from a substitution list */ func RemoveEmptySubstFromSubstAndFormList(sl []SubstAndForm) []SubstAndForm { res := []SubstAndForm{} for _, s := range sl { - if !(s.GetSubst().IsEmpty()) { + if !(s.GetSubst().Empty()) { res = append(res, s) } } @@ -127,10 +121,10 @@ func RemoveEmptySubstFromSubstAndFormList(sl []SubstAndForm) []SubstAndForm { } /* Get a subst list from SubstAndForm lsit */ -func GetSubstListFromSubstAndFormList(l []SubstAndForm) []Unif.Substitutions { - res := []Unif.Substitutions{} +func GetSubstListFromSubstAndFormList(l []SubstAndForm) Lib.List[Lib.List[Unif.MixedSubstitution]] { + res := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() for _, saf := range l { - res = append(res, saf.GetSubst()) + res.Append(saf.GetSubst()) } return res } @@ -197,9 +191,9 @@ func MergeSubstAndForm(s1, s2 SubstAndForm) (error, SubstAndForm) { return nil, s1 } - new_subst, _ := Unif.MergeSubstitutions(s1.GetSubst().Copy(), s2.GetSubst().Copy()) + new_subst, succeeded := Unif.MergeMixedSubstitutions(s1.GetSubst(), s2.GetSubst()) - if new_subst.Equals(Unif.Failure()) { + if !succeeded { Glob.Anomaly("MSAF", fmt.Sprintf("Error : MergeSubstitutions returns failure between : %v and %v \n", s1.ToString(), s2.ToString())) return errors.New("Couldn't merge two substitutions"), MakeEmptySubstAndForm() } diff --git a/src/Core/subst_and_form_and_terms.go b/src/Core/subst_and_form_and_terms.go index 0b72fe73..3268db17 100644 --- a/src/Core/subst_and_form_and_terms.go +++ b/src/Core/subst_and_form_and_terms.go @@ -37,32 +37,33 @@ package Core import ( + "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Unif" ) /* Stock the substitution and the corresponding list of formulas */ type SubstAndFormAndTerms struct { - s Unif.Substitutions + s Lib.List[Unif.MixedSubstitution] f FormAndTermsList } -func (s SubstAndFormAndTerms) GetSubst() Unif.Substitutions { - return s.s.Copy() +func (s SubstAndFormAndTerms) GetSubst() Lib.List[Unif.MixedSubstitution] { + return Lib.ListCpy(s.s) } func (s SubstAndFormAndTerms) GetForm() FormAndTermsList { return s.f.Copy() } -func (s *SubstAndFormAndTerms) SetSubst(subst Unif.Substitutions) { - s.s = subst.Copy() +func (s *SubstAndFormAndTerms) SetSubst(subst Lib.List[Unif.MixedSubstitution]) { + s.s = Lib.ListCpy(subst) } func (s *SubstAndFormAndTerms) SetForm(form FormAndTermsList) { s.f = form.Copy() } func (saf SubstAndFormAndTerms) IsEmpty() bool { - return saf.s.IsEmpty() && saf.f.IsEmpty() + return saf.s.Empty() && saf.f.IsEmpty() } func (s1 SubstAndFormAndTerms) Equals(s2 SubstAndFormAndTerms) bool { - return s1.GetSubst().Equals(s2.GetSubst()) && s1.GetForm().Equals(s2.GetForm()) + return Lib.ListEquals(s1.GetSubst(), s2.GetSubst()) && s1.GetForm().Equals(s2.GetForm()) } func (s SubstAndFormAndTerms) Copy() SubstAndFormAndTerms { if s.IsEmpty() { @@ -80,8 +81,8 @@ func (s SubstAndFormAndTerms) ToSubstAndForm() SubstAndForm { } func (s SubstAndFormAndTerms) ToString() string { res := "{ " - if !s.GetSubst().IsEmpty() { - res += s.GetSubst().ToString() + if !s.GetSubst().Empty() { + res += Lib.ListToString(s.GetSubst()) } res += " - " if !s.GetForm().IsEmpty() { @@ -92,11 +93,11 @@ func (s SubstAndFormAndTerms) ToString() string { return res } -func MakeSubstAndFormAndTerms(subst Unif.Substitutions, form FormAndTermsList) SubstAndFormAndTerms { - return SubstAndFormAndTerms{subst.Copy(), form.Copy()} +func MakeSubstAndFormAndTerms(subst Lib.List[Unif.MixedSubstitution], form FormAndTermsList) SubstAndFormAndTerms { + return SubstAndFormAndTerms{Lib.ListCpy(subst), form.Copy()} } func MakeEmptySubstAndFormAndTerms() SubstAndFormAndTerms { - return SubstAndFormAndTerms{Unif.MakeEmptySubstitution(), FormAndTermsList{}} + return SubstAndFormAndTerms{Lib.NewList[Unif.MixedSubstitution](), FormAndTermsList{}} } /* Check if a substitution is inside a list of SubstAndForm */ diff --git a/src/Core/substitutions_search.go b/src/Core/substitutions_search.go index 6049da39..a12c709d 100644 --- a/src/Core/substitutions_search.go +++ b/src/Core/substitutions_search.go @@ -46,18 +46,21 @@ import ( ) /* Return the list of metavariable from a substitution */ -func GetMetaFromSubst(subs Unif.Substitutions) Lib.Set[AST.Meta] { +func GetMetaFromSubst(subs Lib.List[Unif.MixedSubstitution]) Lib.Set[AST.Meta] { res := Lib.EmptySet[AST.Meta]() - for _, singleSubs := range subs { - meta, term := singleSubs.Get() - res = res.Add(meta) + for _, singleSubs := range subs.GetSlice() { + switch s := singleSubs.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + meta, term := s.Val.Get() + res = res.Add(meta) - switch typedTerm := term.(type) { - case AST.Meta: - res = res.Add(typedTerm) - case AST.Fun: - res = res.Union(AST.GetMetasOfList(typedTerm.GetArgs())) + switch typedTerm := term.(type) { + case AST.Meta: + res = res.Add(typedTerm) + case AST.Fun: + res = res.Union(AST.GetMetasOfList(typedTerm.GetArgs())) + } } } @@ -65,7 +68,10 @@ func GetMetaFromSubst(subs Unif.Substitutions) Lib.Set[AST.Meta] { } /* Remove substitution without mm */ -func RemoveElementWithoutMM(subs Unif.Substitutions, mm Lib.Set[AST.Meta]) Unif.Substitutions { +func RemoveElementWithoutMM( + subs Lib.List[Unif.MixedSubstitution], + mm Lib.Set[AST.Meta], +) Lib.List[Unif.MixedSubstitution] { debug(Lib.MkLazy(func() string { return fmt.Sprintf( "MM : %v", @@ -74,8 +80,8 @@ func RemoveElementWithoutMM(subs Unif.Substitutions, mm Lib.Set[AST.Meta]) Unif. })) res := Unif.Substitutions{} + subst_to_reorganize := Unif.Substitutions{} - subsToReorganize := Unif.Substitutions{} relevantMetas := mm.Copy() hasChanged := true @@ -87,50 +93,55 @@ func RemoveElementWithoutMM(subs Unif.Substitutions, mm Lib.Set[AST.Meta]) Unif. Lib.ListToString(relevantMetas.Elements()), ) })) - for _, singleSubs := range subs { - meta, term := singleSubs.Get() - - switch typedTerm := term.(type) { - case AST.Meta: - switch { - case relevantMetas.Contains(meta) && - relevantMetas.Contains(typedTerm): - res.Set(meta, typedTerm) - - case relevantMetas.Contains(meta) && - relevantMetas.Contains(typedTerm): - subsToReorganize.Set(meta, typedTerm) - } + for _, singleSubs := range subs.GetSlice() { + switch single_subst := singleSubs.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + meta, term := single_subst.Val.Get() + + switch typedTerm := term.(type) { + case AST.Meta: + if relevantMetas.Contains(meta) && + relevantMetas.Contains(typedTerm) { + subst_to_reorganize.Set(meta, typedTerm) + res.Set(meta, typedTerm) + } - default: - if relevantMetas.Contains(meta) { - res.Set(meta, term) - for _, candidateMeta := range term.GetMetas().Elements().GetSlice() { - if !relevantMetas.Contains(candidateMeta) { - hasChanged = true + default: + if relevantMetas.Contains(meta) { + res.Set(meta, term) + for _, candidateMeta := range term.GetMetas().Elements().GetSlice() { + if !relevantMetas.Contains(candidateMeta) { + hasChanged = true + } } + relevantMetas = relevantMetas.Union(term.GetMetas()) } - relevantMetas = relevantMetas.Union(term.GetMetas()) } } } } debug( - Lib.MkLazy(func() string { return fmt.Sprintf("Subst intermédiaire res : %v", res.ToString()) }), + Lib.MkLazy(func() string { + return fmt.Sprintf( + "Intermediary subst res : %s", + res.ToString(), + ) + }), ) debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Subst intermédiaire subst_to_reorganize : %v", - subsToReorganize.ToString()) + "Intermediary subst subst_to_reorganize : %s", + subst_to_reorganize.ToString(), + ) }), ) - subsToReorganize = ReorganizeSubstitution(subsToReorganize) - Unif.EliminateMeta(&subsToReorganize) - Unif.Eliminate(&subsToReorganize) - ms, _ := Unif.MergeSubstitutions(res, subsToReorganize) + subst_to_reorganize = ReorganizeSubstitution(subst_to_reorganize) + Unif.EliminateMeta(&subst_to_reorganize) + Unif.Eliminate(&subst_to_reorganize) + ms, _ := Unif.MergeSubstitutions(res, subst_to_reorganize) debug( Lib.MkLazy(func() string { return fmt.Sprintf("Finale subst : %v", ms.ToString()) }), @@ -140,13 +151,25 @@ func RemoveElementWithoutMM(subs Unif.Substitutions, mm Lib.Set[AST.Meta]) Unif. Glob.Anomaly("REWM", "MergeSubstitutions returns failure") } - return ms + result := Lib.NewList[Unif.MixedSubstitution]() + for _, unif := range ms { + result.Append(Unif.MkMixedFromSubst(unif)) + } + + for _, s := range subs.GetSlice() { + switch subst := s.TySubstitution().(type) { + case Lib.Some[Unif.TySubstitution]: + result.Append(Unif.MkMixedFromTy(subst.Val)) + } + } + return result } -/* * -* Take a substitution wich conatins elements like (meta_mother, meta_current), returning only relevante substitution like (meta_mother, meta_mother) -* (X, X2) (Y, X2) -> (X, Y) +/** + * Take a substitution wich conatins elements like (meta_mother, meta_current), returning only + * relevant substitutions like (meta_mother, meta_mother) + * e.g., (X, X2) (Y, X2) -> (X, Y) **/ func ReorganizeSubstitution(subs Unif.Substitutions) Unif.Substitutions { res := Unif.Substitutions{} @@ -172,16 +195,22 @@ func ReorganizeSubstitution(subs Unif.Substitutions) Unif.Substitutions { } /* Check if a substitution contains a metavirbale which is inside a given list of metavariable (check for the key, not the value) */ -func ContainsMetaMother(s Unif.Substitutions, mm Lib.Set[AST.Meta]) bool { - for _, subst := range s { - k, v := subst.Get() - if mm.Contains(k) { +func ContainsMetaMother(s Lib.List[Unif.MixedSubstitution], mm Lib.Set[AST.Meta]) bool { + for _, subst := range s.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.None[Unif.Substitution]: + // In this case, [s] is a TySubstitution and hence it always contains a meta from the top level return true - } else { - switch vtype := v.(type) { - case AST.Meta: - if mm.Contains(vtype) { - return true + case Lib.Some[Unif.Substitution]: + k, v := s.Val.Get() + if mm.Contains(k) { + return true + } else { + switch vtype := v.(type) { + case AST.Meta: + if mm.Contains(vtype) { + return true + } } } } @@ -218,7 +247,7 @@ func ApplySubstitutionOnTerm(old_symbol AST.Meta, new_symbol, t AST.Term) AST.Te /* Apply substitutions on a list of terms */ func ApplySubstitutionsOnTermList( - s Unif.Substitutions, + s Lib.List[Unif.MixedSubstitution], tl Lib.List[AST.Term], ) Lib.List[AST.Term] { res := Lib.MkList[AST.Term](tl.Len()) @@ -231,17 +260,23 @@ func ApplySubstitutionsOnTermList( return res } -func ApplySubstitutionsOnTerm(s Unif.Substitutions, t AST.Term) AST.Term { - if t != nil { - term_res := t.Copy() - for _, subst := range s { - old_symbol, new_symbol := subst.Get() - term_res = ApplySubstitutionOnTerm(old_symbol, new_symbol, term_res) +func ApplySubstitutionsOnTerm(substs Lib.List[Unif.MixedSubstitution], t AST.Term) AST.Term { + if t == nil { + return t + } + + for _, subst := range substs.GetSlice() { + switch s := subst.GetMixed().(type) { + case Lib.Left[Unif.TySubstitution, Unif.Substitution]: + meta, ty := s.Val.Get() + t = t.SubstTy(meta, ty) + case Lib.Right[Unif.TySubstitution, Unif.Substitution]: + meta, term := s.Val.Get() + t = t.ReplaceSubTermBy(meta, term) } - return term_res - } else { - return nil } + + return t } /* Apply substElement on a term list */ @@ -259,63 +294,29 @@ func ApplySubstitutionOnTermList( return res } -/* Apply a substitution on a formula */ -func ApplySubstitutionOnFormula(old_symbol AST.Meta, new_symbol AST.Term, f AST.Form) AST.Form { - var res AST.Form - - switch nf := f.(type) { - case AST.Pred: - res = AST.MakePred( - nf.GetIndex(), - nf.GetID(), - nf.GetTyArgs(), - ApplySubstitutionOnTermList(old_symbol, new_symbol, nf.GetArgs()), - ) - case AST.Not: - res = AST.MakeNot(f.GetIndex(), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetForm())) - case AST.And: - res_tmp := Lib.NewList[AST.Form]() - for _, val := range nf.GetChildFormulas().GetSlice() { - res_tmp.Append(ApplySubstitutionOnFormula(old_symbol, new_symbol, val)) - } - res = AST.MakeAnd(f.GetIndex(), res_tmp) - case AST.Or: - res_tmp := Lib.NewList[AST.Form]() - for _, val := range nf.GetChildFormulas().GetSlice() { - res_tmp.Append(ApplySubstitutionOnFormula(old_symbol, new_symbol, val)) - } - res = AST.MakeOr(f.GetIndex(), res_tmp) - case AST.Imp: - res = AST.MakeImp(f.GetIndex(), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetF1()), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetF2())) - case AST.Equ: - res = AST.MakeEqu(f.GetIndex(), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetF1()), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetF2())) - case AST.Ex: - res = AST.MakeEx(f.GetIndex(), nf.GetVarList(), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetForm())) - case AST.All: - res = AST.MakeAll(f.GetIndex(), nf.GetVarList(), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetForm())) - default: - res = f +/* Apply substitutions on Formula */ +func ApplySubstitutionsOnFormula(s Lib.List[Unif.MixedSubstitution], f AST.Form) AST.Form { + // FIXME: check that line, it shouldn't happen + if f == nil { + return f } - return res -} - -/* Apply substitutions on Formula */ -func ApplySubstitutionsOnFormula(s Unif.Substitutions, f AST.Form) AST.Form { - if f != nil { - form_res := f.Copy() - for _, subst := range s { - old_symbol, new_symbol := subst.Get() - form_res = ApplySubstitutionOnFormula(old_symbol, new_symbol, form_res) + for _, subst := range s.GetSlice() { + switch s := subst.GetMixed().(type) { + case Lib.Left[Unif.TySubstitution, Unif.Substitution]: + meta, ty := s.Val.Get() + f = f.SubstTy(meta, ty) + case Lib.Right[Unif.TySubstitution, Unif.Substitution]: + meta, term := s.Val.Get() + f = f.ReplaceMetaByTerm(meta, term) } - return form_res - } else { - return nil } + + return f } /* For each element of the substitution, apply it on the entire formula list */ -func ApplySubstitutionsOnFormulaList(s Unif.Substitutions, lf Lib.List[AST.Form]) Lib.List[AST.Form] { +func ApplySubstitutionsOnFormulaList(s Lib.List[Unif.MixedSubstitution], lf Lib.List[AST.Form]) Lib.List[AST.Form] { lf_res := Lib.NewList[AST.Form]() for _, f := range lf.GetSlice() { new_form := ApplySubstitutionsOnFormula(s, f) @@ -326,20 +327,12 @@ func ApplySubstitutionsOnFormulaList(s Unif.Substitutions, lf Lib.List[AST.Form] } /* Apply substitutions on FormAndTerm */ -func ApplySubstitutionsOnFormAndTerms(s Unif.Substitutions, fat FormAndTerms) FormAndTerms { - // if fat != FormAndTerms{} { - form_res := fat.GetForm() - tl_res := fat.GetTerms() - for _, subst := range s { - old_symbol, new_symbol := subst.Get() - form_res = ApplySubstitutionOnFormula(old_symbol, new_symbol, form_res) - //tl_res = ApplySubstitutionOnTermList(old_symbol, new_symbol, tl_res) - } - return MakeFormAndTerm(form_res, tl_res) +func ApplySubstitutionsOnFormAndTerms(s Lib.List[Unif.MixedSubstitution], fat FormAndTerms) FormAndTerms { + return MakeFormAndTerm(ApplySubstitutionsOnFormula(s, fat.GetForm()), fat.GetTerms()) } /* For each element of the substitution, apply it on the entire formAndTerms list */ -func ApplySubstitutionsOnFormAndTermsList(s Unif.Substitutions, lf FormAndTermsList) FormAndTermsList { +func ApplySubstitutionsOnFormAndTermsList(s Lib.List[Unif.MixedSubstitution], lf FormAndTermsList) FormAndTermsList { lf_res := MakeEmptyFormAndTermsList() for _, f := range lf { new_form := ApplySubstitutionsOnFormAndTerms(s, f) @@ -350,7 +343,7 @@ func ApplySubstitutionsOnFormAndTermsList(s Unif.Substitutions, lf FormAndTermsL } /* Apply a substitution on a metaGenerator list */ -func ApplySubstitutionOnMetaGenList(s Unif.Substitutions, lf []MetaGen) []MetaGen { +func ApplySubstitutionOnMetaGenList(s Lib.List[Unif.MixedSubstitution], lf []MetaGen) []MetaGen { lf_res := []MetaGen{} for _, f := range lf { new_form := ApplySubstitutionOnMetaGen(s, f) @@ -362,35 +355,35 @@ func ApplySubstitutionOnMetaGenList(s Unif.Substitutions, lf []MetaGen) []MetaGe } /* Apply a substitution on a metaGen form */ -func ApplySubstitutionOnMetaGen(s Unif.Substitutions, mg MetaGen) MetaGen { - form_res := mg.GetForm().GetForm() - terms_res := mg.GetForm().Terms - for _, subst := range s { - old_symbol, new_symbol := subst.Get() - form_res = ApplySubstitutionOnFormula(old_symbol, new_symbol, form_res) - terms_res = ApplySubstitutionOnTermList(old_symbol, new_symbol, terms_res) - } - return MakeMetaGen(MakeFormAndTerm(form_res, terms_res), mg.GetCounter()) +func ApplySubstitutionOnMetaGen(s Lib.List[Unif.MixedSubstitution], mg MetaGen) MetaGen { + return MakeMetaGen(MakeFormAndTerm( + ApplySubstitutionsOnFormula(s, mg.GetForm().GetForm()), + ApplySubstitutionsOnTermList(s, mg.f.GetTerms())), mg.GetCounter()) } /* Dispatch a list of substitution : containing mm or not */ -func DispatchSubst(subsList []Unif.Substitutions, mm Lib.Set[AST.Meta]) ([]Unif.Substitutions, []Unif.Substitutions, []Unif.Substitutions) { - var subsWithMM []Unif.Substitutions - var subsWithMMUncleared []Unif.Substitutions - var subsWithoutMM []Unif.Substitutions - - for _, subs := range subsList { +func DispatchSubst( + subsList Lib.List[Lib.List[Unif.MixedSubstitution]], + mm Lib.Set[AST.Meta], +) (Lib.List[Lib.List[Unif.MixedSubstitution]], + Lib.List[Lib.List[Unif.MixedSubstitution]], + Lib.List[Lib.List[Unif.MixedSubstitution]]) { + subsWithMM := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() + subsWithMMUncleared := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() + subsWithoutMM := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() + + for _, subs := range subsList.GetSlice() { removedSubs := subs if Glob.IsDestructive() { removedSubs = RemoveElementWithoutMM(subs, mm) } - if !removedSubs.IsEmpty() { - subsWithMM = Unif.AppendIfNotContainsSubst(subsWithMM, removedSubs) - subsWithMMUncleared = Unif.AppendIfNotContainsSubst(subsWithMMUncleared, subs) + if !removedSubs.Empty() { + subsWithMM.Add(Lib.ListEquals, removedSubs) + subsWithMMUncleared.Add(Lib.ListEquals, subs) } else { - subsWithoutMM = Unif.AppendIfNotContainsSubst(subsWithoutMM, subs) + subsWithoutMM.Add(Lib.ListEquals, subs) } } diff --git a/src/Lib/either.go b/src/Lib/either.go new file mode 100644 index 00000000..531524c3 --- /dev/null +++ b/src/Lib/either.go @@ -0,0 +1,103 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +package Lib + +import ( + "fmt" +) + +/* This file implements the Either type (sum type). */ + +type Either[A, B any] interface { + isEither() +} + +type Left[A, B any] struct { + Val A +} + +type Right[A, B any] struct { + Val B +} + +func (Left[A, B]) isEither() {} +func (Right[A, B]) isEither() {} + +func MkLeft[A, B any](x A) Either[A, B] { + return Left[A, B]{Val: x} +} + +func MkRight[A, B any](y B) Either[A, B] { + return Right[A, B]{Val: y} +} + +func EitherToString[A, B Stringable](u Either[A, B], left, right string) string { + switch x := u.(type) { + case Left[A, B]: + return fmt.Sprintf("%s(%s)", left, x.Val.ToString()) + case Right[A, B]: + return fmt.Sprintf("%s(%s)", right, x.Val.ToString()) + } + return "" +} + +func EitherEquals[A, B Comparable](u, v Either[A, B]) bool { + switch x := u.(type) { + case Left[A, B]: + switch y := v.(type) { + case Left[A, B]: + return x.Val.Equals(y.Val) + case Right[A, B]: + return false + } + case Right[A, B]: + switch y := v.(type) { + case Left[A, B]: + return false + case Right[A, B]: + return x.Val.Equals(y.Val) + } + } + + return false +} + +func EitherCpy[A Copyable[A], B Copyable[B]](u Either[A, B]) Either[A, B] { + switch x := u.(type) { + case Left[A, B]: + return MkLeft[A, B](x.Val.Copy()) + case Right[A, B]: + return MkRight[A, B](x.Val.Copy()) + } + return u +} diff --git a/src/Lib/list.go b/src/Lib/list.go index b0da6659..7ff93f3b 100644 --- a/src/Lib/list.go +++ b/src/Lib/list.go @@ -258,6 +258,16 @@ func (l List[T]) Any(pred Func[T, bool]) bool { return false } +func (l List[T]) Filter(pred Func[T, bool]) List[T] { + res := NewList[T]() + for _, el := range l.values { + if pred(el) { + res.Append(el) + } + } + return res +} + func ToStrictlyOrderedList[T StrictlyOrdered](l List[T]) StrictlyOrderedList[T] { return StrictlyOrderedList[T]{values: l} } diff --git a/src/Mods/assisted/assistant.go b/src/Mods/assisted/assistant.go index 46cc47cc..d3aa0480 100644 --- a/src/Mods/assisted/assistant.go +++ b/src/Mods/assisted/assistant.go @@ -38,6 +38,7 @@ import ( "github.com/GoelandProver/Goeland/Core" "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Search" "github.com/GoelandProver/Goeland/Unif" ) @@ -185,7 +186,8 @@ func selectStatus() int { func printFormListFromState(st *Search.State, id int) { fmt.Printf("\nState nº%d:\n", id) - printSubList("Applied subs", st.GetAppliedSubst().GetSubst()) + // FIXME: why is this all fmt.Printf? + fmt.Printf("Applied subs: %s", Lib.ListToString(st.GetAppliedSubst().GetSubst(), Lib.WithEmpty("(empty subst)"))) printSubList("X - Atomic", st.GetAtomic()) printSubList("A - Alpha", st.GetAlpha()) printSubList("B - Beta", st.GetBeta()) @@ -211,15 +213,15 @@ func printSubList[T Glob.Stringable](title string, list []T) { func printGoelandChoice(st *Search.State) { found := false - allSubs := []Unif.Substitutions{} + allSubs := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() withSubs := true for _, form := range st.GetAtomic() { canClose, subs := Search.ApplyClosureRules(form.GetForm(), st) if canClose { found = true - if len(subs) > 0 && !subs[0].IsEmpty() { - allSubs = append(allSubs, subs...) + if !subs.Empty() && !subs.At(0).Empty() { + allSubs.Append(subs.GetSlice()...) } else { withSubs = false } @@ -229,7 +231,7 @@ func printGoelandChoice(st *Search.State) { if found { str := " └ Goéland would apply the Closure rule" if withSubs { - str += " with the following substitution: " + allSubs[0].ToString() + str += " with the following substitution: " + Lib.ListToString(allSubs.At(0), Lib.WithEmpty("(empty subst)")) } else { str += " without any subsitutions" } @@ -358,14 +360,17 @@ func selectFormula(forms Core.FormAndTermsList) int { func selectSubstitution(substs []Core.SubstAndForm) int { fmt.Printf("Found closure rule with substitution that is used elsewhere.\n") fmt.Printf("Here is the list of possible substitutions :\n") - uniqueSubs := []Unif.Substitutions{} + uniqueSubs := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() for _, sub := range substs { - uniqueSubs = Unif.AppendIfNotContainsSubst(uniqueSubs, sub.GetSubst()) + uniqueSubs.Add( + Lib.ListEquals[Unif.MixedSubstitution], + sub.GetSubst(), + ) } - for i, elem := range uniqueSubs { - fmt.Printf("[%d] %v\n", i, elem.ToString()) + for i, elem := range uniqueSubs.GetSlice() { + fmt.Printf("[%d] %v\n", i, Lib.ListToString(elem, Lib.WithEmpty("(empty subst)"))) } isSubstitutionValid := false @@ -373,8 +378,10 @@ func selectSubstitution(substs []Core.SubstAndForm) int { for !isSubstitutionValid { fmt.Printf("Select a substitution ~> ") fmt.Scanf("%d", &choice) - if choice < len(uniqueSubs) && choice >= 0 { - fmt.Printf("You selected the substitution %v.\n", uniqueSubs[choice].ToString()) + if choice < uniqueSubs.Len() && choice >= 0 { + fmt.Printf("You selected the substitution %v.\n", + Lib.ListToString(uniqueSubs.At(choice), Lib.WithEmpty("(empty subst)")), + ) isSubstitutionValid = true fmt.Println("-------------------------") } else { diff --git a/src/Mods/assisted/rules.go b/src/Mods/assisted/rules.go index 9e288dc6..cdce6820 100644 --- a/src/Mods/assisted/rules.go +++ b/src/Mods/assisted/rules.go @@ -81,7 +81,12 @@ func applyAtomicRule(state Search.State, fatherId uint64, c Search.Communication clos_res_after_apply_subst, subst_after_apply_subst := Search.ApplyClosureRules(f.GetForm(), &state) if clos_res_after_apply_subst { - boolSubsts, resSubsts := searchAlgo.ManageClosureRule(fatherId, &state, c, Unif.CopySubstList(subst_after_apply_subst), f.Copy(), nodeId, originalNodeId) + boolSubsts, resSubsts := searchAlgo.ManageClosureRule( + fatherId, + &state, + c, + subst_after_apply_subst.Copy(Lib.ListCpy[Unif.MixedSubstitution]), + f.Copy(), nodeId, originalNodeId) if !boolSubsts { finalBool = false } diff --git a/src/Mods/dmt/rewrite.go b/src/Mods/dmt/rewrite.go index 53072b5a..6d55a724 100644 --- a/src/Mods/dmt/rewrite.go +++ b/src/Mods/dmt/rewrite.go @@ -60,7 +60,11 @@ func rewriteGeneric(tree Unif.DataStructure, atomic AST.Form, form AST.Form, pol var err error = nil if isUnified, unif := tree.Unify(form); isUnified { - rewritten, err = getRewrittenFormulas(rewritten, unif, atomic, polarity) + unif_substs := []Unif.MatchingSubstitutions{} + for _, substs := range unif { + unif_substs = append(unif_substs, substs.MatchingSubstitutions()) + } + rewritten, err = getRewrittenFormulas(rewritten, unif_substs, atomic, polarity) } else { rewritten = rewriteFailure(atomic) } @@ -86,7 +90,9 @@ func getRewrittenFormulas(rewritten []Core.IntSubstAndForm, unif []Unif.Matching func addRewrittenFormulas(rewritten []Core.IntSubstAndForm, unif Unif.MatchingSubstitutions, atomic AST.Form, equivalence Lib.List[AST.Form]) []Core.IntSubstAndForm { // Keep only useful substitutions - useful_subst := Core.RemoveElementWithoutMM(unif.GetSubst(), atomic.GetMetas()) + useful_subst := Unif.ToSubstitutions( + Core.RemoveElementWithoutMM(Unif.FromSubstitutions(unif.GetSubst()), atomic.GetMetas()), + ) meta_search := atomic.GetMetas() if !checkMetaAreFromSearch(meta_search, useful_subst) { Glob.Anomaly("DMT", fmt.Sprintf("There is at least one meta in final subst which is not from search : %v - %v - %v", useful_subst.ToString(), atomic.ToString(), unif.GetForm().ToString())) @@ -121,12 +127,19 @@ func getAtomAndPolarity(atom AST.Form) (AST.Form, bool) { func rewriteFailure(atomic AST.Form) []Core.IntSubstAndForm { return []Core.IntSubstAndForm{ - Core.MakeIntSubstAndForm(-1, Core.MakeSubstAndForm(Unif.Failure(), Lib.MkListV(atomic))), + Core.MakeIntSubstAndForm( + -1, + Core.MakeSubstAndForm(Lib.MkListV(Unif.MkMixedFromSubst(Unif.Failure()[0])), Lib.MkListV(atomic)), + ), } } func addUnifToAtomics(atomics []Core.IntSubstAndForm, candidate AST.Form, unif Unif.MatchingSubstitutions) []Core.IntSubstAndForm { - substAndForm := Core.MakeSubstAndForm(unif.GetSubst().Copy(), Lib.MkListV(candidate)) + mixed := Lib.NewList[Unif.MixedSubstitution]() + for _, subst := range unif.GetSubst() { + mixed.Append(Unif.MkMixedFromSubst(subst)) + } + substAndForm := Core.MakeSubstAndForm(mixed, Lib.MkListV(candidate)) if isBotOrTop(candidate) { atomics = Core.InsertFirstIntSubstAndFormList(atomics, Core.MakeIntSubstAndForm(unif.GetForm().GetIndex(), substAndForm)) } else { diff --git a/src/Mods/dmt/rewritten.go b/src/Mods/dmt/rewritten.go index d21c7e8d..a68b16f3 100644 --- a/src/Mods/dmt/rewritten.go +++ b/src/Mods/dmt/rewritten.go @@ -39,7 +39,6 @@ package dmt import ( "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Core" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Unif" @@ -48,7 +47,7 @@ import ( func substitute(form AST.Form, subst Unif.Substitutions) AST.Form { for _, s := range subst { old_symbol, new_symbol := s.Get() - form = Core.ApplySubstitutionOnFormula(old_symbol, new_symbol, form) + form = form.ReplaceMetaByTerm(old_symbol, new_symbol) } return form } diff --git a/src/Mods/equality/bse/equality.go b/src/Mods/equality/bse/equality.go index b13b3020..d0c1b2f2 100644 --- a/src/Mods/equality/bse/equality.go +++ b/src/Mods/equality/bse/equality.go @@ -68,12 +68,22 @@ func TryEquality(atomics_for_dmt Core.FormAndTermsList, st Search.State, new_ato debug(Lib.MkLazy(func() string { return "EQ is applicable !" })) atomics_plus_dmt := append(st.GetAtomic(), atomics_for_dmt...) res_eq, subst_eq := EqualityReasoning(st.GetEqStruct(), st.GetTreePos(), st.GetTreeNeg(), atomics_plus_dmt.ExtractForms(), original_node_id) + + send_to_proof_search := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() + for _, substs := range subst_eq { + local_list := Lib.NewList[Unif.MixedSubstitution]() + for _, subst := range substs { + local_list.Append(Unif.MkMixedFromSubst(subst)) + } + send_to_proof_search.Append(local_list) + } + if res_eq { Search.UsedSearch.ManageClosureRule( father_id, &st, cha, - subst_eq, + send_to_proof_search, Core.MakeFormAndTerm( AST.EmptyPredEq, Lib.NewList[AST.Term](), diff --git a/src/Mods/equality/bse/equality_rules_try_apply.go b/src/Mods/equality/bse/equality_rules_try_apply.go index 950bd296..cfc5a359 100644 --- a/src/Mods/equality/bse/equality_rules_try_apply.go +++ b/src/Mods/equality/bse/equality_rules_try_apply.go @@ -229,8 +229,7 @@ func checkUnifInTree(t AST.Term, tree Unif.DataStructure) (bool, Lib.List[AST.Te for _, subst := range ms { debug( Lib.MkLazy(func() string { - return fmt.Sprintf("Unif found with %v :%v", - subst.GetForm().ToString(), subst.GetSubst().ToString()) + return fmt.Sprintf("Unif found with: %s", subst.ToString()) }), ) result_list.Append(subst.GetForm().(Unif.TermForm).GetTerm()) diff --git a/src/Mods/equality/bse/equality_types.go b/src/Mods/equality/bse/equality_types.go index 7d117918..482e272d 100644 --- a/src/Mods/equality/bse/equality_types.go +++ b/src/Mods/equality/bse/equality_types.go @@ -120,7 +120,7 @@ func (equs Equalities) removeHalf() Equalities { /* Retrieve equalities from a datastructure */ func retrieveEqualities(dt Unif.DataStructure) Equalities { res := Equalities{} - meta_ty := AST.MkTyMeta("META_TY_EQ") + meta_ty := AST.MkTyMeta("META_TY_EQ", -1) MetaEQ1 := AST.MakerMeta("METAEQ1", -1, meta_ty) MetaEQ2 := AST.MakerMeta("METAEQ2", -1, meta_ty) @@ -134,7 +134,7 @@ func retrieveEqualities(dt Unif.DataStructure) Equalities { _, eq_list := dt.Unify(eq_pred) for _, ms := range eq_list { - ms_ordered := orderSubstForRetrieve(ms.GetSubst(), MetaEQ1, MetaEQ2) + ms_ordered := orderSubstForRetrieve(ms.MatchingSubstitutions().GetSubst(), MetaEQ1, MetaEQ2) eq1_term, ok_t1 := ms_ordered.Get(MetaEQ1) if ok_t1 == -1 { Glob.Anomaly("RI", "Meta_eq_1 not found in map") @@ -151,7 +151,7 @@ func retrieveEqualities(dt Unif.DataStructure) Equalities { /* Retrieve inequalities from a datastructure */ func retrieveInequalities(dt Unif.DataStructure) Inequalities { res := Inequalities{} - meta_ty := AST.MkTyMeta("META_TY_NEQ") + meta_ty := AST.MkTyMeta("META_TY_NEQ", -1) MetaNEQ1 := AST.MakerMeta("META_NEQ_1", -1, meta_ty) MetaNEQ2 := AST.MakerMeta("META_NEQ_2", -1, meta_ty) @@ -165,7 +165,7 @@ func retrieveInequalities(dt Unif.DataStructure) Inequalities { _, neq_list := dt.Unify(neq_pred) for _, ms := range neq_list { - ms_ordered := orderSubstForRetrieve(ms.GetSubst(), MetaNEQ1, MetaNEQ2) + ms_ordered := orderSubstForRetrieve(ms.MatchingSubstitutions().GetSubst(), MetaNEQ1, MetaNEQ2) neq1_term, ok_t1 := ms_ordered.Get(MetaNEQ1) if ok_t1 == -1 { Glob.Anomaly("RI", "Meta_eq_1 not found in map") diff --git a/src/Search/child_management.go b/src/Search/child_management.go index 787b4f5a..90afaeeb 100644 --- a/src/Search/child_management.go +++ b/src/Search/child_management.go @@ -127,8 +127,10 @@ func (ds *destructiveSearch) childrenClosedByThemselves(args wcdArgs, proofChild // Remove all the metavariables that have been introduced in this node: the parent do not know them. substForFather := Core.RemoveElementWithoutMM(args.st.GetAppliedSubst().GetSubst(), args.st.GetMM()) - if !substForFather.IsEmpty() { - args.st.SetSubstsFound([]Core.SubstAndForm{Core.MakeSubstAndForm(substForFather, args.st.GetAppliedSubst().GetForm())}) + if !substForFather.Empty() { + args.st.SetSubstsFound( + []Core.SubstAndForm{Core.MakeSubstAndForm(substForFather, args.st.GetAppliedSubst().GetForm())}, + ) } else { args.st.SetSubstsFound([]Core.SubstAndForm{}) } @@ -159,8 +161,9 @@ func (ds *destructiveSearch) passSubstToParent(args wcdArgs, proofChildren [][]P debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "All children agree on the substitution(s) : %v", - Unif.SubstListToString(Core.GetSubstListFromSubstAndFormList(substs))) + "All children agree on the substitution(s) : %s", + Unif.SubstsToString(Core.GetSubstListFromSubstAndFormList(substs)), + ) }), ) @@ -177,14 +180,15 @@ func (ds *destructiveSearch) passSubstToParent(args wcdArgs, proofChildren [][]P // Remove all the metas introduced by the current node to only retrieve relevant ones for the parent. resultingSubstsAndForms := []Core.SubstAndForm{} - resultingSubsts := []Unif.Substitutions{} + resultingSubsts := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() for _, subst := range substs { debug( Lib.MkLazy(func() string { return fmt.Sprintf( "Check the susbt, remove useless element and merge with applied subst :%v", - subst.GetSubst().ToString()) + Lib.ListToString(subst.GetSubst(), Lib.WithEmpty("")), + ) }), ) err, merged := Core.MergeSubstAndForm(subst, args.st.GetAppliedSubst()) @@ -194,18 +198,18 @@ func (ds *destructiveSearch) passSubstToParent(args wcdArgs, proofChildren [][]P return err } - cleaned := Core.RemoveElementWithoutMM(merged.GetSubst().Copy(), args.st.GetMM()) + cleaned := Core.RemoveElementWithoutMM(merged.GetSubst(), args.st.GetMM()) substAndFormCleaned := Core.MakeSubstAndForm(cleaned, subst.GetForm()) // If the cleaned subst is empty, we don't need to do anything. // Otherwise, we have to check if the cleaned substitution is already in the resulting substs list // and, if applicable, add the formula to the list of substituted formulas. // It is useful for the nondestructive mode, to store with which formula the contradiction has been found. - if !cleaned.IsEmpty() { + if !cleaned.Empty() { // Check if the new substitution is already in the list, merge formulas added := false - for i := 0; !added && i < len(resultingSubsts); i++ { - if resultingSubstsAndForms[i].GetSubst().Equals(cleaned) { + for i := 0; !added && i < resultingSubsts.Len(); i++ { + if Lib.ListEquals(resultingSubstsAndForms[i].GetSubst(), cleaned) { added = true resultingSubstsAndForms[i] = resultingSubstsAndForms[i].AddFormulas(subst.GetForm()) } @@ -213,7 +217,7 @@ func (ds *destructiveSearch) passSubstToParent(args wcdArgs, proofChildren [][]P if !added { resultingSubstsAndForms = append(resultingSubstsAndForms, substAndFormCleaned.Copy()) - resultingSubsts = append(resultingSubsts, substAndFormCleaned.GetSubst()) + resultingSubsts.Append(substAndFormCleaned.GetSubst()) } newMetas = Glob.UnionIntList(newMetas, retrieveMetaFromSubst(cleaned)) @@ -278,7 +282,9 @@ func (ds *destructiveSearch) manageOpenedChild(args wcdArgs) { // If the completeness mode is active, then we need to deal with forbidden substitutions. if Glob.GetCompleteness() { - args.st.SetForbiddenSubsts(Unif.AddSubstToSubstitutionsList(args.st.GetForbiddenSubsts(), args.currentSubst.GetSubst())) + forbidden := args.st.GetForbiddenSubsts() + forbidden.Add(Lib.ListEquals[Unif.MixedSubstitution], args.currentSubst.GetSubst()) + args.st.SetForbiddenSubsts(forbidden) } if args.st.GetBTOnFormulas() && len(args.formsBT) > 0 { diff --git a/src/Search/children.go b/src/Search/children.go index 4e94c0b7..c83a2846 100644 --- a/src/Search/children.go +++ b/src/Search/children.go @@ -63,7 +63,7 @@ type Result struct { closed, need_answer bool subst_for_children Core.SubstAndForm subst_list_for_father []Core.SubstAndForm - forbidden []Unif.Substitutions + forbidden Lib.List[Lib.List[Unif.MixedSubstitution]] proof []ProofStruct node_id int original_node_id int @@ -85,8 +85,8 @@ func (r Result) getSubstForChildren() Core.SubstAndForm { func (r Result) getSubstListForFather() []Core.SubstAndForm { return Core.CopySubstAndFormList(r.subst_list_for_father) } -func (r Result) getForbiddenSubsts() []Unif.Substitutions { - return Unif.CopySubstList(r.forbidden) +func (r Result) getForbiddenSubsts() Lib.List[Lib.List[Unif.MixedSubstitution]] { + return r.forbidden.Copy(Lib.ListCpy[Unif.MixedSubstitution]) } func (r Result) getProof() []ProofStruct { return CopyProofStructList(r.proof) @@ -164,12 +164,19 @@ func sendSubToChildren(children []Communication, s Core.SubstAndForm) { debug( Lib.MkLazy(func() string { return fmt.Sprintf("children : %v/%v", i+1, len(children)) }), ) - v.result <- Result{Glob.GetGID(), true, true, s.Copy(), []Core.SubstAndForm{}, Unif.MakeEmptySubstitutionList(), nil, -1, -1, Core.MakeUnifier()} + v.result <- Result{ + Glob.GetGID(), + true, + true, + s.Copy(), + []Core.SubstAndForm{}, + Lib.NewList[Lib.List[Unif.MixedSubstitution]](), + nil, -1, -1, Core.MakeUnifier()} } } /* Send a substitution to a list of child */ -func sendForbiddenToChildren(children []Communication, s []Unif.Substitutions) { +func sendForbiddenToChildren(children []Communication, s Lib.List[Lib.List[Unif.MixedSubstitution]]) { debug( Lib.MkLazy(func() string { return fmt.Sprintf("Send forbidden to children : %v", len(children)) }), ) @@ -187,8 +194,8 @@ func (ds *destructiveSearch) sendSubToFather(c Communication, closed, need_answe debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Send subst to father : %v, closed : %v, need answer : %v", - Unif.SubstListToString(Core.GetSubstListFromSubstAndFormList(subst_for_father)), + "Send subst to father : %s, closed : %v, need answer : %v", + Unif.SubstsToString(Core.GetSubstListFromSubstAndFormList(subst_for_father)), closed, need_answer) }), ) @@ -219,7 +226,14 @@ func (ds *destructiveSearch) sendSubToFather(c Communication, closed, need_answe ) select { - case c.result <- Result{Glob.GetGID(), closed, need_answer, Core.MakeEmptySubstAndForm(), Core.CopySubstAndFormList(subst_for_father), Unif.MakeEmptySubstitutionList(), st.GetProof(), node_id, original_node_id, st.GetGlobUnifier()}: + case c.result <- Result{ + Glob.GetGID(), + closed, + need_answer, + Core.MakeEmptySubstAndForm(), + Core.CopySubstAndFormList(subst_for_father), + Lib.NewList[Lib.List[Unif.MixedSubstitution]](), + st.GetProof(), node_id, original_node_id, st.GetGlobUnifier()}: if need_answer { ds.waitFather(father_id, st, c, Core.FusionSubstAndFormListWithoutDouble(subst_for_father, given_substs), node_id, original_node_id, []int{}, meta_to_reintroduce) } else { diff --git a/src/Search/destructive.go b/src/Search/destructive.go index 5ad1f40b..0bd76a0a 100644 --- a/src/Search/destructive.go +++ b/src/Search/destructive.go @@ -62,7 +62,7 @@ type BasicSearchAlgorithm interface { ProofSearch(uint64, State, Communication, Core.SubstAndForm, int, int, []int, bool) DoEndManageBeta(uint64, State, Communication, []Communication, int, int, []int, []int) manageRewriteRules(uint64, State, Communication, Core.FormAndTermsList, int, int, []int) - ManageClosureRule(uint64, *State, Communication, []Unif.Substitutions, Core.FormAndTerms, int, int) (bool, []Core.SubstAndForm) + ManageClosureRule(uint64, *State, Communication, Lib.List[Lib.List[Unif.MixedSubstitution]], Core.FormAndTerms, int, int) (bool, []Core.SubstAndForm) manageResult(c Communication) (Core.Unifier, []ProofStruct, bool) } @@ -142,7 +142,7 @@ func (ds *destructiveSearch) doOneStep(limit int, formula AST.Form) (bool, int) PrintSearchResult(result) } - if unif := unifier.GetUnifier(); !unif.IsEmpty() { + if unif := unifier.GetUnifier(); !unif.Empty() { finalProof = ApplySubstitutionOnProofList(unif, finalProof) } uninstanciatedMeta := RetrieveUninstantiatedMetaFromProof(finalProof) @@ -176,9 +176,9 @@ func (ds *destructiveSearch) chooseSubstitutionDestructive(subst_list []Core.Sub i := 0 saved_i := 0 - // Choix de la subst - celle qui ne contient pas de MM, ou la première + // Choose either a subst that does not contain any meta from the parents, or a random one for i < len(subst_list)-1 && !found { - if !Core.ContainsMetaMother((subst_list)[i].GetSubst(), mm) { + if !Core.ContainsMetaMother(subst_list[i].GetSubst(), mm) { subst_found = subst_list[i] saved_i = i found = true @@ -193,7 +193,7 @@ func (ds *destructiveSearch) chooseSubstitutionDestructive(subst_list []Core.Sub subst_found = subst_found.Copy() } - // Maj subst_list avec les subst restantes pour le BT + // Remember the substs for backtracking if len(subst_list) > 1 { subst_list[saved_i] = subst_list[len(subst_list)-1] subst_list = subst_list[:len(subst_list)-1] @@ -214,7 +214,15 @@ func (ds *destructiveSearch) searchContradictionAfterApplySusbt(father_id uint64 ) // Check if exists a contradiction after applying the substitution if res, subst := ApplyClosureRules(f.GetForm(), &st); res { - ds.ManageClosureRule(father_id, &st, cha, Unif.CopySubstList(subst), f.Copy(), node_id, original_node_id) + ds.ManageClosureRule( + father_id, + &st, + cha, + subst.Copy(Lib.ListCpy[Unif.MixedSubstitution]), + f.Copy(), + node_id, + original_node_id, + ) return true } } @@ -233,7 +241,12 @@ func (ds *destructiveSearch) searchContradiction(atomic AST.Form, father_id uint fAt := Core.MakeFormAndTerm(atomic, Lib.MkList[AST.Term](0)) if clos_res { - ds.ManageClosureRule(father_id, &st, cha, Unif.CopySubstList(subst), fAt, node_id, original_node_id) + ds.ManageClosureRule( + father_id, + &st, + cha, + subst.Copy(Lib.ListCpy[Unif.MixedSubstitution]), + fAt, node_id, original_node_id) return true } return false @@ -299,7 +312,8 @@ func (ds *destructiveSearch) ProofSearch(father_id uint64, st State, cha Communi Lib.MkLazy(func() string { return fmt.Sprintf( "Current substitutions list: %v", - Unif.SubstListToString(Core.GetSubstListFromSubstAndFormList(st.GetSubstsFound()))) + Unif.SubstsToString(Core.GetSubstListFromSubstAndFormList(st.GetSubstsFound())), + ) }), ) } @@ -313,7 +327,12 @@ func (ds *destructiveSearch) ProofSearch(father_id uint64, st State, cha Communi for _, f := range st.GetLF() { if Core.ShowKindOfRule(f.GetForm()) == Core.Atomic { if searchObviousClosureRule(f.GetForm()) { - ds.ManageClosureRule(father_id, &st, cha, []Unif.Substitutions{}, f, node_id, original_node_id) + ds.ManageClosureRule( + father_id, + &st, + cha, + Lib.NewList[Lib.List[Unif.MixedSubstitution]](), + f, node_id, original_node_id) return } step_atomics = append(step_atomics, f) @@ -427,7 +446,8 @@ func (ds *destructiveSearch) waitChildren(args wcdArgs) { Lib.MkLazy(func() string { return fmt.Sprintf( "Current substs : %v", - args.currentSubst.GetSubst().ToString()) + Lib.ListToString(args.currentSubst.GetSubst()), + ) }), ) status, substs, proofs, unifiers := ds.selectChildren(args.c, &args.children, args.currentSubst, args.childOrdering) @@ -502,12 +522,12 @@ func (ds *destructiveSearch) waitFather(father_id uint64, st State, c Communicat ) // Check if the subst was already seen, returns eventually the subst with new formula(s) - if Unif.ContainsSubst(Core.GetSubstListFromSubstAndFormList(given_substs), answer_father.subst_for_children.GetSubst()) { + if Core.GetSubstListFromSubstAndFormList(given_substs).Contains(answer_father.subst_for_children.GetSubst(), Lib.ListEquals[Unif.MixedSubstitution]) { debug( Lib.MkLazy(func() string { return "This substitution was sent by this child" }), ) for _, subst_sent := range given_substs { - if subst_sent.GetSubst().Equals(answer_father.subst_for_children.GetSubst()) { + if Lib.ListEquals(subst_sent.GetSubst(), answer_father.subst_for_children.GetSubst()) { subst = answer_father.getSubstForChildren().AddFormulas(subst_sent.GetForm()) } } @@ -530,21 +550,23 @@ func (ds *destructiveSearch) waitFather(father_id uint64, st State, c Communicat x1 := x.MakeDataStruct(x2, false) st.SetTreeNeg(x1) - // Maj forbidden - if len(answer_father.forbidden) > 0 { + // Update forbidden + if answer_father.forbidden.Len() > 0 { debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Forbidden received : %v", - Unif.SubstListToString(answer_father.getForbiddenSubsts())) + "Forbidden received : %s", + Unif.SubstsToString(answer_father.getForbiddenSubsts()), + ) }), ) st.SetForbiddenSubsts(answer_father.getForbiddenSubsts()) debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "New forbidden fo this state : %v", - Unif.SubstListToString(st.GetForbiddenSubsts())) + "New forbidden for this state: %s", + Unif.SubstsToString(st.GetForbiddenSubsts()), + ) }), ) } else { @@ -598,13 +620,14 @@ func (ds *destructiveSearch) waitFather(father_id uint64, st State, c Communicat debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Apply substitution on myself and wait : %v", - answer_father.getSubstForChildren().GetSubst().ToString()) + "Apply substitution on myself and wait : %s", + Lib.ListToString(answer_father.getSubstForChildren().GetSubst()), + ) }), ) debug( Lib.MkLazy(func() string { - return fmt.Sprintf("Forbidden : %v", Unif.SubstListToString(st_copy.GetForbiddenSubsts())) + return fmt.Sprintf("Forbidden : %s", Unif.SubstsToString(st_copy.GetForbiddenSubsts())) }), ) go ds.ProofSearch(Glob.GetGID(), st_copy, c2, answer_father.getSubstForChildren(), node_id, original_node_id, new_meta_to_reintroduce, false) @@ -740,7 +763,8 @@ func (ds *destructiveSearch) selectChildren(father Communication, children *[]Co }), ) - if len(res.subst_list_for_father) == 1 && res.subst_list_for_father[0].GetSubst().Equals(current_subst.GetSubst()) { + if len(res.subst_list_for_father) == 1 && + Lib.ListEquals(res.subst_list_for_father[0].GetSubst(), current_subst.GetSubst()) { debug( Lib.MkLazy(func() string { return fmt.Sprintf( @@ -758,12 +782,16 @@ func (ds *destructiveSearch) selectChildren(father Communication, children *[]Co // Check if there is common substitutions for _, current_subst_from_children := range res.subst_list_for_father { for i := range result_subst { - if current_subst_from_children.GetSubst().Equals(result_subst[i].GetSubst()) { + if Lib.ListEquals( + current_subst_from_children.GetSubst(), + result_subst[i].GetSubst(), + ) { debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Subst in common found : %v !", - current_subst_from_children.GetSubst().ToString()) + "Subst in common found : %s !", + Lib.ListToString(current_subst_from_children.GetSubst()), + ) }), ) common_substs = append(common_substs, result_subst[i].AddFormulas(current_subst_from_children.GetForm())) @@ -780,17 +808,20 @@ func (ds *destructiveSearch) selectChildren(father Communication, children *[]Co v.ToString()) }), ) - if !v.GetSubst().Equals(new_current_subst.GetSubst()) { + if !Lib.ListEquals(v.GetSubst(), new_current_subst.GetSubst()) { added := false debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Result_subst :%v", - Unif.SubstListToString(Core.GetSubstListFromSubstAndFormList(result_subst))) + "Result_subst :%s", + Unif.SubstsToString( + Core.GetSubstListFromSubstAndFormList(result_subst), + ), + ) }), ) for i := range result_subst { - if v.GetSubst().Equals(result_subst[i].GetSubst()) { + if Lib.ListEquals(v.GetSubst(), result_subst[i].GetSubst()) { added = true debug( Lib.MkLazy(func() string { return "Subst already in result_subst" }), @@ -811,9 +842,11 @@ func (ds *destructiveSearch) selectChildren(father Communication, children *[]Co debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "New result susbt : %v", - Unif.SubstListToString( - Core.GetSubstListFromSubstAndFormList(result_subst))) + "New result susbt : %s", + Unif.SubstsToString( + Core.GetSubstListFromSubstAndFormList(result_subst), + ), + ) }), ) } @@ -869,7 +902,7 @@ func (ds *destructiveSearch) selectChildren(father Communication, children *[]Co if !new_current_subst.IsEmpty() { new_result_subst := []Core.SubstAndForm{} for _, s := range result_subst { - if !s.GetSubst().Equals(new_current_subst.GetSubst()) { + if !Lib.ListEquals(s.GetSubst(), new_current_subst.GetSubst()) { err, new_subst := Core.MergeSubstAndForm(s.Copy(), new_current_subst.Copy()) if err != nil { @@ -884,8 +917,9 @@ func (ds *destructiveSearch) selectChildren(father Communication, children *[]Co debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "New subst at the end : %v", - Unif.SubstListToString(Core.GetSubstListFromSubstAndFormList(result_subst))) + "New subst at the end : %s", + Unif.SubstsToString(Core.GetSubstListFromSubstAndFormList(result_subst)), + ) }), ) default: @@ -978,8 +1012,10 @@ func (ds *destructiveSearch) tryRewrite(rewritten []Core.IntSubstAndForm, f Core newRewritten = Core.CopyIntSubstAndFormAndTermsList(newRewritten[1:]) // If we didn't rewrite as itself ? - if !choosenRewritten.GetSaf().GetSubst().Equals(Unif.Failure()) { - // Create a child with the current rewriting rule and make this process to wait for him, with a list of other subst to try + if Unif.UnifSucceeded(choosenRewritten.GetSaf().GetSubst()) { + // Create a child with the current rewriting rule and make this process to wait for him, + // with a list of other subst to try + // all atomics but not the chosen one state.SetLF(append(remainingAtomics.Copy(), choosenRewrittenForm.Copy())) state.SetBTOnFormulas(true) // I need to know that I can bt on form and my child needs to know it to to don't loop @@ -992,7 +1028,7 @@ func (ds *destructiveSearch) tryRewrite(rewritten []Core.IntSubstAndForm, f Core state.SetCurrentProofRuleName("Rewrite") state.SetCurrentProofIdDMT(choosenRewritten.GetId_rewrite()) - if choosenRewritten.GetSaf().GetSubst().IsEmpty() { + if choosenRewritten.GetSaf().GetSubst().Empty() { choosenRewritten = Core.MakeEmptyIntSubstAndFormAndTerms() } @@ -1017,24 +1053,32 @@ func (ds *destructiveSearch) tryRewrite(rewritten []Core.IntSubstAndForm, f Core } } -//ILL TODO Clean the following function and be careful with the Coq output. /** * clos_res and subst are the result of applyClosureRule. * Manage this result, dispatch the subst and recreate data structures. * Return if the branch is closed without variable from its father **/ -func (ds *destructiveSearch) ManageClosureRule(father_id uint64, st *State, c Communication, substs []Unif.Substitutions, f Core.FormAndTerms, node_id int, original_node_id int) (bool, []Core.SubstAndForm) { +func (ds *destructiveSearch) ManageClosureRule( + father_id uint64, + st *State, + c Communication, + substs Lib.List[Lib.List[Unif.MixedSubstitution]], + f Core.FormAndTerms, + node_id int, + original_node_id int, +) (bool, []Core.SubstAndForm) { mm := st.GetMM().Copy() subst := st.GetAppliedSubst().GetSubst() mm = mm.Union(Core.GetMetaFromSubst(subst)) - substs_with_mm, substs_with_mm_uncleared, substs_without_mm := Core.DispatchSubst(Unif.CopySubstList(substs), mm) + substs_with_mm, substs_with_mm_uncleared, substs_without_mm := + Core.DispatchSubst(substs.Copy(Lib.ListCpy[Unif.MixedSubstitution]), mm) unifier := st.GetGlobUnifier() appliedSubst := st.GetAppliedSubst().GetSubst() switch { - case len(substs) == 0: + case substs.Empty(): debug( Lib.MkLazy(func() string { return "Branch closed by ¬⊤ or ⊥ or a litteral and its opposite!" }), ) @@ -1061,24 +1105,27 @@ func (ds *destructiveSearch) ManageClosureRule(father_id uint64, st *State, c Co ds.sendSubToFather(c, true, false, Glob.GetGID(), *st, []Core.SubstAndForm{}, node_id, original_node_id, []int{}) } - case len(substs_without_mm) > 0: + case !substs_without_mm.Empty(): debug( Lib.MkLazy(func() string { return fmt.Sprintf( "Contradiction found (without mm) : %v", - Unif.SubstListToString(substs_without_mm)) + Unif.SubstsToString(substs_without_mm)) }), ) - if Glob.GetAssisted() && !substs_without_mm[0].IsEmpty() { + if Glob.GetAssisted() && !substs_without_mm.At(0).Empty() { fmt.Printf("The branch can be closed by using a substitution which has no impact elsewhere!\nApplying it automatically : ") - fmt.Printf("%v !\n", Unif.SubstListToString(substs_without_mm)) + fmt.Printf("%v !\n", Unif.SubstsToString(substs_without_mm)) } st.SetSubstsFound([]Core.SubstAndForm{st.GetAppliedSubst()}) // Proof - st.SetCurrentProofRule(fmt.Sprintf("⊙ / %v", substs_without_mm[0].ToString())) + st.SetCurrentProofRule(fmt.Sprintf( + "⊙ / %s", + Lib.ListToString(substs_without_mm.At(0), Lib.WithEmpty("(empty subst)")), + )) st.SetCurrentProofRuleName("CLOSURE") st.SetCurrentProofFormula(f.Copy()) st.SetCurrentProofNodeId(node_id) @@ -1086,8 +1133,8 @@ func (ds *destructiveSearch) ManageClosureRule(father_id uint64, st *State, c Co st.SetProof(append(st.GetProof(), st.GetCurrentProof())) // As no MM is involved, these substitutions can be unified with all the others having an empty subst. - for _, subst := range substs_without_mm { - merge, _ := Unif.MergeSubstitutions(appliedSubst, subst) + for _, subst := range substs_without_mm.GetSlice() { + merge, _ := Unif.MergeMixedSubstitutions(appliedSubst, subst) unifier.AddSubstitutions(appliedSubst, merge) } st.SetGlobUnifier(unifier) @@ -1095,12 +1142,12 @@ func (ds *destructiveSearch) ManageClosureRule(father_id uint64, st *State, c Co ds.sendSubToFather(c, true, false, Glob.GetGID(), *st, []Core.SubstAndForm{}, node_id, original_node_id, []int{}) } - case len(substs_with_mm) > 0: + case !substs_with_mm.Empty(): debug( Lib.MkLazy(func() string { return "Contradiction found (with mm) !" }), ) - // TODO : REMOVE vu qu fait dans wait father ? + // FIXME: should this be removed as it's done in WaitForFather? st.SetCurrentProofRule("⊙") st.SetCurrentProofRuleName("CLOSURE") st.SetCurrentProofFormula(f.Copy()) @@ -1109,10 +1156,13 @@ func (ds *destructiveSearch) ManageClosureRule(father_id uint64, st *State, c Co st.SetProof(append(st.GetProof(), st.GetCurrentProof())) meta_to_reintroduce := []int{} - for _, subst_for_father := range substs_with_mm { - // Check if subst_for_father is failure - if subst_for_father.Equals(Unif.Failure()) { - Glob.Anomaly("MCR", fmt.Sprintf("Error : SubstForFather is failure between : %v and %v \n", subst_for_father.ToString(), st.GetAppliedSubst().ToString())) + for _, subst_for_father := range substs_with_mm.GetSlice() { + if !Unif.UnifSucceeded(subst_for_father) { + Glob.Anomaly("MCR", fmt.Sprintf( + "Error : SubstForFather is failure between : %s and %s \n", + Lib.ListToString(subst_for_father, Lib.WithEmpty("(empty substs)")), + st.GetAppliedSubst().ToString()), + ) } debug( Lib.MkLazy(func() string { return fmt.Sprintf("Formula = : %v", f.ToString()) }), @@ -1155,17 +1205,19 @@ func (ds *destructiveSearch) ManageClosureRule(father_id uint64, st *State, c Co debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Send subst(s) with mm to father : %v", - Unif.SubstListToString( - Core.GetSubstListFromSubstAndFormList(st.GetSubstsFound()))) + "Send subst(s) with mm to father : %s", + Unif.SubstsToString( + Core.GetSubstListFromSubstAndFormList(st.GetSubstsFound()), + ), + ) }), ) sort.Ints(meta_to_reintroduce) // Add substs_with_mm found with the corresponding subst - for i, subst := range substs_with_mm { - mergeUncleared, _ := Unif.MergeSubstitutions(appliedSubst, substs_with_mm_uncleared[i]) - mergeCleared, _ := Unif.MergeSubstitutions(appliedSubst, subst) + for i, subst := range substs_with_mm.GetSlice() { + mergeUncleared, _ := Unif.MergeMixedSubstitutions(appliedSubst, substs_with_mm_uncleared.At(i)) + mergeCleared, _ := Unif.MergeMixedSubstitutions(appliedSubst, subst) unifier.AddSubstitutions(mergeCleared, mergeUncleared) } st.SetGlobUnifier(unifier) diff --git a/src/Search/exchanges.go b/src/Search/exchanges.go index ce345ac2..3b069cce 100644 --- a/src/Search/exchanges.go +++ b/src/Search/exchanges.go @@ -83,7 +83,13 @@ func ResetExchangesFile() { } } -func makeJsonExchanges(father_uint uint64, st State, ss_subst []Unif.Substitutions, subst_received Unif.Substitutions, calling_function string) exchanges_struct { +func makeJsonExchanges( + father_uint uint64, + st State, + ss_subst Lib.List[Lib.List[Unif.MixedSubstitution]], + subst_received Lib.List[Unif.MixedSubstitution], + calling_function string, +) exchanges_struct { // ID id_process := Glob.GetGID() id := int(id_process) @@ -109,16 +115,16 @@ func makeJsonExchanges(father_uint uint64, st State, ss_subst []Unif.Substitutio // Subt sr := "" - if len(st.GetAppliedSubst().GetSubst()) > 0 { - sr += st.GetAppliedSubst().GetSubst().ToString() + if !st.GetAppliedSubst().GetSubst().Empty() { + sr += Lib.ListToString(st.GetAppliedSubst().GetSubst(), Lib.WithEmpty("(empty subst)")) } - if len(subst_received) > 0 { - sr += subst_received.ToString() + if !subst_received.Empty() { + sr += Lib.ListToString(subst_received, Lib.WithEmpty("(empty subst)")) } ss := "" - if len(ss_subst) > 0 { - ss += Unif.SubstListToString(ss_subst) + if !ss_subst.Empty() { + ss += Unif.SubstsToString(ss_subst) } // fmt.Printf("Id = %v, version = %v, father = %v, forms = %v, mm = %v, mc = %v, ss = %v, sr = %v\n", id, version, father, forms, mm, mc, ss, sr) @@ -135,7 +141,9 @@ func WriteExchanges(father uint64, st State, sub_sent []Core.SubstAndForm, subst } else { file_exchanges.WriteString("[\n") } - json_content := makeJsonExchanges(father, st, Core.RemoveEmptySubstFromSubstList(Core.GetSubstListFromSubstAndFormList(sub_sent)), subst_received.GetSubst(), calling_function) + json_content := makeJsonExchanges(father, st, + Core.RemoveEmptySubstFromSubstList(Core.GetSubstListFromSubstAndFormList(sub_sent)), + subst_received.GetSubst(), calling_function) json_string, _ := json.MarshalIndent(json_content, "", " ") file_exchanges.Write(json_string) mutex_file_exchanges.Unlock() diff --git a/src/Search/incremental/rulesManager.go b/src/Search/incremental/rulesManager.go index c1ce7b1f..38c0bd53 100644 --- a/src/Search/incremental/rulesManager.go +++ b/src/Search/incremental/rulesManager.go @@ -189,7 +189,7 @@ func (rm *RulesManager) trySubstitutionClosureRules() (applied Rule, subs SubLis negTree := new(Unif.Node).MakeDataStruct(negativeRules.GetFormList(), false) - substitutions := []Unif.MatchingSubstitutions{} + substitutions := []Unif.MixedSubstitutions{} for _, posRule := range positiveRules { success, currentSubst := negTree.Unify(posRule.GetForm()) @@ -200,7 +200,7 @@ func (rm *RulesManager) trySubstitutionClosureRules() (applied Rule, subs SubLis } for _, substitution := range substitutions { - subs = append(subs, NewFromOldSub(substitution)) + subs = append(subs, NewFromOldSub(substitution.MatchingSubstitutions())) } return applied, subs diff --git a/src/Search/incremental/search.go b/src/Search/incremental/search.go index 9f37b97c..b606e099 100644 --- a/src/Search/incremental/search.go +++ b/src/Search/incremental/search.go @@ -42,7 +42,7 @@ func (is *incrementalSearch) SetApplyRules(func(uint64, Search.State, Search.Com } // ManageClosureRule implements Search.SearchAlgorithm. -func (is *incrementalSearch) ManageClosureRule(uint64, *Search.State, Search.Communication, []Unif.Substitutions, Core.FormAndTerms, int, int) (bool, []Core.SubstAndForm) { +func (is *incrementalSearch) ManageClosureRule(uint64, *Search.State, Search.Communication, Lib.List[Lib.List[Unif.MixedSubstitution]], Core.FormAndTerms, int, int) (bool, []Core.SubstAndForm) { Glob.Fatal("NDS", "Incremental search not compatible with the equality plugin for now.") return false, []Core.SubstAndForm{} } diff --git a/src/Search/nonDestructiveSearch.go b/src/Search/nonDestructiveSearch.go index 092ca29f..bfe2edd3 100644 --- a/src/Search/nonDestructiveSearch.go +++ b/src/Search/nonDestructiveSearch.go @@ -54,6 +54,17 @@ func NewNonDestructiveSearch() BasicSearchAlgorithm { return nil } +func getMetas(substs Lib.List[Unif.MixedSubstitution]) Lib.List[AST.Meta] { + metas := Lib.NewList[AST.Meta]() + for _, subst := range substs.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + metas.Append(s.Val.Key()) + } + } + return metas +} + func (nds *nonDestructiveSearch) setApplyRules(function func(uint64, State, Communication, Core.FormAndTermsList, int, int, []int)) { Glob.Fatal("NDS", "Non-destructive search not compatible with the assisted plugin for now.") } @@ -69,7 +80,7 @@ func (nds *nonDestructiveSearch) manageRewriteRules(fatherId uint64, state State /* Choose substitution - whitout meta in lastAppliedSubst */ func (nds *nonDestructiveSearch) chooseSubstitutionWithoutMetaLastApplyNonDestructive(sl []Core.SubstAndForm, ml Lib.List[AST.Meta]) (Core.SubstAndForm, []Core.SubstAndForm) { for i, v := range sl { - if !AST.IsIncludeInsideOF(v.GetSubst().GetMeta(), ml) { + if !AST.IsIncludeInsideOF(getMetas(v.GetSubst()), ml) { return v, Core.RemoveSubstFromSubstAndFormList(i, sl) } } @@ -79,7 +90,7 @@ func (nds *nonDestructiveSearch) chooseSubstitutionWithoutMetaLastApplyNonDestru /* Choose substitution - whith meta in lastAppliedSubst */ func (nds *nonDestructiveSearch) chooseSubstitutionWithtMetaLastApplyNonDestructive(sl []Core.SubstAndForm, last_applied_subst Core.SubstAndForm) (Core.SubstAndForm, []Core.SubstAndForm) { for i, v := range sl { - if !v.GetSubst().Equals(last_applied_subst.GetSubst()) { + if !Lib.ListEquals(v.GetSubst(), last_applied_subst.GetSubst()) { return v, Core.RemoveSubstFromSubstAndFormList(i, sl) } } @@ -88,12 +99,12 @@ func (nds *nonDestructiveSearch) chooseSubstitutionWithtMetaLastApplyNonDestruct /* Choose the best substitution among subst_found_at_this_step and subst_found */ func (nds *nonDestructiveSearch) chooseSubstitutionNonDestructive(substs_found_this_step []Core.SubstAndForm, st *State) Core.SubstAndForm { - res, sl := nds.chooseSubstitutionWithoutMetaLastApplyNonDestructive(substs_found_this_step, st.GetLastAppliedSubst().GetSubst().GetMeta()) + res, sl := nds.chooseSubstitutionWithoutMetaLastApplyNonDestructive(substs_found_this_step, getMetas(st.GetLastAppliedSubst().GetSubst())) if !res.IsEmpty() { // subst without meta in last applied meta found in substs_found_at_this_step st.SetSubstsFound(append(sl, st.GetSubstsFound()...)) return res } else { - res, sl = nds.chooseSubstitutionWithoutMetaLastApplyNonDestructive(st.GetSubstsFound(), st.GetLastAppliedSubst().GetSubst().GetMeta()) + res, sl = nds.chooseSubstitutionWithoutMetaLastApplyNonDestructive(st.GetSubstsFound(), getMetas(st.GetLastAppliedSubst().GetSubst())) if !res.IsEmpty() { // subst without meta in last applied meta found in substs_found st.SetSubstsFound(append(sl, substs_found_this_step...)) return res @@ -121,16 +132,19 @@ func (nds *nonDestructiveSearch) chooseSubstitutionNonDestructive(substs_found_t } /* Take a substitution, returns the id of the formula which introduce the metavariable */ -func (nds *nonDestructiveSearch) catchFormulaToInstantiate(subst_found Unif.Substitutions) int { +func (nds *nonDestructiveSearch) catchFormulaToInstantiate(subst_found Lib.List[Unif.MixedSubstitution]) int { meta_to_reintroduce := -1 - for _, subst := range subst_found { - meta, term := subst.Get() - if meta.GetFormula() < meta_to_reintroduce || meta_to_reintroduce == -1 { - meta_to_reintroduce = meta.GetFormula() - } - if term.IsMeta() { - if term.ToMeta().GetFormula() < meta_to_reintroduce || meta_to_reintroduce == -1 { - meta_to_reintroduce = term.ToMeta().GetFormula() + for _, subst := range subst_found.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + meta, term := s.Val.Get() + if meta.GetFormula() < meta_to_reintroduce || meta_to_reintroduce == -1 { + meta_to_reintroduce = meta.GetFormula() + } + if term.IsMeta() { + if term.ToMeta().GetFormula() < meta_to_reintroduce || meta_to_reintroduce == -1 { + meta_to_reintroduce = term.ToMeta().GetFormula() + } } } } @@ -142,7 +156,12 @@ func (nds *nonDestructiveSearch) catchFormulaToInstantiate(subst_found Unif.Subs **/ func (nds *nonDestructiveSearch) instantiate(fatherId uint64, state *State, c Communication, index int, s Core.SubstAndForm) { debug( - Lib.MkLazy(func() string { return fmt.Sprintf("Instantiate with subst : %v ", s.GetSubst().ToString()) }), + Lib.MkLazy(func() string { + return fmt.Sprintf( + "Instantiate with subst : %s", + Lib.ListToString(s.GetSubst(), Lib.WithEmpty("(empty subst)")), + ) + }), ) newMetaGenerator := state.GetMetaGen() reslf := Core.ReintroduceMeta(&newMetaGenerator, index, state.GetN()) @@ -190,12 +209,15 @@ func (nds *nonDestructiveSearch) instantiate(fatherId uint64, state *State, c Co } } - if !found { // Vérifier dans substapplied - for _, subst := range state.GetAppliedSubst().GetSubst() { - original_meta, original_term := subst.Get() - if !found && original_meta.GetName() == new_meta.GetName() && !found { - association_subst.Set(new_meta, original_term) - found = true + if !found { + for _, subst := range state.GetAppliedSubst().GetSubst().GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + original_meta, original_term := s.Val.Get() + if !found && original_meta.GetName() == new_meta.GetName() && !found { + association_subst.Set(new_meta, original_term) + found = true + } } } } @@ -211,58 +233,50 @@ func (nds *nonDestructiveSearch) instantiate(fatherId uint64, state *State, c Co } } - new_subst, same_key := Unif.MergeSubstitutions(association_subst, state.GetAppliedSubst().GetSubst()) + mixed_assoc_subst := Lib.NewList[Unif.MixedSubstitution]() + for _, subst := range association_subst { + mixed_assoc_subst.Append(Unif.MkMixedFromSubst(subst)) + } + new_subst, same_key := Unif.MergeMixedSubstitutions(mixed_assoc_subst, state.GetAppliedSubst().GetSubst()) if same_key { Glob.PrintInfo("PS", "Same key in S2 and S1") } - if new_subst.Equals(Unif.Failure()) { + + if !Unif.UnifSucceeded(new_subst) { Glob.Anomaly("PS", "MergeSubstitutions return failure") } - new_subst, same_key = Unif.MergeSubstitutions(new_subst, s.GetSubst()) + new_subst, same_key = Unif.MergeMixedSubstitutions(new_subst, s.GetSubst()) if same_key { Glob.PrintInfo("PS", "Same key in S2 and S1") } - if new_subst.Equals(Unif.Failure()) { + + if !Unif.UnifSucceeded(new_subst) { Glob.Anomaly("PS", "MergeSubstitutions return failure") } - // Then associate with the substitution (if possible) - // for _, new_meta := range new_metas { - // found := false - // for original_meta, original_term := range s.GetSubst() { - // if !found && original_meta.GetName() == new_meta.GetName() && !found { - // new_subst[new_meta] = original_term - // found = true - // } else { // Test inverse pour le cas meta/meta - // if !found && original_term.IsMeta() && original_term.GetName() == new_meta.GetName() && !found { - // new_subst[new_meta] = original_term - // found = true - // } - // } - // } - // } - debug( Lib.MkLazy(func() string { return fmt.Sprintf( "Applied subst: %s", - state.GetAppliedSubst().GetSubst().ToString()) + Lib.ListToString(state.GetAppliedSubst().GetSubst(), Lib.WithEmpty("(empty subst)")), + ) }), ) debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Real substitution applied : %s", new_subst.ToString()) + "Real substitution applied : %s", Lib.ListToString(new_subst, Lib.WithEmpty("(empty subst)"))) }), ) state.SetLF(Core.ApplySubstitutionsOnFormAndTermsList(new_subst, state.GetLF())) - ms, same_key := Unif.MergeSubstitutions(state.GetAppliedSubst().GetSubst(), new_subst) + ms, same_key := Unif.MergeMixedSubstitutions(state.GetAppliedSubst().GetSubst(), new_subst) if same_key { Glob.Anomaly("PS", "Same key in S2 and S1") } - if ms.Equals(Unif.Failure()) { + + if !Unif.UnifSucceeded(ms) { Glob.Anomaly("PS", "MergeSubstitutions return failure") } state.SetAppliedSubst(Core.MakeSubstAndForm(ms, s.GetForm())) @@ -296,14 +310,14 @@ func (nds *nonDestructiveSearch) manageSubstFoundNonDestructive(father_id uint64 st.SetSubstsFound(st.GetSubstsFound()[1:]) } - choosenSubstMetas := new_choosen_subst.GetSubst().GetMeta() + choosenSubstMetas := getMetas(new_choosen_subst.GetSubst()) debug(Lib.MkLazy(func() string { return fmt.Sprintf( "Choosen subst : %v - HasInCommon : %v", - new_choosen_subst.GetSubst().ToString(), + Lib.ListToString(new_choosen_subst.GetSubst(), Lib.WithEmpty("(empty subst)")), AST.HasMetaInCommonWith( choosenSubstMetas, - st.GetLastAppliedSubst().GetSubst().GetMeta(), + getMetas(st.GetLastAppliedSubst().GetSubst()), ), ) })) diff --git a/src/Search/proof.go b/src/Search/proof.go index 1fa3e56f..6d292ee7 100644 --- a/src/Search/proof.go +++ b/src/Search/proof.go @@ -404,7 +404,7 @@ func RetrieveUninstantiatedMetaFromProof(proofStruct []ProofStruct) Lib.Set[AST. } /* Apply subst on a proof tree */ -func ApplySubstitutionOnProofList(s Unif.Substitutions, proof_list []ProofStruct) []ProofStruct { +func ApplySubstitutionOnProofList(s Lib.List[Unif.MixedSubstitution], proof_list []ProofStruct) []ProofStruct { new_proof_list := []ProofStruct{} for _, p := range proof_list { @@ -412,7 +412,10 @@ func ApplySubstitutionOnProofList(s Unif.Substitutions, proof_list []ProofStruct new_result_formulas := []IntFormAndTermsList{} for _, f := range p.GetResultFormulas() { - new_result_formulas = append(new_result_formulas, MakeIntFormAndTermsList(f.GetI(), Core.ApplySubstitutionsOnFormAndTermsList(s, f.GetFL()))) + new_result_formulas = append( + new_result_formulas, + MakeIntFormAndTermsList(f.GetI(), Core.ApplySubstitutionsOnFormAndTermsList(s, f.GetFL())), + ) } p.SetResultFormulasProof(new_result_formulas) diff --git a/src/Search/rules.go b/src/Search/rules.go index 855aafcb..b9b490b3 100644 --- a/src/Search/rules.go +++ b/src/Search/rules.go @@ -59,17 +59,9 @@ var strToPrintMap map[string]string = map[string]string{ "EXISTS": "∃", } -/** -* ApplyClosureRules -* Search closure rules (not true or false), and call search conflict if no obvious closure found -* Datas : -* form : the formula for which we are looking for the contradiction -* state : a state, containing all the formula of the current step -* Result : -* a boolean, true if a contradiction was found, false otherwise -* a substitution, the substitution which make the contradiction (possibly empty) -**/ -func ApplyClosureRules(form AST.Form, state *State) (result bool, substitutions []Unif.Substitutions) { +func ApplyClosureRules(form AST.Form, state *State) (bool, Lib.List[Lib.List[Unif.MixedSubstitution]]) { + result := false + substitutions := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() debug(Lib.MkLazy(func() string { return "Start ACR" })) if searchObviousClosureRule(form) { @@ -78,10 +70,14 @@ func ApplyClosureRules(form AST.Form, state *State) (result bool, substitutions f := form.Copy() - substFound, subst := searchInequalities(form) + substFound, substs := searchInequalities(form) if substFound { result = true - substitutions = append(substitutions, subst) + mixed_substs := Lib.NewList[Unif.MixedSubstitution]() + for _, subst := range substs { + mixed_substs.Append(Unif.MkMixedFromSubst(subst)) + } + substitutions.Append(mixed_substs) } substFound, matchSubsts := searchClosureRule(f, *state) @@ -92,10 +88,10 @@ func ApplyClosureRules(form AST.Form, state *State) (result bool, substitutions for _, subst := range matchSubsts { debug(Lib.MkLazy(func() string { return fmt.Sprintf("MSL : %v", subst.ToString()) })) - if subst.GetSubst().Equals(Unif.MakeEmptySubstitution()) { + if subst.IsSubstsEmpty() { result = true } else { - if !searchForbidden(state, subst) { + if !searchForbidden(state, subst.MatchingSubstitutions()) { result = true } } @@ -104,13 +100,13 @@ func ApplyClosureRules(form AST.Form, state *State) (result bool, substitutions debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Subst found between : %v and %v : %v", + "Subst found between : %s and %s : %s", form.ToString(), subst.GetForm().ToString(), - subst.GetSubst().ToString()) + subst.ToString()) }), ) - substitutions = Unif.AppendIfNotContainsSubst(substitutions, subst.GetSubst()) + substitutions.Add(Lib.ListEquals[Unif.MixedSubstitution], subst.GetSubsts()) } } } @@ -121,8 +117,15 @@ func ApplyClosureRules(form AST.Form, state *State) (result bool, substitutions func searchForbidden(state *State, s Unif.MatchingSubstitutions) bool { foundForbidden := false - for _, substForbidden := range state.GetForbiddenSubsts() { - forbiddenShared := Core.AreEqualsModuloaLaphaConversion(s.GetSubst(), substForbidden) + for _, substForbidden := range state.GetForbiddenSubsts().GetSlice() { + substs := Unif.Substitutions{} + for _, subst := range substForbidden.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + substs = append(substs, s.Val) + } + } + forbiddenShared := Core.AreEqualsModuloaLaphaConversion(s.GetSubst(), substs) if forbiddenShared { foundForbidden = true @@ -194,7 +197,7 @@ func searchInequalities(form AST.Form) (bool, Unif.Substitutions) { } /* Search a contradiction between a formula and another in the datastructure */ -func searchClosureRule(f AST.Form, st State) (bool, []Unif.MatchingSubstitutions) { +func searchClosureRule(f AST.Form, st State) (bool, []Unif.MixedSubstitutions) { switch nf := f.(type) { case AST.Pred: return st.GetTreeNeg().Unify(f) diff --git a/src/Search/search.go b/src/Search/search.go index cb5e019b..c55ab779 100644 --- a/src/Search/search.go +++ b/src/Search/search.go @@ -49,7 +49,7 @@ import ( type SearchAlgorithm interface { Search(AST.Form, int) bool SetApplyRules(func(uint64, State, Communication, Core.FormAndTermsList, int, int, []int)) - ManageClosureRule(uint64, *State, Communication, []Unif.Substitutions, Core.FormAndTerms, int, int) (bool, []Core.SubstAndForm) + ManageClosureRule(uint64, *State, Communication, Lib.List[Lib.List[Unif.MixedSubstitution]], Core.FormAndTerms, int, int) (bool, []Core.SubstAndForm) } var UsedSearch SearchAlgorithm @@ -118,10 +118,13 @@ func printStandardSolution(status string) { fmt.Printf("%s SZS status %v for %v\n", "%", status, Glob.GetProblemName()) } -func retrieveMetaFromSubst(s Unif.Substitutions) []int { +func retrieveMetaFromSubst(substs Lib.List[Unif.MixedSubstitution]) []int { res := []int{} - for _, s_element := range s { - res = Glob.AppendIfNotContainsInt(res, s_element.Key().GetFormula()) + for _, subst := range substs.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + res = Glob.AppendIfNotContainsInt(res, s.Val.Key().GetFormula()) + } } return res } diff --git a/src/Search/state.go b/src/Search/state.go index d0fe1082..8c3a6f85 100644 --- a/src/Search/state.go +++ b/src/Search/state.go @@ -64,7 +64,7 @@ type State struct { proof []ProofStruct current_proof ProofStruct bt_on_formulas bool - forbidden []Unif.Substitutions + forbidden Lib.List[Lib.List[Unif.MixedSubstitution]] unifier Core.Unifier eqStruct eqStruct.EqualityStruct } @@ -134,7 +134,7 @@ func (s State) GetCurrentProof() ProofStruct { func (s State) GetBTOnFormulas() bool { return s.bt_on_formulas } -func (s State) GetForbiddenSubsts() []Unif.Substitutions { +func (s State) GetForbiddenSubsts() Lib.List[Lib.List[Unif.MixedSubstitution]] { return s.forbidden } func (s State) GetGlobUnifier() Core.Unifier { @@ -245,8 +245,8 @@ func (st *State) SetCurrentProofNodeId(i int) { func (st *State) SetBTOnFormulas(b bool) { st.bt_on_formulas = b } -func (st *State) SetForbiddenSubsts(s []Unif.Substitutions) { - st.forbidden = Unif.CopySubstList(s) +func (st *State) SetForbiddenSubsts(s Lib.List[Lib.List[Unif.MixedSubstitution]]) { + st.forbidden = s.Copy(Lib.ListCpy[Unif.MixedSubstitution]) } func (s *State) SetGlobUnifier(u Core.Unifier) { s.unifier = u.Copy() @@ -285,7 +285,7 @@ func MakeState(limit int, tp, tn Unif.DataStructure, f AST.Form) State { []ProofStruct{}, current_proof, false, - []Unif.Substitutions{}, + Lib.NewList[Lib.List[Unif.MixedSubstitution]](), Core.MakeUnifier(), eqStruct.NewEqStruct()} } @@ -353,7 +353,7 @@ func (st State) Print() { debug(Lib.MkLazy(func() string { return "Subst_found: " })) debug( Lib.MkLazy(func() string { - return Unif.SubstListToString(Core.GetSubstListFromSubstAndFormList(st.GetSubstsFound())) + return Unif.SubstsToString(Core.GetSubstListFromSubstAndFormList(st.GetSubstsFound())) }), ) } @@ -363,9 +363,16 @@ func (st State) Print() { debug(Lib.MkLazy(func() string { return st.GetLastAppliedSubst().ToString() })) } - if len(st.forbidden) > 0 { + if st.forbidden.Len() > 0 { debug(Lib.MkLazy(func() string { return "Forbidden:" })) - debug(Lib.MkLazy(func() string { return Unif.SubstListToString(st.forbidden) })) + debug( + Lib.MkLazy(func() string { + return st.forbidden.ToString( + func(m Lib.List[Unif.MixedSubstitution]) string { + return Lib.ListToString(m) + }, Lib.WithSep(" ; ")) + }), + ) } debug( diff --git a/src/Unif/data_structure.go b/src/Unif/data_structure.go index 763ae197..c3d9f2a7 100644 --- a/src/Unif/data_structure.go +++ b/src/Unif/data_structure.go @@ -47,6 +47,6 @@ type DataStructure interface { IsEmpty() bool MakeDataStruct(Lib.List[AST.Form], bool) DataStructure InsertFormulaListToDataStructure(Lib.List[AST.Form]) DataStructure - Unify(AST.Form) (bool, []MatchingSubstitutions) + Unify(AST.Form) (bool, []MixedSubstitutions) Copy() DataStructure } diff --git a/src/Unif/matching.go b/src/Unif/matching.go index 4a24fe15..2091101a 100644 --- a/src/Unif/matching.go +++ b/src/Unif/matching.go @@ -54,10 +54,17 @@ func InitDebugger() { /*** Unify ***/ /* Helper function to avoid using MakeMachine() outside of this file. */ -func (n Node) Unify(formula AST.Form) (bool, []MatchingSubstitutions) { +func (n Node) Unify(formula AST.Form) (bool, []MixedSubstitutions) { machine := makeMachine() res := machine.unify(n, formula) - return !reflect.DeepEqual(machine.failure, res), res // return found, res + // As we have transformed type metas to terms, we get everything in a term substitution. + // But externally, we want to have a substitution of both (term) metas to terms and (type) metas to types. + // We use MixedSubstitution to properly manage things internally. + mixed_substs := []MixedSubstitutions{} + for _, subst := range res { + mixed_substs = append(mixed_substs, subst.toMixed()) + } + return !reflect.DeepEqual(machine.failure, res), mixed_substs } /* Tries to find the substitutions needed to unify the formulae with the one described by the sequence of instructions. */ @@ -67,11 +74,10 @@ func (m *Machine) unify(node Node, formula AST.Form) []MatchingSubstitutions { switch formula_type := formula.(type) { case AST.Pred: // Transform the predicate to a function to make the tool work properly - // FIXME: transform type arguments into terms to unify them m.terms = Lib.MkListV[AST.Term](AST.MakerFun( formula_type.GetID(), - formula_type.GetTyArgs(), - formula_type.GetArgs(), + Lib.NewList[AST.Ty](), + getFunctionalArguments(formula_type.GetTyArgs(), formula_type.GetArgs()), )) result = m.unifyAux(node) @@ -254,7 +260,7 @@ func (m *Machine) end(instrTerm AST.Term) Status { func (m *Machine) right() Status { if m.isUnlocked() { m.q += 1 - if m.q > m.terms.Len() { + if m.q >= m.terms.Len() { return Status(ERROR) } m.topLevelCount += 1 diff --git a/src/Unif/matching_substitutions.go b/src/Unif/matching_substitutions.go index 7a727207..7ed91cb5 100644 --- a/src/Unif/matching_substitutions.go +++ b/src/Unif/matching_substitutions.go @@ -40,9 +40,197 @@ import ( "fmt" "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" + "github.com/GoelandProver/Goeland/Typing" ) +type TySubstitution struct { + k AST.TyMeta + v AST.Ty +} + +func MkTySubstitution(k AST.TyMeta, v AST.Ty) TySubstitution { + return TySubstitution{k, v} +} + +func (s TySubstitution) ToString() string { + return fmt.Sprintf("%s |-> %s", s.k.ToString(), s.v.ToString()) +} + +func (s TySubstitution) Equals(oth any) bool { + if os, ok := oth.(TySubstitution); ok { + return os.k.Equals(s.k) && os.v.Equals(s.v) + } + return false +} + +func (s TySubstitution) Copy() TySubstitution { + return MkTySubstitution(s.k.Copy().(AST.TyMeta), s.v.Copy()) +} + +func (s TySubstitution) Get() (AST.TyMeta, AST.Ty) { + return s.k, s.v +} + +type MixedSubstitution struct { + s Lib.Either[TySubstitution, Substitution] +} + +func translateFromSubst(subst Substitution) MixedSubstitution { + if AST.IsTType(subst.k.GetTy()) { + return MixedSubstitution{Lib.MkLeft[TySubstitution, Substitution]( + MkTySubstitution( + AST.TyMetaFromMeta(subst.k), + AST.TermToTy(subst.v), + ), + )} + } else { + return MixedSubstitution{Lib.MkRight[TySubstitution, Substitution]( + MakeSubstitution( + subst.k, + translateTermRec(subst.v), + ))} + } +} + +func translateTermRec(term AST.Term) AST.Term { + switch trm := term.(type) { + case AST.Fun: + // Already converted: do nothing (either everything is converted or nothing) + if !trm.GetTyArgs().Empty() { + return term + } + + ty_args := Lib.NewList[AST.Ty]() + opt_ty := Typing.QueryGlobalEnv(trm.GetName()) + switch ty := opt_ty.(type) { + case Lib.Some[AST.Ty]: + switch t := ty.Val.(type) { + case AST.TyPi: + for i := 0; i < t.VarsLen(); i++ { + ty_args.Append(AST.TermToTy(trm.GetArgs().At(i))) + } + } + } + args := trm.GetArgs() + args = trm.GetArgs().Slice(ty_args.Len(), trm.GetArgs().Len()) + + return AST.MakerFun( + trm.GetID(), + ty_args, + Lib.ListMap(args, translateTermRec), + ) + } + return term +} + +func MkMixedFromSubst(subst Substitution) MixedSubstitution { + return MixedSubstitution{Lib.MkRight[TySubstitution, Substitution](subst)} +} + +func MkMixedFromTy(subst TySubstitution) MixedSubstitution { + return MixedSubstitution{Lib.MkLeft[TySubstitution, Substitution](subst)} +} + +func FromSubstitutions(substs Substitutions) Lib.List[MixedSubstitution] { + mixed_substs := Lib.MkList[MixedSubstitution](len(substs)) + for i, subst := range substs { + mixed_substs.Upd(i, MixedSubstitution{Lib.MkRight[TySubstitution, Substitution](subst)}) + } + return mixed_substs +} + +func ToSubstitutions(mixed_substs Lib.List[MixedSubstitution]) Substitutions { + substs := Substitutions{} + for _, subst := range mixed_substs.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Substitution]: + substs = append(substs, s.Val) + } + } + return substs +} + +func (m MixedSubstitution) ToString() string { + return Lib.EitherToString[TySubstitution, Substitution](m.s, "TySubst", "TrmSubst") +} + +func (m MixedSubstitution) Equals(oth any) bool { + if om, ok := oth.(MixedSubstitution); ok { + return Lib.EitherEquals[TySubstitution, Substitution](m.s, om.s) + } + return false +} + +func (m MixedSubstitution) Copy() MixedSubstitution { + return MixedSubstitution{Lib.EitherCpy[TySubstitution, Substitution](m.s)} +} + +func (m MixedSubstitution) Substitution() Lib.Option[Substitution] { + switch s := m.s.(type) { + case Lib.Right[TySubstitution, Substitution]: + return Lib.MkSome(s.Val) + } + return Lib.MkNone[Substitution]() +} + +func (m MixedSubstitution) TySubstitution() Lib.Option[TySubstitution] { + switch s := m.s.(type) { + case Lib.Left[TySubstitution, Substitution]: + return Lib.MkSome(s.Val) + } + return Lib.MkNone[TySubstitution]() +} + +func (m MixedSubstitution) GetMixed() Lib.Either[TySubstitution, Substitution] { + return m.s +} + +type MixedSubstitutions struct { + form AST.Form + substs []MixedSubstitution +} + +func (m MixedSubstitutions) GetForm() AST.Form { + return m.form.Copy() +} + +func (m MixedSubstitutions) GetSubsts() Lib.List[MixedSubstitution] { + return Lib.MkListV(m.substs...) +} + +func (m MixedSubstitutions) GetTrmSubsts() Substitutions { + out_substs := Substitutions{} + for _, subst := range m.substs { + switch s := subst.s.(type) { + case Lib.Right[TySubstitution, Substitution]: + out_substs = append(out_substs, s.Val) + } + } + return out_substs +} + +func (m MixedSubstitutions) GetTySubsts() Lib.List[TySubstitution] { + out_substs := Lib.NewList[TySubstitution]() + for _, subst := range m.substs { + switch s := subst.s.(type) { + case Lib.Left[TySubstitution, Substitution]: + out_substs.Append(s.Val) + } + } + return out_substs +} + +func (m MixedSubstitutions) ToString() string { + substs_list := Lib.MkListV(m.substs...) + return m.GetForm().ToString() + " {" + Lib.ListToString(substs_list, Lib.WithEmpty("")) + "}" +} + +func (m MixedSubstitutions) IsSubstsEmpty() bool { + return len(m.substs) == 0 +} + type MatchingSubstitutions struct { form AST.Form subst Substitutions @@ -64,6 +252,68 @@ func (m MatchingSubstitutions) Print() { m.GetSubst().Print() } +func (m MatchingSubstitutions) toMixed() MixedSubstitutions { + substs := []MixedSubstitution{} + for _, subst := range m.subst { + substs = append(substs, translateFromSubst(subst)) + } + return MixedSubstitutions{m.form, substs} +} + func MakeMatchingSubstitutions(form AST.Form, subst Substitutions) MatchingSubstitutions { return MatchingSubstitutions{form.Copy(), subst.Copy()} } + +func (m MixedSubstitutions) MatchingSubstitutions() MatchingSubstitutions { + return MakeMatchingSubstitutions(m.form, m.GetTrmSubsts()) +} + +func translateToSubst(subst MixedSubstitution) Substitution { + switch s := subst.s.(type) { + case Lib.Left[TySubstitution, Substitution]: + return MakeSubstitution( + s.Val.k.ToTermMeta(), + AST.TyToTerm(s.Val.v), + ) + case Lib.Right[TySubstitution, Substitution]: + return s.Val + } + + Glob.Anomaly("unification internals", "Found neither a type substitution nor a substitution") + return MakeSubstitution(AST.MakeEmptyMeta(), nil) +} + +func MergeMixedSubstitutions(substs1, substs2 Lib.List[MixedSubstitution]) (Lib.List[MixedSubstitution], bool) { + translated_substs1 := Lib.ListMap(substs1, translateToSubst).GetSlice() + translated_substs2 := Lib.ListMap(substs2, translateToSubst).GetSlice() + + merged_tmp, _ := MergeSubstitutions(translated_substs1, translated_substs2) + + success := !merged_tmp.Equals(Failure()) + + merged := Lib.MkList[MixedSubstitution](len(merged_tmp)) + for i, subst := range merged_tmp { + merged.Upd(i, translateFromSubst(subst)) + } + return merged, success +} + +func SubstsToString(substs Lib.List[Lib.List[MixedSubstitution]]) string { + return substs.ToString( + func(m Lib.List[MixedSubstitution]) string { + return Lib.ListToString(m) + }, Lib.WithSep(" ; ")) +} + +func UnifSucceeded(unifs Lib.List[MixedSubstitution]) bool { + if unifs.Empty() { + return true + } + + succeeded := true + switch subst := unifs.At(0).Substitution().(type) { + case Lib.Some[Substitution]: + succeeded = !subst.Val.Equals(Failure()[0]) + } + return succeeded +} diff --git a/src/Unif/parsing.go b/src/Unif/parsing.go index 9674909d..69dd16be 100644 --- a/src/Unif/parsing.go +++ b/src/Unif/parsing.go @@ -61,7 +61,7 @@ func (t TermForm) RenameVariables() AST.Form { return t } func (t TermForm) ReplaceTermByTerm(AST.Term, AST.Term) (AST.Form, bool) { return t, false } -func (t TermForm) SubstTy(AST.TyBound, AST.Ty) AST.Form { +func (t TermForm) SubstTy(AST.TyGenVar, AST.Ty) AST.Form { return t } func (t TermForm) GetIndex() int { return t.index } @@ -109,6 +109,11 @@ func (t TermForm) ReplaceMetaByTerm(meta AST.Meta, term AST.Term) AST.Form { } func MakerTermForm(t AST.Term) TermForm { + switch trm := t.(type) { + case AST.Fun: + args := getFunctionalArguments(trm.GetTyArgs(), trm.GetArgs()) + t = AST.MakerFun(trm.GetID(), Lib.NewList[AST.Ty](), args) + } return makeTermForm(AST.MakerIndexFormula(), t.Copy()) } @@ -154,14 +159,39 @@ func ParseFormula(formula AST.Form) Sequence { } /* Parses a predicate to machine instructions */ +func getFunctionalArguments(ty_args Lib.List[AST.Ty], trm_args Lib.List[AST.Term]) Lib.List[AST.Term] { + args := Lib.ListMap(ty_args, AST.TyToTerm) + + for _, arg := range trm_args.GetSlice() { + switch term := arg.(type) { + case AST.Meta: + args.Append(arg) + case AST.Fun: + args.Append(AST.MakerFun( + term.GetID(), + Lib.NewList[AST.Ty](), + getFunctionalArguments(term.GetTyArgs(), term.GetArgs()), + )) + } + } + + return args +} + func parsePred(p AST.Pred, instructions *Sequence) { instructions.add(makeCheck(p.GetID())) - if p.GetArgs().Len() > 0 { + if !p.GetTyArgs().Empty() || !p.GetArgs().Empty() { instructions.add(Begin{}) instructions.add(Down{}) varCount := 0 postCount := 0 - parseTerms(p.GetArgs(), instructions, Lib.NewList[AST.Meta](), &varCount, &postCount) + parseTerms( + getFunctionalArguments(p.GetTyArgs(), p.GetArgs()), + instructions, + Lib.NewList[AST.Meta](), + &varCount, + &postCount, + ) instructions.add(End{}) } } @@ -210,7 +240,8 @@ func parseTerms( *postCount++ } instructions.add(Down{}) - subst = parseTerms(t.GetArgs(), instructions, subst, varCount, postCount) + subTerms := getFunctionalArguments(t.GetTyArgs(), t.GetArgs()) + subst = parseTerms(subTerms, instructions, subst, varCount, postCount) if rightDefined(terms, i) { *postCount-- instructions.add(Pop{*postCount}) diff --git a/src/Unif/substitutions_tree.go b/src/Unif/substitutions_tree.go index ab123186..5a9be9e7 100644 --- a/src/Unif/substitutions_tree.go +++ b/src/Unif/substitutions_tree.go @@ -63,7 +63,10 @@ func computeSubstitutions(subs []SubstPair, metasToSubs Substitutions, form AST. // Retrieve all the meta of from the tree formula switch typedForm := form.(type) { case AST.Pred: - metasFromTreeForm.Append(typedForm.GetMetaList().GetSlice()...) + trms := getFunctionalArguments(typedForm.GetTyArgs(), typedForm.GetArgs()) + for _, trm := range trms.GetSlice() { + metasFromTreeForm.Append(trm.GetMetaList().GetSlice()...) + } case TermForm: metasFromTreeForm.Append(typedForm.GetTerm().GetMetaList().GetSlice()...) default: From c4b4e6f855f3eeb8ff64a31afbb561991d04b911 Mon Sep 17 00:00:00 2001 From: Johann Rosain Date: Sun, 27 Jul 2025 11:04:30 +0200 Subject: [PATCH 6/8] Fix equality of quantified formulas (forall, exists) --- src/AST/formsDef.go | 10 ++++++++-- src/Lib/int.go | 10 ++++------ src/Mods/gs3/proof.go | 6 ++++++ src/Mods/gs3/sequent.go | 27 +++++++++++++++------------ src/Mods/tptp/proof.go | 12 ++++++++---- src/main.go | 2 ++ 6 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/AST/formsDef.go b/src/AST/formsDef.go index 717a3d27..48f5a7e6 100644 --- a/src/AST/formsDef.go +++ b/src/AST/formsDef.go @@ -100,7 +100,10 @@ func MakerAll(vars Lib.List[TypedVar], forms Form) All { } func (a All) Equals(other any) bool { - return a.quantifier.Equals(other) + if typed, ok := other.(All); ok { + return a.quantifier.Equals(typed.quantifier) + } + return false } func (a All) GetSubFormulasRecur() Lib.List[Form] { @@ -152,7 +155,10 @@ func MakerEx(vars Lib.List[TypedVar], forms Form) Ex { } func (e Ex) Equals(other any) bool { - return e.quantifier.Equals(other) + if typed, ok := other.(Ex); ok { + return e.quantifier.Equals(typed.quantifier) + } + return false } func (e Ex) GetSubFormulasRecur() Lib.List[Form] { diff --git a/src/Lib/int.go b/src/Lib/int.go index 68e24475..a7e4ef5b 100644 --- a/src/Lib/int.go +++ b/src/Lib/int.go @@ -37,24 +37,22 @@ package Lib -type Int struct { - value int -} +type Int int func (s Int) Equals(oth any) bool { if str, ok := oth.(Int); ok { - return s.value == str.value + return s == str } return false } func (s Int) Less(oth any) bool { if str, ok := oth.(Int); ok { - return s.value < str.value + return s < str } return false } func MkInt(s int) Int { - return Int{s} + return Int(s) } diff --git a/src/Mods/gs3/proof.go b/src/Mods/gs3/proof.go index c48b35e2..6f534e4e 100644 --- a/src/Mods/gs3/proof.go +++ b/src/Mods/gs3/proof.go @@ -104,6 +104,12 @@ type GS3Proof struct { deltaHisto []Glob.Pair[AST.Term, Glob.Pair[AST.Form, int]] } +var debug func(Lib.Lazy[string]) + +func InitDebugger() { + debug = Glob.CreateDebugger("GS3") +} + var MakeGS3Proof = func(proof []Search.ProofStruct) *GS3Sequent { gs3Proof := GS3Proof{ rulesApplied: make([]Glob.Pair[Rule, Search.ProofStruct], 0), diff --git a/src/Mods/gs3/sequent.go b/src/Mods/gs3/sequent.go index 7d05880e..aa08fe9f 100644 --- a/src/Mods/gs3/sequent.go +++ b/src/Mods/gs3/sequent.go @@ -34,6 +34,7 @@ package gs3 import ( "strings" + "fmt" "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" @@ -189,20 +190,22 @@ func (seq *GS3Sequent) setAppliedRule(rule Rule) { } func (seq *GS3Sequent) setAppliedOn(hypothesis AST.Form) { - index := -1 - for i, h := range seq.hypotheses.GetSlice() { - if hypothesis.Equals(h) { - index = i - break - } - } - - if index == -1 { - Glob.PrintInfo("APPLIED ON", hypothesis.ToString()) + index_opt := Lib.ListIndexOf(hypothesis, seq.hypotheses) + switch index := index_opt.(type) { + case Lib.Some[int]: + seq.appliedOn = int(index.Val) + case Lib.None[int]: + debug( + Lib.MkLazy(func() string { + return fmt.Sprintf( + "Tried to apply %s in a context composed of the following hypotheses: \n%s", + hypothesis.ToString(), + Lib.ListToString(seq.hypotheses, "\n", "(empty context)"), + ) + }), + ) Glob.Anomaly("GS3", "Failure: tried to apply a missing hypothesis") } - - seq.appliedOn = index } func (seq *GS3Sequent) setTermGenerated(t AST.Term) { diff --git a/src/Mods/tptp/proof.go b/src/Mods/tptp/proof.go index 20733340..fd48c167 100644 --- a/src/Mods/tptp/proof.go +++ b/src/Mods/tptp/proof.go @@ -596,10 +596,14 @@ func performCutAxiomStep(axioms Lib.List[AST.Form], conjecture AST.Form) string /*** Utility Functions ***/ func get(f AST.Form, fl Lib.List[AST.Form]) int { - for i, h := range fl.GetSlice() { - if h.Equals(f) { - return i - } + switch index := Lib.ListIndexOf(f, fl).(type) { + case Lib.Some[int]: + return index.Val + case Lib.None[int]: + Glob.Anomaly( + "TPTP", + fmt.Sprintf("Formula %s not found in context", f.ToString()), + ) } return -1 } diff --git a/src/main.go b/src/main.go index 5a61e71a..ca0ccdb8 100644 --- a/src/main.go +++ b/src/main.go @@ -55,6 +55,7 @@ import ( "github.com/GoelandProver/Goeland/Mods/assisted" "github.com/GoelandProver/Goeland/Mods/dmt" equality "github.com/GoelandProver/Goeland/Mods/equality/bse" + "github.com/GoelandProver/Goeland/Mods/gs3" "github.com/GoelandProver/Goeland/Parser" "github.com/GoelandProver/Goeland/Search" "github.com/GoelandProver/Goeland/Search/incremental" @@ -215,6 +216,7 @@ func initDebuggers() { // Typing.InitDebugger() Unif.InitDebugger() Engine.InitDebugger() + gs3.InitDebugger() } // FIXME: eventually, we would want to add an "interpretation" layer between elab and internal representation that does this From 8d519f9f103ca97f558f8efa71314f467122975f Mon Sep 17 00:00:00 2001 From: Johann Rosain Date: Sun, 27 Jul 2025 11:33:43 +0200 Subject: [PATCH 7/8] Add proper debugging facilities in typing rules --- src/Mods/gs3/sequent.go | 2 +- src/Typing/env-and-context.go | 10 ++++++++++ src/Typing/init.go | 14 +++++++++++++- src/Typing/rules.go | 30 ++++++++++++++++++++++++++++++ src/main.go | 2 +- 5 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/Mods/gs3/sequent.go b/src/Mods/gs3/sequent.go index aa08fe9f..103ff7bf 100644 --- a/src/Mods/gs3/sequent.go +++ b/src/Mods/gs3/sequent.go @@ -200,7 +200,7 @@ func (seq *GS3Sequent) setAppliedOn(hypothesis AST.Form) { return fmt.Sprintf( "Tried to apply %s in a context composed of the following hypotheses: \n%s", hypothesis.ToString(), - Lib.ListToString(seq.hypotheses, "\n", "(empty context)"), + Lib.ListToString(seq.hypotheses, Lib.WithSep("\n"), Lib.WithEmpty("(empty context)")), ) }), ) diff --git a/src/Typing/env-and-context.go b/src/Typing/env-and-context.go index 48b2e240..d46d2615 100644 --- a/src/Typing/env-and-context.go +++ b/src/Typing/env-and-context.go @@ -106,6 +106,16 @@ type Env struct { mut sync.Mutex } +func (env *Env) toString() string { + env.mut.Lock() + result := "Environment:" + for k, v := range env.con { + result += "\n- " + k + ": " + v.ToString() + } + env.mut.Unlock() + return result + "\n" +} + func safeGlobalOperation[T any](f func() T) T { global_env.mut.Lock() res := f() diff --git a/src/Typing/init.go b/src/Typing/init.go index 6411a329..ccbccbc0 100644 --- a/src/Typing/init.go +++ b/src/Typing/init.go @@ -37,13 +37,17 @@ package Typing import ( + "sync" + "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" - "sync" ) var global_env Env var ari_var string +var debug Glob.Debugger +var debug_low_level Glob.Debugger func Init() { global_env = Env{make(map[string]AST.Ty), sync.Mutex{}} @@ -52,6 +56,11 @@ func Init() { initTPTPNativeTypes() } +func InitDebugger() { + debug = Glob.CreateDebugger("typing") + debug_low_level = Glob.CreateDebugger("typing-low") +} + func initTPTPNativeTypes() { for _, ty := range AST.DefinedTPTPTypes().GetSlice() { AddToGlobalEnv(ty.Symbol(), AST.TType()) @@ -106,6 +115,9 @@ func initTPTPNativeTypes() { recordConversion("$to_int", AST.TInt()) recordConversion("$to_rat", AST.TRat()) recordConversion("$to_real", AST.TReal()) + + debug(Lib.MkLazy(func() string { return "TPTP native loaded in global environment" })) + debug_low_level(Lib.MkLazy(global_env.toString)) } func recordBinaryProp(name string) { diff --git a/src/Typing/rules.go b/src/Typing/rules.go index 098aab67..96c0e167 100644 --- a/src/Typing/rules.go +++ b/src/Typing/rules.go @@ -47,10 +47,16 @@ import ( var label = "typing" func TypeCheck(form AST.Form) bool { + debug(Lib.MkLazy(func() string { return fmt.Sprintf("Launching type checking on %s", form.ToString()) })) + return typecheckForm(emptyCon(), form) } func typecheckForm(con Con, form AST.Form) bool { + debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Trying to type-check: %s |- %s : o", con.toString(), form.ToString()) + })) + switch f := form.(type) { case AST.Bot, AST.Top: return true @@ -96,6 +102,10 @@ func typecheckForm(con Con, form AST.Form) bool { } func typecheckTerm(con Con, term AST.Term, ty AST.Ty) bool { + debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Trying to type-check: %s |- %s : %s", con.toString(), term.ToString(), ty.ToString()) + })) + switch t := term.(type) { case AST.Var: if !con.contains(t.GetName(), ty) { @@ -135,6 +145,11 @@ func typecheckTerm(con Con, term AST.Term, ty AST.Ty) bool { } func typecheckType(con Con, ty AST.Ty) bool { + debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Trying to type-check: %s |- %s : %s", + con.toString(), ty.ToString(), AST.TType().ToString()) + })) + switch nty := ty.(type) { case AST.TyBound: if !con.contains(nty.GetName(), AST.TType()) { @@ -206,7 +221,16 @@ func checkFunctional( oty := QueryEnvInstance(name, tys) switch ty := oty.(type) { case Lib.Some[AST.Ty]: + debug_low_level(Lib.MkLazy(func() string { + return fmt.Sprintf("%s has a functional scheme instantiated to %s", debug_str.Run(), ty.Val.ToString()) + })) + instantiated_ty := AST.GetArgsTy(ty.Val) + debug_low_level(Lib.MkLazy(func() string { + return fmt.Sprintf("Arguments will be typechecked against: [%s]", + Lib.ListToString(instantiated_ty, Lib.WithEmpty(""))) + })) + terms_checker := buildTermCheckList( debug_str, ty.Val, @@ -232,6 +256,12 @@ func typecheckRec( typed_terms Lib.List[Lib.Pair[AST.Term, AST.Ty]], tys Lib.List[AST.Ty], ) bool { + + debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Next typecheck: forms (%v), terms (%v), types (%v)", + !forms.Empty(), !typed_terms.Empty(), !tys.Empty()) + })) + calls := []func(chan bool){} for _, form := range forms.GetSlice() { diff --git a/src/main.go b/src/main.go index ca0ccdb8..b77715ee 100644 --- a/src/main.go +++ b/src/main.go @@ -213,7 +213,7 @@ func initDebuggers() { equality.InitDebugger() incremental.InitDebugger() Search.InitDebugger() - // Typing.InitDebugger() + Typing.InitDebugger() Unif.InitDebugger() Engine.InitDebugger() gs3.InitDebugger() From 7695826bf864f7249f30804e2a0f788e46d8344c Mon Sep 17 00:00:00 2001 From: Johann Rosain Date: Mon, 28 Jul 2025 09:30:46 +0200 Subject: [PATCH 8/8] Add some basic tests on the elaboration --- devtools/test-suite/basic/test-typing-elab-1.p | 7 +++++++ devtools/test-suite/basic/test-typing-elab-2.p | 7 +++++++ devtools/test-suite/basic/test-typing-elab-3.p | 4 ++++ src/Engine/tptp-defined-types.go | 2 +- 4 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 devtools/test-suite/basic/test-typing-elab-1.p create mode 100644 devtools/test-suite/basic/test-typing-elab-2.p create mode 100644 devtools/test-suite/basic/test-typing-elab-3.p diff --git a/devtools/test-suite/basic/test-typing-elab-1.p b/devtools/test-suite/basic/test-typing-elab-1.p new file mode 100644 index 00000000..1a650628 --- /dev/null +++ b/devtools/test-suite/basic/test-typing-elab-1.p @@ -0,0 +1,7 @@ +% should fail because $lesseq is a defined function for $int, $rat and $real but is not polymorphic +% for any type +% exit: 1 + +tff(ty_type, type, ty : $tType). + +tff(conj, conjecture, ! [A : ty] : $lesseq(A, A)). diff --git a/devtools/test-suite/basic/test-typing-elab-2.p b/devtools/test-suite/basic/test-typing-elab-2.p new file mode 100644 index 00000000..ad8ea066 --- /dev/null +++ b/devtools/test-suite/basic/test-typing-elab-2.p @@ -0,0 +1,7 @@ +% should fail because $quotient is a defined function for $int, $rat and $real but is not polymorphic +% for any type +% exit: 1 + +tff(ty_type, type, ty : $tType). + +tff(conj, conjecture, ! [A : ty] : $lesseq($quotient(A, A), 1)). diff --git a/devtools/test-suite/basic/test-typing-elab-3.p b/devtools/test-suite/basic/test-typing-elab-3.p new file mode 100644 index 00000000..fed2fe93 --- /dev/null +++ b/devtools/test-suite/basic/test-typing-elab-3.p @@ -0,0 +1,4 @@ +% quotient is defined specifically for integers +% result: NOT VALID + +tff(conj, conjecture, $lesseq($quotient(2, 2), 1)). diff --git a/src/Engine/tptp-defined-types.go b/src/Engine/tptp-defined-types.go index 8ddc3e90..041f8c0d 100644 --- a/src/Engine/tptp-defined-types.go +++ b/src/Engine/tptp-defined-types.go @@ -106,7 +106,7 @@ func initialContext() Context { mkDefined("$remainder_e", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) mkDefined("$remainder_t", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) mkDefined("$remainder_f", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) - mkDefined("$quotient", 2, Lib.MkSome(Lib.MkListV(tRat, tReal)), Parser.MkTypeAll( + mkDefined("$quotient", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), Parser.MkTypeAll( []Lib.Pair[string, Parser.PAtomicType]{ Lib.MkPair("number", tType.(Parser.PAtomicType)), Lib.MkPair("rat_or_real", tType.(Parser.PAtomicType)),