[英]How can two similar functions have different polymorphic types in Haskell?
我幾乎是Haskell的新手,所以如果我缺少關鍵概念,請指出。
讓我們說我們有這兩個功能:
fact n
| n == 0 = 1
| n > 0 = n * (fact (n - 1))
fact
的多態類型是(Eq t, Num t) => t -> t
因為n
在if條件中使用,n必須是有效類型才能進行==
檢查。 因此t
必須是Number
並且t
可以是類約束Eq t
的任何類型
fib n
| n == 1 = 1
| n == 2 = 1
| n > 2 = fib (n - 1) + fib (n - 2)
那么為什么多晶型的fib
是(Eq a, Num a, Num t) => a -> t
?
我不明白,請幫忙。
Haskell總是旨在推導出最通用的類型簽名。
fact
,我們知道輸出的類型應該與輸入的類型相同:
fact n | n == 0 = 1
| n > 0 = n * (fact (n - 1))
這是由於最后一行。 我們使用n * (fact (n-1))
。 所以我們使用乘法(*) :: a -> a -> a
。 因此乘法采用相同類型的兩個成員並返回該類型的成員。 由於我們乘以n
,並且輸入n
,因此輸出與輸入的類型相同。 由於我們使用n == 0
,我們知道(==) :: Eq a => a -> a -> Bool
,這意味着該輸入類型應該具有Eq a =>
,而且0 :: Num a => a
。 所以結果類型是fact :: (Num a, Eq a) => a -> a
。
現在對於fib
,我們看到:
fib n | n == 1 = 1
| n == 2 = 1
| n > 2 = fib (n - 1) + fib (n - 2)
現在我們知道對於n
,類型約束又是Eq a, Num a
,因為我們使用n == 1
和(==) :: Eq a => a -> a -> Bool
和1 :: Num a => a
。 但輸入n
從不直接用於輸出 。 實際上,最后一行有fib (n-1) + fib (n-2)
,但在這里我們使用n-1
和n-2
作為新調用的輸入 。 這意味着我們可以安全地假設輸入類型和輸出類型獨立地起作用。 輸出類型仍然有一個類型約束: Num t
:這是因為前兩個情況返回1
,而1 :: Num t => t
,我們還返回兩個輸出: fib (n-1) + fib (n-2)
,所以再次(+) :: Num t => t -> t -> t
。
不同之處在於, fact
,您直接在算術表達式中使用參數,該算術表達式構成最終結果:
fact n | ... = n * ...
IOW,如果你寫出擴展的算術表達式, n
出現在其中:
fact 3 ≡ n * (n-1) * (n-2) * 1
這修復了參數必須與結果具有相同類型的原因,因為
(*) :: Num n => n -> n -> n
在fib
不是這樣:這里實際結果只包含文字和子結果 。 IOW,擴展的表達式看起來像
fib 3 ≡ (1 + 1) + 1
這里沒有n
,因此參數和結果之間不需要統一。
當然,在這兩種情況下,你還使用n
來決定這個算術表達式的外觀,但為此你剛剛使用了與文字相等的比較,其類型沒有與最終結果相關聯。
請注意,您也可以給fib
一個類型preservig簽名: (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
- 這是一個非常昂貴的功能,在實踐中幾乎沒有用過; 大多數天真地以階乘結束的應用程序實際上只需要像二項式系數那樣的東西,並且這些應用程序可以在沒有因子的情況下更有效地實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.