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 + a)}} 我不喜欢这个解决方案是它是嵌套的。我拥有更深层次的更多的价值。 2 – 为了理解我可以做到类似的事情: def calculate(a: Long) = for (first <- Option(firstFn); second <- Option(secondFn(first))) yield thirdFn(first,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 + 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 + a) 但在这一点上,它确实看起来像原来的val版本。 身份monad存在于Scalaz中更加复杂 http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/Identity.scala.html (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |