Esempio n. 1
0
def _try_decrement_rank(code, min_rank):
    if is_atom(code):
        return code
    elif is_nvar(code):
        return code
    elif is_ivar(code):
        rank = code[1]
        if rank < min_rank:
            return code
        elif rank == min_rank:
            raise CannotDecrementRank
        return IVAR(rank - 1)
    elif is_app(code):
        lhs = _try_decrement_rank(code[1], min_rank)
        rhs = _try_decrement_rank(code[2], min_rank)
        return APP(lhs, rhs)
    elif is_abs(code):
        return ABS(_try_decrement_rank(code[1], min_rank + 1))
    elif is_join(code):
        lhs = _try_decrement_rank(code[1], min_rank)
        rhs = _try_decrement_rank(code[2], min_rank)
        return JOIN(lhs, rhs)
    elif is_quote(code):
        return code
    else:
        raise ValueError(code)
    raise UnreachableError((code, min_rank))
Esempio n. 2
0
def _print_tiny(code, tokens):
    if code is TOP:
        tokens.append('T')
    elif code is BOT:
        tokens.append('_')
    elif is_ivar(code):
        rank = code[1]
        assert rank <= 9
        tokens.append(str(rank))
    elif is_abs(code):
        tokens.append('^')
        _print_tiny(code[1], tokens)
    elif is_app(code):
        head, args = unapply(code)
        tokens.append('(')
        _print_tiny(head, tokens)
        for arg in reversed(args):
            _print_tiny(arg, tokens)
        tokens.append(')')
    elif is_join(code):
        tokens.append('[')
        terms = list(iter_join(code))
        _print_tiny(terms[0], tokens)
        for term in terms[1:]:
            tokens.append('|')
            _print_tiny(term, tokens)
        tokens.append(']')
    else:
        raise NotImplementedError(code)
Esempio n. 3
0
def abstract(body):
    """Abstract one de Bruijn variable and simplify."""
    if body is TOP:
        return body
    elif body is BOT:
        return body
    elif is_atom(body):
        return ABS(body)
    elif is_nvar(body):
        return ABS(body)
    elif is_ivar(body):
        return ABS(body)
    elif is_abs(body):
        return ABS(body)
    elif is_join(body):
        lhs = abstract(body[1])
        rhs = abstract(body[2])
        return join(lhs, rhs)
    elif is_app(body):
        if body[2] is IVAR(0) and is_const(body[1]):
            # Eta contract.
            return decrement_rank(body[1])
        else:
            return ABS(body)
    elif is_quote(body):
        return ABS(body)
    else:
        raise ValueError(body)
    raise UnreachableError(body)
Esempio n. 4
0
def approximate_var(code, direction, rank):
    """Locally approximate wrt one variable."""
    assert is_code(code), code
    assert direction is TOP or direction is BOT, direction
    assert isinstance(rank, int) and rank >= 0, rank
    result = set()
    if not occurs(code, rank):
        result.add(code)
    elif is_ivar(code):
        assert code[1] == rank, code
        result.add(code)
        result.add(direction)
    elif is_app(code):
        for lhs in approximate_var(code[1], direction, rank):
            for rhs in approximate_var(code[2], direction, rank):
                result.add(app(lhs, rhs))
    elif is_abs(code):
        for body in approximate_var(code[1], direction, rank + 1):
            result.add(abstract(body))
    elif is_join(code):
        for lhs in approximate_var(code[1], direction, rank):
            for rhs in approximate_var(code[2], direction, rank):
                result.add(join(lhs, rhs))
    else:
        raise ValueError(code)
    return tuple(sorted(result, key=complexity))
Esempio n. 5
0
def dump(code, f):
    head = code
    args = []
    while is_app(head):
        args.append(head[2])
        head = head[1]
    if is_nvar(head):
        _dump_head_argc(SYMB_TO_INT[_NVAR], 1 + len(args), f)
        _dump_raw_bytes(head[1], f)
    elif is_ivar(head):
        _dump_head_argc(SYMB_TO_INT[_IVAR], 1 + len(args), f)
        _dump_raw_bytes(str(head[1]), f)
    elif is_join(head):
        args.append(head[2])
        args.append(head[1])
        _dump_head_argc(SYMB_TO_INT[_JOIN], len(args), f)
    elif is_quote(head):
        args.append(head[1])
        _dump_head_argc(SYMB_TO_INT[_QUOTE], len(args), f)
    elif is_abs(head):
        args.append(head[1])
        _dump_head_argc(SYMB_TO_INT[_ABS], len(args), f)
    elif is_fun(head):
        args.append(head[2])
        args.append(head[1])
        _dump_head_argc(SYMB_TO_INT[_FUN], len(args), f)
    else:
        try:
            head = SYMB_TO_INT[head]
        except KeyError:
            raise ValueError('Failed to serialize code: {}'.format(code))
        _dump_head_argc(head, len(args), f)
    for arg in reversed(args):
        dump(arg, f)
