如何重构所需的else子句?

Asi*_*sik 7 c# f#

我有一个看起来有点像这样的C#方法:

bool Eval() {
  // do some work
  if (conditionA) {
     // do some work
     if (conditionB) {
       // do some work
       if (conditionC) {
         // do some work
         return true;
       }
     }
  }
  return false;
}
Run Code Online (Sandbox Code Playgroud)

在F#中,由于强制性的其他分支,这最终看起来有点丑陋:

let eval() =
  // do some work
  if conditionA then
    // do some work
    if conditionB then
      // do some work
      if conditionC then
        // do some work
        true
      else
        false
    else
      false
  else
    false
Run Code Online (Sandbox Code Playgroud)

用F#写这个更干净的方法是什么?

Dan*_*iel 13

module Condition =
  type ConditionBuilder() =
    member x.Bind(v, f) = if v then f() else false
    member x.Return(v) = v
  let condition = ConditionBuilder()

open Condition

let eval() =
  condition {
    // do some work
    do! conditionA
    // do some work
    do! conditionB
    // do some work
    do! conditionC
    return true
  }
Run Code Online (Sandbox Code Playgroud)

  • @Brian:FWIW,我也不是顽固的FP"亚文化"的一部分.但是,您可以说这是F#的广告,因为它的目的是:1)有趣/有趣,2)展示F#相当多样化的解决问题的工具包,3)推动对值得学习的概念的兴趣,可能是新的一些程序员(monads).那是_awful_? (5认同)
  • @Brian - 我相信你已经意识到了这一点,但我们在C#和F#中所喜爱的许多功能被认为是编程群众多年来的"深奥","精英","一般无用".直到有远见的人认为群众不是那么愚蠢并且可以弄清楚发生了什么. (5认同)
  • @Brian我相信你的评论有点不合适.人们可以自己决定什么是不可读的,什么是不好的答案.除了伦理之外,可读性是旁观者的眼睛 - 来自不同背景的不同人在阅读不同编码风格时更容易或更难. (3认同)
  • 我的意见是,这是一个糟糕的答案.我认为绝大多数程序员更愿意看到原始代码,或者像我的代码那样使用基本的if-thens和单个本地可变变量,而不是使用深奥的语言特性引入新的控件抽象的代码.我不知道什么,更优雅?保存一行?我只是不明白.我想FP社区中存在多种亚文化,我完全不接触这个. (2认同)
  • 我想我的主要担心是,我将这个问题解释为F#newbie语法问题(OP不知道'if statement'),所以我不认为涉及monad的一堆答案是介绍这个人的最好方法对语言和社区.对于不知道原始海报的背景/背景,以及稍后发现/阅读问题的人,知道什么样的答案对他们最有用,这总是一个挑战. (2认同)

Tom*_*cek 9

如评论中所述,您可以反转条件.这简化了C#代码,因为您可以编写:

if (!conditionA) return false;
// do some work
Run Code Online (Sandbox Code Playgroud)

虽然F#没有命令性返回(如果你想返回,你需要真假分支),它实际上也简化了这段代码,因为你可以写:

let eval() = 
  // do some work 
  if not conditionA then false else
  // do some work 
  if not conditionB then false else
  // do some work 
  if not conditionC then false else
    // do some work 
    true 
Run Code Online (Sandbox Code Playgroud)

您仍然需要false多次写入,但至少您不必将代码缩进太多.有无限数量的复杂解决方案,但这可能是最简单的选择.至于更复杂的解决方案,您可以使用允许使用命令式返回F#计算表达式.这类似于Daniel的计算,但更强大一些.


Bri*_*ian 6

好吧,既然'做一些工作'已经势在必行(大概),那么我认为

let eval() =
    let mutable result = false
    ... // ifs
        result <- true
    ... // no more elses
    result
Run Code Online (Sandbox Code Playgroud)

更短更合理.(换句话说,else只对if返回值的表达式是强制性的;因为你正在做必要的工作,所以使用if不需要的语句else.)


Cha*_*ion 6

请不要害怕提取功能.这是控制复杂逻辑的关键.

let rec partA () =
  // do some work
  let aValue = makeA ()
  if conditionA 
  then partB aValue 
  else false
and partB aValue =
  // do some work
  let bValue = makeB aValue
  if conditionB 
  then partC bValue
  else false
and partC bValue =
  // do some work
  conditionC 
Run Code Online (Sandbox Code Playgroud)

  • @Daniel - State可以作为参数传递. (2认同)