Advertisement
Guest User

Untitled

a guest
Jul 29th, 2015
198
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.52 KB | None | 0 0
  1. import scala.annotation.tailrec
  2. import scala.util.control.TailCalls
  3. import scala.util.control.TailCalls._
  4. import scalaz.Applicative
  5. import scalaz.Free._
  6. import scalaz.Monad
  7. import scalaz.OptionT
  8.  
  9. /*
  10. * A possible limitation with writing monadic code in Scala. Because of Scala's
  11. * limited tail recursion optimisation (as opposed to Haskell's more general
  12. * tail *call* optimisation) some recursive calls in monadic code results in
  13. * growing the stack.
  14. *
  15. * As a demonstration, try running MonadTest.subtract(Some(1000000), Some(1000000))
  16. * or running MonadTest.flatSubtract(Some(1000000), Some(1000000)).
  17. * This will result in a StackOverflowException.
  18. *
  19. * If we try adding the @tailrec annotation to subtract or flatSubtract the
  20. * code will not compile, indicating that Scala doesn't optimise these
  21. * functions.
  22. *
  23. * As we can see in the implementation of flatSubtract, the recursive call to
  24. * flatSubtract is within two nested flatMap calls, so the flatMap call is not
  25. * a tail call, and flatSubtract is not tail recursive.
  26. */
  27.  
  28. object MonadTest {
  29. // @tailrec
  30. def subtract(ma : Option[Int], mb : Option[Int]) : Option[Int] = {
  31. for {
  32. a <- ma
  33. b <- mb
  34. r <- if (b == 0)
  35. Some(a)
  36. else if (b < 0)
  37. None
  38. else
  39. subtract(Some(a - 1), Some(b - 1))
  40. } yield r
  41. }
  42.  
  43. // @tailrec
  44. def flatSubtract(ma: Option[Int], mb: Option[Int]) : Option[Int] = {
  45. ma.flatMap{ a =>
  46. mb.flatMap{ b =>
  47. if (b == 0)
  48. Some(a)
  49. else if (b < 0)
  50. None
  51. else
  52. flatSubtract(Some(a - 1), Some(b - 1))
  53. }
  54. }
  55. }
  56.  
  57. def trampolineSubtract(ma: OptionT[Trampoline, Int], mb: OptionT[Trampoline, Int]): OptionT[Trampoline, Int] = {
  58. for {
  59. a <- ma
  60. b <- mb
  61. r <- if (b == 0)
  62. OptionT.some[Trampoline, Int](a)
  63. else if (b < 0)
  64. OptionT.none[Trampoline, Int]
  65. else {
  66. val na = OptionT.some[Trampoline, Int](a - 1)
  67. val nb = OptionT.some[Trampoline, Int](b - 1)
  68. trampolineSubtract(na, nb)
  69. }
  70. } yield r
  71. }
  72.  
  73. def freeSubtract(ma: Option[Int], mb: Option[Int]): Option[Int] = {
  74. for {
  75. a <- ma
  76. b <- mb
  77. na = OptionT.some[Trampoline, Int](a)
  78. nb = OptionT.some[Trampoline, Int](b)
  79. r <- trampolineSubtract(na, nb).run.run
  80. } yield r
  81. }
  82.  
  83. implicit val tailrecInstance: Monad[TailRec] =
  84. new Monad[TailRec] {
  85. override def point[A](a: => A) = TailCalls.done(a)
  86. override def bind[A, B](ta: TailRec[A])(f: A => TailRec[B]) = ta flatMap f
  87. }
  88.  
  89. def tailrecSubtract(ma: OptionT[TailRec, Int], mb: OptionT[TailRec, Int]): OptionT[TailRec, Int] = {
  90. for {
  91. a <- ma
  92. b <- mb
  93. r <- if (b == 0)
  94. OptionT.some[TailRec, Int](a)
  95. else if (b < 0)
  96. OptionT.none[TailRec, Int]
  97. else {
  98. val na = OptionT.some[TailRec, Int](a - 1)
  99. val nb = OptionT.some[TailRec, Int](b - 1)
  100. tailrecSubtract(na, nb)
  101. }
  102. } yield r
  103. }
  104.  
  105. def tailcallSubtract(ma: Option[Int], mb: Option[Int]): Option[Int] = {
  106. for {
  107. a <- ma
  108. b <- mb
  109. na = OptionT.some[TailRec, Int](a)
  110. nb = OptionT.some[TailRec, Int](b)
  111. r <- tailrecSubtract(na, nb).run.result
  112. } yield r
  113. }
  114. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement