[英]How to implement a fast type inference procedure for SKI combinators in Python?
如何在 Python 中為SKI 組合子實現一個快速的簡單類型推斷程序?
我對 2 個函數感興趣:
typable
:如果給定的 SKI 術語具有類型,則返回 true(我想它應該比搜索具體類型工作得更快)。
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
理論問題:
我閱讀了Hindley–Milner 類型系統。 有 2 個算法:算法 J 和算法 W。我是否正確理解它們用於更復雜的類型系統:系統 F? 具有參數多態性的系統? 是否存在在 System F 中可輸入但在簡單類型系統中不可輸入的組合器?
據我了解,要找到一個原則類型,我們需要求解符號表達式之間的方程組。 是否可以通過使用像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.