2015-10-24 122 views

回答

14

type聲明類型同義詞。類型同義詞是現有類型的新名稱。例如,這是多麼String定義in the standard library

type String = [Char] 

String是爲Char的List的另一個名稱。 GHC將在編譯時用[Char]替換程序中的所有用法String

要清楚,String字面上是列表Char s。這只是一個別名。您可以使用String值的所有標準列表功能:

-- length :: [a] -> Int 
ghci> length "haskell" 
7 
-- reverse :: [a] -> [a] 
ghci> reverse "functional" 
"lanoitcnuf" 

data聲明一個新的數據類型,它不像一個類型的同義詞,是不同於其他任何類型的不同。數據類型有多個構造函數定義您的類型的可能情況。例如,這是多麼Bool定義in the standard library

data Bool = False | True 

Bool值可以是TrueFalse。數據類型支持模式匹配,允許您對數據類型的值執行運行時案例分析。

yesno :: Bool -> String 
yesno True = "yes" 
yesno False = "no" 

data類型可以有多個構造(與Bool),可以由其它類型的進行參數設置,可以包含在其內部其他類型,並且可以遞歸指自己。這裏有一個例外的模型來證明這一點。一個Error a包含類型爲a的錯誤消息,並可能導致錯誤消息。

data Error a = Error { value :: a, cause :: Maybe Error } 
type ErrorWithMessage = Error String 

myError1, myError2 :: ErrorWithMessage 
myError1 = Error "woops" Nothing 
myError2 = Error "myError1 was thrown" (Just myError1) 

重要的是要認識到,data聲明瞭一個新類型,是除了系統中的任何其它類型很重要。如果String已被聲明爲data類型包含列表Char(而不是類型同義詞),您將無法使用任何列表功能。

data String = MkString [Char] 
myString = MkString ['h', 'e', 'l', 'l', 'o'] 
myReversedString = reverse myString -- type error 

還有一個更有多種類型聲明:newtype。這很像一個data聲明 - 它引入了一種獨立於任何其他類型的新數據類型,並且可以進行模式匹配 - 除了您僅限於具有單個字段的單個構造函數。換句話說,newtype是一個data類型,它包裝了一個現有的類型。

重要的區別在於成本newtype:編譯器承諾newtype以與其包裝類型相同的方式表示。打包或解包newtype沒有運行時間成本。這使得newtype可用於制定管理(而不是結構)值之間的區別。

newtype s與類型類很好地交互。例如,考慮Monoid,這是一種將元素(mappend)和特殊「空」元素(mempty)組合在一起的類型類。 Int可以通過多種方式製作爲Monoid,包括加0和加1.我們如何選擇哪一個用於IntMonoid實例?最好不要表達偏好,並使用newtype s來啓用或不使用運行時成本。複述the standard library

-- introduce a type Sum with a constructor Sum which wraps an Int, and an extractor getSum which gives you back the Int 
newtype Sum = Sum { getSum :: Int } 
instance Monoid Sum where 
    (Sum x) `mappend` (Sum y) = Sum (x + y) 
    mempty = Sum 0 

newtype Product = Product { getProduct :: Int } 
instance Monoid Product where 
    (Product x) `mappend` (Product y) = Product (x * y) 
    mempty = Product 1 
1

隨着data創建數據類型和聲明構造它:

data NewData = NewDataConstructor 

隨着type定義只是一個別名:

type MyChar = Char 

type情況下,你可以傳遞的價值MyChar類型功能期望Char,反之亦然,但您不能這樣做data MyChar = MyChar Char

2

type作品就像let:它允許你給一個可重複使用的名字的東西,但事情總是工作一樣,如果你有內聯的定義。所以

type ℝ = Double 

f :: ℝ -> ℝ -> ℝ 
f x y = let x2 = x^2 
     in x2 + y 

行爲完全相同的方式一樣

f' :: Double -> Double -> Double 
f' x y = x^2 + y 

如:你可以在你的代碼的任何地方與f',反之亦然更換f;沒有什麼會改變。

OTOH,均爲datanewtype創建不透明抽象。它們更像是一個OO中的類構造函數:即使一些值是實施僅僅根據單個數字,它不一定行爲就像這樣一個數字。例如,

newtype Logscaledℝ = LogScaledℝ { getLogscaled :: Double } 

instance Num LogScaledℝ where 
    LogScaledℝ a + LogScaledℝ b = LogScaledℝ $ a*b 
    LogScaledℝ a - LogScaledℝ b = LogScaledℝ $ a/b 
    LogScaledℝ a * LogScaledℝ b = LogScaledℝ $ a**b 

這裏,雖然Logscaledℝ數據是明智的仍然只是一個Double數,它清楚地表現從Double不同。

相關問題