2013-08-05 71 views
4

我剛剛在Haskell開始編程,而我解決99 Haskell problems,當我幾乎與10日一樣,我以前遇到過這樣的問題:爲什麼Integral約束需要從整體調用長度?

-- Exercise 9 
pack :: Eq a => [a] -> [[a]] 
pack [] = [] 
pack list = let (left,right) = span (== head list) list in 
      left : pack right 

-- Exercise 10   
encode :: (Eq a, Integral c) => [a] -> [(c, a)] 
encode [] = [] 
encode list = map (\x -> (length x, head x)) (pack list) 
-- this doesn't work  ^^^^^^^^ 

產生的錯誤告訴我,

Could not deduce (c ~ Int) 
from the context (Eq a, Integral c) 
    bound by the type signature for 
      encode :: (Eq a, Integral c) => [a] -> [(c, a)] 
    at C:\fakepath\ex.hs:6:11-47 
    `c' is a rigid type variable bound by 
     the type signature for 
     encode :: (Eq a, Integral c) => [a] -> [(c, a)] 
     at C:\fakepath\ex.hs:6:11 
In the return type of a call of `length' 
In the expression: length x 
In the expression: (length x, head x) 

我已經設法通過插入我已閱讀過的函數來解決這個問題Learn you a HaskellfromIntegral

encode list = map (\x -> (fromIntegral $ length x, head x)) (pack list) 

所以,我的問題是,的是,爲什麼需要

我運行了:t length並得到了[a] -> Int,這對我來說是一個相當定義的類型,它應該滿足Integral c約束條件。

+1

只是一個提示:我不認爲你需要'encode [] = []'case,因爲'pack [] = []'和'map _ [] = []'。 –

回答

9

類型簽名(Eq a, Integral c) => [a] -> [(c, a)]表示該功能適用​​於任何類型在適當的類型類ac。使用的實際類型在呼叫站點指定。

舉一個簡單的例子,讓我們來看看空單類型:

:t [] 
[a] 

這意味着是[]代表String空列表,以及Int空單,空單Maybe [Maybe Bool]和任何其他類型,你可以想象。我們可以想象在一個正常的標識包裝的:

empty :: [a] 
empty = [] 

empty明顯的工作方式爲[]相同。所以,你可以看到下面的定義將毫無意義:

empty :: [a] 
empty = [True] 

畢竟[True]永遠是你想要一個[Int][String]或任何其他空列表。

這裏的想法是一樣的,除了我們對變量也有類型類型約束。例如,您可以使用encode返回[(Integer, String)]列表,因爲Integer也位於Integral類中。

因此,你必須返回一些多態性,可能是任何Integral - 正是fromIntegral做什麼。如果您剛剛返回Int,encode只能用作Int而不是任何Integral

+0

很好的答案,謝謝!然而,你是否願意在這裏解決我最後的擔憂:「我應該把它放在'fromIntegral'中,還是應該簡單地將它指定爲encode ::(Eq a)=> [a] - > [(Int,a )]'* *現在我知道了*,這兩種方法看起來都不錯,但我會親自傾向於更簡單的'Int'。 –

+2

我會保留'fromIntegral' - 我發現處理'Int'並定期地施加煩人。另一種選擇是使用'Data.List'中的'genericLength'。 –

相關問題