2010-02-22 43 views
11

代碼的這個特定部分的目的是使size函數比簡單計算elems中的所有元素更有效。我已經解決了總結構成列表的兩種類型,但我似乎無法創建大小函數的簽名。如何匹配類型「任一b」?

instance (Finite a, Finite b) => Finite (Either a b) where 
    elems = combineLists [Left x | x <- elems] [Right x | x <-elems] 
    size ??? = (size a) + (size b) 

從前奏,我們知道Either a b = Left a | Right b

我嘗試的第一件事是匹配Either,但它當然是一種類型,所以這是行不通的。接下來,我試過((Left a) | (Right b)),但是沒有繼續。沒有其他東西似乎與Either a b類型匹配。

我能得到size (Left a)編譯,但由於它缺少b成分,我收到錯誤:

Ambiguous type variable `b' in the constraint: 
    `Finite b' arising from a use of `size' at <interactive>:1:0-12 

這當然是有道理的背景下,但我真的不知道如何匹配Either a b

有人有什麼想法嗎?

+1

您似乎對類型和構造函數之間的區別有點困惑。 「一個b」是一個帶有兩個構造函數的類型,「左」和「右」。類型進入類型簽名,而構造函數進入代碼。這是一個常見的混淆,因爲很多類型使用相同的名稱作爲類型和構造函數,如「data Foo = Foo Int String」;第一個「Foo」是類型,而第二個是構造函數。 – 2010-02-25 20:17:03

回答

25

Either a b類型的東西要麼是Left a或​​,所以你有兩種情況可以分別進行處理:

size (Left x) = size x 
size (Right x) = size x 

關於曖昧類型變量的錯誤是另外一個問題。 如果您只是在解釋器中輸入類似size (Left 1)的東西,則系統無法推斷出該值的「正確」類型。它可以是Either Int anything,只要不知道anything是什麼類型,則不能檢查它是否在Finite(這是size所要求的)類中。

您可以通過指定一個明確的類型簽名避免這樣的問題:

size (Left 1 :: Either Int String) 
0

麻煩似乎是,你需要爲size僞參數,但你不能傳遞假人兩種類型ab在一個單一的Either a b。也許你可以使用elems獲得每種類型的虛擬:

size _ = (size . head) (elems :: [a]) + (size . head) (elems :: [b]) 
0

我以爲你是核心問題是要表示相互兩種類型的在同一時間一個數據類型。 Either a b只能在給定時間爲ab之一。

同時代表ab的簡單數據類型是2元組。這樣的事情的類型簽名是(a, b),這也是創建一個表達式,因此模式MACHING之一:

> :type (4,5) 
(4,5) :: (Num t, Num t1) => (t, t1) 
> let f (a, b) = 2*a + b 
> f (4,5) 
13 

你應該考慮用2元組寫你的第一線,像這樣:

instance (Finite a, Finite b) => Finite (a, b) where 

這是什麼Finite (a, b)代表什麼?成員函數定義是什麼?

+0

其實我已經寫過這個定義,它是a和b的產物,創建了所有a到b的映射 – Fry 2010-02-22 17:03:02