Advertisement
Guest User

Untitled

a guest
May 12th, 2017
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.88 KB | None | 0 0
  1. object Website {
  2. import cats.free.Free
  3. import cats.Comonad
  4. import scala.io._
  5.  
  6. final case class User(username: String)
  7.  
  8. sealed trait Page
  9. final case object Welcome extends Page
  10. final case object TryAgain extends Page
  11.  
  12. type LoginProgram[A] = Free[LoginOp,A]
  13.  
  14. sealed trait LoginOp[A]
  15. final case class Ask[A](prompt: String, reader: String => A) extends LoginOp[A]
  16. final case class Retry[A,B](ask: LoginProgram[A], f: A => LoginProgram[Option[B]], tries: Int) extends LoginOp[Option[B]]
  17. final case class Login(username: String, password: String) extends LoginOp[Option[User]]
  18. final case class Pure[A](a: A) extends LoginOp[A]
  19. final case class Display(page: Page) extends LoginOp[Unit]
  20.  
  21. object LoginOp {
  22. def ask[A](prompt: String, reader: String => A) =
  23. Free.liftF[LoginOp,A](Ask(prompt, reader))
  24.  
  25. def retry[A,B](ask: LoginProgram[A], f: A => LoginProgram[Option[B]], tries: Int) =
  26. Free.liftF[LoginOp,Option[B]](Retry(ask, f, tries))
  27.  
  28. def login(username: String, password: String) =
  29. Free.liftF[LoginOp,Option[User]](Login(username, password))
  30.  
  31. def display(page: Page) =
  32. Free.liftF[LoginOp,Unit](Display(page))
  33.  
  34. implicit object loginOpInstances extends Comonad[LoginOp] {
  35. override def coflatMap[A, B](fa: LoginOp[A])(f: (LoginOp[A]) ⇒ B): LoginOp[B] =
  36. Pure(f(fa))
  37.  
  38. override def extract[A](x: LoginOp[A]): A =
  39. x match {
  40. case Login(u, p) => (u, p) match {
  41. case ("Noel", "password") => Some(User("noelw"))
  42. case _ => None
  43. }
  44. case Display(p) =>
  45. p match {
  46. case TryAgain =>
  47. println("Sorry, couldn't login you in. Try again!")
  48. case Welcome =>
  49. println("Welcome back!")
  50. }
  51. ()
  52. case Ask(p, r) =>
  53. println(p)
  54. r(StdIn.readLine)
  55.  
  56. case r: Retry[a,b] =>
  57. def loop(counter: Int): Option[b] =
  58. counter match {
  59. case 0 => None
  60. case n => r.f(r.ask.run: a).run match {
  61. case None => loop(n - 1)
  62. case Some(a) => Some(a)
  63. }
  64. }
  65.  
  66. loop(r.tries)
  67.  
  68. case Pure(a) => a
  69. }
  70.  
  71. override def map[A, B](fa: LoginOp[A])(f: (A) ⇒ B): LoginOp[B] =
  72. Pure(f(extract(fa)))
  73. }
  74. }
  75.  
  76. val loginPrompt = LoginOp.ask("Enter login stuff", (s: String) => {
  77. val split = s.split(" ")
  78. (split(0), split(1))
  79. })
  80. def loginAttempt(details: (String, String)) = {
  81. val (u, p) = details
  82. LoginOp.login(u, p)
  83. }
  84.  
  85. val attemptLogin = LoginOp.retry(loginPrompt, loginAttempt, 3)
  86.  
  87. object Example {
  88. val login =
  89. for {
  90. user <- attemptLogin
  91. page <- LoginOp.display(user.fold[Page](TryAgain){ u => Welcome })
  92. } yield page
  93. }
  94. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement