예제 #1
0
 def test_pairs(self):
     # Check the types of the functions involving pairs:
     #
     # mk_pair :: a -> b -> (a, b)
     # fst :: (a, b) -> a
     # snd :: (a, b) -> b
     self.check_single_expr(
         parse('mk_pair'),
         ('->', 0, ('->', 1, ('Pair', 0, 1))))
     self.check_single_expr(
         parse('fst'),
         ('->', ('Pair', 0, 1), 0))
     self.check_single_expr(
         parse('snd'),
         ('->', ('Pair', 0, 1), 1))
예제 #2
0
 def test_let_partial_generalization_with_utils(self):
     # More thorough test of "let" partial specialization using
     # utility functions.
     expr = parse(r"""
         \x . \y . \z .
         let const_x = \w . x in
             mk_pair (mk_pair (unify const_x (mk_fn y True))
                              (unify const_x
                                     (mk_fn (mk_pair True False) z)))
                     const_x
         """)
     # In the expression above, if "x" has type "a", "y" has type
     # "b", and "z" has type "c", then "const_x" is initially
     # assigned type "forall d . d -> a".  On its first use it is
     # unified with "b -> Bool", forcing "a" to be "Bool".  On its
     # second use, it is unified with "(Bool, Bool) -> c", forcing
     # "c" to be "Bool".  Note that since "d" is qualified with
     # "forall", "b" is not unified with "(Bool, Bool)".  Therefore
     # the type of the final expression should be:
     #
     # Bool -> b -> Bool -> ((b -> Bool, (Bool, Bool) -> Bool), d -> Bool)
     self.check_single_expr(
         self.def_utils(expr),
         ('->',
          ('Bool',),
          ('->',
           0,
           ('->',
            ('Bool',),
            ('Pair',
             ('Pair',
              ('->', 0, ('Bool',)),
              ('->', ('Pair', ('Bool',), ('Bool',)), ('Bool',))),
             ('->', 1, ('Bool',)))))))
예제 #3
0
 def test_infinite_type_right(self):
     # Check that producing an infinite type by unifying "a -> b"
     # with "a" produces an error.  We do so by attempting to
     # type-check the expression:
     #
     # (\f . unify (\x . f) f)
     self.check_type_error(
         self.def_utils(
             parse(r'\f . unify (\x . f) f')))
예제 #4
0
 def def_utils(self, subexpr):
     # Some useful utility functions for testing complex
     # unifications are:
     #
     # let ignore = \x . True
     #
     # "ignore" has type "a -> Bool"; it ignores its argument and
     # returns a boolean.
     #
     # let ignore2 = \x . \y . True
     #
     # "ignore2" has type "a -> b -> Bool"; it ignores two
     # arguments and returns a boolean.
     #
     # let second = \x . \y . y
     #
     # "second" has type "a -> b -> b"; it ignores its first
     # argument and returns its second.
     #
     # let unify = \x . \y . second (\z . ignore2 (z x) (z y)) x
     #
     # "unify" has type "a -> a -> a"; it forces its two arguments
     # to have the same type, and returns the first argument.
     #
     # let mk_fn = \x . \y . \z . second (unify x z) y
     #
     # "mk_fn" has type "a -> b -> (a -> b)"; given arguments of
     # types "a" and "b", it returns a function of type "a -> b".
     #
     # This function wraps the given subexpressions in the
     # necessary "let" constructs so that it can refer to "ignore",
     # "ignore2", and "unify".
     fns = [
         ('ignore', parse(r'\x . True')),
         ('ignore2', parse(r'\x . \y . True')),
         ('second', parse(r'\x . \y . y')),
         ('unify', parse(r'\x . \y . second (\z . ignore2 (z x) (z y)) x')),
         ('mk_fn', parse(r'\x . \y . \z . second (unify x z) y'))
         ]
     for name, defn in reversed(fns):
         subexpr = LetExpression(name, defn, subexpr)
     return subexpr
예제 #5
0
 def test_let_generalization(self):
     # Check that variables bound with "let" can be used in a
     # general fashion.  For example, in:
     #
     # let id = \x . x in (id (\x . x)) (id True)
     #
     # The first usage of "id" has type "(Bool -> Bool) -> (Bool ->
     # Bool)", and the second usage has type "Bool -> Bool", giving
     # the final expression type "Bool".
     self.check_single_expr(
         parse(r'let id = \x . x in (id (\x . x)) (id True)'),
         ('Bool',))
예제 #6
0
 def test_lambda_non_generalization(self):
     # In contrast to variables bound by "let" expressions,
     # variables bound by lambda abstractions are not general.  For
     # example, this should fail to type check:
     #
     # (\f . (f (\x . x)) (f True))
     #
     # Because the first usage of f must have type "(a -> a) -> b",
     # whereas the second usage must have type "Bool -> c", and
     # these can't be unified.
     self.check_type_error(
         parse(r'\f . (f (\x . x)) (f True)'))
예제 #7
0
 def test_infinite_type(self):
     # Applying a function to itself produces an infinite type.
     # For example, in the expression:
     #
     # (\f . f f)
     #
     # if "f" has type "a", then in order to apply "f" to itself,
     # "a" must be unified with "a -> b".  It's impossible to do
     # this without creating an infinitely recursive type, which we
     # don't permit.
     self.check_type_error(
         parse(r'\f . f f'))
예제 #8
0
 def test_let_shadowing(self):
     # When a let expression redefines a variable bound in an outer
     # expression, the outer definition needs to be restored once
     # the let expression is exited.  For example, in:
     #
     # (\x . (let x = \y . y in x) x)
     #
     # The "x" appearing inside "let x = \y . y in x" has type
     # "forall b . b -> b", whereas the "x" appearing at the end
     # has type "a", giving the entire expression type "a -> a".
     self.check_single_expr(
         parse(r'\x . (let x = \y . y in x) x'),
         ('->', 0, 0))
예제 #9
0
 def test_s_combinator(self):
     # Check the type of the "S" combinator:
     #
     # (\x . \y . \z . x z (y z))
     #
     # It sould have type:
     #
     # (a -> b -> c) -> (a -> b) -> a -> c
     self.check_single_expr(
         parse(r'\x . \y . \z . x z (y z)'),
         ('->',
          ('->', 0, ('->', 1, 2)),
          ('->', ('->', 0, 1), ('->', 0, 2))))
예제 #10
0
 def test_lambda_shadowing(self):
     # When a lambda expression redefines a variable bound in an
     # outer expression, the outer definition needs to be restored
     # once the lambda expression is exited.  For example, in:
     #
     # (\x . (\x . x True) (\y . x))
     #
     # The "x" appearing inside "(\x . x True)" has type "Bool ->
     # a", whereas the "x" appearing inside "(\y . x)" has type
     # "a", giving the entire expression type "a -> a".
     self.check_single_expr(
         parse(r'\x . (\x . x True) (\y . x)'),
         ('->', 0, 0))
예제 #11
0
 def test_nested_lets(self):
     # When a let-expression appears inside a second
     # let-expression, type variables appearing in the outer "let"
     # are not re-generalized.  For example, in:
     #
     # (\x . let f = (\y . x) in let g = f True in g)
     #
     # if "x" has type "a", then "f" is assigned a type of "forall
     # b . b -> a", and "g" is assigned a type of "a", *not*
     # "forall a . a".  Therefore the whole expression has type (a
     # -> a).
     self.check_single_expr(
         parse(r'\x . let f = \y . x in let g = f True in g'),
         ('->', 0, 0))
예제 #12
0
 def test_mutually_recursive_type(self):
     # A more complex example of an infinite type, involving the
     # mutual recursion of two types, is the expression:
     #
     # (\f . \g . ignore2 (unify f (\x . g)) (unify g (\x . f)))
     #
     # (where "unify" and "ignore2" are defined in def_utils()).
     #
     # If "f" has type "a" and "g" has type "b", this expression
     # forces "a" to be unified with "c -> b" and forces "b" to be
     # unified with "d -> a", resulting in a mutual recursion of
     # two types; which produces an infinite type.
     self.check_type_error(
         self.def_utils(
             parse(r'\f . \g . ignore2 (unify f (\x . g)) (unify g (\x . f))')))
예제 #13
0
 def test_partial_specialization(self):
     # When a type specialization does not affect the entire type,
     # we try to short-cut it to avoid creating extraneous type
     # variables.  For example, in:
     #
     # (\f . let g = (\x . \y . f y) in g True)
     #
     # type-checking of (\x . \y . f y) causes f's type to be
     # refined to "a -> b", and "g" is assigned a type of "forall c
     # . c -> a -> b".  When "g" is applied to "True", the "a -> b"
     # portion of the type doesn't need to be specialized.  The
     # final type of the whole expression should be "(a -> b) -> (a
     # -> b)".
     self.check_single_expr(
         parse(r'\f . let g = \x . \y . f y in g True'),
         ('->', ('->', 0, 1), ('->', 0, 1)))
