Esempio n. 1
0
def test_typecheck_recursion():
    then = TypeScheme.from_str("a -> Then a")
    else_ = TypeScheme.from_str("a -> Else a")
    if_then_else = TypeScheme.from_str("Bool -> Then a -> Else a -> a")
    Nil = TypeScheme.from_str("[a]")
    tail = TypeScheme.from_str("[a] -> [a]")
    matches = TypeScheme.from_str("a -> b -> Bool")
    add = TypeScheme.from_str("a -> a -> a")
    env = BuiltinEnvDict({
        "if": if_then_else,
        "then": then,
        "else": else_,
        "matches": matches,
        "Nil": Nil,
        "+": add,
        "tail": tail,
    })
    phi, t = typecheck(
        # I need to put parenthesis because of the failure of precedence we
        # have; otherwise we could use $ to connect if then and else (they are
        # still functions): 'if cond $ then result $ else other_result'.
        # `matches` would be a simple pattern matching function.  The real
        # function would have to operate on values and patterns (which are no
        # representable here.)
        parse_expression("""
            let count xs = if (xs `matches` Nil) \
                              (then 0) \
                              (else let ts = tail xs in 1 + (count ts))
            in count
            """),
        env,
    )
    # The count functions counts the number of elements.
    unify(Type.from_str("[a] -> Number"), t)
Esempio n. 2
0
def test_basic_builtin_types():
    with pytest.raises(TypeError):
        # not :: Bool -> Bool, but passed a Number
        typecheck(parse_expression("not 0"), builtins_env)

    phi, t = typecheck(parse_expression("not True"), builtins_env)
    assert t == BoolType
    phi, t = typecheck(parse_expression("not False"), builtins_env)
    assert t == BoolType

    userfuncs = {"toString": TypeScheme.from_str("a -> [Char]")}
    phi, t = typecheck(parse_expression("either toString id"),
                       dict(builtins_env, **userfuncs))
    assert len(find_tvars(t)) == 1
    unify(Type.from_str("Either a [Char] -> [Char]"), t)
Esempio n. 3
0
def test_combinators():
    # Since they're closed expressions they should type-check
    K = parse_expression(r"\a b -> a")
    TK = Type.from_str("a -> b -> a")
    phi, t = typecheck(K, EMPTY_TYPE_ENV)
    # we can't ensure TK == t, but they must unify, in fact they
    # must be same type with alpha-renaming.
    unify(TK, t)

    S = parse_expression(r"\x y z -> x z (y z)")
    TS = Type.from_str("(a -> b -> c) -> (a -> b) -> a -> c")
    phi, t = typecheck(S, EMPTY_TYPE_ENV)
    unify(TS, t)

    # But the paradoxical combinator doesn't type-check
    Y = parse_expression(r"\f -> (\x -> f (x x))(\x -> f (x x))")
    with pytest.raises(TypeError):
        phi, t = typecheck(Y, EMPTY_TYPE_ENV)
Esempio n. 4
0
    def __mod__(self, other):
        if isinstance(other, Type):
            from xotl.fl.typecheck import unify

            return unify(self, other)
        else:  # pragma: no cover
            t1 = type(self).__name__
            t2 = type(other).__name__
            raise TypeError(
                f"unsupported operand type(s) for %: '{t1}' and '{t2}'")
Esempio n. 5
0
def test_composition():
    phi, t = typecheck(parse_expression("let id x = x in id . id"),
                       builtins_env)
    unify(Type.from_str("a -> a"), t)
    unify(Type.from_str("(a -> a) -> (a -> a)"), t)

    phi, t = typecheck(parse_expression("Left . Right"), builtins_env)
    unify(Type.from_str("a -> Either (Either b a) c"), t)

    # In our case, (+) is not polymorphic (Number is not a type-class), so it
    # can't be composed with Either.
    with pytest.raises(TypeError):
        typecheck(parse_expression("(+) . Left"), builtins_env)
    # If we had a polymorphic (+), it would be composable
    phi, t = typecheck(
        parse_expression("(+) . Left"),
        dict(builtins_env, **{"+": TypeScheme.from_str("a -> a -> a")}),
    )
    unify(Type.from_str("a -> Either a b -> Either a b"), t)
    phi, t = typecheck(
        parse_expression("(+) . Right"),
        dict(builtins_env, **{"+": TypeScheme.from_str("a -> a -> a")}),
    )
    unify(Type.from_str("b -> Either a b -> Either a b"), t)
Esempio n. 6
0
def test_regression_missing_dynamic_builtins():
    phi, t = typecheck(parse_expression("let pair x y = (x, y) in pair 1 2"))
    assert unify(t, Type.from_str("(Number, Number)"))