F# - 健全性检查和选项

标签 f# options

我对 F# 还很陌生,所以在多年的 C#/Java OOP 之后,我很难改变我的心态。

我有一个事件处理程序 MyForm.SelectFile(filePath:String)这将打开一个对话框,让您选择要读取的文件。选择文件后,Parser.LoadFile(filePath:String)叫做:

static member LoadFile(filePath:String) =
    if not <| ZipFile.IsZipFile(filePath) then
        failwith "invalid file specified."
    use zipFile = new ZipFile(filePath)
    if zipFile.Count <> 2 || zipFile |> Seq.exists(fun x -> x.FileName <> "alpha" && x.FileName <> "beta")  then
        failwith "invalid file specified."
    zipFile |> fun x -> Parser.Parse(x.OpenReader())

我总是希望所选文件是一个有效的 zip 存档,其中包含 2 个没有扩展名的文件:“alpha”和“beta”。

首先,有没有更好的方法来清理我的输入?

我的 if 语句很长,我确信 F# 可以提供更好的解决方案,但我真的想不通。

二、使用failwith迫使我处理 MyForm.SelectFile(filePath:String) 中的异常方法,我认为 Options 可能是更好的解决方案。

如果我需要执行两个不同的连续检查( ZipFile.IsZipFile 和内容),我无法弄清楚如何使用它们,因为在这两者之间我必须实例化一个 ZipFile .

在 C# 中,我只会返回 null每当检查失败,然后根据 null 检查返回值会让我知道我是否需要提示错误或继续。

当前代码:
type Parser with

    static member isValidZipFile (zipFile:ZipFile) =
        (zipFile.Count = 2) && (zipFile |> Seq.forall(fun x -> (x.FileName = "alpha") || (x.FileName = "beta")))

    static member LoadFile(filePath:String) =
        if not <| ZipFile.IsZipFile(filePath) then
            None
        else
            use zipFile = new ZipFile(filePath)
            if not <| Parser.isValidZipFile(zipFile) then
                None
            else
                Some(seq { for zipEntry in zipFile do yield Parser.Parse(zipEntry.OpenReader()) } |> Seq.toArray)

最佳答案

首先,你的函数的最后一行可能会更优雅一些,如果它是这样写的:

zipFile.OpenReader() |> Parser.Parse

其次,就您考虑使用 Option 而言,您走在正确的轨道上.在这种情况下,这真的很简单:
static member LoadFile(filePath:String) =
    if not <| ZipFile.IsZipFile(filePath) then None else
    use zipFile = new ZipFile(filePath)
    if zipFile.Count <> 2 || zipFile |> Seq.exists(fun x -> x.FileName <> "alpha" && x.FileName <> "beta") then None else
    Some (zipFile.OpenReader() |> Parser.Parse)

最后一行也可以写成:
zipFile.OpenReader() |> Parser.Parse |> Some

现在,你提到你不喜欢长 if陈述。让我们把它变成一个函数!而且我通常更喜欢带有“正”名称的函数,即 isValidInput函数通常比 isInvalidInput 更有帮助.因此,让我们创建一个函数来检查 zipfile 是否实际有效:
let isValid (z:ZipFile) =
    z.Count = 2 && z |> Seq.forAll(fun x -> x.FileName = "alpha" || x.FileName = "beta")

现在您的 LoadFile函数可以变成:
static member LoadFile(filePath:String) =
    if not <| ZipFile.IsZipFile(filePath) then None else
    use zipFile = new ZipFile(filePath)
    if not <| isValid zipFile then None else
    zipFile.OpenReader() |> Parser.Parse |> Some

这看起来很容易阅读,所以我们现在可以停止重构。

关于F# - 健全性检查和选项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39875837/

相关文章:

parameters - 为什么此 F# 函数的参数值似乎变为 0?

python - Pandas Python-read_csv 未读取每一行的完整数据

JavaScript:在选择不同的下拉菜单项时,我希望显示更多选项

f# - 在计算表达式中为 if..then 构造的 else 分支调用零背后的直觉

interface - F# 中的对象表达式和捕获的状态

java - Java集包含多个返回选项

size - 我可以在 protobuf 中为数字设置最大值吗?

c - Windows Shell:通过C代码更改Shell颜色

build - 我对我应该引用哪个 fsharp.core 以及如何去做感到困惑

f# - F# 中的重载 + 运算符