首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类型统一算法在python中,如何拒绝统一(a -> b,int -> int)

类型统一算法在python中,如何拒绝统一(a -> b,int -> int)
EN

Stack Overflow用户
提问于 2020-12-19 02:50:49
回答 1查看 153关注 0票数 0

我在玩类型统一,我从这里得到了算法,https://eli.thegreenplace.net/2018/unification/

我的问题是:我想使用这个作为类型推断步骤,我调整了上面页面的代码,并添加了Lark解析器来解析和统一X -> Y == W -> Z表达式,意思类似于unify(_(X, Y), _(Y, W))。我还用poly表示多类型,或类型变量,mono表示像int,str,bool这样的单类型。

我以为a -> b == int -> int会被拒绝。我可以理解为什么没有被拒绝,因为unify(f(A, B), f(1, 1))是完美的。但我希望它失败。我不知道这是否应该在后面的步骤中完成,在类型检查类型时,这将在类型推断时间之后发生,但对我的应用程序来说,这似乎是错误的。

我用来进行类型推断的统一算法是正确的吗?如果没有,如何解决统一unify(a -> b, int -> int)问题,使其被拒绝?(任何关于主题的论文都会很好)或者我只是把这些球混合在一起,这应该在类型检查之后完成?

这是我的代码,为了执行你需要的Lark pip install lark-parser,我使用python3.8进行测试

代码语言:javascript
复制
from typing import (
    Dict,
    Any,
    NamedTuple,
    Optional,
    Callable,
    TypedDict,
    Generic,
    TypeVar,
    Iterable,
    Sequence,
    Tuple,
    Union,
)
from lark import Lark, Transformer as LarkTransformer

Subst = Dict[str, "TTerm"]


class TTerm:
    "Type term"

    def unify_eq(self, other) -> bool:
        pass


class TArrow(TTerm):
    def __init__(self, t1, t2):
        self.t1 = t1
        self.t2 = t2

    def unify_eq(self, other) -> bool:
        return (
            other.__class__ is TArrow
            and self.t1.unify_eq(other.t1)
            and self.t2.unify_eq(other.t2)
        )

    def __repr__(self):
        return f"({self.t1} -> {self.t2})"


class TPoly(TTerm):
    def __init__(self, name):
        self.name = name

    def unify_eq(self, other):
        return other.__class__ is TPoly and self.name == other.name

    def __eq__(self, other):
        return other.__class__ is self.__class__ and self.name == other.name

    def __repr__(self):
        return self.name


class TMono(TTerm):
    def __init__(self, val):
        self.val = val

    def unify_eq(self, other):
        return self.__class__ is other.__class__ and self.val == other.val

    def __eq__(self, other):
        return other.__class__ is self.__class__ and self.val == other.val

    def __repr__(self):
        return self.val


class TUnification:
    def __init__(self, t1: TTerm, t2: TTerm):
        self.t1 = t1
        self.t2 = t2

    def unify(self):
        return unify(self.t1, self.t2, {})

    def __repr__(self):
        return f"unify({self.t1}, {self.t2})"


def unify(x: TTerm, y: TTerm, subst: Optional[Subst]) -> Optional[Subst]:
    print(f"unify({x}, {y}, {subst})")
    if subst is None:
        return None
    elif x.unify_eq(y):
        return subst
    elif isinstance(x, TPoly):
        return unify_var(x, y, subst)
    elif isinstance(y, TPoly):
        return unify_var(y, x, subst)
    elif isinstance(x, TArrow) and isinstance(y, TArrow):
        subst = unify(x.t1, y.t1, subst)
        subst = unify(x.t2, y.t2, subst)
        return subst
    else:
        return None


def unify_var(v: TPoly, x: TTerm, subst: Subst) -> Optional[Subst]:
    print(f"unify_var({v}, {x}, {subst})")
    if v.name in subst:
        return unify(subst[v.name], x, subst)
    elif isinstance(x, TPoly) and x.name in subst:
        return unify(v, subst[x.name], subst)
    elif occurs_check(v, x, subst):
        return None
    else:
        return {**subst, v.name: x}


def occurs_check(v: TPoly, term: TTerm, subst: Subst) -> bool:
    if v == term:
        return True
    elif isinstance(term, TPoly) and term.name in subst:
        return occurs_check(v, subst[term.name], subst)
    elif isinstance(term, TArrow):
        return occurs_check(v, term.t1, subst) or occurs_check(v, term.t2, subst)
    else:
        return False


grammar = r"""
    unification : term "==" term
    ?term       : tarrow | POLY -> poly | MONO -> mono
    ?tarrow     : term "->" term | "(" term ")"
    POLY        : /[a-z]/
    MONO        : /(int|str|bool)/

    %import common.WS
    %import common.SH_COMMENT
    %import common.INT
    %ignore WS
    %ignore SH_COMMENT
"""

parser = Lark(grammar, start="unification", parser="lalr")


class Transformer(LarkTransformer):
    def unification(self, tree):
        return TUnification(tree[0], tree[1])

    def poly(self, tree):
        return TPoly(tree[0].value)

    def mono(self, tree):
        return TMono(tree[0].value)

    def tarrow(self, tree):
        return TArrow(tree[0], tree[1])


def parse(input_):
    return Transformer().transform(parser.parse(input_))


print(parse("a -> b == int -> int").unify())

输出

代码语言:javascript
复制
unify((a -> b), (int -> int), {})
unify(a, int, {})
unify_var(a, int, {})
unify(b, int, {'a': int})
unify_var(b, int, {'a': int})
{'a': int, 'b': int}
EN

回答 1

Stack Overflow用户

发布于 2020-12-19 02:55:14

,但我希望它失败

不过,这是正确的行为。在a -> b中,ab不必是不同的类型,所以a == b是非常好的。因此,int -> int也很好。

如果你真的需要拒绝int -> int,你可以为这个类型创建一个额外的约束,比如TArrow(a, b, constraints=[NotEqual(a, b)]),然后在树中向下传播它。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65362422

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档