Scala中的自定义控件结构?

时间:2010-08-26 13:54:57

标签: scala functional-programming control-structure

在使用Java或C ++进行编程时,有很多次我遇到了一个简单的模式,自定义控件结构可以减少代码中的样板。它类似于:

 if( Predicate ){
     Action

     return Value
 }

即“return if”类型语句。我尝试使用foo[A,B]( pred:((A,A)=>Boolean), value:Option[B] )这样的签名来创建函数,但最后我会检查是否已经返回Some或None。我被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内的尾递归。

4 个答案:

答案 0 :(得分:7)

我会使用部分功能:

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!"
}

通常,您不需要return语句。 If-expression将计算到每个块中使用的最后一个表达式。您可能需要帮助编译器找出if表达式的类型结果,但不需要返回。

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

如果whatevs功能不是你所说的那么我建议使用原始模式匹配。

答案 1 :(得分:2)

看起来你正在使用它作为代码控制流中的条件转义

你也可以在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 :(得分:2)

嗯,据我所知,你希望控制结构中的返回退出它所嵌入的函数。

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

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

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

答案 3 :(得分:1)

我不知道为什么你会想要这个。这是您要编写的代码:

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
}

对我而言,“普通”版本看起来更清晰。一方面,它非常清楚返回的是什么。它甚至不是更冗长。我怀疑你有一个更复杂的用例。如果您告诉我们,也许我们可以指导您更合适的模式。