不同的是,在fact
,你在一個算術表達式,構成了最終的結果直接使用參數:
fact n | ... = n * ...
督察,如果你寫出來的擴展算術表達式,n
出現在它:
fact 3 ≡ n * (n-1) * (n-2) * 1
這可修復參數必須具有相同類型的結果,因爲
(*) :: Num n => n -> n -> n
並非如此在fib
:這裏的實際結果只是由文字和sub-結果。 IOW,擴大表情看起來像
fib 3 ≡ (1 + 1) + 1
沒有n
在這裏,所以爭論和結果需要之間沒有統一。
當然,在這兩種情況下,您還使用n
來決定這個算術表達式的外觀,但是因爲您剛剛使用了文字的相等比較,而文字的類型並未連接到最終結果。
請注意,您也可以提供fib
類型預處理簽名:(Eq a, Num a, Num t) => a -> t
嚴格比(Eq t, Num t) => t -> t
更一般。相反,你可以通過一個轉換功能之後它使一個fact
不需要輸入和輸出是相同類型,:
fact' :: (Eq a, Integral a, Num t) => a -> t
fact' = fromIntegral . fact
這沒有很大的意義,但因爲Integer
幾乎是唯一可以在fact
中可靠使用的類型,但要達到上述版本,您需要從Integer
開始。因此,如果有的話,你應該做到以下幾點:
fact'' :: (Eq t, Integral a, Num t) => a -> t
fact'' = fact . fromIntegral
這可以被也被用來作爲Int -> Integer
,這是有點明智的。
我會推薦雖然只保留簽名(Eq t, Num t) => t -> t
雖然,並只在實際需要添加轉換操作。或者真的,我推薦根本不使用fact
- 這是一個非常昂貴的功能,在實踐中幾乎沒有什麼實際用處;大多數應用程序天真地結束了一個階乘,實際上只需要類似binomial coefficients,並且這些應用程序可以在沒有階乘的情況下更高效地實現。
因爲您不在輸出中使用輸入參數。 –
對不起,我沒有完全明白你的意思。 @WillemVanOnsem – James