如何在使用 For In 语句时使此 F# 函数正确 return 为布尔值?
How do I make this F# Function properly return a boolean value while using a For In statement?
抱歉,如果我的标题描述性不够,我不确定如何表述问题...
我习惯用 C# 编程,并且一直在涉足 F#。我正在尝试编写一个在某些 C# 脚本中使用的函数,用于检查字符串是否为数字。我有一个像这样写的 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
如果我放入 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
我收到这个错误
FS0001 This expression was expected to have type 'bool' but here has type 'unit'
...如果我像在第一个代码块中那样将 true 保留在底部,我会收到一条关于它返回布尔值的警告,但应该被忽略,我不太明白。
FS0020 The result of this expression has type 'bool' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.
这是我写的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;
}
我该如何处理?
F# 不支持“early return”——即您不能在中间停止函数执行。代码总是要运行从头到尾,完整。是的,这是一项功能,而不是错误。它迫使您编写更清晰、更易理解和可维护的代码。
一般函数式编程的迭代方式是递归:你写一个函数,决定是继续迭代还是停止,前者调用自己,后者不调用.
递归是迭代的最终基础,但对于大多数日常情况,标准库提供了各种各样的专用函数,这些函数本身是建立在递归或其他此类函数之上的。
例如,在这种特殊情况下,看起来您要尝试做的是检查字符串中的所有字符以查看它们是否都是数字。看:有一个特殊函数用于检查序列中每个元素的谓词 - Seq.forall
:
let IsNumeric (entry : string) =
entry |> Seq.forall (fun c -> (c >= '0') && (c <= '9'))
F# 因为大多数函数式语言不支持早期 return。最后评估的表达式是 return 值。
规范的解决方案是使用递归函数,它编译为简单循环 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
您可以使用 ILSpy、ILDasm 或 SharpLab
检查它编译的内容
大多数 F#-ish 都可以使用
let isNumeric str =
String.forall (fun c -> (c >= '0' && c <= '9') || c = '.' || c = '-') str
最正确的是使用,因为你不检查正确性,..-
将是正确的数字
let isNumeric (str: string) = System.Double.TryParse str |> fst
您似乎在寻找 .forall
或 .exists
:
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")
您也可以在此处使用部分评估:
let isNumericChar (ch: char): bool =
ch >= '0' && ch <= '9'
let isNumeric = String.forall isNumericChar
printfn "%A" (isNumeric "12345")
printfn "%A" (isNumeric "12a345")
对于惯用的 F# 代码,我建议使用 Fyodor Soikin 或其他用户描述的解决方案。由于 F# 函数没有早期 return,您要么必须使用递归,要么通常使用内置函数。在你的情况下,Seq.forall
是你想要使用的。
但是,我仍然想添加另一个目前未提及的解决方案。可能 C# 代码最惯用的转换是使用 mutable
变量。代码如下所示:
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
通常有人会告诉你,它使用了一个可变的,并且没有功能。但在那种情况下,它并不是很重要。
虽然你应该能够理解递归,以及如何用递归和不可变变量来解决它。这段代码仍然是惯用的,并且在某些情况下更容易理解。
没有理由不在有限范围内使用可变变量。
抱歉,如果我的标题描述性不够,我不确定如何表述问题... 我习惯用 C# 编程,并且一直在涉足 F#。我正在尝试编写一个在某些 C# 脚本中使用的函数,用于检查字符串是否为数字。我有一个像这样写的 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
如果我放入 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
我收到这个错误
FS0001 This expression was expected to have type 'bool' but here has type 'unit'
...如果我像在第一个代码块中那样将 true 保留在底部,我会收到一条关于它返回布尔值的警告,但应该被忽略,我不太明白。
FS0020 The result of this expression has type 'bool' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.
这是我写的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;
}
我该如何处理?
F# 不支持“early return”——即您不能在中间停止函数执行。代码总是要运行从头到尾,完整。是的,这是一项功能,而不是错误。它迫使您编写更清晰、更易理解和可维护的代码。
一般函数式编程的迭代方式是递归:你写一个函数,决定是继续迭代还是停止,前者调用自己,后者不调用.
递归是迭代的最终基础,但对于大多数日常情况,标准库提供了各种各样的专用函数,这些函数本身是建立在递归或其他此类函数之上的。
例如,在这种特殊情况下,看起来您要尝试做的是检查字符串中的所有字符以查看它们是否都是数字。看:有一个特殊函数用于检查序列中每个元素的谓词 - Seq.forall
:
let IsNumeric (entry : string) =
entry |> Seq.forall (fun c -> (c >= '0') && (c <= '9'))
F# 因为大多数函数式语言不支持早期 return。最后评估的表达式是 return 值。
规范的解决方案是使用递归函数,它编译为简单循环 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
您可以使用 ILSpy、ILDasm 或 SharpLab
检查它编译的内容大多数 F#-ish 都可以使用
let isNumeric str =
String.forall (fun c -> (c >= '0' && c <= '9') || c = '.' || c = '-') str
最正确的是使用,因为你不检查正确性,..-
将是正确的数字
let isNumeric (str: string) = System.Double.TryParse str |> fst
您似乎在寻找 .forall
或 .exists
:
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")
您也可以在此处使用部分评估:
let isNumericChar (ch: char): bool =
ch >= '0' && ch <= '9'
let isNumeric = String.forall isNumericChar
printfn "%A" (isNumeric "12345")
printfn "%A" (isNumeric "12a345")
对于惯用的 F# 代码,我建议使用 Fyodor Soikin 或其他用户描述的解决方案。由于 F# 函数没有早期 return,您要么必须使用递归,要么通常使用内置函数。在你的情况下,Seq.forall
是你想要使用的。
但是,我仍然想添加另一个目前未提及的解决方案。可能 C# 代码最惯用的转换是使用 mutable
变量。代码如下所示:
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
通常有人会告诉你,它使用了一个可变的,并且没有功能。但在那种情况下,它并不是很重要。
虽然你应该能够理解递归,以及如何用递归和不可变变量来解决它。这段代码仍然是惯用的,并且在某些情况下更容易理解。
没有理由不在有限范围内使用可变变量。