0

I am trying to write a function that returns the variables contained in a class of type Rule. I need to iterate through it and get all variables and store them in a set.

class Rule:
    # head is a function
    # body is a *list* of functions
    def __init__(self, head, body):
        self.head = head
        self.body = body
    def __str__(self):
        return str(self.head) + ' :- ' + str(self.body)
    def __eq__(self, other):
        if not isinstance(other, Rule):
            return NotImplemented
        return self.head == other.head and self.body == other.body
    def __hash__(self):
        return hash(self.head) + hash(self.body)


class RuleBody:
    def __init__(self, terms):
        assert isinstance(terms, list)
        self.terms = terms
    def separator(self):
        return ','
    def __str__(self):
        return '(' + (self.separator() + ' ').join(
            list(map(str, self.terms))) + ')'
    def __eq__(self, other):
        if not isinstance(other, RuleBody):
            return NotImplemented
        return self.terms == other.terms
    def __hash__(self):
        return hash(self.terms)

My function is the following:

def variables_of_clause (self, c : Rule) -> set :
        returnSet = set()
        l = getattr(c, 'body')
        for o in l:
            returnSet.add(o)

Testing function

# The variables in a Prolog rule p (X, Y, a) :- q (a, b, a) is [X; Y]
def test_variables_of_clause (self):
        c = Rule (Function ("p", [Variable("X"), Variable("Y"), Atom("a")]),
                    RuleBody ([Function ("q", [Atom("a"), Atom("b"), Atom("a")])]))
        #assert
        (self.variables_of_clause(c) == set([Variable("X"), Variable("Y")]))

I keep getting an error that says: TypeError: 'RuleBody' is not iterable.

5
  • 1
    Seems like the thing you want to iterate through is the terms of your RuleBody, e.g. l.terms Commented May 10, 2020 at 21:25
  • What part of my code do I change to l.terms? It does not work if I change my for loop to it. Commented May 10, 2020 at 22:24
  • If the error emanates from for o in l: and l is an instance of RuleBody then you could try for o in l.terms: Commented May 10, 2020 at 22:30
  • I did that. Now I get errors from the last function in RuleBody which says " TypeError: unhashable type: 'list' " Commented May 10, 2020 at 22:35
  • So one error is solved and you now have another one to figure out. Perhaps you would like to post a question with a minimal reproducible example and a traceback of the exception this time. Commented May 10, 2020 at 22:36

1 Answer 1

2

RuleBody.terms is a list, not RuleBody, you can iterate over RuleBody.terms instead, however, you can make your RuleBody class iterable (by basically making it return RuleBody.terms's elements), using the __iter__ method:

class RuleBody:
    ... # everything
    ...
    def __iter__(self):
        return iter(self.terms)
Sign up to request clarification or add additional context in comments.

2 Comments

@PatrickArtner I was just so used to using dunders inside class definitions, I realize using the built-in is better. Thx.
Thank you for your answer. Unfortunately, I cannot change my class. I can only change the code in my function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.