gpt4 book ai didi

f# - 管道序列中的异常处理

转载 作者:行者123 更新时间:2023-12-03 10:05:23 24 4
gpt4 key购买 nike

我正在开发一个基本的 2D CAD 引擎,并且管道运算符(operator)显着改进了我的代码。基本上,几个函数从空间中的一个点 (x,y) 开始,并在多次移动操作后计算最终位置:

let finalPosition =
startingPosition
|> moveByLengthAndAngle x1 a1
|> moveByXandY x2 y2
|> moveByXandAngle x3 a3
|> moveByLengthAndAngle x4 a4
// etc...

这非常容易阅读,我想保持这种方式。各种x1、a1等在实际代码中显然是有含义的名字。

现在新的要求是引入异常处理。围绕整个操作链进行大尝试/使用是不够的,因为我想知道哪条线导致了异常。我需要知道哪个参数无效,以便用户知道必须更改哪个参数。

例如,如果第一行 (moveByLengthAndAngle x1 a1) 引发异常,我想告诉类似“嘿,-90 是 a1 的无效值!a1 必须介于 45 和 90 之间!”。鉴于可以在序列中使用许多相同类型的操作,因此为每个操作定义不同的异常类型是不够的(在此示例中,我无法判断错误是第一次还是最后一次)。

显而易见的解决方案是将链拆分为单个 let 语句,每个语句都在其各自的 try/with 中。然而,这会使我漂亮且可读的代码有点困惑,不再那么可读了。

有没有办法在不牺牲当前代码的可读性和优雅性的情况下满足这个要求?

(注意。现在每个 moveBy 函数都会在出现错误时引发异常,但我可以自由更改例如返回一个选项、一个更大的元组或其他任何需要的东西)。

最佳答案

Rick 描述的解决方案只会处理在评估管道中函数的参数时引发的异常。但是,它不会处理流水线函数引发的异常(如 in answer to your other question 所述)。

例如,假设您有这些简单的功能:

let times2 n = n * 2
let plus a b = a + b
let fail n = failwith "inside fail"

10 // This will handle exception that happens when evaluating arguments
|> try plus (failwith "evaluating args") with _ -> 0
|> times2
|> try fail with _ -> 0 // This will not handle the exception from 'fail'!

为了解决这个问题,您可以编写一个函数,将任何其他函数包装在异常处理程序中。您的 protect 的想法函数将接受一个函数(例如 times2fail )并将返回一个新函数,该函数从管道(数字)获取输入并将其传递给函数( times2fail ),但将在异常处理程序中执行此操作:
let protect msg f = 
fun n ->
try
f n
with _ ->
// Report error and return 0 to the pipeline (do something smarter here!)
printfn "Error %s" msg
0

现在您可以保护管道中的每个函数,它还将处理评估这些函数时发生的异常:
let n =
10 |> protect "Times" times2
|> protect "Fail" fail
|> protect "Plus" (plus 5)

关于f# - 管道序列中的异常处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8249744/

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