F# 参数检查

4

F#有一些简洁的参数检查函数,可以像这样使用:

let foo (bar : string) : string =
    if bar = null then
        nullArg "bar"
    ...

我更喜欢一种更规范的表达方式,例如Code Contracts:

let foo (bar : string) : string =
    Contract.Requires (bar <> null, "bar is null")
...

我梦想写的代码是这样的,但是:
let nonNull (expr : Expr) : unit =
    // quotation magic

let foo (bar : string) : string =
    nonNull <@ bar @>
    ...

问题是:这个能用F#表达吗?或者换句话说,是否有一个针对非空的工作实现可以使用F#?在我看来好像没有,但也许这里有人可以确认一下。

1
我认为这不会起作用。引号<@ bar @>没有包含任何关于参数名称的信息。 - svick
2
@MarkSeemann 的动机是简洁、精确地表达函数契约。 - Bent Rasmussen
@MarkSeeman 这种方式不够简洁;同时也不是我偏爱的表达契约的方式。我意识到这有些吹毛求疵,但如果您采用其他方式可能会产生不同的效果。实际上,这只是我尝试模拟 Eiffel 和其他语言中“要求”构造的一种方式。 - Bent Rasmussen
1
@BentRasmussen 确实,这是挑剔,但是 if bar = null then nullArg "bar" 有32个字符,而 Contract.Requires (bar <> null, "bar is null") 有46个字符,所以我不明白为什么它不够紧凑。一般来说,.NET没有Eiffel式的断言... - Mark Seemann
1
不是答案,而且只是间接相关的,但是取消引用在这个方向上做了一些事情,因此很有趣(除了,正如@TomasPetricek指出的那样,一切都取决于引用是否有足够的信息隔离)。 - Ruben Bartelink
显示剩余3条评论
1个回答

4
如评论中@svick所提到的,目前这种方法不太可行,因为<@ bar @>实际上会被表示为Value(null, typeof<string>)。因此,您可以检查该值是否为null,但目前无法获取参数的名称。
你可以做的部分如下:
open Microsoft.FSharp.Quotations

let nonNull (expr : Expr) =
  match expr with 
  | Patterns.Value(null, _) -> failwith "it is null"
  | _ -> ()

不过,这可能会在下一个版本中得到改善 :-) 这个F#特性请求需要能够在引用中表示变量的名称。因此,也许可以等待 F# 的下一个版本!


很好,很好,很高兴看到其他人也有类似的想法。 :-) 谢谢你的回答 Thomas。既然这是目前最好的选择,我会将其标记为答案(并在用户声音上投票)。 - Bent Rasmussen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接