简体   繁体   中英

Infinite loop scala code

object Prop {
  def simplify(prop : Prop) : Prop = {
    prop match {
      case Not(Or(a,b)) => simplify(And(Not(a),Not(b)))
      case Not(And(a,b)) => simplify(Or(Not(a),Not(b)))
      case Not(Not(a)) => simplify(a)
      case _ => {
        if (simplify(prop) == prop) prop
        else prop
      }
    }
  }
}

I'm pretty sure I've an infinite loop caused by my 'default' case. I'm using recursion in all cases. Which is meant to be, but, only if the Prop can be simplified. As soon as the Prop can't be simplified, it should return the whole thing.

I don't see how I can test for any further simplification. (I'm not allowed to use other libraries, as suggested in freenodes #scala channel).

Can someone explain whether it IS the 'case _' causing the loop, and how to solve it? How can I test for possible simplification without making a loop?

Thanks in advance!

It is pretty obvious what happens and you are right with the default case . If your input prop does not match any of the cases you are invoking:

simplify(prop)

with the same argument. Because previously it caused recursive call to simplify() and you are calling your function with the same input, it enters simplify() again. So this is not an infinite loop but rather never terminated recursive call:

...simplify(simplify(simplify(simplify(simplify(simplify(simplify(prop)))))))

However the fix (based on your code) is simple:

if (simplify(prop) == prop) prop
    else prop

just replace it with...

 case _ => prop

Both branches return the same value. This is actually correct if you think about if for a while. You have a set of optimizations. If none of them matched your expressions it means it can no longer be simplified. Hence you are returning it as-is.

BTW looks like you are doing boolean expressions simplification using case classes. You might by interested in my article where I do the same but with arithmetic expressions.

The problem is that you're trying to do two things in one step that need to happen in sequence—applying De Morgan's law (and removing double negation) and recursively simplifying any children. This is why just dropping a case And(a, b) => And(simplify(a), simplify(b)) into your match won't work.

Try the following:

val deMorganAndDoubleNegation: Prop => Prop = {
  case Not(Or(a, b)) => And(Not(a), Not(b))
  case Not(And(a, b)) => Or(Not(a), Not(b))
  case Not(Not(a)) => a
  case a => a
}

val simplify: Prop => Prop = deMorganAndDoubleNegation andThen {
  case And(a, b) => And(simplify(a), simplify(b))
  case Or(a, b) => Or(simplify(a), simplify(b))
  case Not(a) => Not(simplify(a))
  case a => a
}

Yes, default case is causing the loop. if (simplify(prop) == prop) prop is problematic line. You don't need to test if it can be simplified further because when you are in the default case all possible simplifications are tried.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM