I am trying to implement a method that should take an arbitrary method or code block and it should convert the method or code-block to retry-able method.
Following example is intended to demonstrate what I need
import scala.util.{Try,Success,Failure}
object Retry {
retry[A, B](f: A => Try[B], r: Int): A => Try[B] = {
// return a function g and when g is invoked with parameters
// f should be tried (if failed) r number of time otherwise
// result of first successful execution of f should be returned
// from g. retry should work with any arbitrary function with
// any number/type of parameters
}
}
If you want to abstract over arity, which is pretty advanced, you'll have to use shapeless, a library for generic programming.
Building on #chengpohi's answer:
import shapeless._, ops.function._
import scala.util.Try
def retry[F, L <: HList, R](f: F, r: Int = 1)(implicit fnToP: FnToProduct.Aux[F, L => R], fnFromP: FnFromProduct.Aux[L => R, F]): F = {
val fn = fnToP(f)
def repeat(a: L): R = {
for (_ <- 0 to r) {
val tried = Try(fn(a))
if (tried.isSuccess) {
return tried.get
}
}
throw new RuntimeException(s"retry $r failed")
}
fnFromP(repeat _)
}
It works:
scala> var i = 0
i: Int = 0
scala> val f = retry( (a: Int) => if (i < 10) {i += 1; println(s"try $i"); throw new RuntimeException} else a * 3, 42)
f: Int => Int = shapeless.ops.FnFromProductInstances$$anon$2$$Lambda$1489/1404497488#1d49a23c
scala> f(5)
try 1
try 2
try 3
try 4
try 5
try 6
try 7
try 8
try 9
try 10
res4: Int = 15
scala> var i = 0
i: Int = 0
scala> val f = retry( (a: String, b: Int) => if (i < 10) {i += 1; println(s"try $i"); throw new RuntimeException} else a * b, 42)
f: (String, Int) => String = shapeless.ops.FnFromProductInstances$$anon$3$$Lambda$1492/121867201#1a22b89c
scala> f("foo", 5)
try 1
try 2
try 3
try 4
try 5
try 6
try 7
try 8
try 9
try 10
res5: String = foofoofoofoofoo
def retry[A, B](f: A => B, r: Int = 1): A => B = {
def repeat(a: A): B = {
for (_ <- 0 to r) {
val tried = Try(f(a))
if (tried.isSuccess) {
return tried.get
}
}
throw new RuntimeException(s"retry $r failed")
}
repeat
}
There is a simple way to do this, try if Success and return, otherwise throw Exception
Related
I'd love to have let construct similar to the one in Haskell in Scala. I tried a few ways, but none seems to be good. Here's some code:
object CustomLet extends App {
val data = for (i <- 1 to 1024; j <- 1 to 512) yield (i % j) * i * (i + 1) - 1
def heavyCalc() = { println("heavyCalc called"); data.sum }
def doSomethingWithRes(res: Int) = {
println(s"${res * res}")
1
}
def cond(value: Int): Boolean = value > 256
// not really usable, even though it's an expression (2x heavyCalc calls)
def withoutLet() = if (cond(heavyCalc())) doSomethingWithRes(heavyCalc()) else 0
// not an expression
def letWithVal(): Int = {
val res = heavyCalc()
if (cond(res)) doSomethingWithRes(res)
else 0
}
// a lot of code to simulate "let", at least it is an expression
def letWithMatch(): Int = heavyCalc() match {
case res => if (cond(res)) doSomethingWithRes(res) else 0
}
// not perfect solution from
// http://stackoverflow.com/questions/3241101/with-statement-equivalent-for-scala/3241249#3241249
def let[A, B](param: A)(body: A => B): B = body(param)
// not bad, but I'm not sure if it could handle more bindings at once
def letWithApp(): Int = let(heavyCalc()) {res => if (cond(res)) doSomethingWithRes(res) else 0}
List[(String, () => Int)](
("withoutLet", withoutLet),
("letWithVal", letWithVal),
("letWithMatch", letWithMatch),
("letWithApp", letWithApp)
).foreach(
item => item match {
case (title, func) => {
println(s"executing $title")
val ret = func()
println(s"$title finished with $ret")
println()
}
}
)
}
This is the ideal look of it (with only one binding, more could be separated by ,; not sure about the in keyword):
// desired look
def letTest(): Int =
let res = heavyCalc() in
if (cond(res)) doSomethingWithRes(res) else 0
I'm not sure if it's possible, but I have no experience with most of advanced Scala stuff like macros, so I can't really tell.
EDIT1: To be clear, the main things I'm expecting from it are: being expression and relatively simple syntax (like the one outlined above).
You could use a forward pipe:
object ForwardPipeContainer {
implicit class ForwardPipe[A](val value: A) extends AnyVal {
def |>[B](f: A => B): B = f(value)
}
}
to be used like this:
import ForwardPipeContainer._
def f(i: Int) = i * i
println( f(3) |> (x => x * x) )
You can put multiple arguments in a tuple:
println( (f(2), f(3)) |> (x => x._1 * x._2) )
which looks better if combined with partial function synatx:
println( (f(2), f(3)) |> { case (x, y) => x * y } )
This answer is a variation of What is a good way of reusing function result in Scala, and both are based on Cache an intermediate variable in an one-liner where I got the initial idea from.
def letTest(): Int =
let res = heavyCalc() in
if (cond(res)) doSomethingWithRes(res) else 0
I would write this:
def letTest(): Int = {
val res = heavyCalc()
if (cond(res)) doSomethingWithRes(res) else 0
}
Ignoring laziness, let is just a construct that introduces a lexical scope, binds some terms to some names then returns an expression. So in Scala you would do
{ // new lexical scope
// bind terms section
val a = f()
def b = a + g() // may be I don't want g to be evaluated unless b is needed
val c = h()
// result expression
if (c) b else a
}
Macros should be able to enforce this syntactic layout if you want to ensure that there is nothing else going on in the block. There is actually a SIP (Scala Improvement Process) proposal called Spores that would enforce some of the same constraints (and an additional one: that you don't capture a reference of an enclosing object unknowingly).
Note that blocks in Scala are expressions that evaluate to the last expression in the block. So let me take a random let example from Haskell:
aaa = let y = 1+2
z = 4+6
in let f = 3
e = 3
in e+f
This translates to:
val aaa = {
val y = 1 + 2
val z = 4 + 6
val u = {
val f = 3
val e = 3
e + f
}
u
}
As you can see the block statement can be used as an expression.
When I look at Scala libraries I see code like this. Why put test [A] .
def test[A](block : Int => Unit) : Unit = {
block(10)
}
test { u =>
println(u)
}
This is just as valid I suppose. It runs the same way.
def test(block : Int => Unit) : Unit = {
block(10)
}
I've just been curious what the reasoning(or design pattern) is behind it. Thanks.
The type parameter A makes no sense here because it is not used.
def test[A](block: Int => A): A = block(10)
Here A specifies the return type.
When there a generic type next to the function, it means that the function is a generic function.
The following is a very simple example:
// generic functions which returns type of `A`
def test1[A](x: A) = x
def test2[A](x: => A) = { println("Hello"); x }
val x1 = test1(1)
// x1: Int = 1
val x2 = test1("Hello World")
// x2: java.lang.String = Hello World
val x3 = test2(123.4)
// Hello
// x3: Double = 123.4
val x4 = test2("Test2")
// Hello
// x4: java.lang.String = Test2
As you can see, the return type of test1 and test2 are determined by the type of their arguments.
The following is another use case.
// We could implement `map` function ourself.
// We don't care about what type of List contains,
// so we make it a generic function.
def map[A, B](xs: List[A], f: A => B): List[B] = {
var result: List[B] = Nil
for (i <- xs) {
result ++= List(f(i))
}
result
}
// Now use can map any type of List to another List.
map(List("1", "2", "3"), (x: String) => x.toInt)
//res1: List[Int] = List(1, 2, 3)
I want to do this:
var (a, b) = (0, 0)
a = (b = 100)
but Scala is complaining that
error: type mismatch;
found : Unit
required: Int
What I want is to assign a and b to the same value.
Why Scala make it Unit where it should be Int?
Your statement is an assignment, which returns Unit.
See this related question for reasons why. You can do this, if you want:
scala> var (a,b) = (0,0)
a: Int = 0
b: Int = 0
scala> a = {b = 100; b}
a: Int = 100
scala> var a,b,c,d,e,f,g = 0
a: Int = 0
b: Int = 0
c: Int = 0
d: Int = 0
e: Int = 0
f: Int = 0
g: Int = 0
scala> var f,i,j,k,m,n,o = new Object{}
f: java.lang.Object = $anon$1#11ce012
i: java.lang.Object = $anon$2#baf4ae
j: java.lang.Object = $anon$3#15e68d
k: java.lang.Object = $anon$4#1d3633c
m: java.lang.Object = $anon$5#118317f
n: java.lang.Object = $anon$6#15998cb
o: java.lang.Object = $anon$7#13e6f83
scala>
Why ask why? Assignment expressions have type Unit and that's how it is. No chained assignments. Period.
You can define a special assignment operator (it must end with a colon as it must be right associative) for your own types, or write a generic wrapper (including implit conversions) for general types. I wouldn't recommend to actually use this, but here it goes:
case class M[T](var t:T) {
def =: (m: M[T]):M[T] = {m.t = t ; this}
}
implicit def anyToM[T](v:T) = M(v)
implicit def mToAny[T](m:M[T]) = m.t
def main(args: Array[String]) {
var a = M(0)
var b = M(0)
var c = M(0)
a =: b =: c =: 100
println(a + b + c) //--> 300
}
I think it is always a bad idea to summon heavy magick in order to save a few keystrokes. In Germany we would call this "to shoot sparrows with a cannon"...
case class assign[T](v: T) {
def to(vals: (T => Unit)*) { vals.foreach{ vv => vv(v) } }
}
var (a,b) = (0,0)
assign(39) to (a = _, b = _)
assert(a == 39)
assert(b == 39)
Or you can rename it to emulate a rather simple version of a with statement.
with(20) do (a = _, b = _, print)
I am Peter Pilgrim. I watched Martin Odersky create a control abstraction in Scala. However I can not yet seem to repeat it inside IntelliJ IDEA 9. Is it the IDE?
package demo
class Control {
def repeatLoop ( body: => Unit ) = new Until( body )
class Until( body: => Unit ) {
def until( cond: => Boolean ) {
body;
val value: Boolean = cond;
println("value="+value)
if ( value ) repeatLoop(body).until(cond)
// if (cond) until(cond)
}
}
def doTest2(): Unit = {
var y: Int = 1
println("testing ... repeatUntil() control structure")
repeatLoop {
println("found y="+y)
y = y + 1
}
{ until ( y < 10 ) }
}
}
The error message reads:
Information:Compilation completed with 1 error and 0 warnings
Information:1 error
Information:0 warnings
C:\Users\Peter\IdeaProjects\HelloWord\src\demo\Control.scala
Error:Error:line (57)error: Control.this.repeatLoop({
scala.this.Predef.println("found y=".+(y));
y = y.+(1)
}) of type Control.this.Until does not take parameters
repeatLoop {
In the curried function the body can be thought to return an expression (the value of y+1) however the declaration body parameter of repeatUntil clearly says this can be ignored or not?
What does the error mean?
Here is a solution without the StackOverflowError.
scala> class ConditionIsTrueException extends RuntimeException
defined class ConditionIsTrueException
scala> def repeat(body: => Unit) = new {
| def until(condition: => Boolean) = {
| try {
| while(true) {
| body
| if (condition) throw new ConditionIsTrueException
| }
| } catch {
| case e: ConditionIsTrueException =>
| }
|
| }
| }
repeat: (body: => Unit)java.lang.Object{def until(condition: => Boolean): Unit}
scala> var i = 0
i: Int = 0
scala> repeat { println(i); i += 1 } until(i == 3)
0
1
2
scala> repeat { i += 1 } until(i == 100000)
scala> repeat { i += 1 } until(i == 1000000)
scala> repeat { i += 1 } until(i == 10000000)
scala> repeat { i += 1 } until(i == 100000000)
scala>
According to Jesper and Rex Kerr here is a solution without the Exception.
def repeat(body: => Unit) = new {
def until(condition: => Boolean) = {
do {
body
} while (!condition)
}
}
You don't need the 2nd pair of braces, the usage should be:
repeatLoop (x) until (cond) //or...
repeatLoop {x} until {cond}
And not:
repeatLoop {x} { until(cond) } //EXTRA PAIR OF BRACES
The error means that Scala thinks you are trying to call a method with a signature something like:
def repeatLoop(x: => Unit)(something: X) //2 parameter lists
And can find no such method. It is saying "repeatLoop(body)" does not take parameters. A full code listing for the solution probably looks something a bit more like:
object Control0 {
def repeatLoop(body: => Unit) = new Until(body)
class Until(body: => Unit) {
def until(cond: => Boolean) {
body;
val value: Boolean = cond;
if (value) repeatLoop(body).until(cond)
}
}
def main(args: Array[String]) {
var y: Int = 1
println("testing ... repeatUntil() control structure")
repeatLoop {
println("found y=" + y)
y += 1
}.until(y < 10)
}
}
There are two useful observations to make here:
The solution is not tail-recursive and will result in a StackOverflowError for long iterations (try while (y < 10000))
The until seems the wrong way round to me (it would be more natural to stop when the condition becomes true, not carry on while it is true).
How about a one liner for repeat until.
def repeat(b: => Unit) = new AnyRef {def until(c: => Boolean) {b; while (! c) b}}
Which, for example, gives:-
scala> repeat {
| println("i = "+i)
| i+=1
| } until (i >= 10)
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
As above yet recursive :)
def repeat(b: => Unit) = new {def until(c: => Boolean) = { b; if (c) until(c) }}
var i = 0
repeat {
println(i)
i+=1
} until (i < 10)
It's #tailrec optimized too.
Llove scala :)
What is wrong is the following method?
def someMethod(funcs: => Option[String]*) = {
...
}
That actually "works" under 2.7.7 if you add parens:
scala> def someMethod(funcs: => (Option[String]*)) = funcs
someMethod: (=> Option[String]*)Option[String]*
except it doesn't actually work at runtime:
scala> someMethod(Some("Fish"),None)
scala.MatchError: Some(Fish)
at scala.runtime.ScalaRunTime$.boxArray(ScalaRunTime.scala:136)
at .someMethod(<console>:4)
at .<init>(<console>:6)
at .<clinit>(<console>) ...
In 2.8 it refuses to let you specify X* as the output of any function or by-name parameter, even though you can specify it as an input (this is r21230, post-Beta 1):
scala> var f: (Option[Int]*) => Int = _
f: (Option[Int]*) => Int = null
scala> var f: (Option[Int]*) => (Option[Int]*) = _
<console>:1: error: no * parameter type allowed here
var f: (Option[Int]*) => (Option[Int]*) = _
But if you try to convert from a method, it works:
scala> def m(oi: Option[Int]*) = oi
m: (oi: Option[Int]*)Option[Int]*
scala> var f = (m _)
f: (Option[Int]*) => Option[Int]* = <function1>
scala> f(Some(1),None)
res0: Option[Int]* = WrappedArray(Some(1), None)
So it's not entirely consistent.
In any case, you can possibly achieve what you want by passing in an Array and then sending that array to something that takes repeated arguments:
scala> def aMethod(os: Option[String]*) { os.foreach(println) }
aMethod: (os: Option[String]*)Unit
scala> def someMethod(funcs: => Array[Option[String]]) { aMethod(funcs:_*) }
someMethod: (funcs: => Array[Option[String]])Unit
scala> someMethod(Array(Some("Hello"),Some("there"),None))
Some(Hello)
Some(there)
None
If you really want to (easily) pass a bunch of lazily evaluated arguments, then you need a little bit of infrastructure that as far as I know doesn't nicely exist in the library (this is code for 2.8; view it as inspiration for a similar strategy in 2.7):
class Lazy[+T](t: () => T, lt: Lazy[T]) {
val params: List[() => T] = (if (lt eq null) Nil else t :: lt.params)
def ~[S >: T](s: => S) = new Lazy[S](s _,this)
}
object Lz extends Lazy[Nothing](null,null) {
implicit def lazy2params[T : Manifest](lz: Lazy[T]) = lz.params.reverse.toArray
}
Now you can easily create a bunch of parameters that are lazily evaluated:
scala> import Lz._ // To get implicit def
import Lz._
scala> def lazyAdder(ff: Array[()=>Int]) = {
| println("I'm adding now!");
| (0 /: ff){(n,f) => n+f()}
| }
lazyAdder: (ff: Array[() => Int])Int
scala> def yelp = { println("You evaluated me!"); 5 }
yelp: Int
scala> val a = 3
a: Int = 3
scala> var b = 7
b: Int = 7
scala> lazyAdder( Lz ~ yelp ~ (a+b) )
I'm adding now!
You evaluated me!
res0: Int = 15
scala> val plist = Lz ~ yelp ~ (a+b)
plist: Lazy[Int] = Lazy#1ee1775
scala> b = 1
b: Int = 1
scala> lazyAdder(plist)
I'm adding now!
You evaluated me!
res1: Int = 9
Evidently repeated arguments are not available for by-name parameters.