F#,检查有效参数时合理的程度是多少?
我正在尝试学习一些 F# 中函数式编程的思维方式,因此任何提示都将不胜感激。现在我正在制作一个简单的递归函数,它接受一个列表并返回第 i:th 元素。
let rec nth(list, i) =
match (list, i) with
| (x::xs, 0) -> x
| (x::xs, i) -> nth(xs, i-1)
该函数本身似乎可以工作,但它警告我有关不完整的模式。在这种情况下,我不确定当我匹配空列表时要返回什么,因为如果我执行以下操作:
| ([], _) -> ()
整个函数被视为以单位作为参数的函数。我希望它将 is 视为多态函数。
当我这样做时,我不妨问一下,在认真开发时设计函数时,检查有效参数的合理程度是多少。我应该检查所有内容,以便防止“滥用”该功能吗?在上面的示例中,我可以指定函数来尝试访问列表中大于其大小的元素。我希望我的问题不会太令人困惑:)
I'm trying to learn a little of the mindset of functional programming in F#, so any tips are appreciated. Right now I'm making a simple recursive function which takes a list and returns the i:th element.
let rec nth(list, i) =
match (list, i) with
| (x::xs, 0) -> x
| (x::xs, i) -> nth(xs, i-1)
The function itself seems to work, but it warns me about an incomplete pattern. I'm not sure what to return when I match the empty list in this case, since if I for example do the following:
| ([], _) -> ()
The whole function is treated like a function that takes a unit as argument. I want it to treat is as a polymorphic function.
While I'm at it, I may as well ask how far is reasonable to go to check for valid arguments when designing a function when developing seriously. Should I check for everything, so "misuse" of the function is prevented? In the above example I could for example specify the function to try to access an element in the list that is larger than its size. I hope my question isn't too confusing :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
通过查看标准 F# 库,您可以了解有关“常用”库设计的更多信息。已经有一个函数可以执行您想要的操作,称为
List.nth
,但即使您将其实现为练习,您也可以检查该函数的行为方式:该函数会抛出
System.nth 异常。 ArgumentException
带有一些有关异常的附加信息,以便用户可以轻松找出出了什么问题。要实现相同的功能,您可以使用invalidArg
函数:这可能比仅使用
failwith
更好,后者会引发更一般的异常。使用invalidArg
时,用户可以检查特定类型的异常。正如 kvb 所指出的,另一个选项是返回
option 'a
。许多标准库函数都提供返回选项的版本和引发异常的版本。例如List.pick
和List.tryPick
。因此,在您的情况下,一个好的设计可能是有两个函数 -nth
和tryNth
。You can learn a lot about the "usual" library design by looking at the standard F# libraries. There is already a function that does what you want called
List.nth
, but even if you're implementing this as an exercise, you can check how the function behaves:The function throws
System.ArgumentException
with some additional information about the exception, so that users can easily find out what went wrong. To implement the same functionality, you can use theinvalidArg
function:This is probably better than just using
failwith
which throws a more general exception. When usinginvalidArg
, users can check for a specific type of exceptions.As kvb noted, another option is to return
option 'a
. Many standard library functions provide both a version that returnsoption
and a version that throws an exception. For exampleList.pick
andList.tryPick
. So, maybe a good design in your case would be to have two functions -nth
andtryNth
.如果您希望函数返回有意义的结果并具有与现在相同的类型,那么您别无选择,只能在其余情况下抛出异常。匹配失败将引发异常,因此您不需要更改它,但您可能会发现最好抛出具有更多相关信息的异常:
如果您预计无效列表索引很少见,那么这可能就足够了。然而,另一种选择是更改您的函数,使其返回一个
'a option
:这给调用者带来了额外的负担,调用者现在必须明确处理失败的可能性。
If you want your function to return a meaningful result and to have the same type as it has now, then you have no alternative but to throw an exception in the remaining case. A matching failure will throw an exception, so you don't need to change it, but you may find it preferable to throw an exception with more relevant information:
If you expect invalid list indices to be rare, then this is probably good enough. However, another alternative would be to change your function so that it returns an
'a option
:This places an additional burden on the caller, who must now explicitly deal with the possibility of failure.
据推测,如果采用空列表无效,您最好只是抛出异常?
一般来说,你应该采取何种防御措施的规则并不会因语言的不同而改变——我总是遵循这样的指导原则:如果是公共代码,则对验证输入持偏执态度,但如果是私有代码,你可以不那么严格。 (实际上,如果它是一个大型项目,并且是私有代码,请严格一点......基本上严格程度与可能调用您的代码的开发人员数量成正比。)
Presumably, if taking an empty list is invalid, you're best off just throwing an exception?
Generally the rules for how defensive you should be don't really change from language to language - I always go by the guideline that if it's public be paranoid about validating input, but if it's private code, you can be less strict. (Actually if it's a large project, and it's private code, be a little strict... basically strictness is proportional to the number of developers who might call your code.)