I'm trying to write a performance measurements library for Scala. My idea is to transparently 'mark' sections so that the execution time can be collected. Unfortunately I wasn't able to bend the compiler to my will.
An admittedly contrived example of what I have in mind:
// generate a timing function
val myTimer = mkTimer('myTimer)
// see how the timing function returns the right type depending on the
// type of the function it is passed to it
val act = actor {
loop {
receive {
case 'Int =>
val calc = myTimer { (1 to 100000).sum }
val result = calc + 10 // calc must be Int
self reply (result)
case 'String =>
val calc = myTimer { (1 to 100000).mkString }
val result = calc + " String" // calc must be String
self reply (result)
}
Now, this is the farthest I got:
trait Timing {
def time[T <: Any](name: Symbol)(op: => T) :T = {
val start = System.nanoTime
val result = op
val elapsed = System.nanoTime - start
println(name + ": " + elapsed)
result
}
def mkTimer[T <: Any](name: Symbol) : (() => T) => () => T = {
type c = () => T
time(name)(_ : c)
}
}
Using the time function directly works and the compiler correctly uses the return type of the anonymous function to type the 'time' function:
val bigString = time('timerBigString) {
(1 to 100000).mkString("-")
}
println (bigString)
Great as it seems, this pattern has a number of shortcomings:
forces the user to reuse the same symbol at each invocation
makes it more difficult to do more advanced stuff like predefined project-level timers
does not allow the library to initialize once a data structure for 'timerBigString
So here it comes mkTimer, that would allow me to partially apply the time function and reuse it. I use mkTimer like this:
val myTimer = mkTimer('aTimer)
val myString= myTimer {
(1 to 100000).mkString("-")
}
println (myString)
But I get a compiler error:
error: type mismatch;
found : String
required: () => Nothing
(1 to 100000).mkString("-")
I get the same error if I inline the currying:
val timerBigString = time('timerBigString) _
val bigString = timerBigString {
(1 to 100000).mkString("-")
}
println (bigString)
This works if I do val timerBigString = time('timerBigString) (_: String), but this is not what I want. I'd like to defer typing of the partially applied function until application.
I conclude that the compiler is deciding the return type of the partial function when I first create it, chosing "Nothing" because it can't make a better informed choice.
So I guess what I'm looking for is a sort of late-binding of the partially applied function. Is there any way to do this? Or maybe is there a completely different path I could follow?
Well, thanks for reading this far
-teo
The usual pattern when you want "lazy" generics is to use a class with an apply method
class Timer(name: Symbol) {
def apply[T](op: => T) = time(name)(op)
}
def mkTimer(name: Symbol) = new Timer(name)
Related
I wrote this simple program in my attempt to learn how Cats Writer works
import cats.data.Writer
import cats.syntax.applicative._
import cats.syntax.writer._
import cats.instances.vector._
object WriterTest extends App {
type Logged2[A] = Writer[Vector[String], A]
Vector("started the program").tell
val output1 = calculate1(10)
val foo = new Foo()
val output2 = foo.calculate2(20)
val (log, sum) = (output1 + output2).pure[Logged2].run
println(log)
println(sum)
def calculate1(x : Int) : Int = {
Vector("came inside calculate1").tell
val output = 10 + x
Vector(s"Calculated value ${output}").tell
output
}
}
class Foo {
def calculate2(x: Int) : Int = {
Vector("came inside calculate 2").tell
val output = 10 + x
Vector(s"calculated ${output}").tell
output
}
}
The program works and the output is
> run-main WriterTest
[info] Compiling 1 Scala source to /Users/Cats/target/scala-2.11/classes...
[info] Running WriterTest
Vector()
50
[success] Total time: 1 s, completed Jan 21, 2017 8:14:19 AM
But why is the vector empty? Shouldn't it contain all the strings on which I used the "tell" method?
When you call tell on your Vectors, each time you create a Writer[Vector[String], Unit]. However, you never actually do anything with your Writers, you just discard them. Further, you call pure to create your final Writer, which simply creates a Writer with an empty Vector. You have to combine the writers together in a chain that carries your value and message around.
type Logged[A] = Writer[Vector[String], A]
val (log, sum) = (for {
_ <- Vector("started the program").tell
output1 <- calculate1(10)
foo = new Foo()
output2 <- foo.calculate2(20)
} yield output1 + output2).run
def calculate1(x: Int): Logged[Int] = for {
_ <- Vector("came inside calculate1").tell
output = 10 + x
_ <- Vector(s"Calculated value ${output}").tell
} yield output
class Foo {
def calculate2(x: Int): Logged[Int] = for {
_ <- Vector("came inside calculate2").tell
output = 10 + x
_ <- Vector(s"calculated ${output}").tell
} yield output
}
Note the use of for notation. The definition of calculate1 is really
def calculate1(x: Int): Logged[Int] = Vector("came inside calculate1").tell.flatMap { _ =>
val output = 10 + x
Vector(s"calculated ${output}").tell.map { _ => output }
}
flatMap is the monadic bind operation, which means it understands how to take two monadic values (in this case Writer) and join them together to get a new one. In this case, it makes a Writer containing the concatenation of the logs and the value of the one on the right.
Note how there are no side effects. There is no global state by which Writer can remember all your calls to tell. You instead make many Writers and join them together with flatMap to get one big one at the end.
The problem with your example code is that you're not using the result of the tell method.
If you take a look at its signature, you'll see this:
final class WriterIdSyntax[A](val a: A) extends AnyVal {
def tell: Writer[A, Unit] = Writer(a, ())
}
it is clear that tell returns a Writer[A, Unit] result which is immediately discarded because you didn't assign it to a value.
The proper way to use a Writer (and any monad in Scala) is through its flatMap method. It would look similar to this:
println(
Vector("started the program").tell.flatMap { _ =>
15.pure[Logged2].flatMap { i =>
Writer(Vector("ended program"), i)
}
}
)
The code above, when executed will give you this:
WriterT((Vector(started the program, ended program),15))
As you can see, both messages and the int are stored in the result.
Now this is a bit ugly, and Scala actually provides a better way to do this: for-comprehensions. For-comprehension are a bit of syntactic sugar that allows us to write the same code in this way:
println(
for {
_ <- Vector("started the program").tell
i <- 15.pure[Logged2]
_ <- Vector("ended program").tell
} yield i
)
Now going back to your example, what I would recommend is for you to change the return type of compute1 and compute2 to be Writer[Vector[String], Int] and then try to make your application compile using what I wrote above.
I'm trying to write a class where when you call a function defined in the class, it will store it in an array of functions instead of executing it right away, then user calls exec() to execute it:
class TestA(val a: Int, newAction: Option[ArrayBuffer[(Int) => Int]]) {
val action: ArrayBuffer[(Int) => Int] = if (newAction.isEmpty) ArrayBuffer.empty[(Int) => Int] else newAction.get
def add(b: Int): TestA = {action += (a => a + b); new TestA(a, Some(action))}
def exec(): Int = {
var result = 0
action.foreach(r => result += r.apply(a))
result
}
def this(a:Int) = this(a, None)
}
Then this is my test code:
"delayed action" should "delay action till ready" in {
val test = new TestA(3)
val result = test.add(5).add(5)
println(result.exec())
}
This gives me a result of 16 because 3 was passed in twice and got added twice. I guess the easy way for me to solve this problem is to not pass in value for the second round, like change val a: Int to val a: Option[Int]. It helps but it doesn't solve my real problem: letting the second function know the result of the first execution.
Does anyone have a better solution to this?? Or if this is a pattern, can anyone share a tutorial of it?
Just save the result of the action in the 'result' variable (instatiate it with 'a') and use the previous result as input for the current iteration
def exec(): Int = {
var result = a
action.foreach(r => result = r.apply(result))
result
}
or use the more functional oriented solution that does the same
def exec(): Int = {
action.foldLeft(a)((r, f) => f.apply(r))
}
This question already has answers here:
Equivalent to Ruby's #tap method in Scala [duplicate]
(1 answer)
how to keep return value when logging in scala
(6 answers)
Closed 9 years ago.
Often I have functions like this:
{
val x = foo;
bar(x);
x
}
For example, bar is often something like Log.debug.
Is there a shorter, idiomatic way how to run it? For example, a built-in function like
def act[A](value: A, f: A => Any): A = { f(value); value }
so that I could write just act(foo, bar _).
I'm not sure if i understood the question correctly, but if i do, then i often use this method taken from the Spray toolkit:
def make[A, B](obj: A)(f: A => B): A = { f(obj); obj }
then you can write the following things:
utils.make(new JobDataMap()) { map =>
map.put("phone", m.phone)
map.put("medicine", m.medicine.name)
map.put("code", utils.genCode)
}
Using your act function as written seems perfectly idiomatic to me. I don't know of a built-in way to do it, but I'd just throw this kind of thing in a "commons" or "utils" project that I use everywhere.
If the bar function is usually the same (e.g. Log.debug) then you could also make a specific wrapper function for that. For instance:
def withDebug[A](prefix: String)(value: A)(implicit logger: Logger): A = {
logger.debug(prefix + value)
value
}
which you can then use as follows:
implicit val loggerI = logger
def actExample() {
// original method
val c = act(2 + 2, logger.debug)
// a little cleaner?
val d = withDebug("The sum is: ") {
2 + 2
}
}
Or for even more syntactic sugar:
object Tap {
implicit def toTap[A](value: A): Tap[A] = new Tap(value)
}
class Tap[A](value: A) {
def tap(f: A => Any): A = {
f(value)
value
}
def report(prefix: String)(implicit logger: Logger): A = {
logger.debug(prefix + value)
value
}
}
object TapExample extends Logging {
import Tap._
implicit val loggerI = logger
val c = 2 + 2 tap { x => logger.debug("The sum is: " + x) }
val d = 2 + 2 report "The sum is: "
assert(d == 4)
}
Where tap takes an arbitrary function, and report just wraps a logger. Of course you could add whatever other commonly used taps you like to the Tap class.
Note that Scala already includes a syntactically heavyweight version:
foo match { case x => bar(x); x }
but creating the shorter version (tap in Ruby--I'd suggest using the same name) can have advantages.
Disclaimer: Before someone says it: yes, I know it's bad style and not encouraged. I'm just doing this to play with Scala and try to learn more about how the type inference system works and how to tweak control flow. I don't intend to use this code in practice.
So: suppose I'm in a rather lengthy function, with lots of successive checks at the beginning, which, if they fail, are all supposed to cause the function to return some other value (not throw), and otherwise return the normal value. I cannot use return in the body of a Function. But can I simulate it? A bit like break is simulated in scala.util.control.Breaks?
I have come up with this:
object TestMain {
case class EarlyReturnThrowable[T](val thrower: EarlyReturn[T], val value: T) extends ControlThrowable
class EarlyReturn[T] {
def earlyReturn(value: T): Nothing = throw new EarlyReturnThrowable[T](this, value)
}
def withEarlyReturn[U](work: EarlyReturn[U] => U): U = {
val myThrower = new EarlyReturn[U]
try work(myThrower)
catch {
case EarlyReturnThrowable(`myThrower`, value) => value.asInstanceOf[U]
}
}
def main(args: Array[String]) {
val g = withEarlyReturn[Int] { block =>
if (!someCondition)
block.earlyReturn(4)
val foo = precomputeSomething
if (!someOtherCondition(foo))
block.earlyReturn(5)
val bar = normalize(foo)
if (!checkBar(bar))
block.earlyReturn(6)
val baz = bazify(bar)
if (!baz.isOK)
block.earlyReturn(7)
// now the actual, interesting part of the computation happens here
// and I would like to keep it non-nested as it is here
foo + bar + baz + 42 // just a dummy here, but in practice this is longer
}
println(g)
}
}
My checks here are obviously dummy, but the main point is that I'd like to avoid something like this, where the actually interesting code ends up being way too nested for my taste:
if (!someCondition) 4 else {
val foo = precomputeSomething
if (!someOtherCondition(foo)) 5 else {
val bar = normalize(foo)
if (!checkBar(bar)) 6 else {
val baz = bazify(bar)
if (!baz.isOK) 7 else {
// actual computation
foo + bar + baz + 42
}
}
}
}
My solution works fine here, and I can return early with 4 as return value if I want. Trouble is, I have to explicitly write the type parameter [Int] — which is a bit of a pain. Is there any way I can get around this?
It's a bit unrelated to your main question, but I think, a more effective approach (that doesn't require throwing an exception) to implement return would involve continuations:
def earlyReturn[T](ret: T): Any #cpsParam[Any, Any] = shift((k: Any => Any) => ret)
def withEarlyReturn[T](f: => T #cpsParam[T, T]): T = reset(f)
def cpsunit: Unit #cps[Any] = ()
def compute(bool: Boolean) = {
val g = withEarlyReturn {
val a = 1
if(bool) earlyReturn(4) else cpsunit
val b = 1
earlyReturn2(4, bool)
val c = 1
if(bool) earlyReturn(4) else cpsunit
a + b + c + 42
}
println(g)
}
The only problem here, is that you have to explicitly use cpsunit.
EDIT1: Yes, earlyReturn(4, cond = !checkOK) can be implemented, but it won't be that general and elegant:
def earlyReturn2[T](ret: T, cond: => Boolean): Any #cpsParam[Any, Any] =
shift((k: Any => Any) => if(cond) ret else k())
k in the snippet above represents the rest of the computation. Depending on the value of cond, we either return the value, or continue the computation.
EDIT2: Any chance we might get rid of cpsunit? The problem here is that shift inside the if statement is not allowed without else. The compiler refuses to convert Unit to Unit #cps[Unit].
I think a custom exception is the right instinct here.
I know you can create an anonymous function, and have the compiler infer its return type:
val x = () => { System.currentTimeMillis }
Just for static typing's sake, is it possible to specify its return type as well? I think it would make things a lot clearer.
val x = () => { System.currentTimeMillis } : Long
In my opinion if you're trying to make things more clear it is better to document the expectation on the identifier x by adding a type annotation there rather than the result of the function.
val x: () => Long = () => System.currentTimeMillis
Then the compiler will ensure that the function on the right hand side meets that expectation.
Fabian gave the straightforward way, but some other ways if you like micromanaging sugar include:
val x = new (() => Long) {
def apply() = System.currentTimeMillis
}
or
val x = new Function0[Long] {
def apply() = System.currentTimeMillis
}
or even
val x = new {
def apply(): Long = System.currentTimeMillis
}
since in most situations it makes no difference if it descends from Function, only whether it has an apply.