Skip to content

Instantly share code, notes, and snippets.

@fbrubacher
Created September 29, 2016 16:04
Show Gist options
  • Save fbrubacher/25d79299e3b3c9dffbed5e6b65f6d870 to your computer and use it in GitHub Desktop.
Save fbrubacher/25d79299e3b3c9dffbed5e6b65f6d870 to your computer and use it in GitHub Desktop.
Reading de goes article
// -- in my opinion the wonderful polymorphism of monad type classes in MTL
// -- is the best thing about MTL (rather than transformers themselves), and clearly
// -- superior to how early Free programs were built
//
// -- Nonetheless Free has en equivalent mechanism, which I'm dubbing Free Transformers
// -- FT which goes head-to-head with MTL and even allows developers to target both MTL
// -- and free portions of their code
//
// -- Free Transformesr
//
// class Console f where
// readLine :: f String
// writeLine :: String -> f Unit
trait Cosonle[F[_]] {
def readLine : F[String]
def writeLine(line : String) : F[Unit]
}
def myProgram[F[_]: Console : Monad] : F[Unit]
// laws for these typeclaess can by specified by embedding the functor
// into a suitable computational context such as Free
// The outer functor transforms the inner functor to yield a composite fuctor,
// Free programs are usually built from compositional functors
case class From[A](value : A)
case class To[A](value :A)
type TransferResult = Either[Error, (From[Amount], To[Amount])]
trait Banking[F[_]] {
def accounts : F[NonEmptyList[Account]]
def balance(account : Account) : F[Account]
def tranfer(amount : Amount, from : From[Amount], to : From[Account])
: F[TransferResult]
def withdraw(amount : Amount) : F[Amount]
}
sealed trait BankingF[A]
case class Accounts[A](next : NonEmptyList[Account] => A) extends BankingF[A]
case class Balance[A](next : Amount => A) extends BankingF[A]
case class Transfer[A]( amount : Amount, from : From[Account], to : To[Account],
next : TransferResult => A) extends BankingF[A]
case class Withdraw[A](amount : Amount, next : Amount => A) extends BankingF[A]
)
// now we can create a suitable instance of Free that can be automatically derived
// from any suitable function
implicit def BankingFree[F[_]](implicit F : Banking[F]) : Banking[Free[F, ?]] =
new Banking[Free[F, ?]] {
def accounts : Free[F, NonEmptyList[Account]] = Free.liftF(f.accounts)
def balance(account : Account) : Free[F, Amount] = Free.liftF[F.balance(account)]
def transfer(amount : Amount, from : From[Account], to : From[Acccount]) :
Free[F, TransferResult] = Free.liftF(F.transfer(amount, from, to))
def withdraw(amount : Amount) : Free[F, Amount] = Free.liftF(F.withdraw(amount))
}
// we can define high level programs that operate in our business domain without tangingling
// with banking protocols etc
def example[F[_]: Inject[Banking, ?]] : Free[F, Amount] =
for {
as <- F.accounts
b <- F.balance(as.head)
} yield b
trait Interpreter[F[_], G[_]] = F ~> Free[G, ?]
type ~<[F[_], G[_]] = Interpreter[F, G]
// when using this notio of sequential computation it's helpful to be able to define
// an interpreter that doesn't produce a value whcih can be done using the Const like constructor
type Halt[F[_], A] = F[Unit]
// then an interpreter from f to g which produces no value is simply f~< Halt g
// Now, let’s say that we create the following onion:
// Banking is defined in terms of its protocol, which we want to log.
// The protocol is defined in terms of socket communication.
// Logging is defined in terms of file IO.
val bankingLogging : BankingF ~< Halt LoggingF
val bankingProtocol : BankingF ~< ProtocolF
val protocolSocket : ProtocolF ~< SocketF
val loggingFile : LoggingF ~< FileF
val execFile : FileF ~> IO
val execSocket : SocketF ~> IO
// Denotational Semantics
// 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.
// Denotational semantics provide an unprecedented ability to reason about programs in a composable and modular fashion.
// 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment