user7578060
user7578060

Reputation: 61

The type 'float -> float' does not match the type 'float'

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

Answers (1)

Honza Brestan
Honza Brestan

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

Related Questions