【问题标题】:Custom control structures in Scala?Scala中的自定义控制结构?
【发布时间】:2011-04-04 07:08:06
【问题描述】:

在使用 Java 或 C++ 编程时,我曾多次遇到一个简单的模式,其中自定义控制结构可以减少我代码中的样板。它是这样的:

 if( Predicate ){
     Action

     return Value
 }

即“return if”类型的语句。我尝试过使用foo[A,B]( pred:((A,A)=>Boolean), value:Option[B] ) 之类的签名创建函数,但最后我检查我是否返回了一些或无。我被return 声明绊倒了。

在函数式语言或更具体地说是 Scala 中是否有一种继承方式来制作这种控制结构?

编辑:

我的描述不是很清楚,这让试图帮助我的人感到困惑。我的foo 不起作用的关键原因是它不能短路包含函数的评估。那是

def intersect( geometry:Geometry, reference:Geometry ):Geometry = {
    return_if( withinBounds( geometry, projection ), logToString( logger, "Geometry outside " + projection.toString ), EmptyGeometry() )
    return_if( topologicallyCorrect( geometry ), intersect( correct( geometry ), reference )
    //rest of the function
}

并且仍然允许在 return_if 中进行尾递归。

【问题讨论】:

  • 可能可以通过延续以某种方式获得这种行为(CPS 是 2.8 的“内置”,但必须由编译器开关激活),但我没有对它了解不够。

标签: scala functional-programming control-structure


【解决方案1】:

您似乎将其用作代码控制流的条件转义

如果这确实是解决问题的最优雅的解决方案,您也可以在 Scala 中执行此操作(只需使用要返回的类型注释方法)。有时代码需要像多级过滤器一样工作,而这种模式很适合。

当然,你总是可以嵌套 if 语句,但这会很尴尬。

然而,在 Scala 中还有一些其他的事情需要考虑。一个可以

methodReturningOption.getOrElse(
  // All the code for the None case goes in here
)

在存在合理默认值的情况下,这通常可以很好地整合不同的分支(或者如果没有默认值,您最终会抛出异常)。

或者,您可以为此滥用模式匹配:

None match {  // Could use a real variable instead of None if it helped
  case _ if (Predicate1) => Action1; Value1
  case _ if (Predicate2) => Action2; Value2
  . . .
  case _ => ErrorHandlingPerhaps
}

但是你也可以用不同的方式来思考你的问题,这样这类谓词就变得不那么有用了。 (不知道更多细节,我无法提出建议。)

【讨论】:

    【解决方案2】:

    我会使用偏函数:

    def whatevs[A, B](options : PartialFunction[(A,A), B]) : Option[B] = {
      val myInput = generateInput
      if(options.isDefined(myInput)) {
        Some(options(myInput))
      } else None
    }
    

    那么您的用法可能如下所示:

    whateves {
       case (x,y) if x > y =>   "Biggerz"
       case (x,y) if y > x =>   "Tiny!"
    }
    

    一般来说,您不需要返回语句。 if-expression 将评估为每个块中使用的最后一个表达式。您可能需要帮助编译器找出 if 表达式的类型结果,但不需要返回。

    部分函数是一种在某些条件成立时执行操作的机制。在上面,两个条件是元组中的 x > y 或 y > x。

    如果 whatevs 函数不是您所说的,我建议使用原始模式匹配。

    【讨论】:

      【解决方案3】:

      嗯,据我了解,您希望控制结构中的 return 退出它嵌入的函数。

      所以在你的例子中它应该退出方法相交?

      我不确定这是否可能。因为 return_if 中的 return 总是会退出 return_if 并且我认为没有办法告诉 scala,return 应该退出嵌入的函数 return_if。

      我希望我明白你想做什么:)

      【讨论】:

      • 是的,你是对的。我什至没有想到这一点。如果 return_if 被传递了 return_if 它可能会导致问题。
      • 实现这一点的方法是抛出一个异常,然后由外部方法处理 - 看看break是如何实现的。而不是return,你会调用一个会抛出异常的方法(比如break
      【解决方案4】:

      我不明白你为什么想要这个。这是您要编写的代码:

      def intersect( geometry:Geometry, reference:Geometry ):Geometry = {
      
        return_if( withinBounds( geometry, projection ), 
          logToString( logger, "Geometry outside " + projection.toString ), 
          EmptyGeometry() )
      
        return_if( topologicallyCorrect( geometry ), 
          intersect( correct( geometry )), 
          reference )
      
          // rest of the function
      }
      

      这是在“普通”Scala 中的样子:

      def intersect( geometry:Geometry, reference:Geometry ):Geometry = {
      
        if (withinBounds( geometry, projection )) {
          logToString( logger, "Geometry outside " + projection.toString )
          return EmptyGeometry() }
      
        if( topologicallyCorrect( geometry )) {
          intersect( correct( geometry ))
          return reference }
      
        //rest of the function
      }
      

      对我来说,“普通”版本看起来更清晰。一方面,它非常清楚要返回的内容。它甚至更冗长。我怀疑你有一个更复杂的用例。如果您向我们展示这一点,也许我们可以将您引导至更合适的模式。

      【讨论】:

        猜你喜欢
        • 2013-05-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-24
        • 1970-01-01
        • 1970-01-01
        • 2016-09-28
        • 2020-06-02
        相关资源
        最近更新 更多