Esempio n. 6
0
def occurs(code, rank):
    if is_atom(code) or is_nvar(code) or is_quote(code):
        return False
    elif is_ivar(code):
        return code[1] == rank
    elif is_app(code):
        return occurs(code[1], rank) or occurs(code[2], rank)
    elif is_abs(code):
        return occurs(code[1], rank + 1)
    elif is_join(code):
        return occurs(code[1], rank) or occurs(code[2], rank)
    else:
        raise ValueError(code)
    raise UnreachableError((code, rank))
Esempio n. 7
0
def is_normal(code):
    """Returns whether code is in linear normal form."""
    if is_atom(code) or is_nvar(code) or is_ivar(code):
        return True
    elif is_abs(code):
        return is_normal(code[1])
    elif is_app(code):
        if is_abs(code[1]):
            return False
        return is_normal(code[1]) and is_normal(code[2])
    elif is_join(code):
        return is_normal(code[1]) and is_normal(code[2])
    elif is_quote(code):
        return is_normal(code[1])
    else:
        raise ValueError(code)
    raise UnreachableError(code)
Esempio n. 8
0
def substitute(body, value, rank, budget):
    """Substitute value for IVAR(rank) in body, decremeting higher IVARs.

    This is linear-eager, and will be lazy about nonlinear
    substitutions.

    """
    assert budget in (True, False), budget
    if is_atom(body):
        return body
    elif is_nvar(body):
        return body
    elif is_ivar(body):
        if body[1] == rank:
            return value
        elif body[1] > rank:
            return IVAR(body[1] - 1)
        else:
            return body
    elif is_app(body):
        lhs = body[1]
        rhs = body[2]
        linear = (is_cheap_to_copy(value) or is_const(lhs, rank) or
                  is_const(rhs, rank))
        if linear or budget:
            # Eager substitution.
            if not linear:
                budget = False
            lhs = substitute(lhs, value, rank, False)
            rhs = substitute(rhs, value, rank, False)
            return app(lhs, rhs)
        else:
            # Lazy substitution.
            return APP(ABS(body), value)
    elif is_abs(body):
        body = substitute(body[1], increment_rank(value, 0), rank + 1, budget)
        return abstract(body)
    elif is_join(body):
        lhs = substitute(body[1], value, rank, budget)
        rhs = substitute(body[2], value, rank, budget)
        return join(lhs, rhs)
    elif is_quote(body):
        return body
    else:
        raise ValueError(body)
    raise UnreachableError((body, value, rank, budget))
Esempio n. 9
0
def anonymize(code, var, rank):
    """Convert a nominal variable to a de Bruijn variable."""
    if code is var:
        return IVAR(rank)
    elif is_atom(code) or is_nvar(code) or is_quote(code):
        return code
    elif is_ivar(code):
        return code if code[1] < rank else IVAR(code[1] + 1)
    elif is_abs(code):
        body = anonymize(code[1], var, rank + 1)
        return abstract(body)
    elif is_app(code):
        lhs = anonymize(code[1], var, rank)
        rhs = anonymize(code[2], var, rank)
        return app(lhs, rhs)
    elif is_join(code):
        lhs = anonymize(code[1], var, rank)
        rhs = anonymize(code[2], var, rank)
        return join(lhs, rhs)
    else:
        raise ValueError(code)
Esempio n. 10
0
def _is_linear(code):
    """
    Returns:
        either None if code is nonlinear, else a pair (L, N) of frozensets,
        where L is the set of free IVARs appearing exactly once,
        and N is the set of free IVARs appearing multiply.
    """
    if is_atom(code):
        return EMPTY_SET, EMPTY_SET
    elif is_nvar(code):
        return EMPTY_SET, EMPTY_SET
    elif is_ivar(code):
        rank = code[1]
        return frozenset([rank]), EMPTY_SET
    elif is_app(code):
        lhs = _is_linear(code[1])
        rhs = _is_linear(code[2])
        if lhs is None or rhs is None:
            return None
        return lhs[0] | rhs[0], lhs[1] | rhs[1] | (lhs[0] & rhs[0])
    elif is_abs(code):
        body = _is_linear(code[1])
        if body is None or 0 in body[1]:
            return None
        return (
            frozenset(r - 1 for r in body[0] if r),
            frozenset(r - 1 for r in body[1]),
        )
    elif is_join(code):
        lhs = _is_linear(code[1])
        rhs = _is_linear(code[2])
        if lhs is None or rhs is None:
            return None
        return lhs[0] | rhs[0], lhs[1] | rhs[1]
    elif is_quote(code):
        return EMPTY_SET, EMPTY_SET
    else:
        raise ValueError(code)
    raise UnreachableError(code)
Esempio n. 11
0
def increment_rank(code, min_rank):
    """Increment rank of all IVARs in code."""
    if is_atom(code):
        return code
    elif is_nvar(code):
        return code
    elif is_ivar(code):
        rank = code[1]
        return IVAR(rank + 1) if rank >= min_rank else code
    elif is_abs(code):
        return ABS(increment_rank(code[1], min_rank + 1))
    elif is_app(code):
        lhs = increment_rank(code[1], min_rank)
        rhs = increment_rank(code[2], min_rank)
        return APP(lhs, rhs)
    elif is_join(code):
        lhs = increment_rank(code[1], min_rank)
        rhs = increment_rank(code[2], min_rank)
        return JOIN(lhs, rhs)
    elif is_quote(code):
        return code
    else:
        raise ValueError(code)
    raise UnreachableError((code, min_rank))
Esempio n. 12
0
def is_var(code):
    return is_nvar(code) or is_ivar(code)
Esempio n. 13
0
def app(fun, arg):
    """Apply function to argument and linearly reduce."""
    if fun is TOP:
        return fun
    elif fun is BOT:
        return fun
    elif is_nvar(fun):
        return APP(fun, arg)
    elif is_ivar(fun):
        return APP(fun, arg)
    elif is_app(fun):
        # Try to reduce strict binary functions of quoted codes.
        if fun[1] in (QAPP, LESS, EQUAL):
            lhs = fun[2]
            rhs = arg
            if lhs is TOP or rhs is TOP:
                return TOP
            elif lhs is BOT:
                if rhs is BOT or is_quote(rhs):
                    return BOT
            elif is_quote(lhs):
                if rhs is BOT:
                    return BOT
                elif is_quote(rhs):
                    if fun[1] is QAPP:
                        return QUOTE(app(lhs[1], rhs[1]))
                    if fun[1] is LESS:
                        ans = try_decide_less(lhs[1], rhs[1])
                    elif fun[1] is EQUAL:
                        ans = try_decide_equal(lhs[1], rhs[1])
                    else:
                        raise UnreachableError(fun[1])
                    if ans is True:
                        return true
                    elif ans is False:
                        return false
        return APP(fun, arg)
    elif is_abs(fun):
        body = fun[1]
        return substitute(body, arg, 0, False)
    elif is_join(fun):
        lhs = app(fun[1], arg)
        rhs = app(fun[2], arg)
        return join(lhs, rhs)
    elif is_quote(fun):
        return APP(fun, arg)
    elif fun is EVAL:
        if arg is TOP:
            return TOP
        elif arg is BOT:
            return BOT
        elif is_quote(arg):
            return arg[1]
        else:
            return APP(fun, arg)
    elif fun is QAPP:
        if arg is TOP:
            return TOP
        else:
            return APP(fun, arg)
    elif fun is QQUOTE:
        if arg is TOP:
            return TOP
        elif arg is BOT:
            return BOT
        elif is_quote(arg):
            return QUOTE(QUOTE(arg[1]))
        else:
            return APP(fun, arg)
    elif fun is LESS:
        if arg is TOP:
            return TOP
        else:
            return APP(fun, arg)
    elif fun is EQUAL:
        if arg is TOP:
            return TOP
        else:
            return APP(fun, arg)
    else:
        raise ValueError(fun)
    raise UnreachableError((fun, arg))