Scala 中的自定义控制结构?

发布于 2024-09-15 18:50:27 字数 856 浏览 7 评论 0原文

在使用 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 中进行尾递归。

There are a number of times I've run into a simple pattern when programming in Java or C++ for which a custom control structure could reduce the boilerplate within my code. It goes something like:

 if( Predicate ){
     Action

     return Value
 }

that is, a "return if"-type statement. I've tried making functions with signature like foo[A,B]( pred:((A,A)=>Boolean), value:Option[B] ) but then I wind up checking if I've returned Some or None. I'm tripped up by the return statement.

Is there an inherit way of making such control structures in functional languages or more specifically Scala?

Edit:

I was not as clear with my description and it's confusing people who are trying to help me. The key reason my foo doesn't work is that it can't short-circuit the evaluation of the containing function. That is

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
}

and still allow for tail recursion within the return_if.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

疾风者 2024-09-22 18:50:27

我将使用部分函数:

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-表达式将计算每个块中使用的最后一个表达式。您可能需要帮助编译器找出 if 表达式的类型结果,但不需要返回。

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

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

I would use a partial function:

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

Then your usage could look like the following:

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

In general, you do not need a return statement. If-expression will evaluate to the last expression used in each block. You may need to help the compiler figure out the type-result of the if expression, but the return is unneeded.

Partial Functions are a mechanism to perform an action if some condition holds true. In the above, the two conditions are x > y or y > x from the tuple.

If the whatevs function is not quite what you're talking about I'd recommend using raw pattern matching.

雨的味道风的声音 2024-09-22 18:50:27

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

所以在您的示例中它应该退出方法 intersect 吗?

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

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

Hmm, as far as I understand it you want the return in the control structure to exit the function it is embedded in.

So in your example it should exit the method intersect?

I am not sure if thats possible. Because a return inside the return_if will always exit return_if and I don't think there is a way to tell scala, that the return should exit the function return_if is embedded in.

I hope I understood what you wanted to do :)

染柒℉ 2024-09-22 18:50:27

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

如果这确实是问题的最优雅的解决方案,您也可以在 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
}

但您也可以以不同的方式思考您的问题,以便这些谓词变得不那么有用。 (在不了解更多细节的情况下,我无法提出建议。)

It looks like you're using this as a conditional escape from the control flow of the code.

You can do this in Scala too (just annotate the method with the type to return) if it's really the most elegant solution to the problem. Sometimes code needs to act like a multi-stage filter, and this pattern works well for that.

Of course you can always nest if-statements, but that gets awkward.

There are a couple of other things to consider in Scala, however. One can

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

which usually works pretty well at consolidating different branches in the case that there is a sensible default (or you'll end up throwing an exception if there's not).

Alternatively, you can abuse pattern matching for this:

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
}

But you also might be able to think about your problem in a different way so that these sort of predicates become less useful. (Without knowing more details, I can't suggest something.)

浅忆 2024-09-22 18:50:27

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

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
}

对我来说,“普通”版本看起来更清晰。一方面,它非常清楚返回的是什么。这还不算更冗长。我怀疑你有一个更复杂的用例。如果您向我们展示这一点,也许我们能够引导您找到更合适的模式。

I am at a loss to understand why you would want this. Here's the code you want to write:

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
}

while here's what it looks like in "ordinary" 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
}

To me the "ordinary" version looks a lot clearer. For one thing it makes it very clear what is being returned. It's not even more verbose. I suspect you have a more complex use case. If you show us that, maybe we will be able to direct you to patterns that are more appropriate.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文