0

I wrote a short program that shows the possible output of a DFA. As it is it gives the expected results. But I've been trying to rewrite the function so that it returns the result, rather than using the global variable - and I can't figure it out how to do it. Could someone please explain how I might do this without using the global variable?

result  = set()

def gen_strings(max_length, state = "A", str = ""):
    global result
    if len(str) > max_length:
        return
    if state == "A":
        gen_strings(max_length, "B", str + "0")
        gen_strings(max_length, "C", str + "1")

    elif state == "B":
        gen_strings(max_length, "D", str + "1")

    elif state == "C":
        gen_strings(max_length, "D", str + "0")

    elif state == "D":
        result.add(str)
        gen_strings(max_length, "A", str + "0")
        gen_strings(max_length, "A", str + "1")
2
  • 2
    Pass the variable for result into the function calls as an argument. Commented Sep 4, 2014 at 2:37
  • 2
    As a side note, avoid calling variables str; that hides the class and constructor of the same name. Commented Sep 4, 2014 at 2:42

2 Answers 2

2

There are two options here: top-down accumulation, or bottom-up.


If you do it bottom-up, you can do it without needing to mutate anything. This does make it harder (and, sometimes, impossible) to write your recursion as tail-calls, but that's fine because (a) Python doesn't eliminate tail calls anyway, and (b) even if it did, your algorithm wouldn't benefit because it makes multiple calls. So, I'll show that way first:

def gen_strings(max_length, state = "A", str = ""):
    if len(str) > max_length:
        return set()
    if state == "A":
        return (gen_strings(max_length, "B", str + "0") |
                gen_strings(max_length, "C", str + "1"))

    elif state == "B":
        return gen_strings(max_length, "D", str + "1")

    elif state == "C":
        return gen_strings(max_length, "D", str + "0")

    elif state == "D":
        return ({str} |
                gen_strings(max_length, "A", str + "0")
                gen_strings(max_length, "A", str + "1"))

To do it top-down, just pass result along the same way you pass state and str down:

def gen_strings(max_length, state="A", str="", result=None):
    if len(str) > max_length:
        return
    if state == "A":
        gen_strings(max_length, "B", str + "0", result)
        gen_strings(max_length, "C", str + "1", result)
    # etc.

The problem is that this doesn't return the result, it takes it as a parameter—you have to pass in an empty set at the top level, like this:

result = set()
gen_strings(max_length, result=result)

But you can always wrap that up. Rename gen_strings to gen_strings_r, then write this:

def gen_strings(max_length, state="A", str=""):
    result = set()
    gen_strings_r(max_length, state, str, result)
    return result

Or you can combine the two, pass a value down to be used to build a value to return back upward. This gives you the benefits of bottom-up (avoiding mutation) and top-down (allowing tail calls), which makes it a very common idiom in functional languages, especially pure functional languages. But it has no advantage over plain bottom-up in this case, and it requires even bigger changes to your code, so I won't bother writing it.

Sign up to request clarification or add additional context in comments.

Comments

0

You could use a closure:

def gen_str(max_length, state = "A", str = ""):
    result  = set()    

    def rec_gen_strings(max_length, state = "A", str = ""):

        if len(str) > max_length:
            return
        if state == "A":
            rec_gen_strings(max_length, "B", str + "0")
            rec_gen_strings(max_length, "C", str + "1")

        elif state == "B":
            rec_gen_strings(max_length, "D", str + "1")

        elif state == "C":
            rec_gen_strings(max_length, "D", str + "0")

        elif state == "D":
            result.add(str)
            rec_gen_strings(max_length, "A", str + "0")
            rec_gen_strings(max_length, "A", str + "1")

    rec_gen_strings(max_length, state, str)
    return result

Comments

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.