2010-07-12 54 views
4

爲了把握更好的類型類(首發幾乎從零開始的形式),我在模型2-d的形狀一展身手與面積計算,像這樣:類型類和模塊如何交互?

module TwoDShapes where 

class TwoDShape s where 
    area :: s -> Float 

data Circle = Circle Float deriving Show 
aCircle radius | radius < 0 = error "circle radius must be non-negative" 
       | otherwise = Circle radius 
instance TwoDShape Circle where 
    area (Circle radius) = pi * radius * radius 

data Ellipse = Ellipse Float Float deriving Show 
anEllipse axis_a axis_b | axis_a < 0 || axis_b < 0 = error "ellipse axis length must be non-negative" 
         | otherwise    = Ellipse axis_a axis_b 
instance TwoDShape Ellipse where   
    area (Ellipse axis_a axis_b) = pi * axis_a * axis_b 

等了其他種類的形狀。

這是不錯,但它發生,我試試這個:

module TwoDShapes where 

class TwoDShape s where 
    area :: s -> Float 

data TwoDShapeParams = TwoDShapeParams Float Float Float deriving Show 

instance TwoDShape TwoDShapeParams where 
    area (TwoDShapeParams length_a length_b constant) = foldl (*) 1 [length_a, length_b, constant] 

aCircle radius | radius < 0 = error "circle radius must be non-negative" 
       | otherwise = TwoDShapeParams radius radius pi 

anEllipse axis_a axis_b | axis_a < 0 || axis_b < 0 = error "ellipse axis length must be non-negative" 
         | otherwise    = TwoDShapeParams axis_a axis_b pi 

等,這也未嘗不可。隨着信息化的目標隱藏我改變模塊聲明看起來像這樣:

module TwoDShapes (TwoDShape, area, aCircle, anEllipse, aRectangle, aTriangle) 

稍微讓我驚訝這1)工程和2)在ghci中aCircle計算爲TwoDShapeParams 1.0 1.0 3.1415927這是事實,但我不明白TwoDShapeParams如何在模塊外部可見。我不確定我期待的是什麼,但不是這個。

我真的很喜歡typeclass,它的方法和「聰明的構造函數」是可見的模塊外,沒有別的。可以這樣做嗎?

回答

6

雖然TwoDShapes表示是隱藏的,你已經推導出它Show實例,它允許TwoDShapes類型的任意值被轉換成一個String,所以這是信息泄漏源。一個真正抽象的類型不應該定義一個Show實例,或者實際上同樣暴露有關該表示的信息的實例。只要String與表示無關(請參閱Data.Map.MapData.Array.ArrayShow實例以瞭解此示例),就可以將其轉換爲String

請注意,模塊系統正在完成其工作:您仍然無法參照定義它的模塊外部的TwoDShapes構造函數。

+0

我感到驚訝(我沒有在這臺計算機上安裝Haskell編譯器,所以無法檢查會發生什麼)是,'aCircle'可以在所有非導出類型'TwoDShapeParams' (不是它的值構造函數)出現在它的類型中。 – 2010-07-12 12:06:26

+0

您編寫了'Module TwoDShapes(TwoDShape,...',它輸出* type *'TwoDShape',但不是它的表示。但是,即使你沒有導出類型,你仍然可以導出一個類型爲「TwoDShape」的函數,否則你就無法在其他地方引用'TwoDShape'。 Haskell模塊系統控制標識符的可見性,這就是它的全部功能。 – 2010-07-12 13:17:10

+0

我不是問題的作者:) – 2010-07-12 13:37:38

1

如果在ghci的提示看*TwoDShapes,它可以在模塊中獲得的一切:

http://www.haskell.org/ghc/docs/6.12.1/html/users_guide/interactive-evaluation.html

新的提示是*主,這表明我們的背景下鍵入表達式主模塊的頂層。在我們剛剛加載的模塊Main中的頂層範圍內的所有東西也都在提示符的範圍內(可能包括Prelude,只要Main沒有明確隱藏它)。

語法*模塊表明它是模塊的完整頂級範圍,它有助於提示處鍵入的表達式的範圍。如果沒有*,只能看到模塊的輸出。

嘗試加載TwoDShapes沒有*和檢查aCircle的類型是什麼。