簡體   English   中英

如何在 Python 中為 SKI 組合器實現快速類型推理程序?

[英]How to implement a fast type inference procedure for SKI combinators in Python?

如何在 Python 中為SKI 組合子實現一個快速的簡單類型推斷程序?

我對 2 個函數感興趣:

  1. typable :如果給定的 SKI 術語具有類型,則返回 true(我想它應該比搜索具體類型工作得更快)。

  2. principle_type :如果存在則返回原則類型,否則返回 False。


typable(SKK) = True
typable(SII) = False # (I=SKK). This term does not have a type. Similar to \x.xx

principle_type(S) = (t1 -> t2 -> t3) -> (t1 -> t2) -> t1 -> t3
principle_type(K) = t1 -> t2 -> t1
principle_type(SK) = (t3 -> t2) -> t3 -> t3
principle_type(SKK) = principle_type(I) = t1 -> t1  

理論問題:

  1. 我閱讀了Hindley–Milner 類型系統 有 2 個算法:算法 J 和算法 W。我是否正確理解它們用於更復雜的類型系統:系統 F? 具有參數多態性的系統? 是否存在在 System F 中可輸入但在簡單類型系統中不可輸入的組合器?

  2. 據我了解,要找到一個原則類型,我們需要求解符號表達式之間的方程組。 是否可以通過使用像Z3這樣的 SMT 求解器來簡化算法並加快流程?

我對基本組合器、縮減和解析的實現:

from __future__ import annotations
import typing
from dataclasses import dataclass


@dataclass(eq=True, frozen=True)
class S:
    def __str__(self):
        return "S"

    def __len__(self):
        return 1


@dataclass(eq=True, frozen=True)
class K:
    def __str__(self):
        return "K"

    def __len__(self):
        return 1


@dataclass(eq=True, frozen=True)
class App:
    left: Term
    right: Term

    def __str__(self):
        return f"({self.left}{self.right})"

    def __len__(self):
        return len(str(self))


Term = typing.Union[S, K, App]


def parse_ski_string(s):
    # remove spaces
    s = ''.join(s.split())

    stack = []
    for c in s:
        # print(stack, len(stack))
        if c == '(':
            pass

        elif c == 'S':
            stack.append(S())
        elif c == 'K':
            stack.append(K())
        # elif c == 'I':
        #     stack.append(I())

        elif c == ')':
            x = stack.pop()
            if len(stack) > 0:
                # S(SK)
                f = stack.pop()
                node = App(f, x)
                stack.append(node)
            else:
                # S(S)
                stack.append(x)
        else:
            raise Exception('wrong c = ', c)

    if len(stack) != 1:
        raise Exception('wrong stack = ', str(stack))

    return stack[0]


def simplify(expr: Term):
    if isinstance(expr, S) or isinstance(expr, K):
        return expr

    elif isinstance(expr, App) and isinstance(expr.left, App) and isinstance(expr.left.left, K):
        return simplify(expr.left.right)

    elif isinstance(expr, App) and isinstance(expr.left, App) and isinstance(expr.left.left, App) and isinstance(
            expr.left.left.left, S):
        return simplify(App(App(expr.left.left.right, expr.right), (App(expr.left.right, expr.right))))

    elif isinstance(expr, App):
        l2 = simplify(expr.left)
        r2 = simplify(expr.right)
        if expr.left == l2 and expr.right == r2:
            return App(expr.left, expr.right)
        else:
            return simplify(App(l2, r2))

    else:
        raise Exception('Wrong type of combinator', expr)

# simplify(App(App(K(),S()),K())) = S
# simplify(parse_ski_string('(((SK)K)S)')) = S

簡單,也許不是最快的(但如果類型很小,速度相當快)。

from dataclasses import dataclass

parent = {}


def new_var():
    t1 = len(parent)
    parent[t1] = t1
    return t1


@dataclass
class Fun:
    dom: "int | Fun"
    cod: "int | Fun"


def S():
    t1 = new_var()
    t2 = new_var()
    t3 = new_var()
    return Fun(Fun(t1, Fun(t2, t3)), Fun(Fun(t1, t2), Fun(t1, t3)))


def K():
    t1 = new_var()
    t2 = new_var()
    return Fun(t1, Fun(t2, t1))


def I():
    t1 = new_var()
    return Fun(t1, t1)


def find(t1):
    if isinstance(t1, Fun):
        return Fun(find(t1.dom), find(t1.cod))
    if parent[t1] != t1:
        t2 = find(parent[t1])
        parent[t1] = t2
        return t2
    return t1


def occurs(t1, t2):
    if isinstance(t2, Fun):
        return occurs(t1, t2.dom) or occurs(t1, t2.cod)
    return t1 == t2


def unify(t1, t2):
    t1 = find(t1)
    t2 = find(t2)
    if isinstance(t1, Fun):
        if isinstance(t2, Fun):
            unify(t1.dom, t2.dom)
            unify(t1.cod, t2.cod)
        else:
            assert not occurs(t2, t1)
            parent[t2] = t1
    else:
        assert not (isinstance(t2, Fun) and occurs(t1, t2))
        parent[t1] = t2


def apply(t1, t2):
    t3 = new_var()
    unify(t1, Fun(t2, t3))
    return t3


a = S()
b = K()
ab = apply(a, b)
c = K()
abc = apply(ab, c)
print("#", find(abc))

# Fun(dom=6, cod=6)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM