4

我想知道您是否可以在 F# 中添加类似“null-safe”-operator 之类的东西。我知道在 C# 中可能会有这样的运算符用于下一个更大的版本。

如果没有办法实现这种行为,有没有办法包装一个语句,该语句可能会将 aNullReferenceException放入捕获异常并返回的块中null

我想到了类似的东西:

let sth = %% <@ someobject.method().another().andAnother() @>

where%%是执行表达式并检查异常的自定义运算符。

我做的一个尝试是:

open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation

let (~%%) (right:Expr) =
  try 
    right.CompileUntyped()
    right()
  with
  | ex -> null

但这并没有达到我想要的效果(实际上它甚至没有编译:)

我通读了:

有谁知道如何优雅地为链式方法创建这样一个单行尝试捕获?

4

3 回答 3

6

我认为您不能.?以一种实用且语法上方便的方式将 F# 用作库功能来实现类似于为 C# 提出的运算符之类的东西。虽然,我认为这将是一个非常有用的语言扩展,所以我会将它提交给F# 用户的声音,或许还可以提交一个拉取请求:-)。

异常处理。您的代码示例与 C# 不太一样,因为您只是在处理任意异常。C# 功能的要点是它在每个之后插入 null检查.- 您可以通过转换引用然后编译它来做到这一点,但编译会很慢。您的功能实际上可能只是:

let orNull f = try f () with :? NullReferenceException -> null

然后你可以写

orNull <| fun () -> x.Foo().Bar()

.. 但如前所述,这只是将代码包装在标准try块中并处理异常,因此它不会做与 C# 代码相同的事情。

计算生成器。如果你想要一个更高级的 F# 解决方案,你可以想出一个计算表达式构建器,让你编写如下内容:

safe { let! a = x.Foo()
       let! b = a.Bar()
       return b }

这可以像 C# 运算符一样执行空值检查.?,但是您需要为方法调用链的每个部分单独绑定,因此需要更多输入。计算构建器在Bind成员中插入一个隐藏的空检查,如下所示:

type NullBuilder() = 
  member x.Return(v) = v
  member x.Bind(v, f) = if (box v) = null then null else f v 

let safe = NullBuilder()
于 2014-04-29T15:52:57.563 回答
3

这是个有趣的问题。幸运的是,仅存在于 F# 世界中的代码(即不使用以其他语言编写的 .NET 库)不存在.?旨在解决的普遍问题,因为可空性必须是显式的(使用[<AllowNullLiteral>])。然而,这个概念有一个功能性的对应物:option类型和bind功能(bind是工作流的基础,正如 Tomas 所证明的那样)。

你可以采取这样的方式:

type T() =
    member this.M(b) = if b then Some this else None

T().M(true)
|> Option.bind (fun t -> t.M(true))
|> Option.bind (fun t -> t.M(false)) 
|> Option.bind (fun t -> t.M(true))

并定义一个bind运算符

let (?>) o f = Option.bind f o

并将其缩短为:

T().M(true)
?> fun t -> t.M(true)
?> fun t -> t.M(false)
?> fun t -> t.M(true)

但是,这样做的价值很小。它既不简洁也不清晰。但是,我认为这表明:

  • 您正在处理的一般概念
  • 它与null
  • 这通常是如何用函数式语言处理的
于 2014-04-29T16:37:48.397 回答
1

Maybe 使用 F# worflows,扩展 Maybe monad 的想法,并能够写成这样:

let sth = maybe { someobject.method().another().another() }

请参阅http://santialbo.com/blog/2013/03/27/monads-in-f-sharp/

于 2014-04-29T15:55:16.300 回答