Advertisement
Guest User

Untitled

a guest
Sep 29th, 2016
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.94 KB | None | 0 0
  1. // -- in my opinion the wonderful polymorphism of monad type classes in MTL
  2. // -- is the best thing about MTL (rather than transformers themselves), and clearly
  3. // -- superior to how early Free programs were built
  4. //
  5. // -- Nonetheless Free has en equivalent mechanism, which I'm dubbing Free Transformers
  6. // -- FT which goes head-to-head with MTL and even allows developers to target both MTL
  7. // -- and free portions of their code
  8. //
  9. // -- Free Transformesr
  10. //
  11. // class Console f where
  12. // readLine :: f String
  13. // writeLine :: String -> f Unit
  14.  
  15. trait Cosonle[F[_]] {
  16.  
  17. def readLine : F[String]
  18.  
  19. def writeLine(line : String) : F[Unit]
  20.  
  21. }
  22.  
  23. def myProgram[F[_]: Console : Monad] : F[Unit]
  24.  
  25. // laws for these typeclaess can by specified by embedding the functor
  26. // into a suitable computational context such as Free
  27. // The outer functor transforms the inner functor to yield a composite fuctor,
  28. // Free programs are usually built from compositional functors
  29.  
  30. case class From[A](value : A)
  31. case class To[A](value :A)
  32.  
  33. type TransferResult = Either[Error, (From[Amount], To[Amount])]
  34.  
  35. trait Banking[F[_]] {
  36. def accounts : F[NonEmptyList[Account]]
  37. def balance(account : Account) : F[Account]
  38. def tranfer(amount : Amount, from : From[Amount], to : From[Account])
  39. : F[TransferResult]
  40. def withdraw(amount : Amount) : F[Amount]
  41. }
  42.  
  43. sealed trait BankingF[A]
  44. case class Accounts[A](next : NonEmptyList[Account] => A) extends BankingF[A]
  45. case class Balance[A](next : Amount => A) extends BankingF[A]
  46.  
  47. case class Transfer[A]( amount : Amount, from : From[Account], to : To[Account],
  48. next : TransferResult => A) extends BankingF[A]
  49. case class Withdraw[A](amount : Amount, next : Amount => A) extends BankingF[A]
  50. )
  51.  
  52. // now we can create a suitable instance of Free that can be automatically derived
  53. // from any suitable function
  54.  
  55. implicit def BankingFree[F[_]](implicit F : Banking[F]) : Banking[Free[F, ?]] =
  56. new Banking[Free[F, ?]] {
  57. def accounts : Free[F, NonEmptyList[Account]] = Free.liftF(f.accounts)
  58. def balance(account : Account) : Free[F, Amount] = Free.liftF[F.balance(account)]
  59. def transfer(amount : Amount, from : From[Account], to : From[Acccount]) :
  60. Free[F, TransferResult] = Free.liftF(F.transfer(amount, from, to))
  61. def withdraw(amount : Amount) : Free[F, Amount] = Free.liftF(F.withdraw(amount))
  62. }
  63.  
  64. // we can define high level programs that operate in our business domain without tangingling
  65. // with banking protocols etc
  66.  
  67. def example[F[_]: Inject[Banking, ?]] : Free[F, Amount] =
  68. for {
  69. as <- F.accounts
  70. b <- F.balance(as.head)
  71. } yield b
  72.  
  73.  
  74. trait Interpreter[F[_], G[_]] = F ~> Free[G, ?]
  75.  
  76. type ~<[F[_], G[_]] = Interpreter[F, G]
  77.  
  78. // when using this notio of sequential computation it's helpful to be able to define
  79. // an interpreter that doesn't produce a value whcih can be done using the Const like constructor
  80.  
  81. type Halt[F[_], A] = F[Unit]
  82.  
  83. // then an interpreter from f to g which produces no value is simply f~< Halt g
  84.  
  85. // Now, let’s say that we create the following onion:
  86. // Banking is defined in terms of its protocol, which we want to log.
  87. // The protocol is defined in terms of socket communication.
  88. // Logging is defined in terms of file IO.
  89.  
  90.  
  91. val bankingLogging : BankingF ~< Halt LoggingF
  92.  
  93. val bankingProtocol : BankingF ~< ProtocolF
  94.  
  95. val protocolSocket : ProtocolF ~< SocketF
  96.  
  97. val loggingFile : LoggingF ~< FileF
  98.  
  99. val execFile : FileF ~> IO
  100.  
  101. val execSocket : SocketF ~> IO
  102.  
  103. // Denotational Semantics
  104. // Denotational semantics is a mathematical and compositional way of giving meaning to programs. The meaning of the program as a whole is defined by the meaning of the terms comprising the program.
  105. // Denotational semantics provide an unprecedented ability to reason about programs in a composable and modular fashion.
  106. // The onion architecture provides a way of specifying whole programs using denotational semantics, where the meaning of one domain is precisely and compositionally defined in terms of another doma
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement