在继续探索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#工作流程?
答案 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
对我来说似乎没什么用处,你打算怎么应用它?