added README and some files I missed

This commit is contained in:
William Ball 2025-07-24 21:11:36 -07:00
parent debb9d200c
commit 1e175fdc8f
Signed by: wball
GPG key ID: B8682D8137B70765
4 changed files with 142 additions and 0 deletions

9
README.org Normal file
View file

@ -0,0 +1,9 @@
#+title: README
#+author: William Ball
* FOL Idris
I'm definitely not the first person to do this, but I had an idea a while back for correct by construction FOL terms and formulas in a dependently typed language, and finally got around to playing with it, and it is very cool. The idea is I have a type `Term` representing a term in some first order language, and a type `Formula` representing a formula in that language. Then, through some careful applications of dependent types, it is only possible to construct well-formed formulas. For example, suppose the signature `N` contains a binary function symbol `Plus`, a nullary function symbol (i.e.\nbsp{}constant symbol) `Zero`, and a unary function symbol `S`. Then you can construct the term `Plus(Zero, S(Zero))`, but `Plus(S(Zero(Zero), Zero))` doesn't type check.
Where things start to get really cool is that you can do the same thing with a proof object. So `Proof` is a type representing a proof, but only correct proofs can even be constructed. Typically you'd have representations of terms, formulas, and proofs, but then would have to write code to verify them; verify that the proof is correct and that the terms and formulas are well formed. You can also very easily play with different logics by just tweaking the constructors of `Proof`. For example, by removing the constructor `Contra` from `Proof`, and adding some other constructors that become necessary, you'd have an intuitionist logic. As it stands, the rules and connectives are extremely minimal, with derived rules existing as proofs in the `Logic` module[fn:: `EqRefl` and `EqTrans` are provable from `EqE`, but using `EqE` is quite difficult in general, at least without the theorem `elimBinder (inc t) s = t` stating that adding a variable you don't use to a term then substituting it doesn't do anything, but I was struggling to prove that, not being familiar with Idris's capabilities as a proof assistant.].
I don't really have a goal with this project, and have just been working on it for fun. There's tons more work that can be done. As it stands, this is far less capable/usable than [[https://forgejo.ballcloud.cc/wball/perga][my last proof assistant]], but I think it's pretty cool. It's pretty similar to [[https://github.com/epfl-lara/lisa][lisa]], but with a more trusted kernel and far less usability.

82
src/Logic.idr Normal file
View file

@ -0,0 +1,82 @@
module Logic
import Data.Fin
import Signature
import Term
import Formula
import Context
import Proof
%default total
export
BasicWeaken : {c : Context sig n} -> Proof c phi -> Proof (a :: c) phi
BasicWeaken pf = Weaken pf (Missing SameSubset)
public export
Not : Formula sig n -> Formula sig n
Not phi = Imp phi Bot
export
DoubleNeg : {d : _} -> {c : _} -> {phi : Formula sig d} -> Proof c (Not (Not phi)) -> Proof c phi
DoubleNeg pf = Contra $ ImpE (BasicWeaken pf) (Hyp 0)
public export
And : Formula sig n -> Formula sig n -> Formula sig n
And phi psi = Not (Imp phi (Not psi))
public export
Or : Formula sig n -> Formula sig n -> Formula sig n
Or phi psi = Not (And (Not phi) (Not psi))
export
AndI : {d : _} -> {c : _} -> {phi, psi : Formula sig d} -> Proof c phi -> Proof c psi -> Proof c (And phi psi)
AndI pf1 pf2 = ImpI $ ImpE (ImpE (Hyp 0) (BasicWeaken pf1)) (BasicWeaken pf2)
export
AndEL : {d : _} -> {c : _} -> {phi, psi : Formula sig d} -> Proof c (And phi psi) -> Proof c phi
AndEL pf = Contra $
ImpE (BasicWeaken pf) $
ImpI $
BotE $
ImpE (Hyp 1) (Hyp 0)
export
AndER : {d : _} -> {c : _} -> {phi, psi : Formula sig d} -> Proof c (And phi psi) -> Proof c psi
AndER pf = Contra $
ImpE (BasicWeaken pf) $
ImpI $
Hyp 1
export
AndComm : {d : _} -> {c : _} -> {phi, psi : Formula sig d} -> Proof c (And phi psi) -> Proof c (And psi phi)
AndComm pf = AndI (AndER pf) (AndEL pf)
export
OrIL : {d : _} -> {c : _} -> {phi, psi : Formula sig d} -> Proof c phi -> Proof c (Or phi psi)
OrIL pf = ImpI (ImpE (AndEL (Hyp 0)) (BasicWeaken pf))
export
OrIR : {d : _} -> {c : _} -> {phi, psi : Formula sig d} -> Proof c psi -> Proof c (Or phi psi)
OrIR pf = ImpI (ImpE (AndER (Hyp 0)) (BasicWeaken pf))
export
OrE : {d : _} -> {c : _} -> {phi, psi, chi : Formula sig d} ->
Proof c (Or phi psi) -> Proof (phi :: c) chi -> Proof (psi :: c) chi -> Proof c chi
OrE pfOr pfPhi pfPsi =
Contra $
ImpE (BasicWeaken pfOr) $
AndI
(ImpI (ImpE (Hyp 1) (Weaken pfPhi (There (Missing SameSubset)))))
(ImpI (ImpE (Hyp 1) (Weaken pfPsi (There (Missing SameSubset)))))
export
ExcludedMiddle : {d : _} -> {phi : Formula sig d} -> Proof [] (Or phi (Not phi))
ExcludedMiddle = Contra $
ImpE (Hyp 0) $
OrIL $
Contra $
ImpE (Hyp 1) $
OrIR $
Hyp 0

4
test/src/Main.idr Normal file
View file

@ -0,0 +1,4 @@
module Main
main : IO ()
main = putStrLn "Test successful!"

47
test/test.ipkg Normal file
View file

@ -0,0 +1,47 @@
package fol-test
version = 0.1.0
authors = "William Ball"
-- maintainers =
-- license =
-- brief =
-- readme =
-- homepage =
-- sourceloc =
-- bugtracker =
-- the Idris2 version required (e.g. langversion >= 0.5.1)
-- langversion
-- packages to add to search path
depends = fol
-- modules to install
-- modules =
-- main file (i.e. file to load at REPL)
main = Main
-- name of executable
executable = "fol-test"
-- opts =
sourcedir = "src"
-- builddir =
-- outputdir =
-- script to run before building
-- prebuild =
-- script to run after building
-- postbuild =
-- script to run after building, before installing
-- preinstall =
-- script to run after installing
-- postinstall =
-- script to run before cleaning
-- preclean =
-- script to run after cleaning
-- postclean =