'Recursive interpretation function for a formula of first-order logic.
Raises an ``Undefined`` error when ``parsed`` is an atomic string
but is not a symbol or an individual variable.
:return: Returns a truth value or ``Undefined`` if ``parsed`` is        complex, and calls the interpretation function ``i`` if ``parsed``        is atomic.
:param parsed: An expression of ``logic``.
:type g: Assignment
:param g: an assignment to individual variables.'

def satisfy(self, parsed, g, trace=None):

    if isinstance(parsed, ApplicationExpression):
        (function, arguments) = parsed.uncurry()
        if isinstance(function, AbstractVariableExpression):
            funval = self.satisfy(function, g)
            argvals = tuple((self.satisfy(arg, g) for arg in arguments))
            return (argvals in funval)
        else:
            funval = self.satisfy(parsed.function, g)
            argval = self.satisfy(parsed.argument, g)
            return funval[argval]
    elif isinstance(parsed, NegatedExpression):
        return (not self.satisfy(parsed.term, g))
    elif isinstance(parsed, AndExpression):
        return (self.satisfy(parsed.first, g) and self.satisfy(parsed.second, g))
    elif isinstance(parsed, OrExpression):
        return (self.satisfy(parsed.first, g) or self.satisfy(parsed.second, g))
    elif isinstance(parsed, ImpExpression):
        return ((not self.satisfy(parsed.first, g)) or self.satisfy(parsed.second, g))
    elif isinstance(parsed, IffExpression):
        return (self.satisfy(parsed.first, g) == self.satisfy(parsed.second, g))
    elif isinstance(parsed, EqualityExpression):
        return (self.satisfy(parsed.first, g) == self.satisfy(parsed.second, g))
    elif isinstance(parsed, AllExpression):
        new_g = g.copy()
        for u in self.domain:
            new_g.add(parsed.variable.name, u)
            if (not self.satisfy(parsed.term, new_g)):
                return False
        return True
    elif isinstance(parsed, ExistsExpression):
        new_g = g.copy()
        for u in self.domain:
            new_g.add(parsed.variable.name, u)
            if self.satisfy(parsed.term, new_g):
                return True
        return False
    elif isinstance(parsed, LambdaExpression):
        cf = {}
        var = parsed.variable.name
        for u in self.domain:
            val = self.satisfy(parsed.term, g.add(var, u))
            cf[u] = val
        return cf
    else:
        return self.i(parsed, g, trace)
