杨博 (Yang Bo)
杨博 (Yang Bo)
杨博 (Yang Bo)
A keyword for creating monadic control flow.
A keyword for creating monadic control flow.
Monadic should be a scala.AnyVal after https://github.com/scala/bug/issues/10595 is resolved.
com.thoughtworks.dsl.domains.scalaz for using this Monadic keyword with scalaz.Monad.
com.thoughtworks.dsl.domains.cats for using this Monadic keyword with cats.Monad.
A Keyword to put the value to the context.
A Keyword to put the value to the context.
Purely functional programming languages usually do not support native first-class mutable variables. In those languages, mutable states can be implemented in state monads.
杨博 (Yang Bo)
Put and Get support multiple states.
The following code creates a formatter that Put parts of content into a List[Any]
of string buffers.
def format: Double => Int => List[Any] => String = { !Put("x=" :: !Get[List[Any]]) !Put(!Get[Double] :: !Get[List[Any]]) !Put(",y=" :: !Get[List[Any]]) !Put(!Get[Int] :: !Get[List[Any]]) !Return((!Get[List[Any]]).reverse.mkString) } format(0.5)(42)(Nil) should be("x=0.5,y=42")
The behavior of the above code is equivalent to the following code based on native Scala var
:
def varBasedState(initialValue: String): Int = { var v = initialValue v should be("initial value") v = "changed value" v should be("changed value") return 0 } varBasedState("initial value") should be(0)
The parameter of a scala.Function1 can be read from Get keyword, and changed by Put keyword.
def dslBasedState: String => Int = { !Get[String]() should be("initial value") !Put("changed value") !Get[String]() should be("changed value") !Return(0) } dslBasedState("initial value") should be(0)
The implementation of Get and Put keywords does not use native Scala var
,
though its behavior is similar to var
.
A Keyword to early return a lifted value from the enclosing function.
A Keyword to early return a lifted value from the enclosing function.
杨博 (Yang Bo)
Since this Return keyword can automatically lift the return type,
TailCalls.done
can be omitted.
import scala.util.Random import scala.util.control.TailCalls import scala.util.control.TailCalls.TailRec def randomInt(): TailRec[Int] = { while (true) { val r = Random.nextInt(100) if (r % 10 != r / 10) { !Return(r) } } throw new AssertionError("Unreachable code"); } val r = randomInt().result r should be < 100 r % 10 should not be r / 10
Suppose you are generating a random integer less than 100, whose first digit and second digit is different. A solution is generating integers in an infinite loop, and Return from the loop when the generated integer conforms with requirements.
import scala.util.Random import scala.util.control.TailCalls import scala.util.control.TailCalls.TailRec def randomInt(): TailRec[Int] = { while (true) { val r = Random.nextInt(100) if (r % 10 != r / 10) { !Return(TailCalls.done(r)) } } throw new AssertionError("Unreachable code"); } val r = randomInt().result r should be < 100 r % 10 should not be r / 10
杨博 (Yang Bo)
杨博 (Yang Bo)
杨博 (Yang Bo)
This Yield
keyword must be put inside a function that returns Stream[Element]
or Stream[Element] !! ...
,
or it will not compile.
"def f(): Int = !Yield(1)" shouldNot compile
杨博 (Yang Bo)
Contains built-in domain-specific Keywords and their corresponding interpreters.