Example #1
0
    def testReprType(self):
        test_data = [
            (Ta, "TVar(a)"),
            (Type("bool"), "Type(bool, [])"),
            (Type("list", Ta), "Type(list, [TVar(a)])"),
            (Type("tree", Ta, Tb), "Type(tree, [TVar(a), TVar(b)])"),
            (Type("fun", Ta, Tb), "Type(fun, [TVar(a), TVar(b)])"),
        ]

        for T, repr_T in test_data:
            self.assertEqual(repr(T), repr_T)
Example #2
0
    def testCheckTypeFail(self):
        test_data = [
            Type("bool", Ta),
            Type("bool", Ta, Ta),
            Type("fun"),
            Type("fun", Ta),
            Type("fun", Ta, Ta, Ta),
            TFun(Type("bool", Ta), Type("bool")),
            TFun(Type("bool"), Type("bool", Ta)),
            Type("random")
        ]

        for T in test_data:
            self.assertRaises(TheoryException, thy.check_type, T)
Example #3
0
def to_internal_tvars(pat_T):
    """Add underscore to each type variable in the pattern."""
    if pat_T.ty == HOLType.TVAR:
        return TVar("_" + pat_T.name)
    elif pat_T.ty == HOLType.TYPE:
        return Type(pat_T.name,
                    *[to_internal_tvars(arg) for arg in pat_T.args])
Example #4
0
    def testInductList(self):
        Ta = TVar("a")
        Tlista = Type("list", Ta)
        list_ext = induct.add_induct_type(
            "list", ["a"], [("nil", Tlista, []), ("cons", TFun(Ta, Tlista, Tlista), ["x", "xs"])])

        nil = Const("nil", Tlista)
        cons = Const("cons", TFun(Ta, Tlista, Tlista))
        x = Var("x", Ta)
        xs = Var("xs", Tlista)
        x2 = Var("x'", Ta)
        xs2 = Var("xs'", Tlista)
        P = Var("P", TFun(Tlista, boolT))
        xlist = Var("x", Tlista)

        res = [
            AxType("list", 1),
            AxConstant("nil", Tlista),
            AxConstant("cons", TFun(Ta, Tlista, Tlista)),
            Theorem("list_nil_cons_neq", Thm([], logic.neg(eq(nil, cons(x, xs))))),
            Theorem("list_cons_inject", Thm([], imp(eq(cons(x, xs), cons(x2, xs2)), conj(eq(x, x2), eq(xs, xs2))))),
            Theorem("list_induct", Thm([], imp(P(nil), all(x, all(xs, imp(P(xs), P(cons(x, xs))))), P(xlist)))),
            Attribute("list_induct", "var_induct")
        ]
        self.assertEqual(list_ext.data, res)
Example #5
0
    def run_test(self, thy_name, pat, t, *, vars=None, svars=None, tyinst=None, inst=None, failed=None):
        context.set_context(thy_name, vars=vars, svars=svars)

        pat, t = Term(pat), Term(t)
        inst = Inst((nm, Term(s)) for nm, s in inst.items()) if inst is not None else Inst()
        if tyinst is not None:
            inst.tyinst = TyInst((nm, Type(s)) for nm, s in tyinst.items())

        if failed is not None:
            self.assertRaises(failed, first_order_match, pat, t)
            return

        self.assertEqual(first_order_match(pat, t), inst)
Example #6
0
    def testSubst(self):
        test_data = [
            (Ta, {
                "a": Tb
            }, Tb),
            (Ta, {
                "b": Tb
            }, Ta),
            (TFun(Ta, Tb), {
                "a": Tb
            }, TFun(Tb, Tb)),
            (TFun(Ta, Tb), {
                "a": Tb,
                "b": Ta
            }, TFun(Tb, Ta)),
            (Type("list", Ta), {
                "a": Tb
            }, Type("list", Tb)),
        ]

        for T, tyinst, res in test_data:
            self.assertEqual(T.subst(tyinst), res)
Example #7
0
def check_modify():
    """Check a modified item for validity."""
    data = json.loads(request.get_data().decode("utf-8"))
    error = {}
    item = data['content']
    thy = basic.load_theory('list')
    if item['ty'] == 'thm' or item['ty'] == 'thm.ax':
        vars = {}
        for v in item['vars'].split('\n'):
            (nm, T) = parser.parse_thm_vars(thy, v)
            if nm:
                vars[nm.strip()] = T.strip()
        item['vars'] = vars
    if item['ty'] == 'type.ind':
        constrs, temp_list = [], []
        if len(item['data_name'].split(' ')) > 1:
            temp_list.append(item['data_name'].split(' ')[0][1:])
            item['name'] = item['data_name'].split(' ')[1]
        else:
            item['name'] = item['data_name']
        item['args'] = temp_list
        apd = Type(item['name'], *(TVar(nm) for nm in item['args']))
        for c in item['data_content'].split('\n'):
            constr = parser.parse_type_ind(thy, c)
            type_list = constr['type'] + [apd]
            constr['type'] = str(TFun(type_list))
            constrs.append(constr)
        item['constrs'] = constrs
    # if item['ty'] == 'def.ind' or item['ty'] == 'def' or item['ty'] == 'def.pred':
    #     item['name'] = parser.parse_thm_vars(thy, item['data_name'])[0]
    #     item['type'] = parser.parse_thm_vars(thy, item['data_name'])[1]

    with open_file(data['file_name'], 'r') as f:
        f_data = json.load(f)
    try:
        thy = basic.load_imported_theory(f_data['imports'],
                                         user_info['username'])
        for d in data['prev_list']:
            parser.parse_extension(thy, d)
        file_data_to_output(thy, item)
    except Exception as e:
        exc_detailed = traceback2.format_exc()
        return jsonify({
            "failed": e.__class__.__name__,
            "message": str(e),
            "detail_content": exc_detailed
        })

    return jsonify({'content': item, 'error': error})
Example #8
0
    def testInductAdd(self):
        nat = Type("nat")
        plus = Const("plus", TFun(nat, nat, nat))
        zero = Const("zero", nat)
        S = Const("Suc", TFun(nat, nat))
        m = Var("m", nat)
        n = Var("n", nat)

        ext = induct.add_induct_def(
            'plus', TFun(nat, nat, nat), [
                eq(plus(zero, n), n),
                eq(plus(S(m), n), S(plus(m, n)))])
        
        res = [
            AxConstant("plus", TFun(nat, nat, nat)),
            Theorem("plus_def_1", Thm([], eq(plus(zero, n), n))),
            Attribute("plus_def_1", "hint_rewrite"),
            Theorem("plus_def_2", Thm([], eq(plus(S(m), n), S(plus(m, n))))),
            Attribute("plus_def_2", "hint_rewrite"),
        ]
        self.assertEqual(ext.data, res)
Example #9
0
    def testInductPredicate(self):
        nat = Type("nat")
        even = Const("even", TFun(nat, boolT))
        zero = Const("zero", nat)
        Suc = Const("Suc", TFun(nat, nat))
        n = Var("n", nat)
        prop_zero = even(zero)
        prop_Suc = Term.mk_implies(even(n), even(Suc(Suc(n))))
        data = [("even_zero", prop_zero), ("even_Suc", prop_Suc)]
        even_ext = induct.add_induct_predicate("even", TFun(nat, boolT), data)
        a1 = Var("_a1", nat)
        P = Var("P", boolT)

        res = [
            AxConstant("even", TFun(nat, boolT)),
            Theorem("even_zero", Thm([], even(zero))),
            Attribute("even_zero", "hint_backward"),
            Theorem("even_Suc", Thm.mk_implies(even(n), even(Suc(Suc(n))))),
            Attribute("even_Suc", "hint_backward"),
            Theorem("even_cases", Thm.mk_implies(even(a1), imp(eq(a1,zero), P), all(n, imp(eq(a1,Suc(Suc(n))), even(n), P)), P))
        ]
        self.assertEqual(even_ext.data, res)
Example #10
0
    def testInductProd(self):
        Ta = TVar("a")
        Tb = TVar("b")
        Tab = Type("prod", Ta, Tb)
        prod_ext = induct.add_induct_type(
            "prod", ["a", "b"], [("Pair", TFun(Ta, Tb, Tab), ["a", "b"])])

        a = Var("a", Ta)
        b = Var("b", Tb)
        a2 = Var("a'", Ta)
        b2 = Var("b'", Tb)
        pair = Const("Pair", TFun(Ta, Tb, Tab))
        P = Var("P", TFun(Tab, boolT))
        x = Var("x", Tab)

        res = [
            AxType("prod", 2),
            AxConstant("Pair", TFun(Ta, Tb, Tab)),
            Theorem("prod_Pair_inject", Thm([], imp(eq(pair(a, b), pair(a2, b2)), conj(eq(a, a2), eq(b, b2))))),
            Theorem("prod_induct", Thm([], imp(all(a, all(b, P(pair(a, b)))), P(x)))),
            Attribute("prod_induct", "var_induct")
        ]
        self.assertEqual(prod_ext.data, res)
Example #11
0
    def testInductNat(self):
        nat = Type("nat")
        nat_ext = induct.add_induct_type(
            "nat", [], [("zero", nat, []), ("Suc", TFun(nat, nat), ["n"])])
        
        zero = Const("zero", nat)
        S = Const("Suc", TFun(nat, nat))
        n = Var("n", nat)
        n2 = Var("n'", nat)
        x = Var("x", nat)
        P = Var("P", TFun(nat, boolT))

        res = [
            AxType("nat", 0),
            AxConstant("zero", nat),
            AxConstant("Suc", TFun(nat, nat)),
            Theorem("nat_zero_Suc_neq", Thm([], logic.neg(eq(zero, S(n))))),
            Theorem("nat_Suc_inject", Thm([], imp(eq(S(n), S(n2)), eq(n, n2)))),
            Theorem("nat_induct", Thm([], imp(P(zero), all(n, imp(P(n), P(S(n)))), P(x)))),
            Attribute("nat_induct", "var_induct")
        ]

        self.assertEqual(nat_ext.data, res)
Example #12
0
# Author: Bohua Zhan

from kernel.type import Type, TFun
from kernel.term import Term, Const
from kernel.thm import Thm
from kernel import macro
from logic.conv import Conv, ConvException, all_conv, rewr_conv, \
    then_conv, arg_conv, arg1_conv, every_conv, binop_conv
from logic.proofterm import ProofTerm, ProofTermMacro, ProofTermDeriv, refl
from logic.logic_macro import apply_theorem
from logic import logic
from logic import term_ord
"""Utility functions for natural number arithmetic."""

natT = Type("nat")
zero = Const("zero", natT)
Suc = Const("Suc", TFun(natT, natT))
one = Suc(zero)
plus = Const("plus", TFun(natT, natT, natT))
times = Const("times", TFun(natT, natT, natT))


def is_Suc(t):
    return t.is_comb() and t.fun == Suc


def mk_plus(*args):
    if not args:
        return zero
    elif len(args) == 1:
        return args[0]
Example #13
0
def add_induct_type(name, targs, constrs):
    """Add the given inductive type to the theory.
    
    The inductive type is specified by name, arity (as list of default
    names of type arguments), and a list of constructors (triple
    consisting of name of the constant, type of the constant, and a
    list of suggested names of the arguments).

    For example, the natural numbers is specified by:
    (nat, [], [(0, nat, []), (Suc, nat => nat, ["n"])]).

    List type is specified by:
    (list, ["a"], [(nil, 'a list, []), (cons, 'a => 'a list => 'a list, ["x", "xs"])]).

    """
    exts = TheoryExtension()

    # Add to type and term signature.
    exts.add_extension(AxType(name, len(targs)))
    for cname, cT, _ in constrs:
        exts.add_extension(AxConstant(cname, cT))

    # Add non-equality theorems.
    for (cname1, cT1, vars1), (cname2, cT2,
                               vars2) in itertools.combinations(constrs, 2):
        # For each A x_1 ... x_m and B y_1 ... y_n, get the theorem
        # ~ A x_1 ... x_m = B y_1 ... y_n.
        argT1, _ = cT1.strip_type()
        argT2, _ = cT2.strip_type()
        lhs_vars = [Var(nm, T) for nm, T in zip(vars1, argT1)]
        rhs_vars = [Var(nm, T) for nm, T in zip(vars2, argT2)]
        A = Const(cname1, cT1)
        B = Const(cname2, cT2)
        lhs = A(*lhs_vars)
        rhs = B(*rhs_vars)
        neq = logic.neg(Term.mk_equals(lhs, rhs))
        th_name = name + "_" + cname1 + "_" + cname2 + "_neq"
        exts.add_extension(Theorem(th_name, Thm([], neq)))

    # Add injectivity theorems.
    for cname, cT, vars in constrs:
        # For each A x_1 ... x_m with m > 0, get the theorem
        # A x_1 ... x_m = A x_1' ... x_m' --> x_1 = x_1' & ... & x_m = x_m'
        if vars:
            argT, _ = cT.strip_type()
            lhs_vars = [Var(nm, T) for nm, T in zip(vars, argT)]
            rhs_vars = [Var(nm + "'", T) for nm, T in zip(vars, argT)]
            A = Const(cname, cT)
            assum = Term.mk_equals(A(*lhs_vars), A(*rhs_vars))
            concls = [
                Term.mk_equals(var1, var2)
                for var1, var2 in zip(lhs_vars, rhs_vars)
            ]
            concl = logic.mk_conj(*concls) if len(concls) > 1 else concls[0]
            th_name = name + "_" + cname + "_inject"
            exts.add_extension(Theorem(th_name, Thm.mk_implies(assum, concl)))

    # Add the inductive theorem.
    tvars = [TVar(targ) for targ in targs]
    T = Type(name, *tvars)
    var_P = Var("P", TFun(T, boolT))
    ind_assums = []
    for cname, cT, vars in constrs:
        A = Const(cname, cT)
        argT, _ = cT.strip_type()
        args = [Var(nm, T2) for nm, T2 in zip(vars, argT)]
        C = var_P(A(*args))
        As = [var_P(Var(nm, T2)) for nm, T2 in zip(vars, argT) if T2 == T]
        ind_assum = Term.mk_implies(*(As + [C]))
        for arg in reversed(args):
            ind_assum = Term.mk_all(arg, ind_assum)
        ind_assums.append(ind_assum)
    ind_concl = var_P(Var("x", T))
    th_name = name + "_induct"
    exts.add_extension(
        Theorem(th_name, Thm.mk_implies(*(ind_assums + [ind_concl]))))
    exts.add_extension(Attribute(th_name, "var_induct"))

    return exts
Example #14
0
def setT(T):
    return Type("set", T)
Example #15
0
 def type(self, *args):
     return Type(str(args[-1]), *args[:-1])
Example #16
0
# Author: Bohua Zhan
"""Utility functions for GCL (Guarded Command Language)."""

from kernel.type import TFun, Type, boolT
from kernel.term import Term, Const
from logic import basic
from logic.nat import natT, to_binary
from logic import logic
from logic import function

thy = basic.load_theory("gcl")

varType = Type("varType")
Ident = Const("Ident", TFun(natT, varType))
Para = Const("Para", TFun(varType, natT, varType))

scalarValue = Type("scalarValue")
NatV = Const("NatV", TFun(natT, scalarValue))
BoolV = Const("BoolV", TFun(boolT, scalarValue))

stateT = TFun(varType, scalarValue)


