Custom expression "let" in Scala

I would like to have a let construct similar to the one in Haskell in Scala. I tried several ways, but no one seems good. Here is the 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 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 an ideal view (with a single binding, more can be separated,, 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 this is possible, but I have no experience with most of Scala's advanced stuff, such as macros, so I can't say.

EDIT1: To be clear, the main things that I expect from him are expression and relatively simple syntax (like the one described above).

+4
source share
2 answers

You can use the direct channel:

 object ForwardPipeContainer { implicit class ForwardPipe[A](val value: A) extends AnyVal { def |>[B](f: A => B): B = f(value) } } 

for use as follows:

 import ForwardPipeContainer._ def f(i: Int) = i * i println( f(3) |> (x => x * x) ) 

You can put several arguments in a tuple:

 println( (f(2), f(3)) |> (x => x._1 * x._2) ) 

which looks better when combined with the partial synatx function:

 println( (f(2), f(3)) |> { case (x, y) => x * y } ) 

This answer is an option. What is a good way to reuse the result of a function in Scala , and both of them are based on the cache of an intermediate variable in a single-line file , from where I got the original idea.

+6
source
 def letTest(): Int = let res = heavyCalc() in if (cond(res)) doSomethingWithRes(res) else 0 

I would write the following:

 def letTest(): Int = { val res = heavyCalc() if (cond(res)) doSomethingWithRes(res) else 0 } 

Ignoring laziness, let's just construct a statement that introduces a lexical region, associates some terms with some names, and 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 apply this syntax layout if you want to make sure that nothing is happening in the block. In fact, there is a SIP (Scala Improvement Process) proposal called Spores that would enforce some of the same limitations (and the additional one: that you don’t commit a reference to an object that does not matter).

Note that blocks in Scala are expressions that evaluate to the last expression in a block. So let me take a random , let’s example from Haskell:

 aaa = let y = 1+2 z = 4+6 in let f = 3 e = 3 in e+f 

It means:

 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 operator can be used as an expression.

+3
source

Source: https://habr.com/ru/post/1498709/


All Articles