我希望let
构造类似于Scala中Haskell中的那个。我尝试了几种方法,但似乎没有一种方法。这是一些代码:
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()
}
}
)
}
这是它的理想外观(只有一个绑定,更多可以由,
分隔;不确定in
关键字):
// desired look
def letTest(): Int =
let res = heavyCalc() in
if (cond(res)) doSomethingWithRes(res) else 0
我不确定它是否可能,但我没有使用大多数高级Scala之类的东西,比如宏,所以我无法说出来。
EDIT1:要明确的是,我期待的主要内容是:表达和相对简单语法(如上所述)。
答案 0 :(得分:6)
您可以使用正向管道:
object ForwardPipeContainer {
implicit class ForwardPipe[A](val value: A) extends AnyVal {
def |>[B](f: A => B): B = f(value)
}
}
这样使用:
import ForwardPipeContainer._
def f(i: Int) = i * i
println( f(3) |> (x => x * x) )
您可以在元组中放置多个参数:
println( (f(2), f(3)) |> (x => x._1 * x._2) )
如果与部分函数synatx结合使用看起来更好:
println( (f(2), f(3)) |> { case (x, y) => x * y } )
这个答案是What is a good way of reusing function result in Scala的变体,两者都基于Cache an intermediate variable in an one-liner,我从中得到了最初的想法。
答案 1 :(得分:3)
def letTest(): Int =
let res = heavyCalc() in
if (cond(res)) doSomethingWithRes(res) else 0
我会这样写:
def letTest(): Int = {
val res = heavyCalc()
if (cond(res)) doSomethingWithRes(res) else 0
}
忽略懒惰,让只是一个引入词法范围的构造,将一些术语绑定到某些名称然后返回一个表达式。所以在Scala你会做
{ // 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
}
如果要确保块中没有其他内容,宏应该能够强制执行此语法布局。实际上有一个名为Spores的SIP(Scala改进流程)提案会强制执行一些相同的约束(另外一个:你不会在不知不觉中捕获一个封闭对象的引用)。
请注意,Scala中的块是表达式,用于计算块中的最后一个表达式。所以,让我从Haskell中获取random let 示例:
aaa = let y = 1+2
z = 4+6
in let f = 3
e = 3
in e+f
这转换为:
val aaa = {
val y = 1 + 2
val z = 4 + 6
val u = {
val f = 3
val e = 3
e + f
}
u
}
如您所见,block语句可用作表达式。