赋值:这个表达式应该有类型 unit

Assignment: this expression was expected to have the type unit

我正在写一些非常简单的东西,一个找到 int 的所有因子的程序。这是我的

let factor n=
  let ls=[]
  for i=1 to n do
    if i % n =0 then ls = i::ls
  l

如果我这样做,它会弹出一个错误 This expression was expected to have the type unit。但我试图在 if..then.. 之后放置一个打印内容的表达式,假设为 return 类型单元,但它仍然给出相同的错误。我对此迷路了。有人可以帮忙吗?谢谢

=是比较,不是赋值。你想要

let factor n =
    let mutable ls = []
    for i = 1 to n do
        if n % i = 0 then ls <- i::ls
    ls

let factor n =
    let ls = ref []
    for i = 1 to n do
        if n % i = 0 then ls := i::(!ls)
    !ls

但是请注意,这两种解决方案都非常单一,因为对于这个问题有同样简单的不可变解决方案。

您正试图将 ls 变成一个可变变量并用 = 赋值给它。虽然这是可能的,但通过使用 mutable (1) or ref (2)<-:= 赋值运算符,这在函数世界中通常是不鼓励的。
朴素算法的一个可能更惯用的实现可能是:

let factor n =
    let rec factorLoop curr divs =
        if curr > n then divs
        else
            if n % curr = 0
            then factorLoop (curr+1) (curr::divs)
            else factorLoop (curr+1) divs
    factorLoop 1 [] |> List.rev

> factor 12;;
val it : int list = [1; 2; 3; 4; 6; 12]

这里的 main 函数定义了一个递归的内部 factorLoop 函数。递归是我们可以避免在函数式语言中多次使用可变变量的方法。递归内部函数沿着 curr 变量线程化,该变量是要测试的当前除数和当前找到的除数列表 divs。结果包括 1n。这可以分别通过改变curr的初始值和factorLoop.

第一行的终止条件来改变。

值得注意的是,利用F#库可以全部缩减为一行:

let factor n =
    [1..n] |> List.filter (fun x -> n % x = 0)

这里我们构建一个值列表 1..n 并将它们提供给 List.filter,后者将给定的谓词(在行尾)应用于 select 上的除数 n。但是,如果 n 很大,临时列表将变得非常大。我们可以使用惰性评估序列来代替,这不会影响内存使用:

let factor n =
    {1..n} |> Seq.filter (fun x -> n % x = 0) |> Seq.toList

这里我们过滤 'lazy' 序列,只将(小得多的)结果序列转换为末尾的列表:

> factor 10000000;;
val it : int list =
  [1; 2; 4; 5; 8; 10; 16; 20; 25; 32; ... etc