刚开始学习F#,我正在尝试为 e 生成和评估泰勒系列的前10个术语。我最初写这个代码来计算它:
let fact n = function
| 0 -> 1
| _ -> [1 .. n] |> List.reduce (*)
let taylor e =
let term n = (e ** n) / (fact n)
[1 .. 10]
|> List.map (term)
|> List.reduce (+)
由于**
运算符不适用于int
,因此会导致错误。
显然,我需要将所有内容都转换为float
,以便一切正常运行。所以:
let fact (n: float) = function
| 0.0 -> 1.0
| _ -> [1.0 .. n] |> List.reduce (*)
let taylor (e: float) =
let term (n: float) = (e ** n) / (fact n)
[1.0 .. 10.0]
|> List.map (term)
|> List.reduce (+)
产生编译器错误:
EvaluatingEtotheX.fs(9,39): error FS0001: The type 'float -> float' does not match the type
'float'
EvaluatingEtotheX.fs(9,36): error FS0043: The type 'float -> float' does not match the type
'float'
(第9行是let term n = (e ** n) / (fact n)
所在的位置。)
为什么这不起作用?无论如何,这个错误究竟意味着什么?为什么编译器关心我传递了一个产生float
而不是实际float
值的函数?请注意,我刚开始学习F#,所以我不熟悉为什么在这种情况下不能工作。
答案 0 :(得分:8)
您正在混合使用两种语法来定义fact
函数。
使用function
关键字时,它会隐式添加一个参数,然后在定义的分支中使用。如果您检查fact
定义的签名,则会看到float -> float -> float
而不是float -> float
。您定义中的第一个浮点数对应n
,第二个浮点数是您使用function
关键字添加的。
您可以使用函数关键字
let fact = function
| 0.0 -> 1.0
| n -> [1.0 .. n] |> List.reduce (*)
或显式匹配表达式(编译器将能够将n
的类型推断为float
,无需手动指定)
let fact n =
match n with
| 0.0 -> 1.0
| _ -> [1.0 .. n] |> List.reduce (*)
旁注,即使在这种情况下它不是一个实际问题,将浮点数与精确值进行比较通常不是一个好主意,因为它们的二进制表示。在你的情况下,让fact
对整数进行操作然后转换结果可能是有意义的:
let term n = (e ** n) / (float (fact (int n))) // assumes fact : int -> int