【问题标题】:How can I repeat calling a function until it returns None?如何重复调用函数直到它返回 None?
【发布时间】:2018-07-17 07:18:15
【问题描述】:

假设我有两个函数

Func<Id, Option<Employee>> FindEmployee

如果找到Id,则返回员工,否则返回None

Func<Employee, Option<Entry>> PromptPassword

它会打开一个询问密码的对话框,如果点击确定按钮,它将返回用户条目;如果点击取消,它将返回 None

我想有一个优雅的方式来组合这两个函数,基本上我想做的:

FindEmployee.Map(emp => 
  {
     while (true)
     {
         var result = PromptPassword (emp);
         if (result.IsNone)
         {
             return false;
         }

         bool matched = result.Where(a => a.EntryContent == emp.Password)
                              .Some(r => true)
                              .None(false);
         if (matched)
             return true;
      }
  });

最终结果是一个选项 你看,我想一直提示输入密码,直到用户正确输入密码。但是在Map 中使用while 循环实在是太难看了。

它必须有更好的方法来写这个。谁能给个提示?

谢谢

【问题讨论】:

  • 出于好奇,这是哪个 Option?它来自 F# 还是其他库?
  • 另外,为什么 PromptPassword 会收到一个 Employee?为什么,如果密码验证发生在以bool matches = ... 开头的行的后面。 while(true){...} 将永远迭代。我的意思是,无论其优雅程度如何,您的代码 sn-p 都是错误的。它只是行不通。您需要编辑您的问题,以便至少您的 sn-p 代码有意义。
  • @caeus 可能在提示对话框中使用了emp 中的某些值。如果代码为returns,while 循环将不会永远迭代。我认为没有理由相信 OP 的代码不起作用。
  • @JLRishe,你说得对。它会让它结束。 “emp”是什么类型的?员工或选项
  • @caeus 鉴于 OP 正在访问emp.Password,我想它是Employee

标签: c# functional-programming language-extension


【解决方案1】:

在 F# 中,我可能会这样表达您的算法:

findEmployee |> Option.map (fun emp ->
    let rec loop () =
        match PromptPassword emp with
        | None -> false
        | Some a -> a.EntryContent = emp.Password || loop ()
    loop ())

C# 中的等价物可能如下所示:

FindEmployee.Map(emp =>
    {
        do {
            var result = PromptPassword(emp);
            if (result.IsNone) return false;
        } while (result.Where(a => a.EntryContent == emp.Password).IsNone);
        return true;
    });

【讨论】:

    【解决方案2】:

    定义一个这样的函数

    bool Insist(Employee:emp){
      var result = PromptPassword (emp);
      if (result.IsNone)
      {
         return false;
      }
    
      bool matched = result.Where(a => a.EntryContent == emp.Password)
                                  .Some(r => true)
                                  .None(false);
      if(matched)
      {
         return true;
      }else
      {
         return Insist(emp);
      }
    
    }
    

    那你就去吧

    FindEmployee(id).Map(emp => 
      {
         return Insist(emp);
      });
    

    【讨论】:

    • 我认为您可以将第二部分更改为FindEmployee.Map(Insist)。不确定这是否有很大的改进。我认为 OP 正在寻找一种预先建立的模式来在 FP/Rx 中做这种事情。
    • 好吧,我不确定这在 C# 中是否可行。当他在寻求 FP 建议时,没有什么 FP 这么好的递归了。哈哈
    • 我确实觉得我应该只使用传入函数编写一个附加方法。感谢回复
    【解决方案3】:

    你可以使用 goto 语句对吗?然后摆脱while循环......

    【讨论】:

    • 这是在开玩笑吗?
    • OP 正在询问一种更好 和更优雅的方式来完成他们正在做的事情。我想大多数人都会同意goto 不会比他们拥有的更好。
    猜你喜欢
    • 1970-01-01
    • 2023-01-12
    • 1970-01-01
    • 2022-11-21
    • 2022-12-25
    • 1970-01-01
    • 2015-02-14
    • 1970-01-01
    • 2011-12-15
    相关资源
    最近更新 更多