Nice!You can also look at the similar libraries for inspiration:
Hello, all,
We, some people from ThoughtWorks China, have created a macro library that converts native imperative syntax to scalaz's monadic expression. But, before we release the first version of this library, we found a very tough problem: what is the best name for the project, the source file and the methods.
Currently, our project is named scalaz-monad-factory. I guess the name is inappropriate, because this project does not create monads, instead, it uses scalaz's monad to create functional expressions.
The current usage is very simple:
import scalaz.std.list._
val transformer = com.thoughtworks.scalazMonadFactory.Transformer[List]
val list1 = List("foo", "bar", "baz")
val list2 = List("Hello", "World!")
val concatList = transformer.async(transformer.await(list1).substring(0, 2) + " " + transformer.await(list2).substring(1, 4))
Assert.assertEquals(List("fo ell", "ba ell", "ba ell", "fo orl", "ba orl", "ba orl"), concatList)
The method transformer.async
is a macro and transformer.await
is a fake method to fetch the result of a monadic value. You can put any Scala expressions in the async
macro and it will magically turn your code into monadic expressions. You can visit the test cases for more information
So, the code val concatList = transformer.async(transformer.await(list1).substring(0, 2) + " " + transformer.await(list2).substring(1, 4))
will be translated to monadic expression:
val concatList = Monad[List].bind(list2) { (string2: String) =>
Monad[List].map(list1) { (string1: String) =>
string1.substring(0, 2) + " " + string2.substring(1, 4)
}
}
Which also equals to list comprehension supported by Scala Standard Library:
val concatList = for {
string1 <- list1
string2 <- list2
} yield (string1.substring(0, 2) + " " + string2.substring(1, 4))
Currently, the await
method is implicit, so we can also write like this:
import transformer._
val concatList = async(list1.substring(0, 2) + " " + list2.substring(1, 4))
async
Everything is good until now, except the macro name async
.
async
is a C# 4.5 keyword to perform CPS transformation. When our macro works with some kind of Cont
monad, it will do the same thing as C# async
, but it also cooperates well with other monads, e.g. IO
monad, Option
monad, and List
monad shown before. So I think the name should be more general than async
.
do
Another candidate name for the macro is do
, because there is a similiar do
notation in Haskell. Unfortunately do
is a keyword in Scala, so we must quoted it like this:
val concatList = transformer.`do`(transformer.await(list1).substring(0, 2) + " " + transformer.await(list2).substring(1, 4))
apply
I also thought about simply use apply
as the macro name, this will allow users treatingtransformer
itself as a function:
val concatList = transformer(transformer.await(list1).substring(0, 2) + " " + transformer.await(list2).substring(1, 4))
Other candidate names are: monadic
, transform
await
await
In C# 4.5, await
is a keyword to wait a Task
, which must be nested in a async
method. OurTransformer.await
, which is used to get the result from a monadic value, evaluates immediately forOption
monad and List
monad, and may only blocking wait for IO
monad or other asynchronous monads. So it is also good to have a more general name.
<-
<-
is the syntax in Haskell. Haskell's x <- action
corresponds to current val x = transformer.await(action)
in our project. Unfortunately <-
is a keyword in Scala, so we must quoted it like this:
val concatList = transformer.`do`(transformer.`<-`(list1).substring(0, 2) + " " + transformer.`<-`(list2).substring(1, 4))
This is a less annoying problem than do
, because we may use implicit call for most time.
Another option is providing a implicit class with a postfix await
method, so we can writeaction.await
. This syntax is less trivial than transformer.await(action)
, and also more explicit and more clear than implicit calls.
I created a survey to gather your opinion: https://jinshuju.net/f/TUZeAO.
We need you.
Thanks!