2014-04-04 71 views
-1
let rec calcTotalMonths ~moneyOwed:moneyOwed ~interestRate:interestRate ~monthlyPayment:monthlyPayment ~months:months=0 = ( 
    let newBalance = (moneyOwed -. monthlyPayment) *. interestRate in 
    match newBalance <= 0. with 
    true -> months 
    | false -> calcTotalMonths newBalance interestRate monthlyPayment months+1 
);; 

我想知道爲什麼我一直得到不明白返回類型

File "budget.ml", line 19, characters 12-73: 
Error: This expression has type 
     moneyOwed:float -> 
     interestRate:float -> monthlyPayment:float -> months:'a -> 'b 

爲什麼幾個月類型「一當它清楚地使用‘+’操作符上幾個月。它也會在遞歸的基本情況下返回幾個月,所以它爲什麼是'b'作爲返回類型。

編輯: 做傑夫的建議

File "budget.ml", line 19, characters 12-77: 
Error: This expression has type 
     moneyOwed:float -> 
     interestRate:float -> monthlyPayment:float -> months:int -> 'a 
     but an expression was expected of type int 

回答

2

移動可選參數在調用點前和使用標籤:

let rec calcTotalMonths ?(months=0) ~moneyOwed ~interestRate ~monthlyPayment = 
    let newBalance = (moneyOwed -. monthlyPayment) *. interestRate in 
    if newBalance <= 0.0 then 
    months 
    else 
    calcTotalMonths 
     ~months:(months + 1) 
     ~moneyOwed:newBalance 
     ~interestRate 
     ~monthlyPayment 

注意,這裏使用了一些簡寫標記參數:~argname:argname可以只用~argname所取代。將可選參數從最後一個位置移開是爲了避免標記參數系統的不幸的一面:有關詳細信息,請參見the manual's description of optional arguments

看着這個,我覺得你只打算使用calcTotalMonths內的months參數,並且該參數的可選性存在將它從外部調用者隱藏的可能性。如果是這樣,這不是很好的風格。一個更好的做法是嵌套函數來處理循環:

let calcTotalMonths ~moneyOwed ~interestRate ~monthlyPayment = 
    let rec loop months balance = 
    let newBalance = (balance -. monthlyPayment) *. interestRate in 
    if newBalance <= 0.0 then months 
    else loop (months + 1) newBalance in 
    loop 0 moneyOwed 

(忽略,如果你真的需要的參數。)

3

你不適用+到幾個月後,你把它應用到的calcTotalMonths結果。函數應用比中綴運算符具有更高的優先級。

(calcTotalMonths newBalance interestRate monthlyPayment months) + 1 

你應該這樣寫::

,如果你寫這個表達式解釋

calcTotalMonths newBalance interestRate monthlyPayment (months + 1) 

更新

它看起來像你想months是一個可選參數的默認值爲0.定義方式如下所示:

? (months = 0) 

注意:拖尾可選參數不是一個好的形式,因爲它會導致部分應用函數的問題。

更新2

最後,如果你想調用已標記的論點,但沒有提供標籤,你只能提供非可選參數的函數。這對您不起作用,因爲您需要在遞歸調用中提供月份。如果你在遞歸調用中提供了所有的標籤,我認爲事情會起作用。

更新3

對於它的價值(適量),這裏是我會怎麼寫這個功能。除非他們正在解決嚴重的問題,否則我不使用標記或可選參數。另外,我覺得一個輔助功能是一種更好的方式來處理迭代次數(月):(我只注意到GSG還展示瞭如何使用一個輔助功能)

let monthsUntilPaid owed interest payment = 
    let rec go balance months = 
     let balance' = (balance -. payment) *. interest in 
     if balance' <= 0.0 then months else go balance' (months + 1) 
    in 
    go owed 0 

+1

所以這次修復上個類型的問題,但對於整個返回類型的功能? –