gpt4 book ai didi

validation - F# 使用匹配来验证参数

转载 作者:行者123 更新时间:2023-12-03 22:39:21 27 4
gpt4 key购买 nike

我正在学习 F#。我想知道验证输入参数的最佳实践。在我的天真中,我以为我可以做这样的事情:

let foo = match bar with
| <test for valid> -> bar
| _ -> "invalid"

当然,由于类型不匹配,这不起作用。所以我想看看有经验的 F# 程序员在这类事情上使用的模式。匹配?如果/那么/否则?

还有什么?

最佳答案

您遇到问题是因为您试图将一个值绑定(bind)到可能是两种可能类型的东西,具体取决于程序流程 - 这与静态类型不兼容。
如果我有一些值(value)foo ,例如,它不能是 stringint取决于程序流程;它必须在编译时准确地解析为一种类型。
但是,您可以使用 discriminated union可以在一个类型中表示几个不同的选项。
以下是执行此操作的方法的摘要。

结果类型/任一
F# 4.1,目前可通过 nuget 获得,介绍Result类型。您可能会发现这种类型称为 Either在其他语言中。
它是这样定义的:

[<Struct>] 
type Result<'T,'TError> =
/// Represents an OK or a Successful result. The code succeeded with a value of 'T.
| Ok of ResultValue:'T
/// Represents an Error or a Failure. The code failed with a value of 'TError representing what went wrong.
| Error of ErrorValue:'TError
如果您是 F# 4.1 之前的版本(很有可能)。您可以自己定义此类型,但必须删除 [<Struct>]属性。
然后您可以制作 tryParseFloat功能:
let tryParseFloat str =
match System.Double.TryParse str with
| true, f -> Ok f
| _ -> Error <| sprintf "Supplied string (%s) is not a valid float" str
您可以确定成功或失败:
match tryParseFloat "0.0001" with
|Ok v -> // handle success
|Error err -> // handle error
在我看来,这是首选选项,尤其是在内置类型的 F# 4.1+ 中。这是因为它允许您包含与某些事件失败的方式和原因相关的信息。

选项类型/可能 option类型包含 Some 'T或者干脆 None .选项类型用于指示值的存在或不存在, None担任类似于 null 的角色在其他语言中,虽然更安全。
您可能会发现这种类型称为 Maybe在其他语言中。
let tryParseFloat str =
match System.Double.TryParse str with
| true, f -> Some f
| _ -> None
您可以确定成功或失败:
match tryParseFloat "0.0001" with
|Some value -> // handle success
|None -> // handle error

作文
在这两种情况下,您都可以使用关联的 map 轻松组合选项或结果。和 bind Option 中的函数和 Result模块分别:
map :
val map: mapping:('T -> 'U) -> option:'T option -> 'U option   
val map : mapping:('T -> 'U) -> result:Result<'T, 'TError> -> Result<'U, 'TError>
map函数让您从 'a -> 'b 获取普通函数并使其对结果或选项进行操作。
用例:将结果与始终成功并返回新结果的函数相结合。
tryParseFloat "0.001" |> Result.map (fun x -> x + 1.0);;
val it : Result<float,string> = Ok 1.001

绑定(bind):
val bind: binder:('T -> 'U option) -> option:'T option -> 'U option
val bind: binder:('T -> Result<'U, 'TError>) -> result:Result<'T, 'TError> -> Result<'U, 'TError>
bind函数允许您将结果或选项与接受输入并生成结果或选项的函数结合起来
用例:将结果与另一个可能成功或失败的函数组合并返回一个新结果。
例子:
let trySqrt x =
if x < 0.0 then Error "sqrt of negative number is imaginary"
else Ok (sqrt x)
tryParseFloat "0.001" |> Result.bind (fun x -> trySqrt x);;
val it : Result<float,string> = Ok 0.0316227766

tryParseFloat "-10.0" |> Result.bind (fun x -> trySqrt x);;
val it : Result<float,string> = Error "sqrt of negative number is imaginary"

tryParseFloat "Picard's Flute" |> Result.bind (fun x -> trySqrt x);;
val it : Result<float,string> =
Error "Supplied string (Picard's Flute) is not a valid float"


请注意,在这两种情况下,尽管链接了多个操作,但我们返回单个结果或选项 - 这意味着通过遵循这些模式,您只需在所有验证完成后检查一次结果。
这避免了嵌套 if 的潜在可读性噩梦声明或 match陈述。
Railway Oriented Programming 是阅读更多相关信息的好地方。之前提到过的文章。
异常(exception)
最后,您可以选择抛出异常以防止某些值被验证。如果您希望它发生,这绝对不是首选,但如果事件确实非常特殊,这可能是最好的选择。

关于validation - F# 使用匹配来验证参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42557725/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com