2012-10-19 64 views
5

這裏是我的問題:哈斯克爾:有限制等級的元素列表

這個完美的作品:

type Asdf = [Integer] 
type ListOfAsdf = [Asdf] 

現在我想要做相同,但與積分限制等級:

type Asdf2 a = (Integral a) => [a] 
type ListOfAsdf2 = (Integral a) => [Asdf2 a] 

我得到這個錯誤:

Illegal polymorphic or qualified type: Asdf2 a 
Perhaps you intended to use -XImpredicativeTypes 
In the type synonym declaration for `ListOfAsdf2' 

我已經嘗試了很多東西,但我仍然無法使用上述的類限制創建類型。

在此先感謝! =)

戴克

+0

'ListOfAsdf2'也需要一個類型參數。 '輸入ListOfAsdf2 a =整數a => [Asdf2 a]'。 –

+0

我也試過,但是我得到了同樣的錯誤.. =( – dak

+0

是的,你需要'ImpredicativeTypes',就像編譯器說的那樣。但實際上,你不需要type參數 –

回答

5

咆哮對反Existentionallists

我總是喜歡在Haskell抗存在類型的談話,因爲我常常覺得有用existentials。例如,在一些快速檢查測試中,我也有類似的代碼(諷刺的是未經測試的代碼如下):

data TestOp = forall a. Testable a => T String a 

tests :: [TestOp] 
tests = [T "propOne:" someProp1 
     ,T "propTwo:" someProp2 
     ] 

runTests = mapM runTest tests 
runTest (T s a) = putStr s >> quickCheck a 

即使在一些生產代碼一個角落裏,我發現它方便做出的類型我需要一個列表的隨機值:

type R a = Gen -> (a,Gen) 
data RGen = forall a. (Serialize a, Random a) => RGen (R a) 
list = [(b1, str1, random :: RGen (random :: R Type1)) 
     ,(b2, str2, random :: RGen (random :: R Type2)) 
     ] 

回答你的問題

{-# LANGUAGE ExistentialQuantification #-} 
data SomeWrapper = forall a. Integral a => SW a 
5

如果你需要一個背景下,最簡單的辦法是給我們E中的data聲明:

data (Integral a) => IntegralData a = ID [a] 
type ListOfIntegralData a = [IntegralData a] 

*Main> :t [ ID [1234,1234]] 
[ID [1234,1234]] :: Integral a => [IntegralData a] 

這具有確保一個Integral上下文被添加到使用IntegralData數據類型每一個功能的(唯一)的效果。

sumID :: Integral a => IntegralData a -> a 
sumID (ID xs) = sum xs 

主要的原因type同義詞不適合你的工作是類型同義詞被設計成 只是 - 這取代了,不是類型簽名

但是,如果你想要去生存的最好方式是用GADT,因爲它處理爲您的所有量化的問題:

{-# LANGUAGE GADTs #-} 

data IntegralGADT where 
    IG :: Integral a => [a] -> IntegralGADT 
type ListOfIG = [ IntegralGADT ] 

因爲這基本上是一個存在的類型,你可以將它們混合起來:

*Main> :t [IG [1,1,1::Int], IG [234,234::Integer]] 
[IG [1,1,1::Int],IG [234,234::Integer]] :: [ IntegralGADT ] 

根據您的應用,您可能會發現它非常方便。

一個GADT在數據聲明的主要優點是,當你的模式匹配,您隱得到Integral背景:

showPointZero :: IntegralGADT -> String 
showPointZero (IG xs) = show $ (map fromIntegral xs :: [Double]) 

*Main> showPointZero (IG [1,2,3]) 
"[1.0,2.0,3.0]" 

但存在量化有時用於錯誤的原因, (如希望將所有數據混合在一個列表中,因爲這就是您從動態類型語言中習得的 ,而且您還沒有習慣於使用靜態類型及其優點(例如 ))。

這裏我認爲它比它的價值更麻煩,除非你需要需要將不同的 積分類型組合在一起而不轉換它們。我看不到原因 爲什麼這會有所幫助,因爲您在使用它們時必須將其轉換。

例如,你不能定義

unIG (IG xs) = xs 

,因爲它甚至不鍵入檢查。經驗法則:你不能在右邊提到類型a

然而,這是可以的,因爲我們轉換類型a

unIG :: Num b => IntegralGADT -> [b] 
unIG (IG xs) = map fromIntegral xs 

這裏存在量化迫使您將您的數據時,我認爲你原來的計劃是不就得了! 你也可以把所有東西都轉換成Integer而不是這個。

如果你想簡單的事情,讓他們簡單。數據聲明是確保您不會將數據放入數據類型的最簡單方法,除非它已經是某個類型類的成員。