Clojure的“let”等同于Scala

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

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

我也有计算功能。我的第一个方法可以是这样的:

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我可以在一个表达式中定义这个函数。

所以我的目标是用一个表达式定义计算函数。我想出了两个解决方案。

1 – 用scalaz我可以像这样定义它(有更好的方法来做这个与scalaz?):

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

我不喜欢这个解决方案是它是嵌套的。我拥有更深层次的更多的价值。

2 – 为了理解我可以做到类似的事情:

  def calculate(a: Long) = 
    for (first <- Option(firstFn); second <- Option(secondFn(first))) yield thirdFn(first, second, second + a)

从一方面,这种解决方案具有平坦的结构,就像在Clojure中一样,但是从另一方面来说,我需要在函数中包含函数的结果,并从计算结果接收选项(这是很好的,我正在处理null,但是我不想…)

有更好的方法来实现我的目标吗?处理这种情况的惯用方式是什么(可能是我应该留在vals …但让它看起来如此优雅)?

另一方面,它连接到Referential transparency.所有三个功能都是透明的(在我的例子中,首先计算一些像Pi一样的常数),所以理论上它们可以用计算结果代替。我知道这一点,但编译器没有,所以它不能优化我的第一次尝试。这是我的第二个问题:

我可以不知何故(可能用注释)给编译器提示,我的函数是透明的,所以它可以优化我的这个功能(例如在某些缓存中)

编辑

感谢大家的伟大答案!选择一个最佳答案是不可能的(可能是因为他们都很好),所以我会接受最多的投票答案,我觉得这是公平的。

在非递归的情况下,let是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

case class Identity[A](x : A) {
   def map[B](f : A => B) = Identity(f(x))
   def flatMap[B](f : A => Identity[B]) = f(x)
}

这是你的一元计算。调用.x解开结果

def calculateMonad(a : Long) = for {
   first <- Identity(firstFn)
   second <- Identity(secondFn(first))
} yield thirdFn(first, second, second + a)

但在这一点上,它确实看起来像原来的val版本。

身份monad存在于Scalaz中更加复杂

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

翻译自:https://stackoverflow.com/questions/4881443/clojures-let-equivalent-in-scala

转载注明原文:Clojure的“let”等同于Scala