2017-02-17 17 views
5

Только что начал изучать F #, и я пытаюсь генерировать и оценивать первые 10 членов серии Тейлора для e. Изначально я писал этот код, чтобы вычислить его:Тип «float -> float» не соответствует типу «float»

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

Up-голосования, потому что я не вижу никаких причин, почему кто-то вниз проголосовали его даже не дав комментарий, чтобы объяснить, почему , –

ответ

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 
+1

до тех пор, пока аргументы для 'fact' достаточно малы, чтобы не создавать переполнение ... – Onur