实现F#工作流构建器:处理for..in..do构造中的异常

时间:2010-12-05 21:45:17

标签: f#

在继续探索F#工作流构建器时,我决定在构建器中尝试异常处理,特别是在“for..in..do”构造中。

此实验的最终目标是工作流构建器,即使发生异常,它也将继续处理序列。

例如,下面的代码不起作用,因为构建器的For方法似乎直到发生异常的点之后才会被调用(在第一个Directory.EnumerateFiles(dir)调用时)

type failSafeSeq() =
    member this.For(seq1, mapFunction) =
        try
            seq1 |> Seq.collect mapFunction
        with
            ex -> Console.WriteLine ex
                  Seq.empty
    member this.Yield(yieldExpr) = yieldExpr |> Seq.singleton
    member this.YieldFrom(yieldBang) = yieldBang
    member this.Combine(a, b) = Seq.append a b
    member this.Delay(delayFun) = delayFun()
    member this.Zero() = Seq.empty 

let failSafe = new failSafeSeq();

let rec allFilesSeq dir =
    failSafe { for file in Directory.EnumerateFiles(dir) do yield file
               for subdir in Directory.EnumerateDirectories dir do yield! (allFilesSeq subdir) }

[<EntryPoint>]
let main args =
    allFilesSeq "C:\\System Volume Information\\" //almost guaranteed to cause an UnauthorizedAccessException on Windows systems at the first Directory.EnumerateFiles(dir) call.
    |> Seq.iter Console.WriteLine
    0

这是否可以使用F#工作流程?

1 个答案:

答案 0 :(得分:1)

没有;根据{{​​3}}计算表达式,

... for pat in expr do cexpr ...

被翻译为

... b.For(expr, fun pat -> cexpr) ...

表示在expr之前评估For,如果它被抛出,那么当然不会调用For

顺便提一下,您的策略也不会按原样运作,因为seq是懒惰的,例如Seq.collect通常不会抛出(相反,调用它的代码并评估序列可能导致代码运行该抛出)。

还有很多其他方法可以实现“恢复seq s”的内容......我认为工作流程可能是错误的方法,而你只需要为{包装组合器{1}}创建和映射。

真正的最终目标是什么?这个'恢复seq对我来说似乎没什么用处,你打算怎么应用它?