• R/O
  • HTTP
  • SSH
  • HTTPS

提交

标签
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-cqtcocoa誰得pythonphprubygameguibathyscaphec翻訳計画中(planning stage)omegatframeworktwittertestdomvb.netdirectxbtronarduinopreviewerゲームエンジン

A categorical programming language


Commit MetaInfo

修订版f89591928cda9053c1baaa0ff6252d2465c40a95 (tree)
时间2022-02-27 13:21:36
作者Corbin <cds@corb...>
CommiterCorbin

Log Message

Get the typechecker to emit reasonable output.

更改概述

差异

--- a/cammy-rpy/cammylib/arrows.py
+++ b/cammy-rpy/cammylib/arrows.py
@@ -192,7 +192,7 @@ class Case(Arrow):
192192 fdom, fcod = self.f.types(cs)
193193 gdom, gcod = self.g.types(cs)
194194 cs.unify(fcod, gcod)
195- return fdom, cs.functor("sum", [fdom, gdom])
195+ return cs.functor("sum", [fdom, gdom]), fdom
196196
197197 class Curry(Arrow):
198198 _immutable_ = True
@@ -519,16 +519,12 @@ def buildCompound(name, args):
519519 raise BuildProblem("Invalid compound functor: " + name)
520520
521521 def buildArrow(sexp):
522- try:
523- if isinstance(sexp, Atom):
524- return buildUnary(sexp.symbol)
525- elif isinstance(sexp, Functor):
526- args = [buildArrow(arg) for arg in sexp.arguments]
527- return buildCompound(sexp.constructor, args)
528- elif isinstance(sexp, Hole):
529- raise BuildProblem("Holes cannot become arrows")
530- else:
531- assert False, "inconceivable"
532- except BuildProblem as bp:
533- print "Couldn't build Cammy expression:", bp.message
534- raise
522+ if isinstance(sexp, Atom):
523+ return buildUnary(sexp.symbol)
524+ elif isinstance(sexp, Functor):
525+ args = [buildArrow(arg) for arg in sexp.arguments]
526+ return buildCompound(sexp.constructor, args)
527+ elif isinstance(sexp, Hole):
528+ raise BuildProblem("Holes cannot become arrows")
529+ else:
530+ assert False, "inconceivable"
--- a/cammy-rpy/cammylib/hive.py
+++ b/cammy-rpy/cammylib/hive.py
@@ -18,15 +18,18 @@ class Hive(object):
1818 self.exprs = {}
1919
2020 def load(self, atom):
21+ if atom in self.exprs:
22+ return self.exprs[atom]
23+
2124 # print("Loading", atom)
2225 filename = atom + ".cammy"
2326 fullpath = os.path.join(self.hivepath, filename)
24- with open(fullpath, "r") as handle:
25- try:
27+ try:
28+ with open(fullpath, "r") as handle:
2629 sexp, trail = parse(handle.read())
2730 sexp = sexp.canonicalize(self)
2831 self.exprs[atom] = sexp
2932 # print("Loaded", atom, sexp)
3033 return sexp
31- except IOError:
32- raise MissingAtom(atom)
34+ except IOError:
35+ raise MissingAtom(atom)
--- a/cammy-rpy/cammylib/types.py
+++ b/cammy-rpy/cammylib/types.py
@@ -4,6 +4,29 @@ class UnificationFailed(Exception):
44 def __init__(self, message):
55 self.message = message
66
7+def occurs(index, var):
8+ if isinstance(var, Hole):
9+ return var.index == index
10+ elif isinstance(var, Atom):
11+ return False
12+ elif isinstance(var, Functor):
13+ for arg in var.arguments:
14+ if occurs(index, arg):
15+ return True
16+ return False
17+ else:
18+ assert False, "impossible"
19+
20+def occursCheck(index, var):
21+ "If an index occurs in a variable, raise an error."
22+ if occurs(index, var):
23+ raise UnificationFailed("Occurs check: %d in %s" %
24+ (index, var.asStr()))
25+
26+def unhole(sexp):
27+ assert isinstance(sexp, Hole), "implementation error"
28+ return sexp.index
29+
730 class ConstraintStore(object):
831 "A Kanren-style constraint store."
932
@@ -30,31 +53,24 @@ class ConstraintStore(object):
3053 self.constraints.append(Functor(constructor, args))
3154 return rv
3255
33- def walkArg(self, var):
34- if isinstance(var, Atom):
35- return var
36- elif isinstance(var, Functor):
37- return Functor(var.constructor,
38- [self.walkArg(arg) for arg in var.arguments])
39- elif isinstance(var, Hole):
40- return self.walk(var.index)
41- assert False, "impossible"
42-
4356 def walk(self, i):
4457 var = self.constraints[i]
45- if isinstance(var, Hole) and var.index == i:
46- return var
58+ if isinstance(var, Hole) and var.index != i:
59+ return self.walk(var.index)
4760 else:
48- return self.walkArg(var)
61+ return var
4962
5063 def unify(self, i, j):
51- return self.unifyArg(self.walk(i), self.walk(j))
52-
53- def unifyArg(self, vi, vj):
54- print "unifying", vi.asStr(), vj.asStr()
64+ vi = self.walk(i)
65+ vj = self.walk(j)
66+ # print "unifying", vi.asStr(), vj.asStr()
5567 if isinstance(vi, Hole):
68+ if isinstance(vj, Hole) and vi.index == vj.index:
69+ return
70+ occursCheck(vi.index, vj)
5671 self.constraints[vi.index] = vj
5772 elif isinstance(vj, Hole):
73+ occursCheck(vj.index, vi)
5874 self.constraints[vj.index] = vi
5975 elif isinstance(vi, Atom) and isinstance(vj, Atom):
6076 if vi.symbol != vj.symbol:
@@ -69,29 +85,40 @@ class ConstraintStore(object):
6985 if len(vi.arguments) != len(vj.arguments):
7086 raise UnificationFailed("Compound types have different arity?")
7187 for i, argi in enumerate(vi.arguments):
72- self.unifyArg(argi, vj.arguments[i])
88+ self.unify(unhole(argi), unhole(vj.arguments[i]))
7389 else:
7490 raise UnificationFailed("Quite different types: %s. vs %s" %
7591 (vi.asStr(), vj.asStr()))
7692
77-def formatType(sexp):
78- if isinstance(sexp, Hole):
79- return "_%d" % sexp.index
80- elif isinstance(sexp, Atom):
81- return sexp.symbol
82- elif isinstance(sexp, Functor):
83- if sexp.constructor == "hom":
84- return "[%s, %s]" % (formatType(sexp.arguments[0]),
85- formatType(sexp.arguments[1]))
86- elif sexp.constructor == "pair":
87- return "(%s x %s)" % (formatType(sexp.arguments[0]),
88- formatType(sexp.arguments[1]))
89- elif sexp.constructor == "sum":
90- return "(%s + %s)" % (formatType(sexp.arguments[0]),
91- formatType(sexp.arguments[1]))
92- elif sexp.constructor == "list":
93- return "[%s]" % formatType(sexp.arguments[0])
93+
94+LETTERS = "XYZWSTPQ"
95+
96+class TypeExtractor(object):
97+ def __init__(self):
98+ self.d = {}
99+
100+ def addTypeAlias(self, index):
101+ self.d[index] = LETTERS[len(self.d)]
102+
103+ def extractType(self, cs, var):
104+ sexp = cs.walk(var)
105+ if isinstance(sexp, Hole):
106+ if sexp.index not in self.d:
107+ self.addTypeAlias(sexp.index)
108+ return self.d[sexp.index]
109+ elif isinstance(sexp, Atom):
110+ return sexp.symbol
111+ elif isinstance(sexp, Functor):
112+ args = [self.extractType(cs, unhole(arg)) for arg in sexp.arguments]
113+ if sexp.constructor == "hom":
114+ return "[%s, %s]" % (args[0], args[1])
115+ elif sexp.constructor == "pair":
116+ return "(%s x %s)" % (args[0], args[1])
117+ elif sexp.constructor == "sum":
118+ return "(%s + %s)" % (args[0], args[1])
119+ elif sexp.constructor == "list":
120+ return "[%s]" % args[0]
121+ else:
122+ assert False, "whoops"
94123 else:
95- assert False, "whoops"
96- else:
97- assert False, "not whoops"
124+ assert False, "not whoops"
--- a/cammy-rpy/repl.py
+++ b/cammy-rpy/repl.py
@@ -8,7 +8,7 @@ from rpython.rlib.rfile import create_stdio
88 from cammylib.arrows import buildArrow, BuildProblem
99 from cammylib.hive import Hive, MissingAtom
1010 from cammylib.parser import parse
11-from cammylib.types import ConstraintStore, formatType, UnificationFailed
11+from cammylib.types import ConstraintStore, TypeExtractor, UnificationFailed
1212
1313 LINE_BUFFER_LENGTH = 1024
1414
@@ -42,7 +42,8 @@ def repl(hive, stdin, stdout):
4242 print "Arrow:", arrow
4343 cs = ConstraintStore()
4444 domain, codomain = arrow.types(cs)
45- print "Type:", formatType(cs.walk(domain)), "->", formatType(cs.walk(codomain))
45+ extractor = TypeExtractor()
46+ print "Type:", extractor.extractType(cs, domain), "->", extractor.extractType(cs, codomain)
4647 except BuildProblem as bp:
4748 print "Couldn't build arrow:", bp.message
4849 except UnificationFailed as uf:
--- a/cammy-rpy/weave.py
+++ b/cammy-rpy/weave.py
@@ -1,7 +1,10 @@
11 import os
22 import os.path
33
4+from cammylib.arrows import buildArrow, BuildProblem
5+from cammylib.hive import Hive, MissingAtom
46 from cammylib.parser import parse
7+from cammylib.types import ConstraintStore, TypeExtractor, UnificationFailed
58
69
710 def codeblock(code):
@@ -9,6 +12,7 @@ def codeblock(code):
912
1013 def main(argv):
1114 hivepath = argv[-1]
15+ hive = Hive(hivepath)
1216 if not hivepath.endswith(os.sep):
1317 hivepath += os.sep
1418 prefix = len(hivepath)
@@ -29,6 +33,22 @@ def main(argv):
2933
3034 doc.append("## " + atom)
3135 doc.append(codeblock(sexp.asStr()))
36+ try:
37+ sexp = sexp.canonicalize(hive)
38+ arrow = buildArrow(sexp)
39+ cs = ConstraintStore()
40+ domain, codomain = arrow.types(cs)
41+ extractor = TypeExtractor()
42+ doc.append("Type: %s -> %s" % (extractor.extractType(cs, domain),
43+ extractor.extractType(cs, codomain)))
44+ except MissingAtom as ma:
45+ doc.append(
46+ "(Couldn't canonicalize due to missing expression %s)" %
47+ ma.atom)
48+ except BuildProblem:
49+ doc.append("(Couldn't build arrow)")
50+ except UnificationFailed as uf:
51+ doc.append("(Couldn't typecheck: %s)" % uf.message)
3252 if trail:
3353 doc.append(trail)
3454 print "\n\n".join(doc)