def find_instance(self, mono): '''find typeclass instance matching mono''' tool.debug('finding instance of:', self.name, mono.show()) # print('finding instance of:', self.name, 'for:', mono.show()) t = type(mono) matches = [] for scheme, instance in self.instances.items(): # TODO what about depth ? fresh = hm.instantiate( scheme ) try: # note: we unify in a fresh union_find hm.unify(tool.UnionFind(), fresh, mono) matches.append( (scheme, instance) ) except error.Type: pass if not matches: raise error.Type('typeclass {0} has no instance for type {1}' .format( self.name, mono.show() )) if len(matches) > 1: raise error.Type('ambiguous {0} instances for {1}'.format(self.name, mono.show())) return matches[0]
def unify(uf, a, b): a = uf.find(a) b = uf.find(b) ta = type(a) tb = type(b) # sa, sb = hm.show(a, b) # print('typeclass unify', a.show(), 'with:', b.show() ) assert ta is Var or tb is Var if ta is Var and tb is Var: # create a fresh constrained variable with constraint union depth = min(a.depth, b.depth) c = Var(depth, a.context | b.context ) # and link both uf.link(a, c) uf.link(b, c) return var = a if ta is Var else b other = a if tb is Var else b if type(other) is hm.Var: # constrained variable becomes representant uf.link(other, var) return # check instances for tc in var.context: # find a type scheme that matches 'other' in the # instances for this type constructor scheme, instance = tc.find_instance( other.nice(uf) ) # context reduction happens here: we instantiate the # type scheme (possibly containing bounded variables) # and unify with other # propagate further constraints, if any if any( type(b) is Var for b in scheme.bound ): # TODO what about the depth when instantiating scheme ? hm.unify(uf, hm.instantiate(scheme), other) # we made it so far, we may link now uf.link(var, other) return
def find_overload(self, identifier, mono): tool.debug('finding overload for:', identifier, ':', mono.show()) proto = self.definition[identifier] uf = tool.UnionFind() fresh = hm.instantiate(hm.generalize(proto)) vars = fresh.variables() assert len(vars) == 1 hm.unify(uf, fresh, mono) a = next(iter(vars)) t = uf.find( a ) scheme, instance = self.find_instance(t) return instance[identifier]
def unify(uf, a, b): """unify row types ra and rb""" a = uf.find(a) b = uf.find(b) ta = type(a) tb = type(b) assert ta in types and tb in types # print( ra, rb) if ta is Extension and tb is Extension: if a.label == b.label: # unify heads hm.unify(uf, a.mono, b.mono) # unify tails unify(uf, a.tail, b.tail) else: try: # try pulling b's head in a tool.debug("pulling", b.label) pa = a.pull(b.label) unify(uf, pa, b) # it worked: remember pa is originially a uf.link(pa, a) except PullError: try: # try pulling a's head in b tool.debug("pulling", a.label) pb = b.pull(a.label) unify(uf, a, pb) # it worked: remember pa is originially b uf.link(pb, b) except PullError: tool.debug("union") # none of it worked: neither heads is present in # other type. try to unify both to record union # unify a's tail var with a fresh copy of b try: unify(uf, a.var(), b.fresh()) unify(uf, b.var(), a.fresh()) except FreshError: sa, sb = hm.show(a, b) raise error.Type("can not unify row type {0} with {1}".format(sa, sb)) elif ta is Var or tb is Var: var = a if ta is Var else b other = a if tb is Var else b uf.link(var, other) # tool.debug('repr:', other.show()) elif a != b: raise error.Type("can not unify row type {0} with {1}".format(a.show(), b.show())) else: assert ta is Empty and tb is Empty