F#:警告FS0020:此表达式的类型应为';单位';,但是有类型';布尔';
我试图通过研究一些欧拉问题来学习F#,但我发现了一个我一直无法解决的问题。这是我天真的解决办法F#:警告FS0020:此表达式的类型应为';单位';,但是有类型';布尔';,f#,unit-type,F#,Unit Type,我试图通过研究一些欧拉问题来学习F#,但我发现了一个我一直无法解决的问题。这是我天真的解决办法 let compute = let mutable f = false let mutable nr = 0 while f = false do nr <- nr + 20 f = checkMod nr nr 让我们来计算= 设可变f=false 设可变nr=0 而f=假do nr下一行: f = checkMod nr 这
let compute =
let mutable f = false
let mutable nr = 0
while f = false do
nr <- nr + 20
f = checkMod nr
nr
让我们来计算=
设可变f=false
设可变nr=0
而f=假do
nr下一行:
f = checkMod nr
这是一个平等的检查,而不是一个任务,因为我相信你是有意的。将其更改为:
f <- checkMod nr
f在f#中,如果你来自命令式语言,就要稍微习惯一下。while
表达式中的每一行必须计算为unit
(从C++/C#开始考虑void
)。然后,整个表达式的计算结果也是unit
在示例中:
nr <- nr + 20
计算为如上所述的bool
。这将导致报告警告消息。如果您愿意,实际上可以关闭警告。只需将以下内容放在文件的顶部:
#nowarn "0020"
如果您试图采用函数式风格,请尽量避免可变值
例如:
let nr =
let rec compute nr =
if checkMod nr then nr else compute (nr + 20)
compute 0
let multi20 = Seq.initInfinite (fun i -> i*20)
let compute = multi20 |> Seq.find checkMod
由于我可以想象这个weg页面将成为查找有关警告FS0020信息的“标准”场所,下面是我对三种最常见的警告情况的快速总结,以及如何修复它们
故意丢弃仅因副作用而调用的函数的结果:
// you are calling a function for its side-effects, intend to ignore result
let Example1Orig() =
let sb = new System.Text.StringBuilder()
sb.Append("hi") // warning FS0020
sb.Append(" there") // warning FS0020
sb.ToString()
let Example1Fixed() =
let sb = new System.Text.StringBuilder()
sb.Append("hi") |> ignore
sb.Append(" there") |> ignore
sb.ToString()
// the warning is telling you useful info
// (e.g. function does not have an effect, rather returns a value)
let Example2Orig() =
let l = [1;2;3]
List.map (fun x -> x * 2) l // warning FS0020
printfn "doubled list is %A" l
let Example2Fixed() =
let l = [1;2;3]
let result = List.map (fun x -> x * 2) l
printfn "doubled list is %A" result
// '=' versus '<-'
let Example3Orig() =
let mutable x = 3
x = x + 1 // warning FS0020
printfn "%d" x
let Example3Fixed() =
let mutable x = 3
x <- x + 1
printfn "%d" x
警告很有用,指出错误(函数无效):
// you are calling a function for its side-effects, intend to ignore result
let Example1Orig() =
let sb = new System.Text.StringBuilder()
sb.Append("hi") // warning FS0020
sb.Append(" there") // warning FS0020
sb.ToString()
let Example1Fixed() =
let sb = new System.Text.StringBuilder()
sb.Append("hi") |> ignore
sb.Append(" there") |> ignore
sb.ToString()
// the warning is telling you useful info
// (e.g. function does not have an effect, rather returns a value)
let Example2Orig() =
let l = [1;2;3]
List.map (fun x -> x * 2) l // warning FS0020
printfn "doubled list is %A" l
let Example2Fixed() =
let l = [1;2;3]
let result = List.map (fun x -> x * 2) l
printfn "doubled list is %A" result
// '=' versus '<-'
let Example3Orig() =
let mutable x = 3
x = x + 1 // warning FS0020
printfn "%d" x
let Example3Fixed() =
let mutable x = 3
x <- x + 1
printfn "%d" x
混淆赋值运算符和相等比较运算符:
// you are calling a function for its side-effects, intend to ignore result
let Example1Orig() =
let sb = new System.Text.StringBuilder()
sb.Append("hi") // warning FS0020
sb.Append(" there") // warning FS0020
sb.ToString()
let Example1Fixed() =
let sb = new System.Text.StringBuilder()
sb.Append("hi") |> ignore
sb.Append(" there") |> ignore
sb.ToString()
// the warning is telling you useful info
// (e.g. function does not have an effect, rather returns a value)
let Example2Orig() =
let l = [1;2;3]
List.map (fun x -> x * 2) l // warning FS0020
printfn "doubled list is %A" l
let Example2Fixed() =
let l = [1;2;3]
let result = List.map (fun x -> x * 2) l
printfn "doubled list is %A" result
// '=' versus '<-'
let Example3Orig() =
let mutable x = 3
x = x + 1 // warning FS0020
printfn "%d" x
let Example3Fixed() =
let mutable x = 3
x <- x + 1
printfn "%d" x
/'='与'我已经用命令式编程很长时间了,所以习惯函数式编程的思维方式需要一段时间
在您的示例中,您试图找到通过checkMod测试的20个中的第一个倍数。这就是为什么。对于功能如何部分,我建议浏览序列可用的方法。您需要的是通过测试的序列的第一个元素(20的倍数),如下所示:
let nr =
let rec compute nr =
if checkMod nr then nr else compute (nr + 20)
compute 0
let multi20 = Seq.initInfinite (fun i -> i*20)
let compute = multi20 |> Seq.find checkMod
第一个let生成一个无限多的二十个元素的列表(我自己编的)。第二个let在所述列表中找到通过测试的第一个数字。您的任务是确保确实有一个数字将通过测试,但对于命令式代码来说,这当然也是正确的
如果你想把上面的两行压缩成一行,你也可以写
let computeCryptic = Seq.initInfinite ((*) 20) |> Seq.find checkMod
但我发现,在代码中使用这样的特技可能会在几周后试图阅读时导致头痛。与Brian的帖子一样,这里有另一种获得警告FS0020的方法:简而言之,我无意中对函数参数进行了双重设置
作为一名F#新手,我在调试下面的代码时遇到了困难,第二行(让gdp…)给出了警告FS0020:这个表达式应该有'unit'类型,但有'string->^a->unit)*string*float'类型。事实证明,线路根本不是问题;相反,是printfn行出错了。从参数列表中删除逗号分隔符修复了此问题
for country in wb.Regions.``Arab World``.Countries do
let gdp = country.Indicators.``GDP per capita (current US$)``.[2010]
let gdpThous = gdp / 1.0e3
printfn "%s, %s (%.2f)" country.Name, country.CapitalCity, gdpThous
谢谢,这就解决了问题,真不敢相信我在盯着它看了这么久之后错过了:)我的目标是学习函数式编程风格,但没有多少时间来学习,这是一个非常缓慢的过程。是的,很公平。函数式编程对以前只使用命令式语言(例如C/C#/Java)的程序员来说常常是一个巨大的冲击。它需要一种完全不同的思维方式,这种思维方式可以随着时间的推移而学习。但F#的一个好处是,你可以从熟悉的编码风格(基本的)开始在仍然高效的情况下,您可以编写命令式代码,这一事实使您可以优化代码的一小部分,而不必使用其他语言。@gradbot:没错-虽然只有当a)所有功能等价物(通常至少有几个)效率较低时才应该如此,在这种情况下,效率/绩效非常重要@詹姆斯·胡加德:这是一个公平的观点,尽管我倾向于建议直接进入功能性的东西,强迫自己以适当的方式思考是最有用的。至少为我工作过。:)获得此错误的另一种刺激方法是忘记破折号:x