F#:警告FS0020:这个表达式应该有'unit'类型,但是类型'bool'

时间:2009-07-10 10:42:41

标签: 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

当我这样做时,我收到错误消息警告FS0020:此表达式应该具有类型“unit”,但在表达式“nr&lt; - nr +20”上具有类型“bool”。我已经尝试重写和移动表达式,我总是在while语句下面的行上得到错误。

我是用VS2010测试版写的。

6 个答案:

答案 0 :(得分:12)

因为我可以想象这个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    

答案 1 :(得分:10)

以下一行:

f = checkMod nr

是一个相等检查,而不是我认为你打算的任务。将其更改为:

f <- checkMod nr

一切都应该正常。我不确定为什么你在前一行使用了正确的语法而不是那行......

此外,行while f = false do应该真正简化为while not f do;对布尔值的平等检查相当复杂。

正如我所说,我觉得有必要指出你是否有效地尝试使用F#作为命令式语言。在函数式语言(包括F#)中强烈建议不要使用可变变量和while循环,特别是当存在纯函数(和更简单)的解决方案时,就像在这种情况下一样。我建议你阅读一下功能风格的编程。当然,掌握语法本身就是一件有用的事情。

答案 2 :(得分:1)

如果您尝试采用功能样式,请尝试避免使用可变值。

例如:

let nr =
   let rec compute nr =  
      if checkMod nr then nr else compute (nr + 20)
   compute 0     

答案 3 :(得分:0)

如果你来自命令式语言,F#中的{p> while expressions需要一点点习惯。 while表达式中的每一行必须计算为unit(从C ++ / C#中考虑void)。然后整体表达式也评估为unit

在示例中:

nr <- nr + 20

评估为unit

f = checkMod nr

评估为bool,注明Noldorin。这会导致报告警告消息。如果您愿意,您实际上可以关闭警告。只需将以下内容放在文件的顶部:

#nowarn "0020"

答案 4 :(得分:0)

我长期以编程方式编程,所以习惯编程功能需要一段时间。

在您的示例中,您试图找到通过checkMod测试的20的第一个倍数。那是什么部分。对于功能如何部分,我建议浏览序列可用的方法。您需要的是通过测试的序列的第一个元素(20的倍数),如下所示:

let multi20 = Seq.initInfinite (fun i -> i*20)
let compute = multi20 |> Seq.find checkMod

第一个让我们生成一个无限的二十字形列表(我把它做了一个)。第二个让我们找到通过测试的列表中的第一个数字。你的任务是确保实际上有一个数字可以通过测试,但对于命令式代码来说当然也是如此。

如果你想将上面两行压缩成一行,你也可以写

let computeCryptic = Seq.initInfinite ((*) 20) |> Seq.find checkMod

但我发现在几周后尝试阅读时,在代码中拉动这样的特技会导致头痛。

答案 5 :(得分:0)

与Brian的帖子一样,这是另一种获得警告的方法FS0020:简而言之,我不小心弄乱了函数参数。

作为一个F#新手,我很难调试下面的代码,对于第二行(让gdp ...)发出警告FS0020:这个表达式应该有&#39; unit&#39;,但是有类型&#39;(字符串 - &gt; ^ a - &gt;单位)*字符串*浮动&#39;。事实证明,线路根本不是问题;相反,它是打印出来的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