You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1099 lines
34 KiB
Plaintext
1099 lines
34 KiB
Plaintext
.. Copyright (C) 2001-2019 NLTK Project
|
|
.. For license information, see LICENSE.TXT
|
|
|
|
=======================
|
|
Logic & Lambda Calculus
|
|
=======================
|
|
|
|
The `nltk.logic` package allows expressions of First-Order Logic (FOL) to be
|
|
parsed into ``Expression`` objects. In addition to FOL, the parser
|
|
handles lambda-abstraction with variables of higher order.
|
|
|
|
--------
|
|
Overview
|
|
--------
|
|
|
|
>>> from nltk.sem.logic import *
|
|
|
|
The default inventory of logical constants is the following:
|
|
|
|
>>> boolean_ops() # doctest: +NORMALIZE_WHITESPACE
|
|
negation -
|
|
conjunction &
|
|
disjunction |
|
|
implication ->
|
|
equivalence <->
|
|
>>> equality_preds() # doctest: +NORMALIZE_WHITESPACE
|
|
equality =
|
|
inequality !=
|
|
>>> binding_ops() # doctest: +NORMALIZE_WHITESPACE
|
|
existential exists
|
|
universal all
|
|
lambda \
|
|
|
|
----------------
|
|
Regression Tests
|
|
----------------
|
|
|
|
|
|
Untyped Logic
|
|
+++++++++++++
|
|
|
|
Process logical expressions conveniently:
|
|
|
|
>>> read_expr = Expression.fromstring
|
|
|
|
Test for equality under alpha-conversion
|
|
========================================
|
|
|
|
>>> e1 = read_expr('exists x.P(x)')
|
|
>>> print(e1)
|
|
exists x.P(x)
|
|
>>> e2 = e1.alpha_convert(Variable('z'))
|
|
>>> print(e2)
|
|
exists z.P(z)
|
|
>>> e1 == e2
|
|
True
|
|
|
|
|
|
>>> l = read_expr(r'\X.\X.X(X)(1)').simplify()
|
|
>>> id = read_expr(r'\X.X(X)')
|
|
>>> l == id
|
|
True
|
|
|
|
Test numerals
|
|
=============
|
|
|
|
>>> zero = read_expr(r'\F x.x')
|
|
>>> one = read_expr(r'\F x.F(x)')
|
|
>>> two = read_expr(r'\F x.F(F(x))')
|
|
>>> three = read_expr(r'\F x.F(F(F(x)))')
|
|
>>> four = read_expr(r'\F x.F(F(F(F(x))))')
|
|
>>> succ = read_expr(r'\N F x.F(N(F,x))')
|
|
>>> plus = read_expr(r'\M N F x.M(F,N(F,x))')
|
|
>>> mult = read_expr(r'\M N F.M(N(F))')
|
|
>>> pred = read_expr(r'\N F x.(N(\G H.H(G(F)))(\u.x)(\u.u))')
|
|
>>> v1 = ApplicationExpression(succ, zero).simplify()
|
|
>>> v1 == one
|
|
True
|
|
>>> v2 = ApplicationExpression(succ, v1).simplify()
|
|
>>> v2 == two
|
|
True
|
|
>>> v3 = ApplicationExpression(ApplicationExpression(plus, v1), v2).simplify()
|
|
>>> v3 == three
|
|
True
|
|
>>> v4 = ApplicationExpression(ApplicationExpression(mult, v2), v2).simplify()
|
|
>>> v4 == four
|
|
True
|
|
>>> v5 = ApplicationExpression(pred, ApplicationExpression(pred, v4)).simplify()
|
|
>>> v5 == two
|
|
True
|
|
|
|
Overloaded operators also exist, for convenience.
|
|
|
|
>>> print(succ(zero).simplify() == one)
|
|
True
|
|
>>> print(plus(one,two).simplify() == three)
|
|
True
|
|
>>> print(mult(two,two).simplify() == four)
|
|
True
|
|
>>> print(pred(pred(four)).simplify() == two)
|
|
True
|
|
|
|
>>> john = read_expr(r'john')
|
|
>>> man = read_expr(r'\x.man(x)')
|
|
>>> walk = read_expr(r'\x.walk(x)')
|
|
>>> man(john).simplify()
|
|
<ApplicationExpression man(john)>
|
|
>>> print(-walk(john).simplify())
|
|
-walk(john)
|
|
>>> print((man(john) & walk(john)).simplify())
|
|
(man(john) & walk(john))
|
|
>>> print((man(john) | walk(john)).simplify())
|
|
(man(john) | walk(john))
|
|
>>> print((man(john) > walk(john)).simplify())
|
|
(man(john) -> walk(john))
|
|
>>> print((man(john) < walk(john)).simplify())
|
|
(man(john) <-> walk(john))
|
|
|
|
Python's built-in lambda operator can also be used with Expressions
|
|
|
|
>>> john = VariableExpression(Variable('john'))
|
|
>>> run_var = VariableExpression(Variable('run'))
|
|
>>> run = lambda x: run_var(x)
|
|
>>> run(john)
|
|
<ApplicationExpression run(john)>
|
|
|
|
|
|
``betaConversionTestSuite.pl``
|
|
------------------------------
|
|
|
|
Tests based on Blackburn & Bos' book, *Representation and Inference
|
|
for Natural Language*.
|
|
|
|
>>> x1 = read_expr(r'\P.P(mia)(\x.walk(x))').simplify()
|
|
>>> x2 = read_expr(r'walk(mia)').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'exists x.(man(x) & ((\P.exists x.(woman(x) & P(x)))(\y.love(x,y))))').simplify()
|
|
>>> x2 = read_expr(r'exists x.(man(x) & exists y.(woman(y) & love(x,y)))').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
>>> x1 = read_expr(r'\a.sleep(a)(mia)').simplify()
|
|
>>> x2 = read_expr(r'sleep(mia)').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
>>> x1 = read_expr(r'\a.\b.like(b,a)(mia)').simplify()
|
|
>>> x2 = read_expr(r'\b.like(b,mia)').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
>>> x1 = read_expr(r'\a.(\b.like(b,a)(vincent))').simplify()
|
|
>>> x2 = read_expr(r'\a.like(vincent,a)').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
>>> x1 = read_expr(r'\a.((\b.like(b,a)(vincent)) & sleep(a))').simplify()
|
|
>>> x2 = read_expr(r'\a.(like(vincent,a) & sleep(a))').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'(\a.\b.like(b,a)(mia)(vincent))').simplify()
|
|
>>> x2 = read_expr(r'like(vincent,mia)').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'P((\a.sleep(a)(vincent)))').simplify()
|
|
>>> x2 = read_expr(r'P(sleep(vincent))').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'\A.A((\b.sleep(b)(vincent)))').simplify()
|
|
>>> x2 = read_expr(r'\A.A(sleep(vincent))').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'\A.A(sleep(vincent))').simplify()
|
|
>>> x2 = read_expr(r'\A.A(sleep(vincent))').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'(\A.A(vincent)(\b.sleep(b)))').simplify()
|
|
>>> x2 = read_expr(r'sleep(vincent)').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'\A.believe(mia,A(vincent))(\b.sleep(b))').simplify()
|
|
>>> x2 = read_expr(r'believe(mia,sleep(vincent))').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'(\A.(A(vincent) & A(mia)))(\b.sleep(b))').simplify()
|
|
>>> x2 = read_expr(r'(sleep(vincent) & sleep(mia))').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'\A.\B.(\C.C(A(vincent))(\d.probably(d)) & (\C.C(B(mia))(\d.improbably(d))))(\f.walk(f))(\f.talk(f))').simplify()
|
|
>>> x2 = read_expr(r'(probably(walk(vincent)) & improbably(talk(mia)))').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'(\a.\b.(\C.C(a,b)(\d.\f.love(d,f))))(jules)(mia)').simplify()
|
|
>>> x2 = read_expr(r'love(jules,mia)').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'(\A.\B.exists c.(A(c) & B(c)))(\d.boxer(d),\d.sleep(d))').simplify()
|
|
>>> x2 = read_expr(r'exists c.(boxer(c) & sleep(c))').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'\A.Z(A)(\c.\a.like(a,c))').simplify()
|
|
>>> x2 = read_expr(r'Z(\c.\a.like(a,c))').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'\A.\b.A(b)(\c.\b.like(b,c))').simplify()
|
|
>>> x2 = read_expr(r'\b.(\c.\b.like(b,c)(b))').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'(\a.\b.(\C.C(a,b)(\b.\a.loves(b,a))))(jules)(mia)').simplify()
|
|
>>> x2 = read_expr(r'loves(jules,mia)').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
>>> x1 = read_expr(r'(\A.\b.(exists b.A(b) & A(b)))(\c.boxer(c))(vincent)').simplify()
|
|
>>> x2 = read_expr(r'((exists b.boxer(b)) & boxer(vincent))').simplify()
|
|
>>> x1 == x2
|
|
True
|
|
|
|
Test Parser
|
|
===========
|
|
|
|
>>> print(read_expr(r'john'))
|
|
john
|
|
>>> print(read_expr(r'x'))
|
|
x
|
|
>>> print(read_expr(r'-man(x)'))
|
|
-man(x)
|
|
>>> print(read_expr(r'--man(x)'))
|
|
--man(x)
|
|
>>> print(read_expr(r'(man(x))'))
|
|
man(x)
|
|
>>> print(read_expr(r'((man(x)))'))
|
|
man(x)
|
|
>>> print(read_expr(r'man(x) <-> tall(x)'))
|
|
(man(x) <-> tall(x))
|
|
>>> print(read_expr(r'(man(x) <-> tall(x))'))
|
|
(man(x) <-> tall(x))
|
|
>>> print(read_expr(r'(man(x) & tall(x) & walks(x))'))
|
|
(man(x) & tall(x) & walks(x))
|
|
>>> print(read_expr(r'(man(x) & tall(x) & walks(x))').first)
|
|
(man(x) & tall(x))
|
|
>>> print(read_expr(r'man(x) | tall(x) & walks(x)'))
|
|
(man(x) | (tall(x) & walks(x)))
|
|
>>> print(read_expr(r'((man(x) & tall(x)) | walks(x))'))
|
|
((man(x) & tall(x)) | walks(x))
|
|
>>> print(read_expr(r'man(x) & (tall(x) | walks(x))'))
|
|
(man(x) & (tall(x) | walks(x)))
|
|
>>> print(read_expr(r'(man(x) & (tall(x) | walks(x)))'))
|
|
(man(x) & (tall(x) | walks(x)))
|
|
>>> print(read_expr(r'P(x) -> Q(x) <-> R(x) | S(x) & T(x)'))
|
|
((P(x) -> Q(x)) <-> (R(x) | (S(x) & T(x))))
|
|
>>> print(read_expr(r'exists x.man(x)'))
|
|
exists x.man(x)
|
|
>>> print(read_expr(r'exists x.(man(x) & tall(x))'))
|
|
exists x.(man(x) & tall(x))
|
|
>>> print(read_expr(r'exists x.(man(x) & tall(x) & walks(x))'))
|
|
exists x.(man(x) & tall(x) & walks(x))
|
|
>>> print(read_expr(r'-P(x) & Q(x)'))
|
|
(-P(x) & Q(x))
|
|
>>> read_expr(r'-P(x) & Q(x)') == read_expr(r'(-P(x)) & Q(x)')
|
|
True
|
|
>>> print(read_expr(r'\x.man(x)'))
|
|
\x.man(x)
|
|
>>> print(read_expr(r'\x.man(x)(john)'))
|
|
\x.man(x)(john)
|
|
>>> print(read_expr(r'\x.man(x)(john) & tall(x)'))
|
|
(\x.man(x)(john) & tall(x))
|
|
>>> print(read_expr(r'\x.\y.sees(x,y)'))
|
|
\x y.sees(x,y)
|
|
>>> print(read_expr(r'\x y.sees(x,y)'))
|
|
\x y.sees(x,y)
|
|
>>> print(read_expr(r'\x.\y.sees(x,y)(a)'))
|
|
(\x y.sees(x,y))(a)
|
|
>>> print(read_expr(r'\x y.sees(x,y)(a)'))
|
|
(\x y.sees(x,y))(a)
|
|
>>> print(read_expr(r'\x.\y.sees(x,y)(a)(b)'))
|
|
((\x y.sees(x,y))(a))(b)
|
|
>>> print(read_expr(r'\x y.sees(x,y)(a)(b)'))
|
|
((\x y.sees(x,y))(a))(b)
|
|
>>> print(read_expr(r'\x.\y.sees(x,y)(a,b)'))
|
|
((\x y.sees(x,y))(a))(b)
|
|
>>> print(read_expr(r'\x y.sees(x,y)(a,b)'))
|
|
((\x y.sees(x,y))(a))(b)
|
|
>>> print(read_expr(r'((\x.\y.sees(x,y))(a))(b)'))
|
|
((\x y.sees(x,y))(a))(b)
|
|
>>> print(read_expr(r'P(x)(y)(z)'))
|
|
P(x,y,z)
|
|
>>> print(read_expr(r'P(Q)'))
|
|
P(Q)
|
|
>>> print(read_expr(r'P(Q(x))'))
|
|
P(Q(x))
|
|
>>> print(read_expr(r'(\x.exists y.walks(x,y))(x)'))
|
|
(\x.exists y.walks(x,y))(x)
|
|
>>> print(read_expr(r'exists x.(x = john)'))
|
|
exists x.(x = john)
|
|
>>> print(read_expr(r'((\P.\Q.exists x.(P(x) & Q(x)))(\x.dog(x)))(\x.bark(x))'))
|
|
((\P Q.exists x.(P(x) & Q(x)))(\x.dog(x)))(\x.bark(x))
|
|
>>> a = read_expr(r'exists c.exists b.A(b,c) & A(b,c)')
|
|
>>> b = read_expr(r'(exists c.(exists b.A(b,c))) & A(b,c)')
|
|
>>> print(a == b)
|
|
True
|
|
>>> a = read_expr(r'exists c.(exists b.A(b,c) & A(b,c))')
|
|
>>> b = read_expr(r'exists c.((exists b.A(b,c)) & A(b,c))')
|
|
>>> print(a == b)
|
|
True
|
|
>>> print(read_expr(r'exists x.x = y'))
|
|
exists x.(x = y)
|
|
>>> print(read_expr('A(B)(C)'))
|
|
A(B,C)
|
|
>>> print(read_expr('(A(B))(C)'))
|
|
A(B,C)
|
|
>>> print(read_expr('A((B)(C))'))
|
|
A(B(C))
|
|
>>> print(read_expr('A(B(C))'))
|
|
A(B(C))
|
|
>>> print(read_expr('(A)(B(C))'))
|
|
A(B(C))
|
|
>>> print(read_expr('(((A)))(((B))(((C))))'))
|
|
A(B(C))
|
|
>>> print(read_expr(r'A != B'))
|
|
-(A = B)
|
|
>>> print(read_expr('P(x) & x=y & P(y)'))
|
|
(P(x) & (x = y) & P(y))
|
|
>>> try: print(read_expr(r'\walk.walk(x)'))
|
|
... except LogicalExpressionException as e: print(e)
|
|
'walk' is an illegal variable name. Constants may not be abstracted.
|
|
\walk.walk(x)
|
|
^
|
|
>>> try: print(read_expr(r'all walk.walk(john)'))
|
|
... except LogicalExpressionException as e: print(e)
|
|
'walk' is an illegal variable name. Constants may not be quantified.
|
|
all walk.walk(john)
|
|
^
|
|
>>> try: print(read_expr(r'x(john)'))
|
|
... except LogicalExpressionException as e: print(e)
|
|
'x' is an illegal predicate name. Individual variables may not be used as predicates.
|
|
x(john)
|
|
^
|
|
|
|
>>> from nltk.sem.logic import LogicParser # hack to give access to custom quote chars
|
|
>>> lpq = LogicParser()
|
|
>>> lpq.quote_chars = [("'", "'", "\\", False)]
|
|
>>> print(lpq.parse(r"(man(x) & 'tall\'s,' (x) & walks (x) )"))
|
|
(man(x) & tall's,(x) & walks(x))
|
|
>>> lpq.quote_chars = [("'", "'", "\\", True)]
|
|
>>> print(lpq.parse(r"'tall\'s,'"))
|
|
'tall\'s,'
|
|
>>> print(lpq.parse(r"'spaced name(x)'"))
|
|
'spaced name(x)'
|
|
>>> print(lpq.parse(r"-'tall\'s,'(x)"))
|
|
-'tall\'s,'(x)
|
|
>>> print(lpq.parse(r"(man(x) & 'tall\'s,' (x) & walks (x) )"))
|
|
(man(x) & 'tall\'s,'(x) & walks(x))
|
|
|
|
|
|
Simplify
|
|
========
|
|
|
|
>>> print(read_expr(r'\x.man(x)(john)').simplify())
|
|
man(john)
|
|
>>> print(read_expr(r'\x.((man(x)))(john)').simplify())
|
|
man(john)
|
|
>>> print(read_expr(r'\x.\y.sees(x,y)(john, mary)').simplify())
|
|
sees(john,mary)
|
|
>>> print(read_expr(r'\x y.sees(x,y)(john, mary)').simplify())
|
|
sees(john,mary)
|
|
>>> print(read_expr(r'\x.\y.sees(x,y)(john)(mary)').simplify())
|
|
sees(john,mary)
|
|
>>> print(read_expr(r'\x y.sees(x,y)(john)(mary)').simplify())
|
|
sees(john,mary)
|
|
>>> print(read_expr(r'\x.\y.sees(x,y)(john)').simplify())
|
|
\y.sees(john,y)
|
|
>>> print(read_expr(r'\x y.sees(x,y)(john)').simplify())
|
|
\y.sees(john,y)
|
|
>>> print(read_expr(r'(\x.\y.sees(x,y)(john))(mary)').simplify())
|
|
sees(john,mary)
|
|
>>> print(read_expr(r'(\x y.sees(x,y)(john))(mary)').simplify())
|
|
sees(john,mary)
|
|
>>> print(read_expr(r'exists x.(man(x) & (\x.exists y.walks(x,y))(x))').simplify())
|
|
exists x.(man(x) & exists y.walks(x,y))
|
|
>>> e1 = read_expr(r'exists x.(man(x) & (\x.exists y.walks(x,y))(y))').simplify()
|
|
>>> e2 = read_expr(r'exists x.(man(x) & exists z1.walks(y,z1))')
|
|
>>> e1 == e2
|
|
True
|
|
>>> print(read_expr(r'(\P Q.exists x.(P(x) & Q(x)))(\x.dog(x))').simplify())
|
|
\Q.exists x.(dog(x) & Q(x))
|
|
>>> print(read_expr(r'((\P.\Q.exists x.(P(x) & Q(x)))(\x.dog(x)))(\x.bark(x))').simplify())
|
|
exists x.(dog(x) & bark(x))
|
|
>>> print(read_expr(r'\P.(P(x)(y))(\a b.Q(a,b))').simplify())
|
|
Q(x,y)
|
|
|
|
Replace
|
|
=======
|
|
|
|
>>> a = read_expr(r'a')
|
|
>>> x = read_expr(r'x')
|
|
>>> y = read_expr(r'y')
|
|
>>> z = read_expr(r'z')
|
|
|
|
>>> print(read_expr(r'man(x)').replace(x.variable, a, False))
|
|
man(a)
|
|
>>> print(read_expr(r'(man(x) & tall(x))').replace(x.variable, a, False))
|
|
(man(a) & tall(a))
|
|
>>> print(read_expr(r'exists x.man(x)').replace(x.variable, a, False))
|
|
exists x.man(x)
|
|
>>> print(read_expr(r'exists x.man(x)').replace(x.variable, a, True))
|
|
exists a.man(a)
|
|
>>> print(read_expr(r'exists x.give(x,y,z)').replace(y.variable, a, False))
|
|
exists x.give(x,a,z)
|
|
>>> print(read_expr(r'exists x.give(x,y,z)').replace(y.variable, a, True))
|
|
exists x.give(x,a,z)
|
|
>>> e1 = read_expr(r'exists x.give(x,y,z)').replace(y.variable, x, False)
|
|
>>> e2 = read_expr(r'exists z1.give(z1,x,z)')
|
|
>>> e1 == e2
|
|
True
|
|
>>> e1 = read_expr(r'exists x.give(x,y,z)').replace(y.variable, x, True)
|
|
>>> e2 = read_expr(r'exists z1.give(z1,x,z)')
|
|
>>> e1 == e2
|
|
True
|
|
>>> print(read_expr(r'\x y z.give(x,y,z)').replace(y.variable, a, False))
|
|
\x y z.give(x,y,z)
|
|
>>> print(read_expr(r'\x y z.give(x,y,z)').replace(y.variable, a, True))
|
|
\x a z.give(x,a,z)
|
|
>>> print(read_expr(r'\x.\y.give(x,y,z)').replace(z.variable, a, False))
|
|
\x y.give(x,y,a)
|
|
>>> print(read_expr(r'\x.\y.give(x,y,z)').replace(z.variable, a, True))
|
|
\x y.give(x,y,a)
|
|
>>> e1 = read_expr(r'\x.\y.give(x,y,z)').replace(z.variable, x, False)
|
|
>>> e2 = read_expr(r'\z1.\y.give(z1,y,x)')
|
|
>>> e1 == e2
|
|
True
|
|
>>> e1 = read_expr(r'\x.\y.give(x,y,z)').replace(z.variable, x, True)
|
|
>>> e2 = read_expr(r'\z1.\y.give(z1,y,x)')
|
|
>>> e1 == e2
|
|
True
|
|
>>> print(read_expr(r'\x.give(x,y,z)').replace(z.variable, y, False))
|
|
\x.give(x,y,y)
|
|
>>> print(read_expr(r'\x.give(x,y,z)').replace(z.variable, y, True))
|
|
\x.give(x,y,y)
|
|
|
|
>>> from nltk.sem import logic
|
|
>>> logic._counter._value = 0
|
|
>>> e1 = read_expr('e1')
|
|
>>> e2 = read_expr('e2')
|
|
>>> print(read_expr('exists e1 e2.(walk(e1) & talk(e2))').replace(e1.variable, e2, True))
|
|
exists e2 e01.(walk(e2) & talk(e01))
|
|
|
|
|
|
Variables / Free
|
|
================
|
|
|
|
>>> examples = [r'walk(john)',
|
|
... r'walk(x)',
|
|
... r'?vp(?np)',
|
|
... r'see(john,mary)',
|
|
... r'exists x.walk(x)',
|
|
... r'\x.see(john,x)',
|
|
... r'\x.see(john,x)(mary)',
|
|
... r'P(x)',
|
|
... r'\P.P(x)',
|
|
... r'aa(x,bb(y),cc(z),P(w),u)',
|
|
... r'bo(?det(?n),@x)']
|
|
>>> examples = [read_expr(e) for e in examples]
|
|
|
|
>>> for e in examples:
|
|
... print('%-25s' % e, sorted(e.free()))
|
|
walk(john) []
|
|
walk(x) [Variable('x')]
|
|
?vp(?np) []
|
|
see(john,mary) []
|
|
exists x.walk(x) []
|
|
\x.see(john,x) []
|
|
(\x.see(john,x))(mary) []
|
|
P(x) [Variable('P'), Variable('x')]
|
|
\P.P(x) [Variable('x')]
|
|
aa(x,bb(y),cc(z),P(w),u) [Variable('P'), Variable('u'), Variable('w'), Variable('x'), Variable('y'), Variable('z')]
|
|
bo(?det(?n),@x) []
|
|
|
|
>>> for e in examples:
|
|
... print('%-25s' % e, sorted(e.constants()))
|
|
walk(john) [Variable('john')]
|
|
walk(x) []
|
|
?vp(?np) [Variable('?np')]
|
|
see(john,mary) [Variable('john'), Variable('mary')]
|
|
exists x.walk(x) []
|
|
\x.see(john,x) [Variable('john')]
|
|
(\x.see(john,x))(mary) [Variable('john'), Variable('mary')]
|
|
P(x) []
|
|
\P.P(x) []
|
|
aa(x,bb(y),cc(z),P(w),u) []
|
|
bo(?det(?n),@x) [Variable('?n'), Variable('@x')]
|
|
|
|
>>> for e in examples:
|
|
... print('%-25s' % e, sorted(e.predicates()))
|
|
walk(john) [Variable('walk')]
|
|
walk(x) [Variable('walk')]
|
|
?vp(?np) [Variable('?vp')]
|
|
see(john,mary) [Variable('see')]
|
|
exists x.walk(x) [Variable('walk')]
|
|
\x.see(john,x) [Variable('see')]
|
|
(\x.see(john,x))(mary) [Variable('see')]
|
|
P(x) []
|
|
\P.P(x) []
|
|
aa(x,bb(y),cc(z),P(w),u) [Variable('aa'), Variable('bb'), Variable('cc')]
|
|
bo(?det(?n),@x) [Variable('?det'), Variable('bo')]
|
|
|
|
>>> for e in examples:
|
|
... print('%-25s' % e, sorted(e.variables()))
|
|
walk(john) []
|
|
walk(x) [Variable('x')]
|
|
?vp(?np) [Variable('?np'), Variable('?vp')]
|
|
see(john,mary) []
|
|
exists x.walk(x) []
|
|
\x.see(john,x) []
|
|
(\x.see(john,x))(mary) []
|
|
P(x) [Variable('P'), Variable('x')]
|
|
\P.P(x) [Variable('x')]
|
|
aa(x,bb(y),cc(z),P(w),u) [Variable('P'), Variable('u'), Variable('w'), Variable('x'), Variable('y'), Variable('z')]
|
|
bo(?det(?n),@x) [Variable('?det'), Variable('?n'), Variable('@x')]
|
|
|
|
|
|
|
|
`normalize`
|
|
>>> print(read_expr(r'\e083.(walk(e083, z472) & talk(e092, z938))').normalize())
|
|
\e01.(walk(e01,z3) & talk(e02,z4))
|
|
|
|
Typed Logic
|
|
+++++++++++
|
|
|
|
>>> from nltk.sem.logic import LogicParser
|
|
>>> tlp = LogicParser(True)
|
|
>>> print(tlp.parse(r'man(x)').type)
|
|
?
|
|
>>> print(tlp.parse(r'walk(angus)').type)
|
|
?
|
|
>>> print(tlp.parse(r'-man(x)').type)
|
|
t
|
|
>>> print(tlp.parse(r'(man(x) <-> tall(x))').type)
|
|
t
|
|
>>> print(tlp.parse(r'exists x.(man(x) & tall(x))').type)
|
|
t
|
|
>>> print(tlp.parse(r'\x.man(x)').type)
|
|
<e,?>
|
|
>>> print(tlp.parse(r'john').type)
|
|
e
|
|
>>> print(tlp.parse(r'\x y.sees(x,y)').type)
|
|
<e,<e,?>>
|
|
>>> print(tlp.parse(r'\x.man(x)(john)').type)
|
|
?
|
|
>>> print(tlp.parse(r'\x.\y.sees(x,y)(john)').type)
|
|
<e,?>
|
|
>>> print(tlp.parse(r'\x.\y.sees(x,y)(john)(mary)').type)
|
|
?
|
|
>>> print(tlp.parse(r'\P.\Q.exists x.(P(x) & Q(x))').type)
|
|
<<e,t>,<<e,t>,t>>
|
|
>>> print(tlp.parse(r'\x.y').type)
|
|
<?,e>
|
|
>>> print(tlp.parse(r'\P.P(x)').type)
|
|
<<e,?>,?>
|
|
|
|
>>> parsed = tlp.parse('see(john,mary)')
|
|
>>> print(parsed.type)
|
|
?
|
|
>>> print(parsed.function)
|
|
see(john)
|
|
>>> print(parsed.function.type)
|
|
<e,?>
|
|
>>> print(parsed.function.function)
|
|
see
|
|
>>> print(parsed.function.function.type)
|
|
<e,<e,?>>
|
|
|
|
>>> parsed = tlp.parse('P(x,y)')
|
|
>>> print(parsed)
|
|
P(x,y)
|
|
>>> print(parsed.type)
|
|
?
|
|
>>> print(parsed.function)
|
|
P(x)
|
|
>>> print(parsed.function.type)
|
|
<e,?>
|
|
>>> print(parsed.function.function)
|
|
P
|
|
>>> print(parsed.function.function.type)
|
|
<e,<e,?>>
|
|
|
|
>>> print(tlp.parse(r'P').type)
|
|
?
|
|
|
|
>>> print(tlp.parse(r'P', {'P': 't'}).type)
|
|
t
|
|
|
|
>>> a = tlp.parse(r'P(x)')
|
|
>>> print(a.type)
|
|
?
|
|
>>> print(a.function.type)
|
|
<e,?>
|
|
>>> print(a.argument.type)
|
|
e
|
|
|
|
>>> a = tlp.parse(r'-P(x)')
|
|
>>> print(a.type)
|
|
t
|
|
>>> print(a.term.type)
|
|
t
|
|
>>> print(a.term.function.type)
|
|
<e,t>
|
|
>>> print(a.term.argument.type)
|
|
e
|
|
|
|
>>> a = tlp.parse(r'P & Q')
|
|
>>> print(a.type)
|
|
t
|
|
>>> print(a.first.type)
|
|
t
|
|
>>> print(a.second.type)
|
|
t
|
|
|
|
>>> a = tlp.parse(r'(P(x) & Q(x))')
|
|
>>> print(a.type)
|
|
t
|
|
>>> print(a.first.type)
|
|
t
|
|
>>> print(a.first.function.type)
|
|
<e,t>
|
|
>>> print(a.first.argument.type)
|
|
e
|
|
>>> print(a.second.type)
|
|
t
|
|
>>> print(a.second.function.type)
|
|
<e,t>
|
|
>>> print(a.second.argument.type)
|
|
e
|
|
|
|
>>> a = tlp.parse(r'\x.P(x)')
|
|
>>> print(a.type)
|
|
<e,?>
|
|
>>> print(a.term.function.type)
|
|
<e,?>
|
|
>>> print(a.term.argument.type)
|
|
e
|
|
|
|
>>> a = tlp.parse(r'\P.P(x)')
|
|
>>> print(a.type)
|
|
<<e,?>,?>
|
|
>>> print(a.term.function.type)
|
|
<e,?>
|
|
>>> print(a.term.argument.type)
|
|
e
|
|
|
|
>>> a = tlp.parse(r'(\x.P(x)(john)) & Q(x)')
|
|
>>> print(a.type)
|
|
t
|
|
>>> print(a.first.type)
|
|
t
|
|
>>> print(a.first.function.type)
|
|
<e,t>
|
|
>>> print(a.first.function.term.function.type)
|
|
<e,t>
|
|
>>> print(a.first.function.term.argument.type)
|
|
e
|
|
>>> print(a.first.argument.type)
|
|
e
|
|
|
|
>>> a = tlp.parse(r'\x y.P(x,y)(john)(mary) & Q(x)')
|
|
>>> print(a.type)
|
|
t
|
|
>>> print(a.first.type)
|
|
t
|
|
>>> print(a.first.function.type)
|
|
<e,t>
|
|
>>> print(a.first.function.function.type)
|
|
<e,<e,t>>
|
|
|
|
>>> a = tlp.parse(r'--P')
|
|
>>> print(a.type)
|
|
t
|
|
>>> print(a.term.type)
|
|
t
|
|
>>> print(a.term.term.type)
|
|
t
|
|
|
|
>>> tlp.parse(r'\x y.P(x,y)').type
|
|
<e,<e,?>>
|
|
>>> tlp.parse(r'\x y.P(x,y)', {'P': '<e,<e,t>>'}).type
|
|
<e,<e,t>>
|
|
|
|
>>> a = tlp.parse(r'\P y.P(john,y)(\x y.see(x,y))')
|
|
>>> a.type
|
|
<e,?>
|
|
>>> a.function.type
|
|
<<e,<e,?>>,<e,?>>
|
|
>>> a.function.term.term.function.function.type
|
|
<e,<e,?>>
|
|
>>> a.argument.type
|
|
<e,<e,?>>
|
|
|
|
>>> a = tlp.parse(r'exists c f.(father(c) = f)')
|
|
>>> a.type
|
|
t
|
|
>>> a.term.term.type
|
|
t
|
|
>>> a.term.term.first.type
|
|
e
|
|
>>> a.term.term.first.function.type
|
|
<e,e>
|
|
>>> a.term.term.second.type
|
|
e
|
|
|
|
typecheck()
|
|
|
|
>>> a = tlp.parse('P(x)')
|
|
>>> b = tlp.parse('Q(x)')
|
|
>>> a.type
|
|
?
|
|
>>> c = a & b
|
|
>>> c.first.type
|
|
?
|
|
>>> c.typecheck() # doctest: +ELLIPSIS
|
|
{...}
|
|
>>> c.first.type
|
|
t
|
|
|
|
>>> a = tlp.parse('P(x)')
|
|
>>> b = tlp.parse('P(x) & Q(x)')
|
|
>>> a.type
|
|
?
|
|
>>> typecheck([a,b]) # doctest: +ELLIPSIS
|
|
{...}
|
|
>>> a.type
|
|
t
|
|
|
|
>>> e = tlp.parse(r'man(x)')
|
|
>>> print(dict((k,str(v)) for k,v in e.typecheck().items()) == {'x': 'e', 'man': '<e,?>'})
|
|
True
|
|
>>> sig = {'man': '<e, t>'}
|
|
>>> e = tlp.parse(r'man(x)', sig)
|
|
>>> print(e.function.type)
|
|
<e,t>
|
|
>>> print(dict((k,str(v)) for k,v in e.typecheck().items()) == {'x': 'e', 'man': '<e,t>'})
|
|
True
|
|
>>> print(e.function.type)
|
|
<e,t>
|
|
>>> print(dict((k,str(v)) for k,v in e.typecheck(sig).items()) == {'x': 'e', 'man': '<e,t>'})
|
|
True
|
|
|
|
findtype()
|
|
|
|
>>> print(tlp.parse(r'man(x)').findtype(Variable('man')))
|
|
<e,?>
|
|
>>> print(tlp.parse(r'see(x,y)').findtype(Variable('see')))
|
|
<e,<e,?>>
|
|
>>> print(tlp.parse(r'P(Q(R(x)))').findtype(Variable('Q')))
|
|
?
|
|
|
|
reading types from strings
|
|
|
|
>>> Type.fromstring('e')
|
|
e
|
|
>>> Type.fromstring('<e,t>')
|
|
<e,t>
|
|
>>> Type.fromstring('<<e,t>,<e,t>>')
|
|
<<e,t>,<e,t>>
|
|
>>> Type.fromstring('<<e,?>,?>')
|
|
<<e,?>,?>
|
|
|
|
alternative type format
|
|
|
|
>>> Type.fromstring('e').str()
|
|
'IND'
|
|
>>> Type.fromstring('<e,?>').str()
|
|
'(IND -> ANY)'
|
|
>>> Type.fromstring('<<e,t>,t>').str()
|
|
'((IND -> BOOL) -> BOOL)'
|
|
|
|
Type.__eq__()
|
|
|
|
>>> from nltk.sem.logic import *
|
|
|
|
>>> e = ENTITY_TYPE
|
|
>>> t = TRUTH_TYPE
|
|
>>> a = ANY_TYPE
|
|
>>> et = ComplexType(e,t)
|
|
>>> eet = ComplexType(e,ComplexType(e,t))
|
|
>>> at = ComplexType(a,t)
|
|
>>> ea = ComplexType(e,a)
|
|
>>> aa = ComplexType(a,a)
|
|
|
|
>>> e == e
|
|
True
|
|
>>> t == t
|
|
True
|
|
>>> e == t
|
|
False
|
|
>>> a == t
|
|
False
|
|
>>> t == a
|
|
False
|
|
>>> a == a
|
|
True
|
|
>>> et == et
|
|
True
|
|
>>> a == et
|
|
False
|
|
>>> et == a
|
|
False
|
|
>>> a == ComplexType(a,aa)
|
|
True
|
|
>>> ComplexType(a,aa) == a
|
|
True
|
|
|
|
matches()
|
|
|
|
>>> e.matches(t)
|
|
False
|
|
>>> a.matches(t)
|
|
True
|
|
>>> t.matches(a)
|
|
True
|
|
>>> a.matches(et)
|
|
True
|
|
>>> et.matches(a)
|
|
True
|
|
>>> ea.matches(eet)
|
|
True
|
|
>>> eet.matches(ea)
|
|
True
|
|
>>> aa.matches(et)
|
|
True
|
|
>>> aa.matches(t)
|
|
True
|
|
|
|
Type error during parsing
|
|
=========================
|
|
|
|
>>> try: print(tlp.parse(r'exists x y.(P(x) & P(x,y))'))
|
|
... except InconsistentTypeHierarchyException as e: print(e)
|
|
The variable 'P' was found in multiple places with different types.
|
|
>>> try: tlp.parse(r'\x y.see(x,y)(\x.man(x))')
|
|
... except TypeException as e: print(e)
|
|
The function '\x y.see(x,y)' is of type '<e,<e,?>>' and cannot be applied to '\x.man(x)' of type '<e,?>'. Its argument must match type 'e'.
|
|
>>> try: tlp.parse(r'\P x y.-P(x,y)(\x.-man(x))')
|
|
... except TypeException as e: print(e)
|
|
The function '\P x y.-P(x,y)' is of type '<<e,<e,t>>,<e,<e,t>>>' and cannot be applied to '\x.-man(x)' of type '<e,t>'. Its argument must match type '<e,<e,t>>'.
|
|
|
|
>>> a = tlp.parse(r'-talk(x)')
|
|
>>> signature = a.typecheck()
|
|
>>> try: print(tlp.parse(r'-talk(x,y)', signature))
|
|
... except InconsistentTypeHierarchyException as e: print(e)
|
|
The variable 'talk' was found in multiple places with different types.
|
|
|
|
>>> a = tlp.parse(r'-P(x)')
|
|
>>> b = tlp.parse(r'-P(x,y)')
|
|
>>> a.typecheck() # doctest: +ELLIPSIS
|
|
{...}
|
|
>>> b.typecheck() # doctest: +ELLIPSIS
|
|
{...}
|
|
>>> try: typecheck([a,b])
|
|
... except InconsistentTypeHierarchyException as e: print(e)
|
|
The variable 'P' was found in multiple places with different types.
|
|
|
|
>>> a = tlp.parse(r'P(x)')
|
|
>>> b = tlp.parse(r'P(x,y)')
|
|
>>> signature = {'P': '<e,t>'}
|
|
>>> a.typecheck(signature) # doctest: +ELLIPSIS
|
|
{...}
|
|
>>> try: typecheck([a,b], signature)
|
|
... except InconsistentTypeHierarchyException as e: print(e)
|
|
The variable 'P' was found in multiple places with different types.
|
|
|
|
Parse errors
|
|
============
|
|
|
|
>>> try: read_expr(r'')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expression expected.
|
|
<BLANKLINE>
|
|
^
|
|
>>> try: read_expr(r'(')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expression expected.
|
|
(
|
|
^
|
|
>>> try: read_expr(r')')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
)
|
|
^
|
|
>>> try: read_expr(r'()')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
()
|
|
^
|
|
>>> try: read_expr(r'(P(x) & Q(x)')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expected token ')'.
|
|
(P(x) & Q(x)
|
|
^
|
|
>>> try: read_expr(r'(P(x) &')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expression expected.
|
|
(P(x) &
|
|
^
|
|
>>> try: read_expr(r'(P(x) | )')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
(P(x) | )
|
|
^
|
|
>>> try: read_expr(r'P(x) ->')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expression expected.
|
|
P(x) ->
|
|
^
|
|
>>> try: read_expr(r'P(x')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expected token ')'.
|
|
P(x
|
|
^
|
|
>>> try: read_expr(r'P(x,')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expression expected.
|
|
P(x,
|
|
^
|
|
>>> try: read_expr(r'P(x,)')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
P(x,)
|
|
^
|
|
>>> try: read_expr(r'exists')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Variable and Expression expected following quantifier 'exists'.
|
|
exists
|
|
^
|
|
>>> try: read_expr(r'exists x')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expression expected.
|
|
exists x
|
|
^
|
|
>>> try: read_expr(r'exists x.')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expression expected.
|
|
exists x.
|
|
^
|
|
>>> try: read_expr(r'\ ')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Variable and Expression expected following lambda operator.
|
|
\
|
|
^
|
|
>>> try: read_expr(r'\ x')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expression expected.
|
|
\ x
|
|
^
|
|
>>> try: read_expr(r'\ x y')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expression expected.
|
|
\ x y
|
|
^
|
|
>>> try: read_expr(r'\ x.')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expression expected.
|
|
\ x.
|
|
^
|
|
>>> try: read_expr(r'P(x)Q(x)')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: 'Q'.
|
|
P(x)Q(x)
|
|
^
|
|
>>> try: read_expr(r'(P(x)Q(x)')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: 'Q'. Expected token ')'.
|
|
(P(x)Q(x)
|
|
^
|
|
>>> try: read_expr(r'exists x y')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expression expected.
|
|
exists x y
|
|
^
|
|
>>> try: read_expr(r'exists x y.')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expression expected.
|
|
exists x y.
|
|
^
|
|
>>> try: read_expr(r'exists x -> y')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: '->'. Expression expected.
|
|
exists x -> y
|
|
^
|
|
|
|
|
|
>>> try: read_expr(r'A -> ((P(x) & Q(x)) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expected token ')'.
|
|
A -> ((P(x) & Q(x)) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> ((P(x) &) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
A -> ((P(x) &) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> ((P(x) | )) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
A -> ((P(x) | )) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (P(x) ->) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
A -> (P(x) ->) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (P(x) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
End of input found. Expected token ')'.
|
|
A -> (P(x) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (P(x,) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
A -> (P(x,) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (P(x,)) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
A -> (P(x,)) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (exists) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
')' is an illegal variable name. Constants may not be quantified.
|
|
A -> (exists) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (exists x) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
A -> (exists x) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (exists x.) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
A -> (exists x.) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (\ ) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
')' is an illegal variable name. Constants may not be abstracted.
|
|
A -> (\ ) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (\ x) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
A -> (\ x) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (\ x y) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
A -> (\ x y) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (\ x.) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
A -> (\ x.) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (P(x)Q(x)) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: 'Q'. Expected token ')'.
|
|
A -> (P(x)Q(x)) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> ((P(x)Q(x)) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: 'Q'. Expected token ')'.
|
|
A -> ((P(x)Q(x)) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (all x y) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
A -> (all x y) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (exists x y.) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: ')'. Expression expected.
|
|
A -> (exists x y.) -> Z
|
|
^
|
|
>>> try: read_expr(r'A -> (exists x -> y) -> Z')
|
|
... except LogicalExpressionException as e: print(e)
|
|
Unexpected token: '->'. Expression expected.
|
|
A -> (exists x -> y) -> Z
|
|
^
|
|
|
|
|