How Does One Make Scala Control Abstraction in Repeat Until?

后端 未结 4 954
挽巷
挽巷 2021-02-08 12:04

I am Peter Pilgrim. I watched Martin Odersky create a control abstraction in Scala. However I can not yet seem to repeat it inside IntelliJ IDEA 9. Is it the IDE?



        
相关标签:
4条回答
  • 2021-02-08 12:14

    Here is a solution without the StackOverflowError.

    scala>   class ConditionIsTrueException extends RuntimeException
    defined class ConditionIsTrueException
    
    scala>   def repeat(body: => Unit) = new {
     |     def until(condition: => Boolean) = { 
     |       try {
     |         while(true) {
     |           body
     |           if (condition) throw new ConditionIsTrueException
     |         }   
     |       } catch {
     |         case e: ConditionIsTrueException =>
     |       }   
     |     
     |     }   
     |   }
    repeat: (body: => Unit)java.lang.Object{def until(condition: => Boolean): Unit}
    
    scala> var i = 0              
    i: Int = 0
    
    scala> repeat { println(i); i += 1 } until(i == 3)
    0
    1
    2
    
    scala> repeat { i += 1 } until(i == 100000)       
    
    scala> repeat { i += 1 } until(i == 1000000)
    
    scala> repeat { i += 1 } until(i == 10000000)
    
    scala> repeat { i += 1 } until(i == 100000000)
    
    scala> 
    

    According to Jesper and Rex Kerr here is a solution without the Exception.

    def repeat(body: => Unit) = new {
      def until(condition: => Boolean) = { 
        do {
          body
        } while (!condition)
      }   
    }
    
    0 讨论(0)
  • 2021-02-08 12:18

    You don't need the 2nd pair of braces, the usage should be:

    repeatLoop (x) until (cond) //or...
    repeatLoop {x} until {cond}
    

    And not:

    repeatLoop {x} { until(cond) } //EXTRA PAIR OF BRACES
    

    The error means that Scala thinks you are trying to call a method with a signature something like:

    def repeatLoop(x: => Unit)(something: X) //2 parameter lists
    

    And can find no such method. It is saying "repeatLoop(body)" does not take parameters. A full code listing for the solution probably looks something a bit more like:

    object Control0 {
      def repeatLoop(body: => Unit) = new Until(body)
    
      class Until(body: => Unit) {
        def until(cond: => Boolean) {
          body;
          val value: Boolean = cond;
    
          if (value) repeatLoop(body).until(cond)
        }
      }
    
    
      def main(args: Array[String]) {
        var y: Int = 1
        println("testing ... repeatUntil() control structure")
        repeatLoop {
          println("found y=" + y)
          y += 1
        }.until(y < 10)
      }
    }
    

    There are two useful observations to make here:

    1. The solution is not tail-recursive and will result in a StackOverflowError for long iterations (try while (y < 10000))
    2. The until seems the wrong way round to me (it would be more natural to stop when the condition becomes true, not carry on while it is true).
    0 讨论(0)
  • 2021-02-08 12:25

    How about a one liner for repeat until.

    def repeat(b: => Unit) = new AnyRef {def until(c: => Boolean) {b; while (! c) b}}
    

    Which, for example, gives:-

    scala> repeat {
         |   println("i = "+i)
         |   i+=1
         | } until (i >= 10)
    i = 0
    i = 1
    i = 2
    i = 3
    i = 4
    i = 5
    i = 6
    i = 7
    i = 8
    i = 9
    
    0 讨论(0)
  • 2021-02-08 12:31

    As above yet recursive :)

    def repeat(b: => Unit) = new {def until(c: => Boolean) = { b; if (c) until(c) }}
    
    var i = 0
    repeat {
      println(i)
      i+=1
    } until (i < 10)
    

    It's @tailrec optimized too.

    Llove scala :)

    0 讨论(0)
提交回复
热议问题