progs/lecture4.scala
changeset 384 6e1237691307
parent 383 c02929f2647c
child 418 fa7f7144f2bb
equal deleted inserted replaced
383:c02929f2647c 384:6e1237691307
   247 
   247 
   248 // Source.fromURL(url)(encoding)
   248 // Source.fromURL(url)(encoding)
   249 // Source.fromFile(name)(encoding)
   249 // Source.fromFile(name)(encoding)
   250 
   250 
   251 
   251 
       
   252 // Tail recursion
       
   253 //================
       
   254 
       
   255 @tailrec
       
   256 def fact(n: BigInt): BigInt = 
       
   257   if (n == 0) 1 else n * fact(n - 1)
       
   258 
       
   259 
       
   260 fact(10)          
       
   261 fact(1000)        
       
   262 fact(100000)       
       
   263 
       
   264 def factB(n: BigInt): BigInt = 
       
   265   if (n == 0) 1 else n * factB(n - 1)
       
   266 
       
   267 def factT(n: BigInt, acc: BigInt): BigInt =
       
   268   if (n == 0) acc else factT(n - 1, n * acc)
       
   269 
       
   270 
       
   271 factB(1000)
       
   272 
       
   273 
       
   274 factT(10, 1)
       
   275 println(factT(500000, 1))
       
   276 
       
   277 
       
   278 // there is a flag for ensuring a function is tail recursive
       
   279 import scala.annotation.tailrec
       
   280 
       
   281 @tailrec
       
   282 def factT(n: BigInt, acc: BigInt): BigInt =
       
   283   if (n == 0) acc else factT(n - 1, n * acc)
       
   284 
       
   285 factT(100000, 1)
       
   286 
       
   287 // for tail-recursive functions the Scala compiler
       
   288 // generates loop-like code, which does not need
       
   289 // to allocate stack-space in each recursive
       
   290 // call; Scala can do this only for tail-recursive
       
   291 // functions
       
   292 
       
   293 // Moral: Whenever a recursive function is resource-critical
       
   294 // (i.e. works with a large recursion depth), then you need to
       
   295 // write it in tail-recursive fashion.
       
   296 // 
       
   297 // Unfortuantely, Scala because of current limitations in 
       
   298 // the JVM is not as clever as other functional languages. It can 
       
   299 // only optimise "self-tail calls". This excludes the cases of 
       
   300 // multiple functions making tail calls to each other. Well,
       
   301 // nothing is perfect. 
       
   302 
   252 
   303 
   253 
   304 
   254 
   305 
   255 
   306 
   256 // Sudoku 
   307 // Sudoku 
   389 
   440 
   390 time_needed(1, search(game2))
   441 time_needed(1, search(game2))
   391 
   442 
   392 
   443 
   393 
   444 
   394 // Tail recursion
       
   395 //================
       
   396 
       
   397 @tailrec
       
   398 def fact(n: BigInt): BigInt = 
       
   399   if (n == 0) 1 else n * fact(n - 1)
       
   400 
       
   401 
       
   402 fact(10)          
       
   403 fact(1000)        
       
   404 fact(100000)       
       
   405 
       
   406 def factB(n: BigInt): BigInt = 
       
   407   if (n == 0) 1 else n * factB(n - 1)
       
   408 
       
   409 def factT(n: BigInt, acc: BigInt): BigInt =
       
   410   if (n == 0) acc else factT(n - 1, n * acc)
       
   411 
       
   412 
       
   413 factB(1000)
       
   414 
       
   415 
       
   416 
       
   417 
       
   418 factT(10, 1)
       
   419 println(factT(500000, 1))
       
   420 
       
   421 
       
   422 
       
   423 
       
   424 
       
   425 // there is a flag for ensuring a function is tail recursive
       
   426 import scala.annotation.tailrec
       
   427 
       
   428 @tailrec
       
   429 def factT(n: BigInt, acc: BigInt): BigInt =
       
   430   if (n == 0) acc else factT(n - 1, n * acc)
       
   431 
       
   432 factT(100000, 1)
       
   433 
       
   434 // for tail-recursive functions the Scala compiler
       
   435 // generates loop-like code, which does not need
       
   436 // to allocate stack-space in each recursive
       
   437 // call; Scala can do this only for tail-recursive
       
   438 // functions
       
   439 
       
   440 // tail recursive version that searches 
   445 // tail recursive version that searches 
   441 // for all Sudoku solutions
   446 // for all Sudoku solutions
       
   447 import scala.annotation.tailrec
   442 
   448 
   443 @tailrec
   449 @tailrec
   444 def searchT(games: List[String], sols: List[String]): List[String] = games match {
   450 def searchT(games: List[String], sols: List[String]): List[String] = 
   445   case Nil => sols
   451  games match {
   446   case game::rest => {
   452     case Nil => sols
   447     if (isDone(game)) searchT(rest, game::sols)
   453     case game::rest => {
   448     else {
   454       if (isDone(game)) searchT(rest, game::sols)
   449       val cs = candidates(game, emptyPosition(game))
   455       else {
   450       searchT(cs.map(c => update(game, empty(game), c)) ::: rest, sols)
   456         val cs = candidates(game, emptyPosition(game))
   451     }
   457         searchT(cs.map(c => update(game, empty(game), c)) ::: rest, sols)
   452   }
   458      }
   453 }
   459    }
       
   460  }
   454 
   461 
   455 searchT(List(game3), List()).map(pretty)
   462 searchT(List(game3), List()).map(pretty)
   456 
   463 
   457 
   464 
   458 // tail recursive version that searches 
   465 // tail recursive version that searches 
   485               |9724...5.""".stripMargin.replaceAll("\\n", "")
   492               |9724...5.""".stripMargin.replaceAll("\\n", "")
   486 
   493 
   487 searchT(List(game3), Nil).map(pretty)
   494 searchT(List(game3), Nil).map(pretty)
   488 search1T(List(game3)).map(pretty)
   495 search1T(List(game3)).map(pretty)
   489 
   496 
   490 // Moral: Whenever a recursive function is resource-critical
       
   491 // (i.e. works with a large recursion depth), then you need to
       
   492 // write it in tail-recursive fashion.
       
   493 // 
       
   494 // Unfortuantely, Scala because of current limitations in 
       
   495 // the JVM is not as clever as other functional languages. It can 
       
   496 // only optimise "self-tail calls". This excludes the cases of 
       
   497 // multiple functions making tail calls to each other. Well,
       
   498 // nothing is perfect. 
       
   499 
       
   500 
       
   501 
   497 
   502 
   498 
   503 
   499 
   504 
   500 
   505 
   501