Ok, just to show what we may have the following is very short description of what these 2 macro do followed by the copy-paste sample from monadicFlowControl
macro test (with tracing):
- by
transparentMonads
macro: each expression of the monadic type (or of the monadic stack type) may be used in any place where value of its any inner type is expected. In other words, treat the value of the Monad[T]
type as the value of type T
wherever type T
is expected for any depth of inner Monad[T]
types recursively
- by
monadicFlowControl
macro (along with above transparentMonads
feature): sequence of statements is treated as joined by flatMaps-map of detected Monadic Flow Type. In other words, the statements (possibly grouped to subsequences) of the passed block are executed not just unconditionally one by one (as usual flow control) but in terms of Monadic Flow Control (being joined like in the for-comprehension header: statement (or group) execution is controlled by the previous monad)
I want to emphasize that: ones accept any monads including custom ones, even nested to 5 levels (fixable) deep, monadicFlowControl
macro is able to build nested 'fors for each of nested monads and even the tree of
for`s when argument requires it.
Please, pay attention to type of if
argument and fields accessing.
Type checker is always happy!
(IDEA not always, as you may know).
Unfortunately Scala 2 only. But, I hope, full syntax.
The project was a research to feel is it possible in general and to understand the size and the scope of limitations. Project contains lots of readable test cases. Many things are really possible.
import sands.sugar.tms.TransparentMonads._
import scala.util.{Failure, Success, Try}
case class User(id: String)
case class UserBalance(amount: BigDecimal, currencyId: String)
case class BalanceInfoRequest(currencyId: String)
case class BalanceInfoResponse(currencyId: String, currencyBalance: BigDecimal)
def sessionIsActive(sessionId: String): Try[Boolean] = Try(sessionId == "good session")
def getUser(sessionId: String): Try[User] = Try(User("user-id"))
def getUserBalance(userId: String): Try[UserBalance] = Try(UserBalance(10, "USD"))
def getExchangeRate(fromCurrencyId: String, toCurrencyId: String): Try[BigDecimal] = Try(1.1)
def saveAudit(sessionId: String, request: BalanceInfoRequest, response: BalanceInfoResponse): Try[Unit] = Try({})
def raiseError(exception: Exception): Failure[Nothing] = Failure(exception)
def getBalanceInfoResponse(sessionId: String, request: BalanceInfoRequest): Try[BalanceInfoResponse] =
monadicFlowControl[Try[BalanceInfoResponse]] {
val user = if (sessionIsActive(sessionId)) getUser(sessionId) else raiseError(new Exception("Bad session"))
val userBalance = getUserBalance(user.id)
val currencyBalance = if (userBalance.currencyId == request.currencyId)
userBalance.amount
else
userBalance.amount * getExchangeRate(userBalance.currencyId, request.currencyId)
val response = BalanceInfoResponse(request.currencyId, currencyBalance)
saveAudit(sessionId, request, response)
response
}
//Typechecked code with dropped packages:
//[debug] * tms INPUT code.tree:
{
val user = if (tts1[Try, Boolean](sessionIsActive(sessionId)))
getUser(sessionId)
else
raiseError(new Exception("Bad session"));
val userBalance = getUserBalance(tts1[Try, User](user).id);
val currencyBalance = if (tts1[Try, UserBalance](userBalance).currencyId.==(request.currencyId))
tts1[Try, UserBalance](userBalance).amount
else
tts1[Try, UserBalance](userBalance).amount.*(tts1[Try, BigDecimal](getExchangeRate(tts1[Try, UserBalance](userBalance).currencyId, request.currencyId)));
val response = BalanceInfoResponse.apply(request.currencyId, currencyBalance);
saveAudit(sessionId, request, response);
response
}
//[debug] * tms extracted fors code view:
{
for {
valueOfTry$macro$1 <- sessionIsActive(sessionId)
user = if (valueOfTry$macro$1)
getUser(sessionId)
else
raiseError(new Exception("Bad session"))
userValue$macro$2 <- user
userBalance = getUserBalance(userValue$macro$2.id)
userBalanceValue$macro$3 <- userBalance
valueOfTry$macro$4 <- getExchangeRate(userBalanceValue$macro$3.currencyId, request.currencyId)
currencyBalance = if (userBalanceValue$macro$3.currencyId.$eq$eq(request.currencyId))
userBalanceValue$macro$3.amount
else
userBalanceValue$macro$3.amount.$times(valueOfTry$macro$4)
response = BalanceInfoResponse.apply(request.currencyId, currencyBalance)
wcMf$macro$5 <- saveAudit(sessionId, request, response)
} yield {
response
}
}
// FINAL result
// [debug] * tms postprocessed fors code view:
{
for {
valueOfTry$macro$1 <- sessionIsActive(sessionId)
userValue$macro$2 <- if (valueOfTry$macro$1)
getUser(sessionId)
else
raiseError(new Exception("Bad session"))
userBalanceValue$macro$3 <- getUserBalance(userValue$macro$2.id)
valueOfTry$macro$4 <- getExchangeRate(userBalanceValue$macro$3.currencyId, request.currencyId)
currencyBalance = if (userBalanceValue$macro$3.currencyId.$eq$eq(request.currencyId))
userBalanceValue$macro$3.amount
else
userBalanceValue$macro$3.amount.$times(valueOfTry$macro$4)
response = BalanceInfoResponse.apply(request.currencyId, currencyBalance)
wcMf$macro$5 <- saveAudit(sessionId, request, response)
} yield {
response
}
}
The root question is the same: will Scala be able to handle Some(1) + 2
?