我经常遇到以下情况:假设我具有以下三个功能

def firstFn: Int = ...
def secondFn(b: Int): Long = ...
def thirdFn(x: Int, y: Long, z: Long): Long = ...
而且我还有calculate函数。我的第一种方法如下所示:
def calculate(a: Long) = thirdFn(firstFn, secondFn(firstFn), secondFn(firstFn) + a)
它看起来很漂亮,没有任何花括号-仅是一种表达。但这不是最佳选择,因此我得到了以下代码:
def calculate(a: Long) = {
  val first = firstFn
  val second = secondFn(first)

  thirdFn(first, second, second + a)
}
现在是几个用大括号括起来的表达式。在这样的时刻,我有点羡慕Clojure。使用let function,我可以在一个表达式中定义此函数。
因此,我的目标是使用一个表达式定义calculate函数。我想出了两种解决方案。
1-使用 scalaz 我可以这样定义(是否有更好的方法可以使用scalaz?):
  def calculate(a: Long) =
    firstFn |> {first => secondFn(first) |> {second => thirdFn(first, second, second + a)}}
我对此解决方案不满意的是它是嵌套的。我拥有的val越多,嵌套的深度就越大。
2-通过for理解,我可以实现类似的效果:
  def calculate(a: Long) =
    for (first <- Option(firstFn); second <- Option(secondFn(first))) yield thirdFn(first, second, second + a)
一方面,此解决方案具有扁平的结构,就像Clojure中的let,但另一方面,我需要将函数的结果包装在Option中,并从Option接收结果中的calculate(很好,我正在处理null,但是我不这样做't ...,也不想)。
是否有更好的方法可以实现我的目标?处理这种情况的惯用方式是什么(也许我应该继续使用val s ...,但是let的处理方式看起来如此优雅)?
另一方面,它连接到Referential transparency。所有这三个函数都是参照透明的(在我的示例中,firstFn计算像Pi一样的常数),因此从理论上讲,它们可以用计算结果代替。我知道这一点,但是编译器不知道,因此它无法优化我的第一次尝试。这是我的第二个问题:
我可以以某种方式(可能带有批注)提示编译器,我的函数是参照透明的,以便它可以为我优化此函数(例如,在其中进行某种缓存)吗?
编辑
谢谢大家的精彩回答!选择一个最佳答案是不可能的(可能是因为它们都很好),所以我会以最高的投票数接受答案,我认为这很公平。

最佳答案

在非递归情况下,让我们进行lambda的重组。

def firstFn : Int = 42
def secondFn(b : Int) : Long = 42
def thirdFn(x : Int, y : Long, z : Long) : Long = x + y + z

def let[A, B](x : A)(f : A => B) : B = f(x)

def calculate(a: Long) = let(firstFn){first => let(secondFn(first)){second => thirdFn(first, second, second + a)}}

当然,这仍然是嵌套的。无法避免。但是你说你喜欢单子(monad)形式。这是身份单子(monad)
case class Identity[A](x : A) {
   def map[B](f : A => B) = Identity(f(x))
   def flatMap[B](f : A => Identity[B]) = f(x)
}

这是您的单子(monad)计算。通过调用.x解开结果
def calculateMonad(a : Long) = for {
   first <- Identity(firstFn)
   second <- Identity(secondFn(first))
} yield thirdFn(first, second, second + a)

但是在这一点上,它肯定看起来像原始的val版本。

Identity Monad在Scalaz中存在并且更加复杂

http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/Identity.scala.html

关于scala - 与Scala中Clojure的 'let'等效,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4881443/

10-13 22:40