예제 #14
0
 def test_let_partial_generalization_general_part(self):
     # In some situations, "let" may generalize some of its type
     # variables but not others.  For example, in:
     #
     # (\x . let const_x = (\y . x) in const_x (\z . const_x True))
     #
     # if the type of "x" is "a", then the type assigned to
     # "const_x" by the "let" expression is "forall b . b -> a".
     # Then, the first usage of "const_x" is specialized to type (c
     # -> a) -> a, whereas the second is specialized to "Bool ->
     # a", giving the final expression type "a -> a".  This would
     # not work if the type assigned to "const_x" did not include
     # "forall b".
     self.check_single_expr(
         parse(r'\x . let const_x = \y . x in const_x (\z . const_x True)'),
         ('->', 0, 0))
예제 #15
0
 def test_let_partial_generalization_non_general_part(self):
     # In some situations, "let" may generalize some of its type
     # variables but not others.  For example, in:
     #
     # (\x . let const_x = (\y . x) in const_x ((const_x (\z . z)) True))
     #
     # if the type of "x" is initially "a", then the type assigned
     # to "const_x" by the "let" expression will initially be
     # "forall b . b -> a".  Then, the first usage of "const_x"
     # will be specialized to "c -> a", and the second will be
     # specialized to "d -> (Bool -> e)".  Since there is no
     # "forall a" in the type assigned to "const_x", "a" will be
     # unified with "Bool -> e", so the resulting expression will
     # have type "(Bool -> e) -> (Bool -> e)".  If a "forall a" had
     # been present, then unification would not have occurred, and
     # the type would have been "a -> a".
     self.check_single_expr(
         parse(r'\x . let const_x = \y . x in const_x ((const_x (\z . z)) True)'),
         ('->', ('->', ('Bool',), 0), ('->', ('Bool',), 0)))
예제 #16
0
 def test_let_non_generalization(self):
     # When a variable bound with "let" is generalized, types that
     # are constrained by declarations in enclosing scopes should
     # not be generalized.  For example, in:
     #
     # (\f . let x = f True in f x)
     #
     # "let x = f True" constrains f to have type "Bool -> a",
     # giving "x" a type of "a".  Then, "in f x" constrains "x" to
     # have type Bool.  Therefore, "f"'s type becomes "Bool ->
     # Bool", and the final expression should have type "((Bool ->
     # Bool) -> Bool)".
     #
     # If, at the time of the let-binding, we had over-generalized
     # the type of "x" to "forall a. a", then when "x" was used in
     # "in f x", it would have been specialized to a new type
     # variable "b", which would have been constrained to have type
     # "Bool", but "a" would have remained general.  Therefore,
     # "f"'s type would have been "Bool -> a", and the final
     # expressino would have had type "((Bool -> a) -> a)", which
     # is incorrect.
     self.check_single_expr(
         parse(r'\f . let x = f True in f x'),
         ('->', ('->', ('Bool',), ('Bool',)), ('Bool',)))
예제 #17
0
 def test_let_with_bool(self):
     self.check_single_expr(
         parse('let t = True in t'),
         ('Bool',))
예제 #18
0
 def test_mk_fn_func(self):
     # Check the type of the "mk_fn" function defined in
     # def_utils().
     self.check_single_expr(
         self.def_utils(parse('mk_fn')),
         ('->', 0, ('->', 1, ('->', 0, 1))))
예제 #19
0
 def test_simple_let(self):
     self.check_single_expr(
         parse(r'let const = \x . \y . x in const True'),
         ('->', 0, ('Bool',)))
예제 #20
0
    print """Usage: python main.py <expression>

Expression grammar:
    expression: '(' expression ')' |
                '\\' identifier '.' expression |
                'let' identifier '=' expression 'in' expression |
                expression expression |
                identifier

Predefined symbols:"""
    for name in sorted(type_inferrer.get_builtin_names()):
        expr = lambda_calculus.Variable(name)
        ty = type_inferrer.visit(expr)
        canonical_ty = type_inferrer.canonicalize(ty, {})
        print '    {0} :: {1}'.format(
            name, algorithm_w.pretty_print_canonical_type(canonical_ty))
    exit(1)

expr = lambda_calculus.parse(sys.argv[1])
ty = type_inferrer.visit(expr)
canonical_ty = type_inferrer.canonicalize(ty, {})

print """Expression:

{0}

has type:

{1}
""".format(expr, algorithm_w.pretty_print_canonical_type(canonical_ty))
예제 #21
0
 def test_polymorphic_binding_example(self):
     self.check_single_expr(
         parse(r'let id = \x . x in mk_pair (id True) (id id)'),
         ('Pair', ('Bool',), ('->', 0, 0)))
예제 #22
0
 def test_isJust(self):
     self.check_single_expr(
         parse(r'maybe False (\x . True)'),
         ('->', ('Maybe', 0), ('Bool',)))
