Carnap @ TheEdu17
Graham Leach-Krouse
<gleachkr@ksu.edu>
Kansas State University
Interactive Slides available at:
gleachkr.github.io/CADEslidesToday
- Description of the Project
- Some Demonstrations
- A Look Behind the Scenes
- Discussion of Applications
Description of The Project
What is it?
Carnap is an free and open framework for developing formal reasoning applications that run in a standard web browser
For example
- Parsers for formal languages
- Interpreters for languages with compositional semantics
- Proof-checking tools
Carnap aims to be modular, flexible, and generic
Beginning from an extensible higher-order abstract syntax, Carnap can generically perform operations like higher-order unification, semantic evaluation, and term-rewriting on realizations of this syntax.
Why would you make that?
Minimize Barrier to Entry
- Installation is trivial.
- Operating System doesn't matter.
- Familiarity counteracts misology, arithmophobia.
Maximize Adaptability, Extensibility
- Flexibility empowers instructors.
- Adaptability avoids textbook costs.
- Web allows rapid iteration.
- Genericity trades code for data. (Example later)
Take Advantage of Modern Web Technologies
- Websockets
- OAuth
- Markdown Languages
- JSON
How do you make that?
Demonstrations
Language of Propositional Logic
- Countable list of (Boolean-valued) Sentence Letters.
- The constructor for these is essentially of type:
Prop :: Int -> Prop Bool
- Boolean Connectives. Constructors for these are essentially of types:
And :: Conn (Bool -> Bool -> Bool) Not :: Conn (Bool -> Bool) ... etc.
In case that "essentially" makes you nervous:
We can make a lexicon (disjoint union) of symbol types thus:
type PropLexicon = Prop :|: Conn
Hiding some dark magic in that :|:
operator.
But this isn't quite a language yet...
type PropLang = FixLang PropLexicon
Result:
How does the parser work?
We combine a generic parser for Prop a
and
a generic parser for Conn b
Non-generic part: Approximately 7 SLOC
How does the display work?
instance Schematizable Prop where
schematize (Pred n) = λ_ -> "P" ++ show n
instance Schematizable Conn where
schematize Not = λ(p:_) -> "¬" ++ p
Everything derived generically from these declarations.
How does the proof-checker work?
I lied ever so slightly about what's in the language. It also includes schematic sentence letters.
type PropLexicon =
Prop :|: Conn :|: SchematicProp
These are just letters like φ and ψ that usually occur in the statement of inference rules
Logics are specified by declarative rules.
On the board:
In the code:
modusPonens =
[ GammaV 1 ⊢ phi 1
, GammaV 2 ⊢ (phi 1 .→. phi 2)
] ∴ (GammaV 1 :+: GammaV 2) ⊢ phi 2
What about a more complicated language?
Language of First-Order Logic
type FirstOrderLexicon = PropLexicon
:|: FreeVar
:|: Pred
:|: Quant
:|: SchematicPred
Types of Quantifiers
All :: Quant ((Thing -> Bool) -> Bool)
Some :: Quant ((Thing -> Bool) -> Bool)
Result:
Higher-Order Logic?
Fitch style proofs?
Other Language Ingredients
- Function symbols
Func :: Int -> Func (Thing -> Thing)
- Modal/Temporal/Deontic/Epistemic Operators
- Abstraction Operators
Num :: NumberOf ((Thing -> Bool) -> Thing)
- Sequents
(:⊢:) :: Sequent (Bool -> Bool -> Judgement)
Currently Available
- Three Styles of Proof (Montegue, Hardegree, Fitch)
- Nine Proof Systems
-
Compatible with four different well-known textbooks
(Bergmann Moor and Nelson's The Logic Book, Kalish and Montegue's Formal Logic, Hardegree's Modal Logic, and P.D. Magnus' Forall x)
Behind the Scenes
Unification
Proof checking is powered by an implementation of Huet's algorithm.
Huet is complete for higher-order unification problems (if there is a solution, Huet finds it)
Algorithm is non-deterministic, type-directed, and stateful. Haskell is very helpful here.
Higher-order unification is Σ₁-complete, therefore undecidable.
The problems encountered in Carnap's proof-checking are merelysecond-order pattern-matching, an (NP-complete) class decided by Huet.
Run time performace is (surprisingly) not bad.
Syntax
Implicit Fixed Point:data IntList = Nil | Cons Int (IntList)
Explicit Fixed Point (Just an example!):
data PreList b = PreNil | PreCons Int b
data Fix f = Fx (f (Fix f))
type List = Fix Prelist
pattern Nil = Fx PreNil
pattern Cons x y = Fx (PreCons x y)
Example Type Derivation
PreNil :: PreList a b
→ Fx PreNil :: Fix (Prelist a (Fix (Prelist a))
= Nil :: List a
→ PreCons 5 Nil :: Prelist Int (List Int)
→ Fx (PreCons 5 Nil) :: Fix (Prelist Int (List Int))
= Cons 5 Nil :: List Int
Carnap's FixLang
PropLexicon a b :: (Predicate Prop :|: ...) a b
data Fix f b = Fx (f (Fix f) b)
type FixLang f = Fix (Copula :|: f)
FixLang
adds to explicit fix-point construction of
an ADT:
- a type parameter for Carnap's phantom types, and
- the
Copula
type, which binds the language together.
Proof-Checking
- Each line is converted to a Genzen-Style proof tree, by tracing its "deductive pedigree".
- Proof Trees are folded from top to bottom, using Huet at each stage to check that premises and conclusions unify with the premises and conclusions of cited rules, and to compute dependencies.
Applications
Teaching Tool
So Far:
- Introduction to Symbolic Logic
This Fall:
- Formal Logic
- Introduction to Symbolic Logic
- Modal Logic
How did you use Carnap?
- Client-Server with Carnap-Server application (grading automated)
- Interactive textbook, written in markdown.
- In-text exercises, markdown assignments.
- Minimal Logic, with students deriving new rules. (code → data)
What's that like?
Very positive experience.
Student evaluations in top decile for university
Some predictable difficulties.
Planned Applications
- Denotational semantics for a simple programming language
- Systems for core mathematics education (elementary geometry, algebra, number theory...)
- More powerful methods for user interaction
- More efficient unification via Miller-style patterns unification