def convert_term(var_map, s, t):
    """Convert term t with given var_map and state s.

    Examples: given var_map {a: 0, b: 1}, where a is a function
    and b is a scalar.

    convert_term(var_map, s, b) = s (Ident 1)
    convert_term(var_map, s, a(i)) = s (Para (Ident 0) i)
Example #17
0
ctxt = {
    "A": boolT,
    "B": boolT,
    "C": boolT,
    "P": TFun(Ta, boolT),
    "Q": TFun(Ta, boolT),
    "R": TFun(Ta, Ta, boolT),
    "a": Ta,
    "b": Ta,
    "c": Ta,
    "f": TFun(Ta, Ta),
    "nn": TFun(boolT, boolT),
    "m": nat.natT,
    "n": nat.natT,
    "p": nat.natT,
    "xs": Type("list", Ta),
    "ys": Type("list", Ta),
    "zs": Type("list", Ta),
}

A = Var("A", boolT)
B = Var("B", boolT)
C = Var("C", boolT)


class ParserTest(unittest.TestCase):
    def testParseType(self):
        test_data = [
            "'b",
            "nat",
            "'a list",
Example #18
0
A = Var("A", boolT)
B = Var("B", boolT)
C = Var("C", boolT)
Ta = TVar("a")
a = Var("a", Ta)
b = Var("b", Ta)
P = Var("P", TFun(Ta, boolT))
Q = Var("Q", TFun(Ta, boolT))
R = Var("R", TFun(Ta, Ta, boolT))
f = Var("f", TFun(Ta, Ta))
nn = Var("n", TFun(boolT, boolT))
m = Var("m", nat.natT)
n = Var("n", nat.natT)
p = Var("p", nat.natT)
xs = Var("xs", Type("list", Ta))
ys = Var("ys", Type("list", Ta))
zs = Var("zs", Type("list", Ta))
eq = Term.mk_equals
imp = Term.mk_implies
conj = logic.mk_conj
disj = logic.mk_disj
abs = Term.mk_abs
all = Term.mk_all
neg = logic.neg
exists = logic.mk_exists
mk_if = logic.mk_if

class PrinterTest(unittest.TestCase):
    def testPrintLogical(self):
        test_data = [
Example #19
0
# Author: Bohua Zhan

from kernel.type import Type, TFun, boolT
from kernel.term import Term, Const
from kernel.thm import Thm
from kernel.macro import global_macros
from logic import logic
from logic import nat
from logic import function
from logic.nat import natT
from logic.conv import arg_conv
from logic.proofterm import ProofTermMacro, ProofTerm
from logic.logic_macro import apply_theorem
"""Automation for arithmetic expressions."""

aexpT = Type("aexp")

N = Const("N", TFun(natT, aexpT))
V = Const("V", TFun(natT, aexpT))
Plus = Const("Plus", TFun(aexpT, aexpT, aexpT))
Times = Const("Times", TFun(aexpT, aexpT, aexpT))

avalI = Const("avalI", TFun(TFun(natT, natT), aexpT, natT, boolT))


class prove_avalI_macro(ProofTermMacro):
    """Prove a theorem of the form avalI s t n."""
    def __init__(self):
        self.level = 10
        self.sig = Term
Example #20
0
def file_data_to_output(thy, data):
    """Convert items in the theory from json format for the file to
    json format for the web client. Modifies data in-place.
    Also modifies argument thy in parsing the item.

    """
    parser.parse_extension(thy, data)
    if data['ty'] == 'def.ax':
        T = parser.parse_type(thy, data['type'])
        data['type_hl'] = printer.print_type(thy,
                                             T,
                                             unicode=True,
                                             highlight=True)

    elif data['ty'] == 'thm' or data['ty'] == 'thm.ax':
        temp_list = []
        for k, v in data['vars'].items():
            temp_list.append(k + ' :: ' + v)
        ctxt = parser.parse_vars(thy, data['vars'])
        prop = parser.parse_term(thy, ctxt, data['prop'])
        data['prop_hl'] = printer.print_term(thy,
                                             prop,
                                             unicode=True,
                                             highlight=True)
        data['vars_lines'] = temp_list

    elif data['ty'] == 'type.ind':
        constrs = []
        data_content = ''
        for constr in data['constrs']:
            T = parser.parse_type(thy, constr['type'])
            constrs.append((constr['name'], T, constr['args']))
        exts = induct.add_induct_type(data['name'], data['args'], constrs)

        # Obtain items added by the extension
        ext_output = []
        for ext in exts.data:
            s = print_extension(thy, ext)
            if s:
                ext_output.append(s)
        data['ext'] = ext_output

        # Obtain type to be defined
        T = Type(data['name'], *(TVar(nm) for nm in data['args']))
        data['type_hl'] = printer.print_type(thy,
                                             T,
                                             unicode=True,
                                             highlight=True)

        # Obtain types of arguments for each constructor
        data['argsT'] = dict()
        for i, constr in enumerate(data['constrs']):
            str_temp_var = ''
            T = parser.parse_type(thy, constr['type'])
            argsT, _ = HOLType.strip_type(T)
            argsT = [
                printer.print_type(thy, argT, unicode=True, highlight=True)
                for argT in argsT
            ]
            data['argsT'][str(i)] = argsT
            for j, a in enumerate(constr['args']):
                str_temp_term = ''
                for m, t in enumerate(data['argsT'][str(i)][j]):
                    str_temp_term += t[0]
                str_temp_var += ' (' + a + ' :: ' + str_temp_term + ')'
            data_content += '\n' + constr['name'] + str_temp_var
        data['type_content'] = data_content

    elif data['ty'] == 'def.ind' or data['ty'] == 'def.pred':
        container = [[], [], [], '', '', '']
        data_content_list, data_rule_names, data_vars_list, data_new_content, data_rule_name, data_vars_str = container
        T = parser.parse_type(thy, data['type'])
        data['type_hl'] = printer.print_type(thy,
                                             T,
                                             unicode=True,
                                             highlight=True)
        rules = []
        for rule in data['rules']:
            ctxt = parser.parse_vars(thy, rule['vars'])
            prop = parser.parse_term(thy, ctxt, rule['prop'])
            rule['prop_hl'] = printer.print_term(thy,
                                                 prop,
                                                 unicode=True,
                                                 highlight=True)
            rules.append(prop)
        exts = induct.add_induct_def(data['name'], T, rules)

        # Obtain items added by the extension
        ext_output = []
        for ext in exts.data:
            s = print_extension(thy, ext)
            if s:
                ext_output.append(s)
        data['ext'] = ext_output

        if data['ty'] == 'def.ind':
            type_name = 'fun'
        if data['ty'] == 'def.pred':
            type_name = 'inductive'
        data['ext_output'] = '\n'.join(ext_output)
        data['type_name'] = type_name

        for k, r in enumerate(data['rules']):
            vars_str = ''
            data_con = ''
            for m, v in enumerate(r['vars']):
                vars_str += str(m) + '::' + v + '   '
            data_vars_list.append(vars_str)
            for p in r['prop_hl']:
                data_con += p[0]
            data_content_list.append(data_con)
            if 'name' in r:
                data_rule_names.append(r['name'])
        for n, dv in enumerate(data_vars_list):
            data_vars_str += str(n) + ': ' + dv + '\n'
        for j, dc in enumerate(data_content_list):
            data_new_content += str(j) + ': ' + dc + '\n'
            data_rule_name += str(j) + ': ' + dc + '\n'
        data['data_new_content'] = data_new_content
        data['data_rule_name'] = data_rule_name
        data['data_vars_str'] = data_vars_str

    elif data['ty'] == 'def':
        i = 0
        vars = ''
        data_new_content = ''
        data_content_list = []
        data_content_list.append(data['prop'])
        for j, dc in enumerate(data_content_list):
            data_new_content += str(j) + ': ' + dc + '\n'
        for j, v in enumerate(data['vars']):
            vars += str(i) + ': ' + str(j) + '::' + v + '\n'
            i += 1
        data['item_vars'] = vars
        T = parser.parse_type(thy, data['type'])
        data['type_name'] = 'definition'
        data['data_new_content'] = data_new_content
        data['type_hl'] = printer.print_type(thy,
                                             T,
                                             unicode=True,
                                             highlight=True)

        ctxt = parser.parse_vars(thy, data['vars'])
        prop = parser.parse_term(thy, ctxt, data['prop'])
        data['prop_hl'] = printer.print_term(thy,
                                             prop,
                                             unicode=True,
                                             highlight=True)

    # Ignore other types of information.
    else:
        pass
Example #21
0
def comT(T):
    return Type("com", T)
Example #22
0
    def testPrintType(self):
        test_data = [
            (Ta, "'a"),
            (TVar("ab"), "'ab"),
            (Type("bool"), "bool"),
            (Type("list", Ta), "'a list"),
            (Type("list", Type("list", Ta)), "'a list list"),
            (Type("tree", Ta, Tb), "('a, 'b) tree"),
            (TFun(Ta, Tb), "'a => 'b"),
            (TFun(Ta, Tb, Tc), "'a => 'b => 'c"),
            (TFun(TFun(Ta, Tb), Tc), "('a => 'b) => 'c"),
            (TFun(Type("list", Ta), Tb), "'a list => 'b"),
            (TFun(Ta, Type("list", Tb)), "'a => 'b list"),
            (Type("list", TFun(Ta, Tb)), "('a => 'b) list"),
            (Type("list", Type("list", TFun(Ta, Tb))), "('a => 'b) list list"),
            (TFun(Type("list", Ta), Type("list", Tb)), "'a list => 'b list"),
            (Type("list", TFun(Type("list", Ta), Tb)), "('a list => 'b) list"),
        ]

        for T, str_T in test_data:
            self.assertEqual(str(T), str_T)
Example #23
0
    def testParseConstructor(self):
        T = Type("'a => 'b")
        self.assertEqual(T, TFun(TVar('a'), TVar('b')))

        t = Term("(A::bool)")
        self.assertEqual(t, Var('A', BoolType))