Skip to content

Instantly share code, notes, and snippets.

@debasishg
Last active August 29, 2015 14:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save debasishg/8065dc75cf11aaee3d4f to your computer and use it in GitHub Desktop.
Save debasishg/8065dc75cf11aaee3d4f to your computer and use it in GitHub Desktop.
trait AccountRepository {
def query(no: String): \/[NonEmptyList[String], Option[Account]]
def store(a: Account): \/[NonEmptyList[String], Account]
def query(openedOn: Date): \/[NonEmptyList[String], Seq[Account]]
def all: \/[NonEmptyList[String], Seq[Account]]
}
/**
* and an implementation for this trait
**/
/**
* I now inject this trait in a service class with Reader monad as Kleisli as follows.
* So all methods of AccountService return a Kleisli
*/
trait AccountService {
type Valid[A] = NonEmptyList[String] \/ A
type AccountOperation[A] = Kleisli[Valid, AccountRepository, A] // inject Repository
def open(no: String, name: String, rate: Option[BigDecimal], openingDate: Option[Date],
accountType: AccountType): AccountOperation[Account]
def close(no: String, closeDate: Option[Date]): AccountOperation[Account]
def debit(no: String, amount: Amount): AccountOperation[Account]
def credit(no: String, amount: Amount): AccountOperation[Account]
def balance(no: String): AccountOperation[Balance]
}
/**
* Here's a fragment of the implementation of AccountService
*/
class AccountServiceInterpreter extends AccountService {
def open(no: String, name: String) = kleisli[Valid, AccountRepository, Option[Account]] { (repo: AccountRepository) =>
Account.checkingAccount(no, name, None, None, Balance()) match {
case \/-(a) => for {
_ <- repo.store(a)
y <- repo.query(a.no)
} yield y
//..
}
}
//..
}
/**
* As you see above, we can still compose our little DSL by wiring together repo.store & repo.query. It can be much bigger
* than this simple example, where I can still construct the DSL without any interpretation. And at the end I can interpret
* by supplying an appropriate interpreter for AccountRepository. Note here I inject AccountRepository using a Kleisli.
*/
/**
* My question is : how does this strategy compare with Free Monads ? I can implement a free monad for AccountRepository and do the
* same - build the AST for the DSL and then interpret later by providing an interpreter. How do you think the 2 approaches compare ?
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment