简体   繁体   English

在使用 For In 语句时,如何使这个 F# 函数正确返回一个布尔值?

[英]How do I make this F# Function properly return a boolean value while using a For In statement?

Sorry if my title isn't descriptive enough, I wasn't sure how to phrase the problem... I'm used to programming in C# and have been dabbling in F#.对不起,如果我的标题不够描述,我不知道如何表达这个问题......我习惯于用 C# 编程并且一直在涉足 F#。 I'm trying to write a function I use in some C# scripts that checks if the string is numeric.我正在尝试编写一个在某些 C# 脚本中使用的函数,用于检查字符串是否为数字。 I have a F# function written up like this though its not correct according to VS because its expecting an else:我有一个像这样编写的 F# 函数,尽管它根据 VS 不正确,因为它期待一个 else:

let IsNumeric (entry : string) : bool =     // Function to make sure the data entered is numeric
    for c : char in entry do
        if not ((c >= '0') && (c <= '9')) then
            false
    true

If I put in an else statement and remove the true at the bottom:如果我放入 else 语句并删除底部的 true:

let IsNumeric (entry : string) : bool =     // Function to make sure the data entered is numeric
    for c : char in entry do
        if not ((c >= '0') && (c <= '9')) then
            false
        else true

I get this error我收到这个错误

FS0001 This expression was expected to have type 'bool' but here has type 'unit' FS0001 此表达式的类型应为“bool”,但此处的类型为“unit”

... if I keep the true at the bottom like in the first code block I get a warning about it returning a bool but should be ignored which I don't quite understand. ...如果我像第一个代码块一样在底部保留真值,我会收到一条关于它返回一个布尔值的警告,但应该被忽略,我不太明白。

FS0020 The result of this expression has type 'bool' and is implicitly ignored. FS0020 此表达式的结果具有类型 'bool' 并被隐式忽略。 Consider using 'ignore' to discard this value explicitly, eg 'expr |> ignore', or 'let' to bind the result to a name, eg 'let result = expr'.考虑使用 'ignore' 显式丢弃该值,例如 'expr |> ignore',或使用 'let' 将结果绑定到名称,例如 'let result = expr'。

This is the C# method I wrote that I've been trying to adapt:这是我写的 C# 方法,我一直在努力适应:

public static bool IsNumeric(string s) //this just makes sure the string is numeric.
{
    foreach (char c in s)
    {
        if (!(c >= '0' && c <= '9') && c != '.' && c != '-')
        {
            return false;
        }

    }
    return true;
}

How should I approach this?我应该如何处理这个问题?

F# does not support "early return" - ie you can't stop a function execution in the middle. F# 不支持“提前返回” - 即您不能在中间停止函数执行。 The code always has to run from beginning to end, completely.代码总是必须从头到尾完整地运行。 And yes, this is a feature, not a bug.是的,这是一个功能,而不是一个错误。 It forces you to write cleaner, more understandable and maintainable code.它迫使您编写更清晰、更易于理解和可维护的代码。

Generally the way to iterate in functional programming is recursion: you write a function that makes a decision whether to continue iterating or to stop, and in the former case it calls itself, and in the latter case it doesn't.通常,函数式编程中的迭代方式是递归:您编写一个函数来决定是继续迭代还是停止,在前一种情况下它会调用自己,而在后一种情况下则不会。

Recursion is the ultimate foundation of iteration, but for most everyday cases the standard library provides a wide variety of specialized functions, which are themselves built on recursion or on other such functions.递归是迭代的最终基础,但对于大多数日常情况,标准库提供了各种各样的专用函数,这些函数本身是建立在递归或其他此类函数之上的。

For example, in this particular case, it looks like what you're trying to do is check all characters in the string to see if they're all digits.例如,在这种特殊情况下,您似乎要做的是检查字符串中的所有字符以查看它们是否都是数字。 And look: there is a special function for checking a predicate for every element of a sequence - Seq.forall :看看:有一个特殊的函数来检查序列中每个元素的谓词 - Seq.forall

let IsNumeric (entry : string) =
    entry |> Seq.forall (fun c -> (c >= '0') && (c <= '9'))

F# as most functional languages doesn't support early return. F# 作为大多数函数式语言不支持提前返回。 Last evaluated expression is return value.最后评估的表达式是返回值。