예제 #23
0
 def test_curry(self):
     # Check the type of the curry function
     self.check_single_expr(
         parse(r'\f . \x . \y . f (mk_pair x y)'),
         ('->', ('->', ('Pair', 0, 1), 2), ('->', 0, ('->', 1, 2))))
예제 #24
0
 def test_uncurry(self):
     # Check the type of the uncurry function
     self.check_single_expr(
         parse(r'\f . \p . f (fst p) (snd p)'),
         ('->', ('->', 0, ('->', 1, 2)), ('->', ('Pair', 0, 1), 2)))
예제 #25
0
#!/usr/bin/python3
"""Archivo principal de lambda."""
from lambda_calculus import parse, lex
from sys import argv

if len(argv) > 1:
    if argv[1] == '--debug':
        string = argv[2]
        # print(lex(string))
        p = parse(string)
        print('Fin.')
        print(p)
        print(p.value(), ' : ', p.type())
    else:
        p = parse(argv[1])
        if p and p.value():
            print(p.value(), ' : ', p.type())

예제 #26
0
 def test_already_unified(self):
     # Make sure that nothing goes wrong when unifying two types
     # that are already the same.
     self.check_single_expr(
         self.def_utils(parse(r"\x . unify x x")),
         ('->', 0, 0))
예제 #27
0
 def test_unify_func(self):
     # Check the type of the "unify" function defined in
     # def_utils().
     self.check_single_expr(
         self.def_utils(parse('unify')),
         ('->', 0, ('->', 0, 0)))
예제 #28
0
 def test_boolean_example(self):
     self.check_single_expr(
         parse(r'\b . if b False True'),
         ('->', ('Bool',), ('Bool',)))
예제 #29
0
 def test_ignore2_func(self):
     # Check the type of the "ignore2" function defined in
     # def_utils().
     self.check_single_expr(
         self.def_utils(parse('ignore2')),
         ('->', 0, ('->', 1, ('Bool',))))
예제 #30
0
 def test_monomorphic_binding_example(self):
     self.check_type_error(
         parse(r'(\id . mk_pair (id True) (id id)) (\x . x)'))
예제 #31
0
 def test_second_func(self):
     # Check the type of the "second" function defined in
     # def_utils().
     self.check_single_expr(
         self.def_utils(parse('second')),
         ('->', 0, ('->', 1, 1)))
예제 #32
0
"""Archivo principal de Lambda Calculus parser."""
from lambda_calculus import parse
from lambda_calculus import reduce_expression
import sys

inputs_file = sys.argv[1]

with open(inputs_file, 'r') as inputs:
    for input_line in inputs:
        input_entry, result = input_line.split(',')
        print "Input value: "
        print "----> " + input_entry
        output = reduce_expression(parse(input_entry))
        print "Output value: "
        if isinstance(output, str):
            print output
        else:
            print "----> " + str(output) + ":" + output.arity()
        print "Expected value: "
        print "----> " + result
        #output, arity = reduce_expression(parse(input_entry))
        #print "Output value: "
        #if isinstance(output, str):
        #    print output
        #else:
        #    print "----> " + str(output) + ":" + arity
        #print "Expected value: "
        #print "----> " + result
예제 #33
0
    # Nuestros tests.
    ('(\\z:Nat. pred(z)) ((\\x:Nat->Nat. x succ(succ(0))) \\y:Nat. y)', '1', 'Nat'),
    ('(\\x:Nat.succ(x)) 0 0', None, None),
    ('(\\x:Nat->Nat. x succ(succ(0))) \y:Nat. y', '2', 'Nat'),
    ('(\\x:Nat->Nat. x pred(succ(0))) \y:Nat. y', '0', 'Nat'),
    ('(\\x:Nat. if iszero(x) then succ(x) else pred(x)) pred(0)', '1', 'Nat'),
    ('(\\x:Nat. if iszero(x) then succ(x) else pred(x)) succ(0)', '0', 'Nat'),
    ('(\\x:Nat. if iszero(x) then succ(x) then pred(x)) succ(0)', None, None),
    ('(\\x:Nat. if iszero(x) then succ(x) then true) succ(0)', None, None),
]



for test in tests:
    try:
        p = parse(test[0])
        if str(p.value()) == test[1] and str(p.type()) == test[2]:
            print('PASSED', test[0])
        else:
            print('FAILED', test[0])
            if str(p.value()) != test[1]:
                print('Got', str(p.value()), 'but expected', test[1])
            if str(p.type()) != test[2]:
                print('Got', str(p.type()), 'but expected', test[2])
    except:
        if test[1] is None:
            print('PASSED', test[0])
        else:
            print('FAILED', test[0])