Reputation: 61
Just started learning F#, and I am attempting to generate and evaluate the first 10 terms of the Taylor series for e. I originally wrote this code to calculate it:
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 (+)
Which leads to an error because the **
operator does not work for int
.
Obviously I need to cast everything to float
in order for everything to work correctly. So:
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 (+)
Which yields the compiler error:
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'
(Line 9 is where let term n = (e ** n) / (fact n)
is).
Why does this not work? What does this error mean exactly, anyway? Why does the compiler care that I'm passing a function which yields float
and not an actual float
value? Note that I just started learning F# so I am not familiar with why this won't work in this case.
Upvotes: 5
Views: 1395
Reputation: 10947
You are mixing two types of syntax to define the fact
function.
When using the function
keyword, it implicitly adds an argument, which is then used in the defined branches. If you check the signature of your fact
definition, you will see float -> float -> float
instead of float -> float
. The first float in your definition corresponds to n
, the second one is added by the fact you use the function
keyword.
You can use either the function keyword
let fact = function
| 0.0 -> 1.0
| n -> [1.0 .. n] |> List.reduce (*)
or an explicit match expression (compiler will be able to infer the type of n
as float
, no need to specify it manually)
let fact n =
match n with
| 0.0 -> 1.0
| _ -> [1.0 .. n] |> List.reduce (*)
A side note, even though it will not be a practical problem in this case, comparing floats against exact values is generally not a good idea due to their binary representation. In your case it might make sense to keep fact
operating on integers and then cast the result:
let term n = (e ** n) / (float (fact (int n))) // assumes fact : int -> int
Upvotes: 8