Canonical solution would be to use recursive function, which compiles to simple loop if you do it right .规范的解决方案是使用递归函数, 如果你做得对,它会编译成简单的循环。

let isNumeric (str: string) : bool =
    let rec loop index =
        if index >= str.Length then
            true
        else
            let c = str.[index]
            if (c >= '0' && c <= '9') || c = '.' || c = '-' then
                loop (index + 1)
            else false
    loop 0  

You can check what it compiles to with ILSpy, ILDasm or SharpLab你可以用 ILSpy、 ILDAsmSharpLab检查它编译成什么

Most F#-ish is to use大多数 F#-ish 是使用

let isNumeric str =
    String.forall (fun c -> (c >= '0' && c <= '9') || c = '.' || c = '-') str

And most correct is to use, because you don't check correctness and ..- would be correct number最正确的是使用,因为你不检查正确性和..-将是正确的数字

let isNumeric (str: string) = System.Double.TryParse str |> fst

Looks like you're looking for .forall or .exists :看起来您正在寻找.forall.exists

Try it 尝试一下

let isNumericChar (ch: char): bool =
    ch >= '0' && ch <= '9'

let isNumeric (entry: string): bool =
    String.forall isNumericChar entry


printfn "%A" (isNumeric "12345")
printfn "%A" (isNumeric "12a345")

You can also use partial evaluation here:您还可以在此处使用部分评估:

let isNumericChar (ch: char): bool =
    ch >= '0' && ch <= '9'

let isNumeric = String.forall isNumericChar


printfn "%A" (isNumeric "12345")
printfn "%A" (isNumeric "12a345")

For idiomatic F# code, i would suggest the solution describes by Fyodor Soikin or other users.对于惯用的 F# 代码,我建议使用 Fyodor Soikin 或其他用户描述的解决方案。 As F# function has no early return, you either have to use recursion or most often use a built-in function.由于 F# 函数没有提前返回,因此您要么必须使用递归,要么通常使用内置函数。 In your case the Seq.forall is what you want to use.在您的情况下, Seq.forall是您想要使用的。

but still, i want to add another solution that was not mentioned so far.但是,我仍然想添加另一个目前尚未提及的解决方案。 Probalby the most idiomatic conversion of the C# code is, to use a mutable variable.可能 C# 代码最惯用的转换是使用mutable变量。 The code would look like this:代码如下所示:

let isNumeric (entry : string) : bool =
    let mutable ret = true
    for c : char in entry do
        if not ((c >= '0') && (c <= '9')) then
            ret <- false
    ret

Usually some people will tell you, that it uses a mutable, and isn't functional .通常有些人会告诉你,它使用的是可变的,而不是功能性的 But in that case, it isn't really important.但在那种情况下,这并不重要。

While you should be able to understand recursion, and how to solve it with recursion and immutable variables.虽然您应该能够理解递归,以及如何使用递归和不可变变量来解决它。 This code is still idomatic, and in some cases, easier to understand.这段代码仍然是惯用的,在某些情况下,更容易理解。

There is no reason to not use mutables in a limited scope.没有理由不在有限的范围内使用可变参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 F#如何从函数中访问成员 - F# How do I access a member from a function 如何仅通过在F#中使用递归来编写此函数? - How can I write this function only by using recursion in F#? 如何使用 case 语句中的函数返回值以选择每个函数的 MAX? - How do I return a value using a function within a case statement to choose the MAX of each function? F#值不是函数错误 - F# value is not a function error 如何使这个 void 递归函数返回一个值 - How do I make this void recursive function return a value 使用参数在函数中执行操作后,如何返回布尔值? - How do I return a boolean value after I've carried out a operation in a functions by using a parameter? 使用F#优化记录中的函数值访问 - Optimization of function value access in record using F# 如何将所需的 System.Random.Next 重载传递给我的 F# 函数? - How do I pass the desired System.Random.Next overload to my F# function? 我怎样才能给 boolean 一个带有 while 循环的 function 中的值 - how can i give a boolean a value inside a function with a while loop 如何使用 F# 获取作为参数传入函数的变量名称? - How to get a name of a variable coming into a function as a parameter using F#?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM